Skip to content
ThemesIonic — home
WooCommerce

WooCommerce Free Shipping Not Working

Free shipping is a method inside a zone, gated by a requirement. When it does not appear, the customer's address matched a different zone, the minimum was calculated on a different total, or a cached session is holding an old rate.

5 min read beginner

Free shipping is not a global switch. It is a method attached to one shipping zone, offered only when its requirement is met. Two questions answer almost every report: which zone did this address match, and was the requirement actually satisfied at the moment rates were calculated?

Work out which zone matched

WooCommerce evaluates zones top to bottom and stops at the first match. Everything below that zone is ignored, including a more specific one. A "Europe" zone placed above a "Germany" zone means German customers never see the German rates.

Open WooCommerce → Settings → Shipping and check:

  • The order of the zones, not just their contents.
  • Whether the customer's country, state or postcode falls inside the zone you expect.
  • Postcode entries — wildcards and ranges have to be formatted the way WooCommerce expects, and a stray space breaks a match silently.
  • Locations not covered by your zones, which is where every unmatched address lands. If that zone has no methods, those customers see "no shipping options" rather than free shipping.

Then reproduce it. Put a qualifying product in the cart and enter the customer's exact country and postcode in the cart's shipping calculator. Guessing at the zone from the settings screen is how this gets misdiagnosed.

Check the requirement

Open the free shipping method itself. The requirement dropdown offers a minimum order amount, a coupon, or either or both together. Three things trip people up:

The minimum is compared against the cart subtotal, not the total. Tax and existing shipping are not included, so a cart displaying more than the threshold can still fall short.

Coupon discounts are applied first by default. A cart at exactly the minimum drops below it the moment a discount lands. The method has a setting to apply the minimum before coupon discounts — choose deliberately, and say which you chose on the shipping page, because customers will notice the difference.

A coupon requirement means a free-shipping coupon. The coupon must have "Allow free shipping" ticked; an ordinary percentage coupon does not satisfy the requirement no matter how large. If the coupon itself is misbehaving first, start with WooCommerce coupon not working.

Rates are cached per session

WooCommerce caches calculated rates against the customer's session so it is not recalculating on every page load. Change a shipping setting and your own browser can keep showing the old result for a long time.

Clear it properly before concluding a setting did not work:

  • Empty the cart and add the item again.
  • Test in a private window, which starts a fresh session.
  • Purge the page cache and any CDN — the order is in how to clear the WordPress cache.
  • With WP-CLI, clear expired transients:
wp transient delete --expired

Confirm the cart and checkout pages are excluded from page caching at every layer. A cached cart page is the most damaging caching mistake a store can make, and it produces exactly this symptom — see choosing a WordPress cache plugin.

Shipping classes and per-product settings

Shipping classes are the quiet cause of "free shipping works except on some products".

  • A class with its own cost inside the zone can override what you expected.
  • A method configured to charge per class still applies when free shipping is offered by a different method entirely.
  • Virtual and downloadable products need no shipping at all. A cart containing only virtual items produces no shipping section, which reads as "free shipping is broken" but is correct.
  • A product with no weight or dimensions breaks any weight-based rule sharing the zone, and can suppress the whole rate set.

Check the product's Shipping tab, not only the zone.

Hiding the paid methods

WooCommerce shows every qualifying method, so free shipping appears next to your flat rate rather than replacing it. There is no core setting for this. A small filter does it:

add_filter('woocommerce_package_rates', function (array $rates): array {
    $free = array_filter(
        $rates,
        fn (string $key): bool => str_starts_with($key, 'free_shipping'),
        ARRAY_FILTER_USE_KEY,
    );

    return $free !== [] ? $free : $rates;
}, 100);

Put it in a small site-specific plugin rather than the theme, so it survives a theme change, and clear the rate cache afterwards. Note that this hides every other method — including local pickup, which customers may still want. Exclude any method you want to keep before deploying it.

When no rates appear at all

A different problem with the same complaint. Check, in order:

  1. The address matched a zone that has at least one method enabled.
  2. The method itself is enabled, not merely present.
  3. Enable shipping is on in Settings → General, and shipping is not set to "disable shipping and shipping calculations".
  4. The cart is not entirely virtual.
  5. No fatal error is occurring during rate calculation — turn on debug mode and check the log.
  6. A live-rate carrier plugin has valid credentials; a failing API call can suppress the whole rate list including your static methods.

The wider setup, including zone design and carrier integration, is in how to set up WooCommerce shipping.

Isolate a conflict

If the configuration is provably correct and the rate still does not appear, test with the store's plugins narrowed down. Shipping is a popular place for plugins to intervene — discount plugins, cart upsells, currency switchers and multi-vendor plugins all filter package rates. The process in how to fix plugin conflicts in WordPress applies here, ideally on a staging copy rather than the live store.

Verify with real carts

Test four carts in a private window: one below the threshold, one exactly at it, one above it, and one above it with a coupon applied. Then repeat with a domestic and an international address. Those eight combinations expose every version of this bug, and they take five minutes — considerably less than the first customer email asking why they were charged for shipping they were promised.

Frequently asked

WooCommerce shows every method that qualifies. Hiding the paid ones once free shipping is available is not a built-in setting — it needs a small filter or a shipping plugin that adds the option.
That is a setting on the method. Coupons discount before shipping is calculated by default, so a cart just over the threshold can drop under it once a discount applies unless you choose the option that ignores coupon discounts.
Their address matches a different shipping zone, or their cart contains an item in a shipping class the zone excludes. Reproduce it by entering their exact postcode and country in the cart calculator.

Related guides