1

I’m trying to unset two shipping methods only if cart has 4 or less products from a specific shipping class.

Shipping Methods: flat_rate:20 and flat_rate:21

Shipping Class: 182

This is what I have:

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;

    // Shipping Class To Find
    $class = 182;

    // Number Of Shipping Class Items In Cart
    $amount = 4;

    // Shipping Methods To Hide
    $method_key_ids = array('flat_rate:20', 'flat_rate:21');

    // Checking In Cart Items
    foreach( $package['contents'] as $item ) {
        // If We Find The Shipping Class and Number of Items
        if( $item['data']->get_shipping_class_id() == $class && count($package['contents']) <= $amount ){
            foreach( $method_key_ids as $method_key_id ){
                unset($rates[$method_key_id]); // Remove Targeted Methods
            }
            break; // Stop The Loop
        }
    }
    return $rates;
}

I would like to combine the above logic with the below logic:

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class', 10, 2 );
function hide_shipping_method_based_on_shipping_class( $rates, $package ) {
    $targeted_class_ids = array(182); // Shipping Class To Find
    $allowed_max_qty    = 4; // Max allowed quantity for the shipping class
    $shipping_rates_ids = array( // Shipping Method rates Ids To Hide
        'wf_shipping_ups:07',
        'wf_shipping_ups:08',
        'wf_shipping_ups:11',
        'wf_shipping_ups:54',
        'wf_shipping_ups:65',
        'wf_shipping_ups:70',
        'wf_shipping_ups:74',
        'free_shipping:2',
        'request_shipping_quote'
    );
    
    $related_total_qty  = 0;

    // Checking cart items for current package
    foreach( $package['contents'] as $key => $cart_item ) {
        if( in_array( $cart_item['data']->get_shipping_class_id(), $targeted_class_ids ) ){
            $related_total_qty += $cart_item['quantity'];
        }
    }
    
    // When total allowed quantity is more than allowed (for items from defined shipping classes)
    if ( $related_total_qty > $allowed_max_qty ) {
        // Hide related defined shipping methods
        foreach( $shipping_rates_ids as $shipping_rate_id ) {
            if( isset($rates[$shipping_rate_id]) ) {
                unset($rates[$shipping_rate_id]); // Remove Targeted Methods
            }
        }
    }
    return $rates;
}

To create the following logic:

1. If cart has 4 or less products in shipping class 181 unset the following shipping methods:

  • 'flat_rate:20'
  • 'flat_rate:21'

2. If cart has 5 or more products in shipping class 181 unset the following shipping method:

  • 'wf_shipping_ups:07'
  • 'wf_shipping_ups:08'
  • 'wf_shipping_ups:11'
  • 'wf_shipping_ups:54'
  • 'wf_shipping_ups:65'
  • 'wf_shipping_ups:70'
  • 'wf_shipping_ups:74'
  • 'free_shipping:2'
  • 'request_shipping_quote'

Both codes work if I use them individually. But I get an error when I try to use both concurrently.

I get the following error: Cannot redeclare hide_shipping_method_based_on_shipping_class() (previously declared in /functions.php:272)

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399

2 Answers2

2

You should use different function names for each code snippet, but the best way is to merge everything in a unique function.

Here is the way to make it work in a unique function (for items from specific shipping method(s)):

  • hiding some shipping methods when there are 4 or less items in cart
  • hiding some other shipping methods when there are 4 or less items in cart

The code:

add_filter( 'woocommerce_package_rates', 'show_hide_shipping_methods_based_on_shipping_class', 10, 2 );
function show_hide_shipping_methods_based_on_shipping_class( $rates, $package ) {
    $targeted_class_ids  = array(182); // Shipping Class To Find
    
    $allowed_max_qty     = 4; // Max allowed quantity for the shipping class
    
    $shipping_rates_ids1 = array( // Shipping Method rates Ids To Hide if more than 4 items are in cart
        'wf_shipping_ups:07',
        'wf_shipping_ups:08',
        'wf_shipping_ups:11',
        'wf_shipping_ups:54',
        'wf_shipping_ups:65',
        'wf_shipping_ups:70',
        'wf_shipping_ups:74',
        'free_shipping:2',
        'request_shipping_quote',
    );
    
    $shipping_rates_ids2 = array( // Shipping Method rates Ids to Hide if 4 or less items are in cart
        'flat_rate:20',
        'flat_rate:20',
    );
    
    $related_total_qty   = 0; // Initializing

    // Checking cart items for current package
    foreach( $package['contents'] as $key => $cart_item ) {
        if( in_array( $cart_item['data']->get_shipping_class_id(), $targeted_class_ids ) ){
            $related_total_qty += $cart_item['quantity'];
        }
    }
    
    // When total allowed quantity is more than allowed (for items from defined shipping classes)
    if ( $related_total_qty > $allowed_max_qty ) {
        // Hide related defined shipping methods (more than 4 items)
        foreach( $shipping_rates_ids1 as $shipping_rate_id ) {
            if( isset($rates[$shipping_rate_id]) ) {
                unset($rates[$shipping_rate_id]); // Remove Targeted Methods
            }
        }
    } else {
        // Hide related defined shipping methods (4 or less items)
        foreach( $shipping_rates_ids2 as $shipping_rate_id ) {
            if( isset($rates[$shipping_rate_id]) ) {
                unset($rates[$shipping_rate_id]); // Remove Targeted Methods
            }
        }
    }
    return $rates;
}

Code goes in functions.php file of your active child theme (or active theme). Untested it should works.

Refresh the shipping caches:

  1. This code is already saved on your functions.php file.
  2. In a shipping zone settings, disable / save any shipping method, then enable back / save.

    You are done and you can test it.

Handling number of items instead of items cumulated quantity:

Replace:

$related_total_qty += $cart_item['quantity'];

by

$related_total_qty++;
LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • This works very well. The only issue I'm having is that this code is now interfering with the plugin that disables shipping methods based on shipping classes. It seems that this code is taking priority over the plugin. So what I'll have to do is get rid of the plugin and write code manually to achieve my goal. Thanks again for sharing this solution with me. – Wanderlust Consulting Aug 23 '20 at 13:15
0

I assume you've combined those two code snippet by writing them one after another.

As you've used same function name twice, you got that error: Cannot redeclare.....

So, you can try to fix it by renaming the function name of the 2nd snippet like this -

add_filter( 'woocommerce_package_rates', 'hide_shipping_method_based_on_shipping_class_logic_2', 10, 2 );
function hide_shipping_method_based_on_shipping_class_logic_2( $rates, $package ) {
    // other stuffs
}
Jahanggir Jaman
  • 181
  • 1
  • 3