Unsetting WooCommerce shipping method based on cart items shipping classes - php

I’m trying to unset Flat Rate shipping method only if cart has products both with and without shipping class. If all product in cart have shipping class then it should stay.
Have this shipping method: Flat Rate - (flat_rate1) (instance_id=1)
And these shipping classes: 50, 100 and so on, with same way named Slugs: 50, 100…
Flat Rate shipping method has costs set up for these shipping classes, Main Cost and No shipping class cost for this method are not set, so it only appears for products in cart that have shipping classes set.
Got it working
add_filter( 'woocommerce_package_rates', 'unset_shipping_for_unmatched_items', 100, 2 );
function unset_shipping_for_unmatched_items( $rates, $package ) {
// Initialisation
$shipping_classes = array( 50, 100, 150, 200, 250, 300 );
$cart_items = WC()->cart->get_cart();
$cart_items_count = WC()->cart->get_cart_contents_count();
$items_match = false;
$inArray = 0;
$notInArray = 0;
foreach( $cart_items as $cart_item ){
if( in_array( $cart_item[ 'data' ]->get_shipping_class(), $shipping_classes ) && $cart_items_count > 1 ) {
$inArray++;
} else {
$notInArray++;
}
}
if( ( $cart_items_count == $notInArray ) || ( $cart_items_count == $inArray ) ){
$items_match = false;
} else {
$items_match = true;
}
if( $items_match )
unset( $rates['flat_rate:6'] );
return $rates;
}

In WooCommerce the shipping methods ID slugs are a little different, I mean there is a typo error. You will need to add : between the name and the number in the slug: 'flat_rate6'.
Also once you get a matching cart item shipping class, you can break the loop.
Last thing: This hook has 2 available arguments: $rates and $package.
So your code will be:
add_filter( 'woocommerce_package_rates', 'hide_shipping_when_class_is_in_cart', 100, 2 );
function hide_shipping_when_class_is_in_cart( $rates, $package ) {
// Initialisation
$shipping_classes = array( 50, 100, 150, 200, 250, 300 );
$class_exists = false;
foreach( WC()->cart->get_cart() as $cart_item )
if( in_array( $cart_item[ 'data' ]->get_shipping_class_id(), $shipping_classes ) ) {
$class_exists = true;
break; // Stop the loop
}
if( $class_exists )
unset( $rates['flat_rate:6'] );
return $rates;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This should work now.

Related

How can I change the shipping class to flat shipping? (woocommerce)

I'm working on hiding free shipping when there is a fixed price shipping amount based on certain products. This code is working and after certain sum is also disabled. But I want this to work with flat shipping conditional, not post class conditional.
I want it: if ( isset( $rates['flat_rate:1'] ) )
But it works: if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target )
add_filter( 'woocommerce_package_rates', 'bbloomer_hide_free_shipping_for_shipping_class', 9999, 2 );
function bbloomer_hide_free_shipping_for_shipping_class( $rates, $package ) {
$shipping_class_target = 261; // shipping class ID (to find it, see screenshot below)
$subtotal = WC()->cart->get_subtotal();
$in_cart = false;
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
if ( $values[ 'data' ]->get_shipping_class_id() == $shipping_class_target && $subtotal <= 299 ) {
$in_cart = true;
break;
}
}
if ( $in_cart ) {
unset( $rates['free_shipping:2'] ); // shipping method with ID (to find it, see screenshot below)
}
return $rates;
}

Hide some shipping rates based on taxonomy terms in WooCommerce 4.8+

I use this to unset shipping for product with specific tag:
function specific_products_shipping_methods( $rates, $package ){
// etiquette cocolis
$terms = array( 'cocolis' );
$taxonomy = 'product_tag';
foreach( $package['contents'] as $cart_item ) {
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) )
{
unset( $rates['oik_weight_zone_shipping_49'] );
unset( $rates['chrono10'] );
unset( $rates['chrono13'] );
add_filter('woocommerce_shipping_chosen_method', 'reset_default_shipping_method', 10, 2);
}
}
return $rates;
}
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function reset_default_shipping_method( $method, $available_methods ) {
$default_method = 'per_product';
if( array_key_exists($method, $available_methods ) )
return $default_method;
else
return $method;
}
This works fine until update woo 4.8.0
Any idea what’s wrong ?
Thx,
There are some mistakes in your code, try the following revisited and optimized code instead:
add_filter( 'woocommerce_package_rates', 'specific_products_shipping_methods', 10, 2 );
function specific_products_shipping_methods( $rates, $package ){
$terms = array('cocolis'); // Array of term slugs, names or ids
$taxonomy = 'product_tag'; // WooCommerce product tag taxonomy
$rate_keys = array('oik_weight_zone_shipping_49', 'chrono10', 'chrono13'); // Shipping rates to be hidden
$has_unset = false; // Initializing
// Loop through cart items for the current shipping package
foreach( $package['contents'] as $cart_item ) {
// Targeting specific product tags
if ( has_term( $terms, $taxonomy, $cart_item['product_id'] ) ) {
// Loop through shipping rates to be removed (hidden)
foreach( $rate_keys as $rate_key ) {
if (isset($rates[$rate_key]) ) {
unset($rates[$rate_key]);
$has_unset = true; // Flag as unset to enable the filter below
}
}
}
}
if ( $has_unset ) {
add_filter('woocommerce_shipping_chosen_method', 'reset_default_shipping_method', 10, 3 );
}
return $rates;
}
function reset_default_shipping_method( $default, $rates, $chosen_method ) {
$targeted_method = 'per_product'; // The shipping method rate to set as chosen one
if( isset($rates[$targeted_method]) ) {
$default = $targeted_method;
}
return $default;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works in WooCommerce 4.8+.
Don't forget to empty your cart to refresh WooCommerce shipping caches
Note: For WooCommerce categories, define the $taxonomy variable to product_cat instead.

Hide Flat Rate shipping exclusively for a product category in Woocommerce

This is an extension of this question: Remove shipping Flat Rate method for particular Category in WooCommerce 2.6 and 3+
Used the Woo Smart Coupons plugin for a Gift Card product. This HAS to be set to Variation, as we have multiple tiers to select from. (this rules out virtual products) The Gift Card has it's own category for distinction. We have two shipping options set up: Flat Rate + Local Pickup. It's pretty silly to have shipping options for a gift card that gets sent to your Inbox, so I used the following snippet found in the link above:
add_filter( 'woocommerce_package_rates', 'conditional_hide_shipping_methods', 100, 2 );
function conditional_hide_shipping_methods( $rates, $package ){
// Define/replace here your correct category slug (!)
$product_category = 'coupons-gift-cards';
$prod_cat = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( $product_category, 'product_cat', $product_id ) ){
$prod_cat = true;
}
}
$rates_arr = array();
if ( $prod_cat ) {
foreach($rates as $key => $rate) {
if ('free_shipping' === $rate->method_id || 'local_pickup' === $rate->method_id || 'local_delivery' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
break;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
Works like a charm... until you add a product that ISN'T from that category. If someone decides that they want a Gift Card AND a normal product, then the regular shipping options need to be back in place.
EDIT: The checked answer works perfectly! If you want to change the Pickup Label for items like the above situation so they say something like "Download" instead of "Pickup", then add this line after the IF statement that checks which products are matching the categories
foreach( $rates as $rate_key => $rate ) {
//change local_pickup:1 to your shipping method
if ( 'local_pickup:1' == $rate_key){
//set the text for the label
$rates[$rate_key]->label = __( 'Download', 'woocommerce' );
}
}
Here is the correct way to make it work for a unique and exclusive product category, that will hide Flat rate exclusively if there is no others products remaining to this product category:
add_filter( 'woocommerce_package_rates', 'hide_shipping_flat_rate_conditionaly', 90, 2 );
function hide_shipping_flat_rate_conditionaly( $rates, $package ){
// HERE Define your product category (ID, slug or name or an array of values)
$term = 'coupons-gift-cards';
$others = $found = false;
foreach ( WC()->cart->get_cart() as $cart_item ) {
$product_id = $cart_item['product_id'];
if ( has_term( $term, 'product_cat', $cart_item['product_id'] ) )
$found = true;
else
$others = true;
}
if ( $found && ! $others ) {
foreach($rates as $rate_id => $rate) {
if ('flat_rate' === $rate->method_id )
unset($rates[ $rate_id ]);
}
}
return $rates;
}
Code goes on function.php file of your active child theme (or active theme).
This code is tested and fully functional (it will work if you have correctly set your shipping zones).
You might need to refresh shipping cached data: disable, save and enable, save related shipping methods for the current shipping zone, in Woocommerce shipping settings.

Hide shipping methods based on products categories in Woocommerce

With Woocommerce, I would like to hide all shipping methods except "Local pickup" when a defined products category is in cart…
The code below does that for other product types, except variable products:
add_filter( 'woocommerce_package_rates', 'custom_shipping_methods', 100, 2 );
function custom_shipping_methods( $rates, $package ){
// Define/replace here your correct category slug (!)
$cat_slug = 'my_category_slug';
$prod_cat = false;
// Going through each item in cart to see if there is anyone of your category
foreach ( WC()->cart->get_cart() as $values ) {
$product = $values['data'];
// compatibility with WC +3
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
if ( has_term( $cat_slug, 'product_cat', $product_id ) )
$prod_cat = true;
}
$rates_arr = array();
if ( $prod_cat ) {
foreach($rates as $rate_id => $rate) { // <== There was a mistake here
if ('local_pickup' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
What can I do to make it work for variable products too? Any help is appreciated.
I have revisited your code and here is correct way to make it work for variable products too:
add_filter( 'woocommerce_package_rates', 'product_category_hide_shipping_methods', 90, 2 );
function product_category_hide_shipping_methods( $rates, $package ){
// HERE set your product categories in the array (IDs, slugs or names)
$categories = array( 'clothing');
$found = false;
// Loop through each cart item Checking for the defined product categories
foreach( $package['contents'] as $cart_item ) {
if ( has_term( $categories, 'product_cat', $cart_item['product_id'] ) ){
$found = true;
break;
}
}
$rates_arr = array();
if ( $found ) {
foreach($rates as $rate_id => $rate) {
if ('local_pickup' === $rate->method_id) {
$rates_arr[ $rate_id ] = $rate;
}
}
}
return !empty( $rates_arr ) ? $rates_arr : $rates;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
You should need to refresh the shipping caches:
1) First this code is already saved on your function.php file.
2) In Shipping settings, enter in a Shipping Zone and disable a Shipping Method and "save". Then re-enable that Shipping Method and "save". You are done.

Programmatically remove specific shipping method - WooCommerce

I need to remove my UPS shipping methods on the cart and checkout pages after the cart weight surpasses 150lbs. This is along the lines of what I'm thinking...
function is_it_over_onefifty($available_methods){
global $woocommerce;
if ($woocommerce->cart->cart_contents_weight > 150){
//diable shipping
unset( $available_methods['ups'] );
}
else{
//do nothing
}
return $available_methods;
}
add_filter( 'woocommerce_available_shipping_methods', 'is_it_over_onefifty', 10, 1);
add_filter( 'woocommerce_package_rates', 'define_default_shipping_method', 10, 2 );
function define_default_shipping_method( $rates, $package ) {
// Only unset rates if free_shipping is available
if ( isset( $rates['free_shipping:8'] ) ) {
unset( $rates['flat_rate:4'] );
}
return $rates;
}
I had started with a comment, but it became too large.
Below is some solid example code that will get you going where you need to. Note the idea is taken from here: http://www.bolderelements.net/support/knowledgebase/hide-shipping-method-based-on-weight/
add_filter( 'woocommerce_package_rates', 'hide_shipping_weight_based', 10, 2 );
function hide_shipping_weight_based( $rates, $package ) {
// if you don't know what the rates are, you can uncomment below to see all the rates that are available
// var_dump( $rates );
// Set weight variable
$cart_weight = 0;
// Shipping rate to be excluded
$shipping_type = 'ups_';
// Calculate cart's total
foreach( WC()->cart->cart_contents as $key => $value) {
$cart_weight += $value['data']->weight * $value['quantity'];
}
// only if the weight is over 150lbs find / remove specific carrier
if( $cart_weight > 150 ) {
// loop through all of the available rates
foreach( $rates AS $id => $data ) {
// if the rate id starts with "ups_"
if ( 0 === stripos( $id, $shipping_type ) ) {
unset( $rates[ $id ] ); // remove it
}
}
}
return $rates;
}

Categories