WooCommerce: Split cart items from the same order and ship via multiple shipping methods
First things first :).
Product Vendors is a WordPress plugin which will enable marketplace capabilities for WooCommerce.
The Problem to Solve.
Let me explain about the problem we have faced after turning a WooCommerce store to the marketplace. When the customer adds a number of products from various vendors to the cart, shipping options will be shown common for all those cart items. That is the default way WooCommerce handles it. But, there is a high possibility that customer wants to save some money by opting for a local pickup from Vendor A, who is located in the same area and choose a different shipping method for Vendor B.
Prior to WooCommerce 2.1, this problem was not solvable straight as each order had to be shipped using a single shipping method with a single total price. But, from 2.1 onwards, those cart items can be split and grouped separately as different packages and can be shipped individually by using different shipping methods. These packages can be created by various logical groupings of cart items, as a product vendor, product category, cost, etc.
However, we can focus on how the package can be split into packaging items with respect to each Product Vendor. Before getting into implementation details, you can take a look at the screenshot below this article to see how the shipping section of cart page will look like. after the vendor-wise split of packages.
Each Order is a Package!
Each order is considered as the package from WooCommerce 2.1 onwards. The structure of package object is described below.
ship_via --> Associate shipping method with the package. contents --> Array of cart_contents from WC_Cart object.
Remaining fields are self-explanatory.
//'ship_via' => array( 'flat_rate' ), 'contents' => $vendor_items, 'contents_cost' => array_sum( wp_list_pluck( $vendor_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()
Once items are added to the cart, the package can be filtered using the hook woocommerce_cart_shipping_packages. We will have the package object ready for the split at this point.
add_filter( 'woocommerce_cart_shipping_packages', array( &$this, 'th_woocommerce_cart_shipping_packages') );
Product Vendors plugin allows associating each product with multiple vendors. I am still unsure about the actual benefit of such flexibility. But, for our use case, each product will be only associated with the single vendor.
Below part of the code is specific to Vendor-wise split. Basically, a map will be built, which will have a mapping between Vendor ID and an array of cart items associated with the vendor.
$vendor_items_map = array(); foreach ( WC()->cart->get_cart() as $item ) { $product_id = $item['product_id']; // Get vendors for each product. $vendors = get_product_vendors( $product_id ); if ( $item['data']->needs_shipping() ) { if($vendors) { foreach( $vendors as $vendor ) { // Expecting/assuming there is only one Vendor assigned per product. Hm. $vendor_items_map[$vendor->ID][] = $item; break; } } // No vendor associated with the item. else { $vendor_items_map['0'][] = $item; } } }
Here is the heart of the package split. An array of packages will be built where each index will have a package associated with individual vendor. Each package contents will be associated with the array of items from vendor_items_map. Note that all these items split into packages will be part of the single order.
foreach($vendor_items_map as $key => $vendor_items) { $packages[] = array( //'ship_via' => array( 'flat_rate' ), 'contents' => $vendor_items, 'contents_cost' => array_sum( wp_list_pluck( $vendor_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() ) ); }
The Product Vendor Use Case.
See the below list of items from a cart page. Here, the customer purchased multiple items from various vendors. Travel Box and Jute Bag belongs to Vendor 1 and Red Jacket belongs to Vendor 2. Paint doesn’t belong to any Vendor which is directly sold by marketplace owner.

Cart
And here is how shipping section will look like. Notice the vendor-wise split of shipping options. The customer is free to select desired shipping method for each vendor.
There is a catch here. The labels for each package will be displayed as Shipping #1, Shipping #2, etc. At this point of time (WooCommerce 2.3.4), the product packaging code doesn’t look matured as there is any hook present in the template cart-shipping.php, to replace vendor name instead of currently numbered shipping package labels. But, how in the below screenshot you are able to see vendor names across package labels!? Simple..I have overridden the template cart-shipping in my plugin code and changed it.

Cart Total
Solved!
Go Gist!
Here is the GitHub snippet of complete code for reference.
We have a number of high-quality WooCommerce plugins available at Our Shop.
Comments (26)
Hii
I’m trying to implement it on my website, but with no success.
I need to change the “class a” “class b” or should I leave it as is?
any other idea for why it wouldn’t work?
osawoodart.com
please help me :):)
Thank you!
Hi,
Ideally, you do not need to change anything on this.
Just use the snippet as it is. However, make sure that the product is mapped with the vendor perfectly.
Also, if you are still getting this, just approach us via ticket. Our team will surely help you.
This is a wonderful explanation,but doesnt work if i use yith multi vendore plugin.how can we fix this
Hi, this solution looks really interesting and I wish it would work like a flaw with my theme but somehow it doesn’t. Once I added the code to the functions.php of my theme and when I want to add a product to the shopping cart of my shop it keeps trying to add but it cannot. Can you help me out with this please? Thanks ahead!
Hi,
Can you let us know which plugin are you using?
Hello,
Thanks for your fast response. I am using the Woocommerce Product Vendors as markeplace plugin, for shipping the Flexible Shipping plugin from WP Desk and as shopping cart item counter the Woocommerce Menu Cart plugin. Product Vendors works perfect so I dearly hope, that your code is able to split the orders of future vendors on my marketplace as well. To diplay more clearly what happens with and without the code, I made screen captures:
This is without your code added:
https://www.useloom.com/share/3ff07e8096404b5e86164a9ee9826caa
And this is with your code added:
https://www.useloom.com/share/77fc47740b694ccb9c3368ea2adc87a7
-> I am not able to even add the item to the shopping cart :-/
I have spend hours and hours already on searching for the last three days, but yours seems to be the only ‘non plugin’ solution (which is perfect) for splitting the cart per vendor for Product Vendors so please, please help me out on this- you’re basically my last hope…
Thanks so much!
Hi,
Since you are not using our plugin, we won’t be able to directly check your problem. However, we can guide you to find the cause. When you are using our code, then kindly open the console of the browser once and then check the error. Kindly let me know what are you getting there.
Hi,
sorry, was not aware that you offer a marketplace plugin as well. :-/ This page was the first search result while I was searching for ‘woocommerce product vendors split cart’ so I didn’t think this was related to another plugin. Thus I even more appreciate your support for my problem. 🙂 Here is what shows up in console when trying to add an item to the cart while running your code:
https://www.dropbox.com/s/av0a9jmeu5pkaq6/console.jpg?dl=0
-> I don’t understand a word. :-/ Hope you do.
Thanks!
Can this same logic be used to split the cart up based on different shipping addresses?
I need to ship to different shipping addresses and have th eUPS Print label plugin generate packages base don the addresses selcted during checkout.
Hi Jason,
Unfortunately, we won’t be able to provide such a code snippet. Also we do not have any mechanism to use multiple shipping addresses in our UPS plugin. But if required you can contact your developer and see if its possible to modify this code snippet to your requirements.
Hi
I have WooCommerce v3.1.1 and Woocommerce Product Vendors v2.0.34 (latest versions at time of writing).
I can’t find any trace of the get_product_vendors() method — I’m getting the same error that others have mentioned.
Do you know if it has been deprecated/superseded?
Many thanks
Hi Dave,
You’ll have to install our free plugin Multivendor Addon for the snippet to work,
Here’s the link – https://www.pluginhive.com/advanced-shipping-for-woocommerce-multi-vendor-plugin/
Regards,
Lorenzo
Team Xadapter
Hello!
Please can anyone help me regarding same problem but little difference i explain below.
I have a tour booking woocommerce website.
http://www.freewebmall.com
I want to split the orders from shopping cart when any customer purchase bulk tours from cart and pay once.
He will receive separate email with order#no for each tour not one email and one order no for all tour.
Hi,
Thanks for reaching out to us.
Using the existing plugins this cannot be achieved as our plugins use the existing order completion email from WooCommerce. And as per WooCommerce, this email is generated one per order.
We highly regret the inconvenience. However, this seems to be an interesting feature which our team can take up in future.
I get this error when adding this code to the function.php file
Fatal error: Call to undefined function get_product_vendors
Let me know what I am doing wrong ?
Hi Pradeep,
The function get_product_vendors() is suppplied by WooThemes for their Product Vendor plugin.
It will throw the error if the plugin is not activated or not present in your website.
Kindly check this.
Hi I am trying to Split cart items from different vendors, I have added the snipit above to my functions.php but all I get when I go to a cart is a blank page with just “cart” every thing else is blank??? have I missed something?
I get this error when adding this code to the function.php file
Fatal error: Call to undefined function get_product_vendors
I am using the product vendor plugin and adding it below the theme function.php file guide me if i am doing it wrong.
One more thing i want to add is can i use this code for WC Vendors plugin too ?
Hi Anas,
This code snippet works is not related to the type of multi-vendor plugin.
So it will will work with WC-Vendors too.
Hi Anas,
We regret the problem faced by you.
Kindly raise the issue immediately to our support team. They will surely look into it and help you resolve the problem.
Thanks Besty, very helpful post…
It works only for cart and checkout, can we call it on thank you page or order detail page?
Thank you page or order detail page still display total shipping cost.
After splitting the package, is it possible to create separate order for each package?
Hi Sam,
Thanks for reaching out to us.
Yes, currently, the snippet works on the cart and the checkout page.
For showing it in the thank you page, you need to modify the snippet a little. Taking developer’s help on this is recommended.
Hello Anindo,
Thanks for the update on displaying the package-cost on thank you page,
can you please give me rough idea, how we can do it?
?so i add this code to what file? functions.php
Hi Jason,
Yes, you can add this code to Appereance –> Editor –> functions.php.
And you are done!