Hide shipping methods for some shipping classes in WooCommerce

625 views Asked by At

Basically I'm trying to hide the flat rate shipping method "flat_rate:8" when in the cart there is only specific shipping classes (ID 40 to 46 included). However, when in the cart there is any products with shipping classes 47, 48, 49, I want to hide all other shipping methods except this "flat_rate:8". All the details below.

I have 9 shipping class (from ID 40 to 46): XXS, XS, S, ... L, XL, XXL, XXXL and and 5 shipping methods (flate_rate3, local_pickup, flat_rate6, flat_rate7, flat_rate8).

When in my cart I have:

  • A mix a products and at least one of them is either XL, XXL or XXXL
  • only XL, XXL or XXXL products (one or many)

I only want 2 shipping methods to be offered (local_pickup and flate_rate8). Basically, if any >= XL is in the cart, I only want these two methods to appear. I was able with this code to do these 3 pieces of code:

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
    return;

// HERE define your shipping class to find. 47 = shipping class XL
$class = 47;

// HERE define the shipping methods you want to hide
$method_key_ids = array('flat_rate:3', 'flat_rate:6', 'flat_rate:7');

// 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;
}


add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
    return;

// HERE define your shipping class to find. 48 = shipping class XXL
$class = 48;

// HERE define the shipping methods you want to hide
$method_key_ids = array('flat_rate:3', 'flat_rate:6', 'flat_rate:7');

// 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;
}

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
    return;

// HERE define your shipping class to find. 49 = shipping class XXXL
$class = 49;

// HERE define the shipping methods you want to hide
$method_key_ids = array('flat_rate:3', 'flat_rate:6', 'flat_rate:7');

// 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;
}

This is doing the job, only 2 shipping methods are displayed now (local_pickup and flat_rate8).

Then, what I'm looking to do is:

When in my cart I have:

  • only products with a shipping class of XXXS (id=40), XXS (41), XS (43), S (44), M (45), L (46)

I want to remove flat_rate8 and leave available all the other shipping methods. With the current code and setting, right now, when in my cart I have =< L products, I have all the methods available.

I've been trying to replicate the code shown above to hide this flat_rate8 only with "small" products are in the cart but obviously it won't work because when I have a mix cart (XXXL and S for example) it will remove flat_rate8 from the option.

I tried, in addition to the piece of code show above to add this:

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_classd', 10, 2 );
function hide_shipping_method_based_on_shipping_classd( $rates, $package )
{
    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    foreach( $package['contents'] as $package_item ){ // Look at the shipping class of each item in package

        $product_id = $package_item['product_id']; // Grab product_id
        $_product   = wc_get_product( $product_id ); // Get product info using that id

        if( $_product->get_shipping_class_id() != 47 ){ // If we DON'T find this shipping class ID (XL)
            unset($rates['flat_rate:8']); // Then remove this shipping method
            break; // Stop the loop, since we've already removed the shipping method from this package
        }
    }
    return $rates;
}

But it doesnt work:

  • When I have a XL product (id=47) and a S product in the cart, the flat_rate8 is not visibile (It should be, it's a mix of big and small products)
  • When I have only XL product flat_rate8 is here (it's good)
  • When I have small products (XS, S, M, etc.), flat_rate8 is not here (it's good)

I've been looking around many topics, among them:

But I can't figure out a solution to my issue.

1

There are 1 answers

2
LoicTheAztec On BEST ANSWER

Try the following code, where everything is merged in a unique hooked function:

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package )
{   
    // HERE define your shipping class to find
    $classes_group1 = array(47, 48, 49);
    $classes_group2 = array(40, 41, 43, 44, 45, 46);
    
    // HERE define the shipping methods you want to hide
    $method_key_ids1 = array('flat_rate:3', 'flat_rate:6', 'flat_rate:7');
    $method_key_ids2 = array('flat_rate:8');
    
    $found_group1 = $found_group2 = false; // Initializing
    
    // Checking in cart items
    foreach( $package['contents'] as $item ) {
        $shipping_class = $item['data']->get_shipping_class_id();
        
        // Shipping Classes group 1
        if( in_array( $shipping_class, $classes_group1 ) ){
            foreach( $method_key_ids1 as $method_key_id ){
                // Remove the targeted methods 1
                unset($rates[$method_key_id]); 
                $found_group1 = true; // Flag
            }
        }
        // Shipping Classes group 2
        if( in_array( $shipping_class, $classes_group2 ) ){
            foreach( $method_key_ids2 as $method_key_id ){
                $found_group2 = true; // Flag
            }
        }
        
        // If Shipping Classes group 2 alone in cart
        if( ! $found_group1 && $found_group2 ){
            foreach( $method_key_ids2 as $method_key_id ){
                // Remove the targeted methods 2
                unset($rates[$method_key_id]);
            }
        }
    }
    return $rates;
}

Code goes in functions.php file of the active child theme (or active theme). It should works.

Refresh shipping methods:

  • Empty the cart.
  • If needed, go to shipping areas settings, then disable / save and re-enable / save any shipping methods from a shipping zone.