Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally Hide WooCommerce Shipping methods based on shipping class

Using WooCommerce v3.2.4 on This site (here) (WP v4.9) and 11 products with the shipping class of Overweight/Oversize that have a flat rate applied to them:
$20 to Canada and $25 to the US.

All other products have flat rate shipping of $10 (Canada) and $15 (US), unless the order is over $100, then free shipping is applied automatically.

My client wants free shipping to be disabled if there are any overweight/oversize items in the cart. The problem is that the cart says there are no shipping methods available when there are a mix of regular and oversize items in the cart, and no shipping methods are applied.

I'm using XAdapter Woocommerce Shipping Table Rate plugin to apply the higher cost to the "Overweight" Shipping Classes.

UPDATE

I deactivated this plugin, as I realized I could just use the WooCommerce Shipping Zone settings to set a flat rate for specific shipping classes. See screenshot below: Flat Rate Settings for one of my shipping zones

I am using some code to:

  • hide the free shipping and flat rates when the "Overweight" Shipping Class exists in the cart
  • hide the "Overweight" Shipping Method if that class does not exist (163 being the id of the Shipping Class)

Here is that code:

add_filter('woocommerce_package_rates', 'wf_hide_shipping_method_based_on_shipping_class', 100, 2);

function wf_hide_shipping_method_based_on_shipping_class($available_shipping_methods, $package){
    $hide_when_shipping_class_exist = array(
        163 => array(
            'flat_rate:1',
            'flat_rate:2',
            'free_shipping:3',
            'free_shipping:5'
        )
    );

    $hide_when_shipping_class_not_exist = array(
        163 => array( 'wf_woocommerce_shipping_pro:overweightoversizeoverweight')
    );

    $shipping_class_in_cart = array();
    foreach(WC()->cart->cart_contents as $key => $values) {
       $shipping_class_in_cart[] = $values['data']->get_shipping_class_id();
    }

    foreach($hide_when_shipping_class_exist as $class_id => $methods) {
        if(in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }

    foreach($hide_when_shipping_class_not_exist as $class_id => $methods) {
        if(!in_array($class_id, $shipping_class_in_cart)){
            foreach($methods as & $current_method) {
                unset($available_shipping_methods[$current_method]);
            }
        }
    }
    return $available_shipping_methods;
}

EDIT

Here is a list of IDs of the rates per shipping zone:

Canada

  • Regular Flat rate | ID: flat_rate:1
  • Free Shipping | ID: free_shipping:3
  • Local Pickup | ID: local_pickup:4

USA

  • Regular Flat rate | ID: flat_rate:2
  • Free Shipping | ID: free_shipping:5
like image 256
The Hatchery Avatar asked Oct 29 '22 23:10

The Hatchery


1 Answers

UPDATE 2: (Without any plugin need, just settings and code)

The function below will always show "Local pickup" shipping for canada and will:

  1. Hide free shipping methods when "Oversize" shipping class is in cart items. For the "Flat rate" Shipping Methods, the cost will be the one set for "Oversize" shipping class.
  2. if "Oversize" Shipping Class is not set in cart items:
    • If cart amount is less than the target free shipping amount: Hide "Free shipping".
    • If cart amount is over the target free shipping amount: Hide "Flat rate" Shipping Methods.

Here is that code:

add_filter('woocommerce_package_rates', 'wf_hide_shipping_method_based_on_shipping_class', 100, 2);
function wf_hide_shipping_method_based_on_shipping_class($rates, $package){

    // Defining & Initializing variables
    $free_shipping_rates = array(
        'free_shipping:3',
        'free_shipping:5'
    );

    // Defining & Initializing variables
    $shipping_class_id = 163;
    $free = array();
    $over_found = $has_free = false;

    // Check if "Oversize" shipping class (163) is in cart items
    foreach(WC()->cart->get_cart() as $key => $cart_item){
        if($cart_item['data']->get_shipping_class_id() == $shipping_class_id ){
            $over_found = true;
            break;
        }
    }

    // 1. Hiding free shipping but always show Local pickup for Canada
    if( $over_found ){
        foreach($free_shipping_rates as $rate_id) {
            unset( $rates[$rate_id] );
        }
    }
    // 2. Hiding Flat rate OR Free shipping --> depending on cart amount
    //   (but always show Local pickup for Canada)
    else {
        foreach ( $rates as $rate_id => $rate ) {

            // Hide all "Flat rates" when "Free Shipping" is available
            if ( 'free_shipping' === $rate->method_id ) {
                $free[ $rate_id ] = $rate;
                $has_free = true;
            } elseif ( 'local_pickup' === $rate->method_id ) {
                $free[ $rate_id ] = $rate;
            }
        }
        return $has_free ? $free : $rates;
    }
    return $rates;
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested on WooCommerce 3 and works.


Refresh the shipping caches (needed sometimes):
1) First empty your cart.
2) This code is already saved on your function.php file.
3) Go in a shipping zone settings and disable one "flat rate" (for example) and "save". Then re-enable that "flat rate" and "save". You are done and you can test it.

like image 172
LoicTheAztec Avatar answered Nov 13 '22 16:11

LoicTheAztec