-
-
Save mikejolley/347b8f162257f6736c4d to your computer and use it in GitHub Desktop.
/** | |
* This function loops over cart items, and moves any item with shipping class 'special-class' into a new package. | |
* The new package in this example only takes flat rate shipping. | |
*/ | |
function split_special_shipping_class_items( $packages ) { | |
$found_item = false; | |
$special_class = 'special-class'; // edit this with the slug of your shippig class | |
$new_package = current( $packages ); | |
$new_package['contents'] = array(); | |
$new_package['contents_cost'] = 0; | |
$new_package['applied_coupons'] = array(); | |
$new_package['ship_via'] = array( 'flat_rate' ); // Only allow flat rate for items in special class | |
foreach ( WC()->cart->get_cart() as $item_key => $item ) { | |
// Is the product in the special class? | |
if ( $item['data']->needs_shipping() && $special_class === $item['data']->get_shipping_class() ) { | |
$found_item = true; | |
$new_package['contents'][ $item_key ] = $item; | |
$new_package['contents_cost'] += $item['line_total']; | |
// Remove from original package | |
$packages[0]['contents_cost'] = $packages[0]['contents_cost'] - $item['line_total']; | |
unset( $packages[0]['contents'][ $item_key ] ); | |
// If there are no items left in the previous package, remove it completely. | |
if ( empty( $packages[0]['contents'] ) ) { | |
unset( $packages[0] ); | |
} | |
} | |
} | |
if ( $found_item ) { | |
$packages[] = $new_package; | |
} | |
return $packages; | |
} | |
// Hook into shipping packages filter | |
add_filter( 'woocommerce_cart_shipping_packages', 'split_special_shipping_class_items' ); |
Any idea how I would just hide the shipping, instead of returning new packages ?
Lets say I have a product that only is allowed to pickup. if it's in the cart, I would like to hide all shipping methods and only show Local Pickup.
Kind regards
please tell me how to solve this proble?
I have some products that only is allowed to pickup. if i select it, then I would like to hide all other shipping methods and only show Local Pickup. And when i choose another shipping method then it should show the all shipping methods what i have selected.
thanx
Thank you very much for the codes. Worked perfectly!
However, just as @JimmyAppelt and @progbdb are requesting, would it be possible to hide all the other shipping methods and only show Local Pickup with a custom message like 'Shipping is unavailable for the following products. Store pickup only.'?
Thank you very much!
@ianulpindo @progbdb @JimmeyAppelt
I had the same problem where I wanted to force a flat rate shipping on all products if any one of the products met a certain criteria.
I took the above code and replaced lines 14-30 with the following (and it seems to work ok for me):
foreach ( WC()->cart->get_cart() as $item_key => $item ) {
// Are any products in the special class?
if ( $item['data']->needs_shipping() && $special_class === $item['data']->get_shipping_class() ) {
$found_item = true;
}
}
if($found_item == true){
foreach ( WC()->cart->get_cart() as $item_key => $item ) {
$new_package['contents'][ $item_key ] = $item;
$new_package['contents_cost'] += $item['line_total'];
// Remove from original package
$packages[0]['contents_cost'] = $packages[0]['contents_cost'] - $item['line_total'];
unset( $packages[0]['contents'][ $item_key ] );
// If there are no items left in the previous package, remove it completely.
if ( empty( $packages[0]['contents'] ) ) {
unset( $packages[0] );
}
}
}
The code works beautifully, thank you! Is it possible to limit the splitting of packages by country? We ship to 4 countries. We want to split items into multiple packages for only one of these countries. Not all 4. Is there any way to have this code work for the one country and not the other 3?
Thanks again.
I wan't items that match to be free shipping. But regardless what slug i'm using it always say, no shipping method available. Except 'flat_rate'.
Edit: ok it's not free shipping to all countries only to one. So I wanted to use advanced_free_shipping. I need this because the weight gets counted on the whole order if the items are not excluded from package.
Hi! Works great in isolation but when I combine it with another snippet, it doesn’t work and I have no clue why (I’m a php rookie). The code I’m talking about can be found here: https://www.xadapter.com/hide-checkout-fields-based-selected-shipping-method/
I use the code on this github page disable the ‘local pickup’ shipping method from my product. What I end up with are 2 different flat rate shipping methods called ‘flat_rate:9’ end ‘flat_rate:10’. I then use the other code (see link above) to remove the checkout fields for only the ‘flat_rate:10’ shipping method. When I insert this shipping method in this other code (as $shipping_method), the checkout fields are removed regardless of the shipping method selected. When I insert ‘flat_rate:9’, no checkout fields get removed regardless of the shipping method selected. I don’t know why this happens but when I remove the code from this github page, everything works fine. Could anyone help me to find the problem and make these two snippets compatible? I'm guessing it has something to do with how shipping class items are split into a new package that doesn't play nice with the other code...
Hi works great when you are just trying to split the packages up. Im running into issues when im trying to get the sorted products back into the regular items.
I need help with writing code to offer partial free shipping. These are my requirements and product A and product B are the products in the cart
Product A = FREE SHIPPING WHEN 25.00 or more of the product is in the cart or when product B is in the cart
Product B = FLAT RATE SHIPPING ONLY
@progbdb and @JimmyAppelt even if the answer comes quite late. Maybe some people are still interested if you stumble across this article. I use the function of @mikejolley and have added some more functions and overrides.
Here I create the new package for "local_pickup".
/**
* This function loops over cart items, and moves any item with shipping class 'special-class' into a new package.
* The new package only takes local pickup.
*/
function split_special_shipping_class_items( $packages ) {
$found_item = false;
$special_class = 'special-class'; // edit this with the slug of your local pickup shippig class
$new_package = current( $packages );
$new_package['contents'] = array();
$new_package['contents_cost'] = 0;
$new_package['applied_coupons'] = array();
$new_package['ship_via'] = array( 'local_pickup' ); // Only allow local pickup for items in special class
foreach ( WC()->cart->get_cart() as $item_key => $item ) {
// Is the product in the special class?
if ( $item['data']->needs_shipping() && $special_class === $item['data']->get_shipping_class() ) {
$new_package['name'] = 'PickUp'; // your custom label for this package
$found_item = true;
$new_package['contents'][ $item_key ] = $item;
$new_package['contents_cost'] += $item['line_total'];
// Remove from original package
$packages[0]['contents_cost'] = $packages[0]['contents_cost'] - $item['line_total'];
unset( $packages[0]['contents'][ $item_key ] );
// If there are no items left in the previous package, remove it completely.
if ( empty( $packages[0]['contents'] ) ) {
unset( $packages[0] );
}
}
}
if ( $found_item ) {
$packages[] = $new_package;
}
return $packages;
}
function rename_custom_package( $package_name, $i, $package ) {
if ( ! empty( $package['name'] ) ) {
$package_name = $package['name'];
}
return $package_name;
}
@TomLuijts
Hide the Local PickUp option for the package being shipped.
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// HERE define your shipping class to find
$class = 77;
// HERE define the shipping methods you want to hide
$method_key_ids = array('local_pickup:8', 'local_pickup:9');
// Checking in cart items
foreach( $package['contents'] as $item ) {
// If we find the shipping class
if( $item['data']->get_shipping_class_id() == $class ){
foreach( $method_key_ids as $method_key_id ){
unset($rates[$method_key_id]); // Remove the targeted methods
}
break; // Stop the loop
}
}
return $rates;
}
The following lines must be added so that the changes can also be displayed.
// hook into shipping packages filter
add_filter( 'woocommerce_cart_shipping_packages', 'split_special_shipping_class_items' );
// output the new package name
add_filter( 'woocommerce_shipping_package_name', 'rename_custom_package', 10, 3 );
// hide local pickup on dropshipping items
add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
I myself have specified the delivery time and have a message displayed during the checkout, which refers to the Local PickUp articles.
Thanks again to all who contributed directly and indirectly to the code like @dvelopit and @mikejolley .
A picture as it looks like and lines of code you find in my git https://github.com/Crytix/Woocommerce-Local-PickUp-and-Shipping-Split
@prunly - You are a champion! Worked perfectly - thanks for your help :)