Search code examples
phpwoocommercecartshipping-methodquantities

Increase shipping cost by items quantity on WooCommerce split shipping packages


I use the following code to split items into separate WooCommerce shipping packages:

add_filter( 'woocommerce_cart_shipping_packages', 'split_shipping_packages_by_shipping_class' );
 
function split_shipping_packages_by_shipping_class( $packages ) {
       
   $destination = $packages[0]['destination'];  
   $user = $packages[0]['user']; 
   $applied_coupons = $packages[0]['applied_coupons'];
   $packages = array();
    
   foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {    
      $key = $cart_item['data']->get_shipping_class_id();
      $packages[$key]['contents'][$cart_item_key] = $cart_item;
   }
    
   foreach ( $packages as $index => $package ) {
      $total = array_sum( wp_list_pluck( $packages[$index]['contents'], 'line_total' ) );
      $packages[$index]['destination'] = $destination;
      $packages[$index]['user'] = $user;
      $packages[$index]['applied_coupons'] = $applied_coupons;
      $packages[$index]['contents_cost'] = $total;
   }
   return $packages;
}

However, I am also trying to split packages that have items with multiple quantity into separate packages too, OR Multiply the shipping rate cost by the quantity.

I tried:

add_filter( 'woocommerce_package_rates', 'shipping_cost_based_on_number_of_items', 10, 2 );
function shipping_cost_based_on_number_of_items( $rates, $package ) {
    $numer_of_items = (int) sizeof($package['contents']);

    // Loop through shipping rates
    foreach ( $rates as $rate_key => $rate ){
            $has_taxes = false;

            // Set the new cost
            $rates[$rate_key]->cost = $rate->cost * $numer_of_items;

            // Taxes rate cost (if enabled)
            foreach ($rates[$rate_key]->taxes as $key => $tax){
                if( $tax > 0 ){
                    // New tax calculated cost
                    $taxes[$key] = $tax * $numer_of_items;
                    $has_taxes = true;
                }
            }
            // Set new taxes cost
            if( $has_taxes )
                $rates[$rate_key]->taxes = $taxes;
       
    }
    return $rates;
}

However, it did not work. From my testing, it seems that it is not properly getting the sum of items quantity in the package, because when I hard code $number_of_items to 2 it works.

Is it possible to modify the above code to achieve this?


Solution

  • To get the shipping package content quantity sum, replace your last function with:

    add_filter( 'woocommerce_package_rates', 'shipping_cost_based_on_number_of_items', 10, 2 );
    function shipping_cost_based_on_number_of_items( $rates, $package ) {
        $contents_qty = (int) array_sum( array_column($package['contents'], 'quantity') );
    
        // Loop through shipping rates
        foreach ( $rates as $rate_key => $rate ){
            if( $rate->cost > 0 ) {
                // Set the new cost
                $rates[$rate_key]->cost = $rate->cost * $contents_qty;
    
                $has_taxes = false; // Initializing
                $taxes     = array(); // Initializing
    
                // Taxes rate cost (if enabled)
                foreach ($rate->taxes as $key => $tax){
                    if( $tax > 0 ){
                        $taxes[$key] = $tax * $contents_qty;
                        $has_taxes = true;
                    }
                }
                // Set new taxes cost array
                if( $has_taxes ) {
                    $rates[$rate_key]->taxes = $taxes;
                }
            }
        }
        return $rates;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work now.

    Important: You will have to empty your cart to refresh shipping methods cache.