Waving off or discounting the shipping cost of a product, if certain other product is present in the cart

In this article, I will explain the solution to calculate shipping cost.

Requirement : let’s begin the fun

  • If the user has ordered products only from product category “bulky”, each line item in the cart should be charged a delivery fee. These products cannot be mixed and require multiple deliveries.
  • If the user has ordered products only from product category “small”, only one line item in the cart should be charged a delivery fee. These are small products that are delivered together and should only be charged delivery for one item.
  • If the user has ordered products from product category “small” and “bulky” together, then all products from “bulky” category should be charged a delivery fee and all the products from category “small” should be shipped free.  small products can be delivered along with “bulky” products without additional cost.

Any guess how can we achieve this without touching the shipping method which calculates the shipping cost per line item?

First clue for you:

From WooCommerce 2.1 its possible to multiple packages and shipping method’s will calculate the shipping cost for each package separately.

Did you solve it? Second clue for you:

This also provides a flexibility to enforce shipping method on the particular package.

Exactly you can split the packages into the second package.

Code to achieve the same

add_filter( 'woocommerce_cart_shipping_packages', 'wf_category_package_split_packages' );

function wf_category_package_split_packages( $packages ) {
$packages = array();$bulky_items = array();$regular_items = array();$free_items = array();
$cost_items = array();

foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->needs_shipping() ) {
if ( wf_category_package_is_bulk_category($item['data']->id)) {
$bulky_items[] = $item;
} else {
$regular_items[] = $item;
}}}

if(!empty($bulky_items) && !empty($regular_items)){
//if both bulky and regular items available then entire regular items goes to Free shipping
$free_items = $regular_items;
$cost_items = $bulky_items;
}
elseif(empty($bulky_items) && !empty($regular_items) && count($regular_items) > 1)
{
//Except one regular item every thing else will be free shipping
$cost_items[] = array_shift($regular_items);
$free_items = $regular_items;
}
else
$cost_items = array_merge($bulky_items, $regular_items);

// Put inside packages
if ( $cost_items ) {
$packages[] = array(
'ship_via' => array( 'distance_rate_shipping' ),
'contents' => $cost_items,
'contents_cost' => array_sum( wp_list_pluck( $cost_items, 'line_total' ) ),
'applied_coupons' => WC()->cart->applied_coupons,
'destination' => array(
'country' => WC()->customer->get_shipping_country(),
'state' => WC()->customer->get_shipping_state(),
'postcode' => WC()->customer->get_shipping_postcode(),
'city' => WC()->customer->get_shipping_city(),
'address' => WC()->customer->get_shipping_address(),
'address_2' => WC()->customer->get_shipping_address_2()));
}
if ( $free_items ) {
$packages[] = array(
'ship_via' => array( 'free_shipping' ),
'contents' => $free_items,
'contents_cost' => array_sum( wp_list_pluck( $free_items, 'line_total' ) ),
'applied_coupons' => WC()->cart->applied_coupons,
'destination' => array(
'country' => WC()->customer->get_shipping_country(),
'state' => WC()->customer->get_shipping_state(),
'postcode' => WC()->customer->get_shipping_postcode(),
'city' => WC()->customer->get_shipping_city(),
'address' => WC()->customer->get_shipping_address(),
'address_2' => WC()->customer->get_shipping_address_2()));
}
return $packages;
}

Cart view after package split

Cart

Cart

Heavy item is packaged as Shipping Method#1 and calculated shipping cost. And small item packaged separate and free shipping.

Check out WooCommerce Shipping Plugins Store

Comments (2)

  • Sam

    How would you make this work with shipping classes instead of product categories?

    I have shipping class “no-free-shipping” that I need to charge for while the rest of the order ships free.

    Thanks in advance!

    April 28, 2017 at 8:25 am

Leave a Reply