5

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.

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

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
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
The Hatchery
  • 63
  • 1
  • 6
  • We have created a plugin to hide shipping method based on various conditions including shipping class and locations. https://elextensions.com/plugin/conditionally-hide-woocommerce-shipping-methods-plugin/ – YajiV Feb 28 '19 at 18:45

2 Answers2

2

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.

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Thank you so much for your answer. I've implemented that function, but tested it and if I have a mix of oversize and normal items, it now only shows local pickup. I need it to show just the oversize rate if it exists in the cart and local pickup if in Canada shipping zone. Any ideas on that? Getting close. – The Hatchery Nov 19 '17 at 04:36
  • Actually, even if I only have oversize items in the cart, it only shows local pickup. – The Hatchery Nov 19 '17 at 04:50
  • I've added my list of IDs to the end of my question. Thank you so so much for helping me out! I appreciate it very much. I've been ripping my hair out over this for days, haha. – The Hatchery Nov 19 '17 at 05:23
  • @TheHatchery I have retested and updated the code… This is successfully working for your case now… Try it and let me know. – LoicTheAztec Nov 19 '17 at 12:40
  • Thank you for the update. I've implemented the new code, cleared my cache, cleared WC transients, cleared customer data, saved and re-saved my shipping zones but it still only shows and defaults to local pickup if there is a MIX of oversize and regular items in the cart. If there are _only_ oversize items in the cart, or _only_ regular items in the cart, it works as expected. I appreciate any other pointers you might have. – The Hatchery Nov 19 '17 at 21:07
  • 1
    I have updated my question to reflect that I am not using the XAdapter plugin anymore - just the WooCommerce shipping settings and the code above! Works perfectly now. Thank you so much @LoicTheAztec :D – The Hatchery Nov 20 '17 at 00:21
0

This is possible by using Woocommerce Shipping Table Rate, You just need to add the extra rules. You need to add 7 shipping rules, You can see the shipping rules in the below image: Image contains the shipping rule you need to add

For the above rules, you will get the desired results at a cart page. I have attached some screenshot of the cart page in different cases for your references: Note: Shipping class of Hat: Regular & Hoodie: Over weight.

Regular and overweight product ordered together

Over wight product with orders over $100

Free shipping for orders amount over $100 with regular items