Search code examples
phpwordpresswoocommercecartcustom-taxonomy

Count custom taxonomy terms in WooCommerce cart and multiply shipping rates by the number


I'm trying to get the WooCommerce cart calculations to multiply the shipping rates by the number of different custom taxonimies terms in cart.

For example, my custom taxonomy name/slug is 'city'. If there are 3 different product taxonomies terms present (eg. Boston, Washington and New York), the current cart rate should be multiplied by 3.

This is my current code:

add_filter( 'woocommerce_package_rates', 'funkcija');
function funkcija ( $rates ) {
    $cart = WC()->cart;
// here I define the array where custom taxonomies will be saved in the foreach loop
    $mojarray = array();
    // the foreach loop that iterates through cart items and saves every taxonomy term in the array
    foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
        $product_id = $cart_item['product_id'];
       $terms = wp_get_post_terms( $product_id, 'city' );
        $mojarray[] = $terms;
       
    }
//now here the counter is defined, the array is set to contain only unique values of the taxonomies
     $counter = 0;
$noviarray = array_unique($mojarray);
foreach ($noviarray as $value) {
// for each unique taxonomy present in cart, increase the counter by 1
    ++$counter;
    
}
//here the rates totals are taken and multiplied with $counter
   foreach($rates as $key => $rate ) {
        $currenttotal = $rates[$key]->cost;
        $multipliedtotal = $currenttotal * $counter;
        $rates[$key]->cost =  $multipliedtotal;
    }
    
    return $rates;
}

Unfortunately, this code multiplies the rates for every product in the cart. I've gone through the code multiple times and do not understand why it's not working as intended for unique taxonomy terms.

I believe this is testable on any WooCommerce store with any custom taxonomy. Any advice?


Solution

  • Your code contains some mistakes

    • The use of WC()->cart is not necessary, since the woocommerce_package_rates hook contains not 1 but 2 parameters, and from the 2nd, namely $package you can get the necessary information

    • wp_get_post_terms() contains a third parameter, namely $args, so array( 'fields' => 'names' ) has been added

    • Since you currently apply this to all $rates, I added an if condition in my answer where you can specify 1 or more methods. If you don't want this, you can just remove the if condition

    So you get:

    function filter_woocommerce_package_rates( $rates, $package ) {
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return $rates;
    
        // Initialize
        $counter = 0;
        $my_array = array();
    
        // Loop through line items
        foreach ( $package['contents'] as $line_item ) {
            // Get product id
            $product_id = $line_item['product_id'];
    
            // Get terms
            $term_names = wp_get_post_terms( $product_id, 'city', array( 'fields' => 'names' ) );
            
            // Loop through (unique values)
            foreach ( $term_names as $term_name ) {
                // Checks if a value NOT exists in an array
                if ( ! in_array( $term_name, $my_array, true ) ) {
                    // Push one or more elements onto the end of array
                    array_push( $my_array, $term_name );
                }
            }
        }
        
        // Counts all elements in an array
        $counter = count( $my_array );
        
        // Greater than
        if ( $counter > 0 ) {
            // Loop through rates
            foreach ( $rates as $rate_key => $rate ) {
                // Target specific methods, multiple can be added, separated by a comma
                if ( in_array( $rate->method_id, array( 'flat_rate', 'table_rate' ) ) ) {
                    // Get rate cost
                    $cost = $rates[$rate_key]->cost;
                    
                    // Greater than
                    if ( $cost > 0 ) {              
                        // Set rate cost
                        $rates[$rate_key]->cost = $cost * $counter;
                    }
                }
            }
        }
    
        return $rates;
    }
    add_filter( 'woocommerce_package_rates', 'filter_woocommerce_package_rates', 10, 2 );