I also needed to do this and have a workable solution:
First go to functions.php in "Appearance"->"Editor"->"Theme Functions" and add the following code (I highly recommend using a " child theme " first, so you donβt change the theme functions.php ... or you can alternatively create a custom plugin ).
/* Puts items with "free-shipping" shipping class into a different shipping package. */ function free_woocommerce_cart_shipping_packages( $packages ) { // Reset the packages $packages = array(); // Free items $freeshipping_items = array(); $regular_items = array(); // Sort free from regular (replace "free-shipping" below with the shipping class slug you actually use). foreach( WC()->cart->get_cart() as $item ) { if( $item['data']->needs_shipping() ) { if( $item['data']->get_shipping_class() == 'free-shipping' ) { $freeshipping_items[] = $item; } else { $regular_items[] = $item; } } } // Put inside packages: if( $freeshipping_items ) { $packages[] = array( 'ship_via' => array( 'flat_rate' ), 'contents' => $freeshipping_items, 'contents_cost' => array_sum(wp_list_pluck($freeshipping_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( $regular_items ) { $packages[] = array( // 'ship_via' => array( 'usps' ), 'contents' => $regular_items, 'contents_cost' => array_sum(wp_list_pluck($regular_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; } add_filter('woocommerce_cart_shipping_packages', 'free_woocommerce_cart_shipping_packages');
Secondly, go to "Products"->"Shipping Classes" and create a delivery class called " Free Shipping " with a slug called " free-shipping " (the bullet name is what we will bind our custom function to). Then the " Add New Shipping Class ".
Then in your "WooCommerce"->"Settings"->"Shipping"->"Flat Rate" enable the "WooCommerce"->"Settings"->"Shipping"->"Flat Rate" sending and in the " Shipping Class Costs " section put the value " 0.00 " next to the " Free Shipping " class, which we just created. In my case, I also have a " Calculation Type " set to " Per Class ". Then " Save changes ".
Then, finally, in "WooCommerce"->"Settings"->"Shipping"->"Shipping Options" in the " Shipping Methods " section, make sure that " Flat Rate " has a higher " Selection Priority " (in the column of this name) than any other delivery method you use and that it is the last on the list (you can drag to reorder using the menu icon to the left of each option). " Save changes ".
Then edit one of your products that you want to have free shipping, go to " Product Data"->"Shipping " and change the delivery class to " Free Shipping " (the new class you created). Then β Update β this product will save the changes. Then add it to your basket, and also add another item to the basket that has regular non-free delivery.
Test
You should now see that free delivery items receive their own βbatch" delivery line (" Shipping #1 " and " Shipping #2 ") separately from items that should still charge for shipping, even if you have some of them in the basket.
In addition, you can also try a full paid plugin called "Delivery" .
Or this free plugin may also work (no promises).