Disable Free Shipping on a per Product Basis in WooCommerce

Lego Fork Lift

Shipping is one of the most complex aspects of e-commerce. You have to worry about shipping provider regulations, large products that have awkward dimensions & box sizes, small products that the shipping calculators incorrectly estimate and you over charge, or you could have a mix match of product sizes and it’s hard to come up with a fair flat rate shipping fee.

One of the approaches many store owners take is to mark up their products a little more and then offer free shipping. I think this is brilliant idea, but what happens if you have many small items and one large item that throws off the flat rate fee? If you’re using WooCommerce there’s a filter you can use to disable free shipping when a specific product is in the cart.

You simply have to get some information about your products, add that information to a little code snippet, and then put it in your functions.php file in your theme.

Getting the Product ID

WooCommerce Product ID

WooCommerce product ID in address bar.

The only information you need about the product(s) is the product id. This can be done easily by going to the Product page and then editing any existing product. You’ll see the ID in the address bar.

Add Product IDs to Snippet

Now that you have any IDs that you need you just need to add them to the $ineligible array in the following snippet. Then add this snippet to your functions.php file in your theme and upload it to your website.

Disabling Other Shipping Methods

If you offer free shipping why would also offer paid shipping? Especially if it’s the same shipping provider. The snippet I provided works even better once you hide the other available shipping options when free shipping is available.

I hope this article makes your store a little more shipping friendly. :)

Photo Credit: Ricecracker. via Compfight cc

40 thoughts on “Disable Free Shipping on a per Product Basis in WooCommerce

  1. Awesome snippet Patrick!

  2. Great resource, thanks Patrick!

  3. Hi – I need to hide free shipping based on location. How do I do this? Basically what I need to do is offer free shipping only to local customers, and revert to the API plugin Canada Post I have for all other orders. It seems like a simple thing to accomplish, but for the life of me, I can’t figure it out without a snippet of some kind in the theme, but I don’t want to mess up the code… Please help! I’m willing to pay.
    Thanks,
    Rocket Robin

  4. Hi Patrick,
    Thanks for your quick response! Actually, I solved my own problem. If you would suffer me to explain the solution to any other interested readers with the same issue, here it is: Simply, disable the free shipping option, and enable the “Local Delivery” option. In the Local Delivery option, rename it to “FREE DELIVERY” and add the postal codes with wildcards for whichever postal zone you offer free delivery. The time factor involved here is determining which postal codes those are. But the wildcards make it easy; for example, in my case, all of Toronto, Canada can be summarized as” M*”. No doubt this will be very valuable information to many, as it has taken me quite a while to solve this very simple problem…. if anyone has any questions or comments, let me know… http://www.rocketrobin.ca

  5. Hi Patrick,

    This sounds extremely useful, it is exactly what I was looking for. However, when I tried it on my website I got the following error: Parse error: syntax error, unexpected on line (whichever line this function started at).

    I have 26 products that I need to disable free shipping for.
    I enabled free shipping on my website for orders over $100 and then placed this snippet on my function.php file placing the 26 product ID numbers here:

    // set the product ids that are ineligible
    $ineligible = array( ’14009′, ’14031′, ‘etc’, ‘etc’ );

    After updating my whole website went down because of the error and had to log in from my hosting to change the function.php back to normal….. I really like the sound of this solution because it sounds exactly like what I need to do, offer free shipping on orders over $100 for everything except a few items.

    Do you know what am I doing wrong? Any help would be appreciated.

    Thanks.

    • Hi Pam,

      You didn’t happen to copy the opening php tag as well did you? That would be the < ?php on the first line.

      I put that in my snippets because it highlights the syntax but if you copy that into a part of your functions file where the php is already open then you’ll get a syntax error. Let me know if that helps you! :)

  6. I sure did LOL, sorry I’m not very savy on this… Thank you so much for taking the time to reply and specially for posting the code :) I looked everywhere for a way to get this to work the way I need it and was just about to lose my mind when I found this page… I will give it a try tomorrow, this time the proper way. Thanks again!

  7. Great snippet – thank you Patrick.

  8. I cannot seem to get this to work. It still gives me the option of choosing free shipping or standard shipping when in the cart. My client wants to provide gifts with free shipping, while everything else has a flat rate. But, if I have a gift card and other merch together, it gives the buyer the option of flat or free shipping. What I really need is for them to only see the flat shipping price at that point. Any help?

    • I just tested this snippet on my local install and it works fine for me. There’s a couple things you can check into:

      • Did you make sure to copy the gift card product ID into the $ineligible array?
      • If it still doesn’t work disable all other plugins and see if there’s another shipping method doing something

      Other than those you may need to get a developer to look at it because the code works for me.

  9. […] Want some WooCommerce hints? Remi Corson posted a neat tutorial on creating a shortcode to display product categories, and Patrick Rauland wrote a how-to for removing free shipping for certain items. […]

  10. Would I be able to change $ineligible to $eligible to enable free shipping on only those product id’s listed? Looking for a work around to the Fedex Shipping Method nightmare.

    • Hey there, no you can’t just change $ineligible to $eligible. You’d have a write a slightly different filter. That’s a good idea for a blog post for the future.

      • i also want to do what eeBs is doing. To give freeshipping to certain products, so just an opposite to the example you’ve given above. Is there a way to do this?

  11. Hello, I have a rule like this. For orders over 100$ I want to offer free shipping. Certain products tough, which are discounted, are not eligible for free shipping. Your snippet works just fine, but it makes the whole order ineligible for free shipping, even if the order contains 1 ineligible product and 100$ worth of eligible products. Is there any way to modify the code, to offer free shipping for all the orders that have 100$ worth of eligible products(the ones not listed in the array)?

    • Hello Nicu – I’m sure that’s possible but it would be far more in depth. If I had the time I’d love to look into it but I don’t have the time right now. Do let us know if you end up making that. :)

  12. Hi Patrick,

    Great code snippet. Of course I want to be different as I always seem to do. I have a need to enable Free Shipping on a per Product Basis in WooCommerce. But I am not a coder, can you help or point me in the right direction please.

  13. Brilliant and thanks for the pointer.

  14. Hi, Great little snippet that works well however, most of my products are free shipping apart from 3 small items that I will charge postage, so your snippet works for that. But the customer may purchase a large product AND a small item in which case the two would be packed together and the postage would be free.

    How would handle that??

    • You need to add the list of the “3 small products” to the snippet. Then free shipping will be disabled when those products are in the cart and WooCommerce will list of your other available shipping methods.

      • Hi Patrick

        Thanks for your reply. If I add the list of the “3 small products” to the snippet, free shipping is disabled when any of those products are in the cart. That’s great. However I need to disable the postage charge if any of those small (Postage chargeable) products are in the cart WITH a larger FREE shipping product as they will be packed together. Any ideas how that would work?
        Regards
        Richard

        • So there’s a particular product that if it’s included always use free shipping. Even if it’s already been disabled earlier by other products? That would have to be another snippet at a higher priority than this one. If you write a function that goes off at priority 30 that would work.

  15. Will this code work with flat rate shipping too? If so what part of the code do I change?

    • No, this won’t work with Flat Rate shipping. That will use a different filter. I believe the filter you would have to use is woocommerce_shipping_flat_rate_shipping_is_available. You should reach out to a developer to write this for you.

  16. Jordan Lovelle

    Hi Patrick,

    Thanks for the snippet. I was wondering if this was possible to do based on attribute – as in to disallow pickup based on the item’s attribute?

    Thanks.

    • Hey Jordan, that’s certainly possible but you’d have to add a bit of extra logic to check the attribute. This is actually a good idea for another snippet at some point in the future. :)

  17. Patrick,

    Thanks for sharing this awesome snippet! Is there anyway that it could be set up to look at the product category instead of the product id? This would make my shop alot more dummy proof for my admin in the long run.

    Thanks again!

  18. Thanks! It´s exactly what I need. I configure it like a plugin, instead paste the code in functions.php, and it seems works fine ;) I´ll just wait for the book

    • Hey you’re not supposed to know about that yet! ;)

      I’m setting up pages on my site this weekend and the announcement will be Monday morning. Check back then for the blog post. :)

  19. Hi,
    Can you give me a solution how to disable free shipping for a certain role of logged in users?

  20. Hi Patrick. Thanks for this. Is this code working nowadays (with all thoses updates WooCommerce had)?

    Thanks

  21. Hi Patrick,

    Thank you for this! I have gotten your code to work with one of our products. However, when I empty the cart and add a second product to my cart (where I also added its id to the php file as outlined above) the second item show free shipping. I have double checked and I can’t seem to get it to work with more than one product. Any suggestions would be appreciated. I have WC free shipping set to Minimum Order Amount of $20

    • Well hello there fellow Patrick! I just tested this on my own site and it works fine. Most likely there’s an ID wrong, or some other setting messing with this. Try disabling all other plugins and see if one of them is overriding this functionality.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>