WooCommerce: Hide Shipping Rates if Free Shipping Available

If Free Shipping is available, you possibly don’t want to show the other premium shipping options. WooCommerce shows by default all shipping rates that match a given shipping zone, so it’s not possible to achieve this from the settings alone.

Thankfully, the “woocommerce_package_rates” filter allows us to manipulate the shipping rates before they are returned to the frontend. In this example, we will disable all shipping methods but “Free Shipping” so that free shipping remains the only possible choice.

Here’s the code to add to your functions.php. Enjoy!

Remove a given Flat Rate when Free Shipping is available @ WooCommerce Cart / Checkout

PHP Snippet #1: Unset Specific Shipping Rate When Free Shipping Rate is Available

To find the “shipping rate ID” e.g. “free_shipping:8“, please see the screenshot at the bottom of this other tutorial: https://businessbloomer.com/woocommerce-disable-free-shipping-if-cart-has-shipping-class/
/**
 * @snippet       Hide one shipping rate when Free Shipping is available
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 6
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
 
add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 9999, 2 );
  
function bbloomer_unset_shipping_when_free_is_available_in_zone( $rates, $package ) {
   // Only unset rates if free_shipping is available
   if ( isset( $rates['free_shipping:8'] ) ) {
      unset( $rates['flat_rate:1'] );
   }     
   return $rates;
}

PHP Snippet #2: Unset ALL Shipping Rates in ALL Zones when ANY Free Shipping Rate is Available

/**
 * @snippet       Hide ALL shipping rates in ALL zones when Free Shipping is available
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 6
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
 
add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_all_zones', 9999, 2 );
  
function bbloomer_unset_shipping_when_free_is_available_all_zones( $rates, $package ) {
   $all_free_rates = array();
   foreach ( $rates as $rate_id => $rate ) {
      if ( 'free_shipping' === $rate->method_id ) {
         $all_free_rates[ $rate_id ] = $rate;
         break;
      }
   }
   if ( empty( $all_free_rates )) {
      return $rates;
   } else {
      return $all_free_rates;
   } 
}

Shipping rates not hiding after implementing these snippets?

You probably need to:

a) empty the Cart and start testing again

b) clear customer sessions:

Clear Customer Sessions – WooCommerce System Status Tools

Where to add this snippet?

You can place PHP snippets at the bottom of your child theme functions.php file (delete "?>" if you have it there). CSS, on the other hand, goes in your child theme style.css file. Make sure you know what you are doing when editing such files - if you need more guidance, please take a look at my free video tutorial "Where to Place WooCommerce Customization?"

Does this snippet (still) work?

Please let me know in the comments if everything worked as expected. I would be happy to revise the snippet if you report otherwise (please provide screenshots). I have tested this code with Storefront theme, the WooCommerce version listed above and a WordPress-friendly hosting on PHP 7.3.

If you think this code saved you time & money, feel free to join 14,000+ WooCommerce Weekly subscribers for blog post updates or 250+ Business Bloomer supporters for 365 days of WooCommerce benefits. Thank you in advance :)

Need Help with WooCommerce?

Check out these free video tutorials. You can learn how to customize WooCommerce without unnecessary plugins, how to properly configure the WooCommerce plugin settings and even how to master WooCommerce troubleshooting in case of a bug!

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza.

124 thoughts on “WooCommerce: Hide Shipping Rates if Free Shipping Available

  1. What a wonderfull snippet!

    I do have a question, and its probally my limited knowledge.

    Basically we have 2 shipment methods with both 2 variations. Standard Delivery (6,99 or free) and Servicepoint delivery (6,99 or free). These 4 options are 4 different shipping methods on WordPress. Whenever the free shipping becomes available I want to hide the shipping with rates to disapear. And whenever you have to pay for shipping I want the free service point to disappear.

    I have 3 snippets but only the first one works. What am I doing wrong? Thank you to any comments in advance!

    Title: Hide standard delivery if free delivery is available

    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 9999, 2 );
       
    function bbloomer_unset_shipping_when_free_is_available_in_zone( $rates, $package ) {
       // Only unset rates if free_shipping is available
       if ( isset( $rates['free_shipping:5'] ) ) {
          unset( $rates['flat_rate:6'] );
       }     
       return $rates;
    }
    

    Title: Hide paid pickup point if free shipping is available

    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 9999, 2 );
       
    function bbloomer_unset_shipping_when_free_is_available_in_zone2( $rates, $package ) {
       // Only unset rates if free_shipping is available
       if ( isset( $rates['free_shipping:5'] ) ) {
          unset( $rates['sc_service_point:3'] );
       }     
       return $rates;
    }
    

    Title: Hide free pickup point shipping is standard (paid) delivery is available

    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone3', 9999, 2 );
       
    function bbloomer_unset_shipping_when_free_is_available_in_zone3( $rates, $package ) {
       // Only unset rates if free_shipping is available
       if ( isset( $rates['flat_rate:6'] ) ) {
          unset( $rates['sc_service_point:9'] );
       }     
       return $rates;
    }
    
    1. I solved it after scrolling a little bit further, ill keep the post up for anyone who’s wondering how to solve the problem. Empty the cart and hide a new one and rename the function so each snippit is unique.

  2. Works perfect. Just a tip/addition: If you have 2 different free shipping rates (yes, it makes sense if you want to let customers choose their preferred shipping company 😉 ), then simply delete the “break” from PHP Snippet #2. Otherwise it would only show the first free shipping method.

  3. Thank you so much. Still works!

  4. Thanks Rodolfo for this snippet.
    My current setup is as follow:

    I offer two shipping options plus FREE shipping when you buy 3 items +
    To set the FREE shipping rule I am using the plugin Advanced Free Shipping

    My use case now, is that I want to offer the ability to ship the item quicker for those who also qualify for FREE shipping, so after implementing your code, I get the end result where FREE shipping shows and the express shipping shows too but the FREE shipping shows as the second option. In the Shipping zones setup, I have FREE shipping as the top shipping option in the backend, so I’m not sure why the ordering isn’t being taken into account. Could you shed any light on how I make the FREE option be the top shipping option and the express the bottom one?

    1. Weird, it should respect the sorting you have in the admin. Just out of curiosity, can you rename “express shipping” as “ZZZexpress”, to see if it takes alpha sorting instead?

  5. I’ve tried the first option on my site but it doesn’t appear to be working

    1. Weird. To troubleshoot, disable all plugins but WooCommerce and also switch temporarily to “Twentytwenty” theme (load the snippet there in functions.php) as explained here: https://www.businessbloomer.com/lesson/trwm4l01/

      Once you do that, does it work? If yes, you have a problem with your current theme or one of the plugins.

      Hope this helps!

  6. HI thank you for the code. I need something different . i have three shipping methods in my store. 1. Table Rate 2.Free Shipping 3.Local Pickup . in checkout and cart page these three option are available. what i want to do is if some one select the free sipping or the local pickup i want ot show the table rate value as zero(0.00). if they select the table rate then the value should appear. when i used the above code in your post is completely hide the table rate option. so that can not select back. can this be achieved with code? or is there any plugins to get this task done.? please advice needed. thanks in advance.

    1. Hi Terrance, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  7. PHP Snippet #1 works like a charm!

    Great job, thanks 🙂

    1. Cool

  8. Rodolfo, I have used multiple snippets from BusinessBloomer, and I can’t thank you enough for how much you’ve helped my businesses! I used PHP #2 above, and my site is on Woo 4.3.3, Flatsome Theme 3.12.2 (using a child theme), and WordPress 5.4.2. The site is on AWS via Cloudways. The snippet worked like a charm. Thank you again!

    1. Brilliant

  9. Hi Rodolfo and thank you for this post.
    I tried everything you suggested but unfortunately it does not work.

    I have to say that I tried several plugins and no one is working. Maybe it is something related to some setting in particular?

    1. Ciao Antonello, try to empty your cart first and then test again

      1. Hi Rodolfo and thank you for your great snippets!!!

        Maybe Antonello has to change the IDs after the slug according to his settings. IDs “8” & “1” in your example:
        free_shipping:8
        flat_rate:1

        Regards,
        Dimis

  10. God bless You, Rodolfo!!!
    Your snippet works!
    Thank You!

    1. Cheers!

  11. Hi,

    We have a WooCommerce site and are having trouble with the Shipping configurations.

    In a nutshell this is what we need,

    Australian Orders over $100 Free Shipping
    Australia Standard Shipping $10.00
    Australia Express Shipping $15.00
    New Zealand Standard $15.00

    USA, Canada, Ireland $35.00
    All Other Countries $45.00

    I cannot get this done with my developer for some reason, he is having a lot of difficulty doing this. We also wanted to hide the Standard Shipping option on Australian Orders over $100 and default to the Free Shipping option but still have the Express option as an upgrade.

    Lastly, there are some individual products that we offer Free Shipping for and he also cannot find a way to configure this. Obviously it would be required when it is below the $100 threshold only apply if the product is purchased alone. If the cart has other items that are do not have Free Shipping it would then default to the normal options.

    Can this be done, and if so is it custom or is it standard in WooCommerce?

    1. Hi Adrian, thanks so much for your comment! Yes, this is custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  12. Hi!

    I have 2 free shipping methods so i need to unset the other shipping method when either 1 of the free shipping methods is activated.
    I tried below but it didn’t work for the 2nd free shipping method. What am I doing wrong?

    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 10, 2 );
       
    function bbloomer_unset_shipping_when_free_is_available_in_zone( $rates, $package ) {
          
    // Only unset rates if free_shipping is available
    if ( isset( $rates['free_shipping:7'] ) ) {
         unset( $rates['flat_rate:6'] );
    }     
         
    return $rates;
    if ( isset( $rates['free_shipping:3'] ) ) {
    unset( $rates['flat_rate:6'] );
    }     
         
    return $rates;
      
    }
    

    Thank you!

    1. Hi Man, you have to “return $rates” only once, at the very end.

      1. Just what I needed thank you. I always come to your site first for help.

  13. Hello Rodolfo,

    We have created a plugin and published it on WooCommerce.com to solve this problem.
    https://woocommerce.com/products/hide-shipping-methods-for-woocommerce/

    I hope you can include this plugin on your article.

    Thanks,
    Divya

    1. Nice, well done

  14. Worked perfectly. Thankyou very much

    1. Awesome!

  15. Works beautifully!
    Thanks Rodolfo!

    1. Great!

  16. If people are still using legacy shipping methods this will not work, because the shipping methods need to be prefixed with a “legacy_”.

    Took me a while to figure it out.

    1. Thanks!

  17. Hi Rodolpho,

    How can I set woo when I have free shipping over 15$ and 1 product (free+ shipping) who doesn’t be include in the free shipping.

    For example for Free shipping over 15$:
    – product A = 10$ + 5$ shipping and product B = 0€ (promotion) + 5$ shipping
    – Cart = A*2 and B*3
    I would like the shipping cost is 15$ (A*2 >15$ = free shipping and B*3 = 5$*3 = 15$ shipping)

    Usually, I have two shipping option in the cart: 25$ (5 qty) or Free. In this cas a customer can take 2 product A and 20+ product B…

    Thank you very much Rodolpho,

    1. Hi Stan, thanks so much for your comment! Yes, this is possible – unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R

  18. Such a helpful post! Bravo!

    I managed to conditionally hide my Standard Shipping rates when free was available but leave the Express Shipping option always on (even for multiple shipping zones). Couldn’t do it with other plugins and I did it with your nice little code.

    Thank you for your kind contribution to the WooCommerce ecosystem 🙂

  19. Hi Rodolfo,

    It works great for 1 country. But I ship to all EU countries (each country seperate zone) so all the shipping methods got another number as ID. How can I catch them all? Could you update your code so that it loops through all ID’s of the Flat Rate and Free Shippings in all zones?

    Thank you in advanced,
    Frank

    1. Hello Frank, thanks so much for your comment! Yes, this is possible – but unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R

  20. Great job! Still working. Thanks!

  21. Not is working on 3.1.1. Can you help me?

    1. Hi Herbamedica, I just tested my snippet on default Storefront and WooCommerce 3.1.1 and it works fine.

      Go to WP Dashboard > WooCommerce > System Status: what errors do you see in red font?

      Also, take a look at this tutorial to see how to troubleshoot: https://businessbloomer.com/woocommerce-troubleshooting-mistakes-to-avoid/

      Hope this helps!

      R

  22. Thank you very much for sharing the code, but he does not work at 3.0.x.
    have any Update?

    1. Thanks for your feedback Tung. Can you try with the latest 3.0.5 please?

    2. Hi!

      After update to 3.0.7 not work 🙁

      Please help.
      Thanks.

      1. Hey Bela 🙂 Are you sure?

  23. Hi Radolfo
    I really enjoy your videos thank you so much for sharing.
    Please I need help I am trying to tackle an issue.
    I need to hard code the shipping rate per (specific) products in my woo commerce site and hide the other shipping rate values displayed in the checkout page? Please how will I go about this
    Quick overview
    I am running a special where customer get the product for free but have to pay shipping and handling rate of $7.99.
    I do not want them to see the other shipping rates available.

    1. Sophia, thanks for your comment! I can’t specifically help here via the blog, but maybe this might help https://businessbloomer.com/woocommerce-disable-free-shipping-if-cart-has-shipping-class/?

  24. Hi Rodolfo,

    I’ve tried using both snippets above, but I can’t seem to get this to work. When an order amount totals over $50, it should show only free shipping and local pickup (if their zipcode matches the predefined in local settings) and unset the flat_rate. If the amount totals under $50, it should not show free delivery. I have everything working properly with this code:

     
    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 10, 2 );
      
    function bbloomer_unset_shipping_when_free_is_available_in_zone( $rates, $package ) {
         
        // Only unset rates if free_shipping is available
        if ( isset( $rates['free_shipping:8'] ) ) {
        unset( $rates['flat_rate:1'] );
    }   
         
    return $rates;
     
    }
    

    EXCEPT that it does not unset the flat rate. I’m pulling my hair out. Please help!

    1. I was able to get it fixed. Thank you so much for these snippets and tutorials!

      1. Awesome to hear that Chris! What was the problem?

        1. I had two different zones set up in Woocommerce and didn’t realize how they were being affected by the code. Once I was able to sort that out, I had a script run for both sets of zones and it fixed my problem.

          1. Excellent Chris, thank you for the follow up!

  25. Hi,

    Thanks for the great codes! I have the following situation. I use the following code to hide the flat-rate (:1) for zone 1 when free shipping (:2) is available:

    /**
     * @snippet       Hide one shipping option in one zone when Free Shipping is available
     * @how-to        Get CustomizeWoo.com FREE
     * @sourcecode    https://businessbloomer.com/?p=260
     * @author        Rodolfo Melogli
     * @compatible    WooCommerce 2.6.1
     */
     
    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_in_zone', 10, 2 );
      
    function bbloomer_unset_shipping_when_free_is_available_in_zone( $rates, $package ) {
         
        // Only unset rates if free_shipping is available
        if ( isset( $rates['free_shipping:2']  ) ) {
        unset( $rates['flat_rate:1'] );
    }   
         
    return $rates;
     
    }

    However, I have a second zone (zone 1 = Netherlands / zone= Belgium) that uses different id’s for the flat rate (:5) and free shipping (:4). How can I make sure it also hides the flat rate for Belgium (:5) when free shipping (:4) is available there?

    Kind regards,
    Lars

    1. Hello Lars, thanks so much for your comment! You can simply add another “if isset… unset” line to the function, and in this way target multiple shipping methods. Let me know!

  26. Hello Rodolfo,

    I have a multilingual website based on WP 4.5.3 + WC 2.6.4 + the latest WPML

    I want to disable all the shipping rates on all the zones when the free shipping applies (cart over 200 pln, the Polish currency, or over 200 euros), so I pasted at the bottom of functions.php the snippet

    /**
     * @snippet       Hide ALL shipping rates in ALL zones when Free Shipping is available
     * @how-to        Get CustomizeWoo.com FREE
     * @sourcecode    https://businessbloomer.com/?p=260
     * @author        Rodolfo Melogli
     * @compatible    WooCommerce 2.6.1
     */
     
    add_filter( 'woocommerce_package_rates', 'bbloomer_unset_shipping_when_free_is_available_all_zones', 10, 2 );
      
    function bbloomer_unset_shipping_when_free_is_available_all_zones( $rates, $package ) {
         
        $all_free_rates = array();
         
            foreach ( $rates as $rate_id => $rate ) {
            if ( 'free_shipping' === $rate->method_id ) {
                $all_free_rates[ $rate_id ] = $rate;
                break;
            }
        }
         
        if ( empty( $all_free_rates )) {
            return $rates;
            } else {
            return $all_free_rates;
            } 
    }
    

    the same way I did previously with many other snippets on WordPress. I erased all the WC caches and so on but I just can’t have the result I am looking for

    What could it be the issue?

    Thank you so much for your help!

    1. Hello there, and thanks SO MUCH for your comment! I’m afraid I don’t provide custom work or WooCommerce support to free subscribers, I hope this is understandable. I hope you find a working snippet, best of luck 🙂

  27. I tried using your code and it doesn’t work unfortunately, it is still showing the flat rate shipping fee and defaulting to it in woo commerce. Am I doing something wrong

    1. Hey Peter, thanks for your comment! It’s difficult to say as I have no idea about your shipping settings and if you correctly identified the shipping zone codes 🙂 If you want to share your checkout link and explain what you’re trying to hide, that might allow me to troubleshoot your problem! Cheers, R

  28. Hi Rodolfo,
    For WC 2.6+ how would I unset 1 rate in each zone?. Your first snippet worked great for my Local Delivery Shipping Zone but I also need to do the same for my UK Shipping Zone, so how would I add multiple instance IDs to your code?

    Any help would be greatly appreciated.

    Thanks,
    Andy

    1. Hey Andy, thanks for your comment! If I understood well, I guess you just need to add another “unset” line:

      unset( $rates['flat_rate:1'] );
      unset( $rates['free_shipping:6'] );
      // etc.
      
  29. Thank you so much for the snippet, it works!

    1. Brilliant – thanks a lot for your feedback Stray!

  30. Hi Rodolfo!

    First I need to greet you for your great website and all your woocommerce tips! They’re very very useful!!

    And I’d like to show you a snippet that I’m trying to implement in my woocommerce website.

    Basically, I’m trying to hide free shipping option when the order total is under the minimum amount. It happens that it’s not working properly (I get the message “No available shipping methods”), so if you get a time to have a look, I appreciate! Thank you

    1. Hey Taysa, thanks so much for your comment! FYI, you can set up the “minimum free shipping threshold” in the WooCommerce settings, no need to use PHP 🙂 Go to WooCommerce > Settings > Shipping > Free Shipping > Minimum Order Amount 🙂

      1. Hi Rodolfo, thanks for your reply!
        I explain the reason that I’m trying to do that. The woocommerce default shipping calculation is applied to the subtotal, but I’m using a plugin that applies a discount (what is not bein consideratred by woocommerce shipping calculation). So in the snippet I tried to set the free shipping based on “cart_contents_total” and not to “subtotal”. So I thought that if I could hide free shipping ih the cases that the discount decrease the total order amount under the minimum amount it would solve my problem. Could you give me a hint?

        1. P.S. I can’t find any plugin which can do that :-/

          1. Gotcha 🙂

            I took a look at your snippet, it looks perfect apart from the position of “return $rates”. This should be placed OUTSIDE the if statement 🙂 Let me know if that works for you.

            R

          2. Hi Rodolfo!

            I put “return $rates” outside the if statement as you said. Now it’s not giving me the error anymore, but Free shipping is still being showed even that total is under the minimum amount. Do you know if there’s another variable apart from “subtotal” and “cart_contents_total” that is used by woocommerce in the checkout calculation? Thanks again 🙂

            1. Yes Taysa, there are many more variables – check https://docs.woothemes.com/wc-apidocs/class-WC_Cart.html and scroll down until you find get_total( ) – all the other variables will be underneath it. Hope this helps!

  31. Well I appreciate your help , but that code

    add_filter( 'woocommerce_package_rates', 'wcsupport_no_usps_us', 10, 2 );
      
    function wcsupport_no_usps_us( $rates, $package )) {
      
      if ( WC()->shippingclass->shipping_class ==(469) {
        foreach( $rates as $key => $rate ) {
          if (strpos($key,'usps') !== false) {
            unset( $rates[$key] );
          }
        }
      }
     return $rates;
     
    }
    
    

    breaks my store too. Not sure why I can’t figure this out, must be something to do with the shipping classes that I’m not entering correctly. I have taken up too much of your time already and can’t keep breaking the site trying to change and guess what I’m doing wrong every few minutes, so I guess I will just have to skip adding that function.

    Any chance this is closer to the right code I need to make this work or am I way off?

    add_filter( ‘woocommerce_package_rates’, ‘wcsupport_no_usps_us’, 10, 2 );
    function wcsupport_no_usps_us( $rates, $package ) {
    
    if ( WC()->customer->shipping_country == ‘US’ ) {
    // shipping class IDs that need the method removed
    $shipping_classes = array(469,468);
    
    foreach( WC()->cart->cart_contents as $key => $values )
    if( in_array( $values[ ‘data’ ]->get_shipping_class_id(), $shipping_classes ) )
    $if_exists = true;
    
    foreach( $rates as $key => $rate ) {
    if (strpos($key,’usps’) !== false) {
    unset( $rates[$key] );
    }
    }
    }
    
    return $rates;
    
    }
    
    

    Thanks again for your time!

    1. Hey Courtney, I just checked your second code on my dev site and it works like a charm 🙂 Send me your WP and FTP details via the contact page and I’ll get this done for you 🙂

      1. Thank you for checking it out and for all of your help! I was able to add it to store and it is working. I now just have one problem with it.(that hopefully is an easy fix)

        When an item from the shipping class that removes USPS rates gets added (for example shipping class “Watch”) to the cart everything works great and the USPS rates are removed. However if an item from a different class (shipping class “Tshirt” gets added to the cart with the “Watch” item then the USPS rates do not show back up they stay hidden.

        I need the USPS rates to show up if any item other than just shipping class “watch” is in the cart.

        It’s only when only shipping class “watch” is in the cart that I need USPS rates gone.

        Cart contains “Watch” or “Watch” + “Watch” = No USPS

        Cart contains “Watch” + “Tshirt”= USPS rates visible

        Hope this makes sense.

        Code I have implemented on site is this one

        add_filter( 'woocommerce_package_rates', 'wcsupport_no_usps_us', 10, 2 );
        function wcsupport_no_usps_us( $rates, $package ) {
        
        
             // shipping class IDs that need the method removed
            $shipping_classes = array(469,468);
        
            foreach( WC()->cart->cart_contents as $key => $values )
                if( in_array( $values[ 'data' ]->get_shipping_class_id(), $shipping_classes ) )
                    $if_exists = true;
        
            foreach( $rates as $key => $rate ) {
              if (strpos($key,'usps') !== false) {
                unset( $rates[$key] );
              }
            }
          
          return $rates;
        
        }
        
        
        1. Hey Courtney 🙂

          I think you have a couple of missing checks there. First, you’re not really using “$if_exists” – only if that is true you want to remove USPS. Second, you should add a PHP counter that counts how many shipping classes you have while you do the foreach – if this is greater than 1 then you have multiple classes and you don’t want to run the “unset”.

          Hope this helps 🙂

  32. I have a unique situation I hope you could help offer code for my site.

    I want to be able to show only one shipping method when products of a certain shipping class are in the cart, but if a product from another shipping class gets added to the cart I need all the methods to show up again.

    1. Hey Courtney, thanks so much for your comment! I think you can find the solution here: https://bolderelements.net/support/knowledgebase/hide-shipping-method-when-cart-contains-shipping-class. Hope this helps 🙂

      1. Rodolfo thank you I did try to use the shipping class method but it doesn’t seem to produce and results. This is the code I used:

         add_filter( 'woocommerce_package_rates', 'hide_shipping_when_class_is_in_cart', 10, 2 );
         
        function hide_shipping_when_class_is_in_cart( $rates, $package ) {
            // shipping class IDs that need the method removed
            $shipping_classes = array(469);
            $if_exists = false;
         
            foreach( WC()->cart->cart_contents as $key => $values )
                if( in_array( $values[ 'data' ]->get_shipping_class_id(), $shipping_classes ) )
                    $if_exists = true;
         
            if( $if_exists ) unset( $rates['usps'] );
         
            return $rates;
        }
        1. It looks good, however the USPS $rates work slightly different from the default WooCommerce ones. You have to add some more lines of PHP instead of just:

          unset( $rates['usps'] )
          

          This article will help you figure what you need: https://docs.woothemes.com/document/usps-shipping/#section-10

          Hope this helps 🙂

          1. Thank you I’m pretty new to trying to edit my on website code, so I appreciate your time and help. I tried a few variations, but each one broke my site, so not sure what I’m still doing wrong. I used this code now

             add_filter( 'woocommerce_package_rates', 'wcsupport_no_usps_us', 10, 2 );
            function wcsupport_no_usps_us( $rates, $package ) {
            
              if ( WC()->shippingclass->shipping_class ==(469) {
                foreach( $rates as $key => $rate ) {
                  if (strpos($key,'usps') !== false) {
                    unset( $rates[$key] );
                  }
                }
              }
            
            1. Hey Courtney! You have a couple of syntax errors (missing parenthesis):

               
              
              add_filter( 'woocommerce_package_rates', 'wcsupport_no_usps_us', 10, 2 );
              
              function wcsupport_no_usps_us( $rates, $package )) {
              
                if ( WC()->shippingclass->shipping_class ==(469) {
                  foreach( $rates as $key => $rate ) {
                    if (strpos($key,'usps') !== false) {
                      unset( $rates[$key] );
                    }
                  }
                }
              }
              
              
  33. Worked for me!

    Thank you so much, you rock!

    1. Awesome, thanks for your feedback Fred! 🙂

  34. Hi,

    I’ve used this code snippet now to hide flat rate when free shipping is available (above 50€). But for some reasons it’s now always hidden. I want to use flat rate under 50€ (and hide free shipping), while using free shipping above 50€ (and hide flat rate).

    /**
    * woocommerce_package_rates is a 2.1+ hook
    */
    add_filter( ‘woocommerce_package_rates’, ‘hide_shipping_when_free_is_available’, 10, 2 );

    /**
    * Hide shipping rates when free shipping is available
    *
    * @param array $rates Array of rates found for the package
    * @param array $package The package array/object being shipped
    * @return array of modified rates
    */
    function hide_shipping_when_free_is_available( $rates, $package ) {

    // Only modify rates if free_shipping is present
    if ( isset( $rates[‘free_shipping’] ) ) {

    // To unset a single rate/method, do the following. This example unsets flat_rate shipping
    unset( $rates[‘flat_rate’] );

    }

    return $rates;
    }

    Hope you could help me out. Thanks!

    1. Hey Neal thanks for your message. The snippet should work, so I fear you didn’t set up the “Free Shipping” method properly. If you go to WooCommerce/Settings/Shipping/FreeShipping, do you see “50” in the Minimum Order Amount and do you see “A minimum order amount…” in the “Free Shipping Requires…” dropdown?

      1. Hmm that was a stupid mistake of me. Exactly forgot to select ‘a minimum order amount’ in the dropdown. Thanks for helping me out!

        1. Ahaha, excellent 🙂 Glad you sorted it out!

  35. Hello,

    Thanks for the tip, really helpful.. I have added the code to my functions.php file and it does work but only on the checkout page. Any ideas for the cart page?
    Thanks

    1. Thanks for your feedback Nikolas! woocommerce_package_rates should work on both Cart and Checkout page, so this is strange! Did you get this sorted?

  36. Hi Rodolfo,

    Not sure what good i did these few days to find your amazing site. This is like a gold mine for Woo website owners. Thank you so much for sharing!

    I’m trying to implement something similar, would appreciate if you can show me the snippet for this.

    We have 2 delivery options. 1. delivery cost (via flat rate) 2. office pickup

    Now we have 4 payment options at checkout. 1. cards 2. bank 3. COD 4. pay at office

    If a customer selects “office pickup” at checkout page, we want payment option 3. COD to hide.

    How can we achieve this?

    Thank you again!
    Ran

    1. i got this done. Found the solution at wordpress.com 🙂

  37. Hi Rodolfo,

    The shipping methods I’m using on my site are – Flat Rate (Only to Australia) and Australia Post (International). Is there any way I can hide the Australian Post when Flat Rate is available?

    Your help would be much appreciated.

    Many thanks

    1. Hello Rod! Yes of course. Just go to Woocommerce > Settings > shipping and identify your Shipping ID (see image). Then, use the same rule. R

  38. Thanks Rodolfo, helped a lot

  39. Thank you very much for this snippet!!
    I’ve tried so many that did not work, until yours did!
    Best regards,
    Ofer

  40. Hi Rodolfo,

    I’ve tried to add the code without results – I’m trying to hide the local_delivery.

    Any idea?

    Thanks!

    1. Isa, try this:

      add_filter( 'woocommerce_package_rates', 'hide_shipping_when_free_is_available', 10, 2 );
      function hide_shipping_when_free_is_available( $rates, $package ) {
          if ( isset( $rates['free_shipping'] ) ) {
              unset( $rates['local_delivery'] );
          }  
          return $rates;
      }
      
      1. It works perfectly now!
        I just see the free shipping when it’s available. But I have some different options for shipping and I want to leave free_shipping and local_delivery as well. How can I add local_delivery here?

        $free_shipping = $rates[‘free_shipping’];
        $rates = array();
        $rates[‘free_shipping’] = $free_shipping;

        Thanks Rodolfo!

        1. Awesome Isa! If you want to unset all rates but free shipping and local delivery you will have to use the other code:

          ...
          ...
          if ( isset( $rates['free_shipping'] ) ) {
             unset( $rates['flat_rate'] );
             unset( $rates['second_rate'] );
             unset( $rates['third_rate'] );
          	}
          ...
          ...
          
          1. I have now this code:

            add_filter( ‘woocommerce_package_rates’, ‘hide_shipping_when_free_is_available’, 10, 2 );

            function hide_shipping_when_free_is_available( $rates, $package ) {
            if ( isset( $rates[‘free_shipping’] ) ) {
            unset( $rates[‘local_delivery’] );
            unset( $rates[‘WC_Weight_Based_Shipping_main’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432200267’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1429291395’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432200691’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432200297’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432200225’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205333’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205375’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205184’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205425’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205456’] );
            unset( $rates[‘WC_Weight_Based_Shipping_1432205508’] );
            }
            return $rates;
            }

            And I have local_pickup as well, which I want to show with free_shipping when this is available, but still now I see just free_shipping. Any idea?

            Isa

            1. Remove this line: unset( $rates[‘local_delivery’] );

          2. Actually it’s a different shipping local_delivery (we send the package cheaper because it’s local) than local_pickup (user can come to the shop and pick up the package). But anyway, even removing this line
            unset( $rates[‘local_delivery’] );

            The only shipping method available is free shipping.

            1. Weird 🙂

              Try this (if this does not work, then there is some advanced customization that needs to be done due to your template or specific functionalities I’m afraid):



              if ( isset( $rates[‘free_shipping’] ) ) {
              // basically put all the unset rates in one line of code
              unset( $rates[‘flat_rate’], $rates[‘second_rate’], $rates[‘third_rate’] );
              }

          3. Rodolfo,

            It doesn’t work, probably it’s my template as you said. We have tried but the result is still just the free_shipping option.

            Thanks for your help Rodolfo!

            1. No problem Isa, thanks for letting me know 🙂 What template are you using?

              1. I tried something similiar to this to exclude multiple lines within table_rates shipping but to no avail

                // Only unset rates if free_shipping is available
                if ( isset( $rates['free_shipping:7'] ) ) {
                    unset( $rates['table_rate:13:2'] );
                	unset( $rates['table_rate:13:1'] );
                	unset( $rates['table_rate:13:10'] );
                	unset( $rates['table_rate:13:3'] );
                }
                return $rates;
                }
                1. also tried

                  // Only unset rates if free_shipping is available
                  if ( isset( $rates['free_shipping:7'] ) ) {
                      unset( $rates['table_rate:13:2'], $rates['table_rate:13:1'], $rates['table_rate:13:10'], $rates['table_rate:13:3'] );
                  }
                  return $rates;
                  }

                  but also with no joy

                  1. Hi Daniel, thanks so much for your comment! I’m afraid this is custom troubleshooting work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  41. Worked perfectly. Thank You.

    1. Thanks for the feedback Raj!

  42. Nice code snippet. Worked fine but there is a little customization that I want. I also want to display express delivery option that I am managing with Woo commerce Table Rate Shipping plugin. Any idea how to display that express delivery rate too ?

    1. Thanks for your comment Bilal 🙂

      Table rates plugin creates multiple sub-rates called “table_rate-1”, “table_rate-2” etc. You can find the exact IDs under Shipping Zones / your_zone. If you want to target them all, you can use the following:

      foreach ( $rates as $key => $value ) {
                  if ( false !== strpos( $key, "table_rate" ) ) {
                      unset( $rates[$key] );
                  }
              }
      
      

      Hope this helps!

      1. Thanks..it worked..

  43. Hey
    Actually i have setup my shipping options for free shipping (Above 500) and flat rate (Below 500).

    Now the problem is that when an item qualifies for free shipping(ie order above 500), the flat rate charges still keep showing up as an option on cart and checkout page.

    Please help, Thanks

    1. Are you using this function?

      function hide_shipping_when_free_is_available( $rates, $package ) {
           
          // Only modify rates if free_shipping is present
          if ( isset( $rates['free_shipping'] ) ) {
           
              // To unset a single rate/method, do the following. This example unsets flat_rate shipping
              unset( $rates['flat_rate'] );
               
              }
           
          return $rates;
      }
      
      
  44. Hi! Many thanks for your post! I was searching right for this snippet!
    I have 3 shipping methods. If free shipping is available, I’d like to show two of them.
    It was simply to unset the flat rate! Genius!
    Thanks, regards.

    1. Thank you, really appreciate your feedback 🙂

Questions? Feedback? Support? Leave your Comment Now!
_____

If you are writing code, please wrap it between shortcodes: [php]code_here[/php]. Failure to complying with this (as well as going off topic, not writing in English, etc.) will result in comment deletion. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining BloomerArmada to get blog comment reply priority, ask me 1-to-1 WooCommerce questions and enjoy many more perks. Thank you :)

Your email address will not be published. Required fields are marked *