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?
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 );