The whole of WooCommerce shipping rests on one rule: the customer lands in the first matching zone and sees only what you put in it. Understanding that single mechanism solves most delivery problems - including the most common ticket I get from store owners, which is “customers are not being shown any shipping method”.
This piece is about configuring costs and rules. Connecting the carriers themselves - pickup point maps in checkout, labels, tracking - is a separate layer and I covered it in the piece on shipping integrations in Poland. Here the subject is what the customer pays and why.
Shipping zones and the order that decides everything
A zone is a set of geographic areas plus the list of shipping methods available to customers there. WooCommerce → Settings → Shipping.
How matching works:
- WooCommerce walks the zones from the top of the list
- It takes the first one whose area matches the customer’s address
- It shows only the methods from that zone - it does not even look at the rest
Which has a practical consequence: the order of zones in the list matters. If a “Poland” zone sits above a “Warsaw - own delivery” zone, a Warsaw customer only sees the nationwide methods. More specific zones have to sit above general ones. You reorder them by dragging the rows.
At the bottom of the list is a special zone: “Locations not covered by your other zones”. It is the safety net for addresses that match nowhere else. Two sensible options: add no method at all (the customer is told you do not ship there), or add a “shipping quoted separately” method at 0 with an explanation in the description. Leaving an ordinary flat rate there can produce an order to another continent for the price of a domestic parcel.
A layout that works in a typical store:
| Order | Zone | Area | Methods |
|---|---|---|---|
| 1 | Local pickup | home city | pickup, free |
| 2 | Domestic | the whole country | courier, locker, free shipping threshold |
| 3 | European Union | selected countries | international courier |
| 4 | Not covered | rest of the world | no methods |
Methods within a zone
You add methods inside each zone. The three built in are flat rate, free shipping and local pickup; carriers add their own once you install an integration.
Flat rate accepts more than a number - it takes a simple formula. The ones I use most:
15- a fixed amount15 + ( 2 * [qty] )- 15 plus 2 per item[qty] * 8- 8 per item[fee percent="3" min_fee="5"]- a percentage of the cart with a floor
Brackets and spaces matter - a formula with a syntax error simply stops calculating. After every change it is worth putting something in the cart and checking the figure rather than trusting that it saved.
Each method also has its own customer-facing name. That is not cosmetic: “DPD courier - delivery in 1-2 working days” sells better than “Flat rate”, and customers decide faster when they can see a timeframe. The method name is one of the cheapest parts of shortening the path through checkout.
Shipping classes and mixed carts
A shipping class is a label attached to products so they are charged differently from the rest. Typical uses: oversized items, heavy goods, stock shipped directly by a supplier, anything needing a pallet.
Setup has two stages: first you create the classes (Shipping → Shipping classes), then you assign them to products, and finally inside a specific method’s settings you give a cost for each class.
That is also where the setting people most often miss lives - how a mixed cart is calculated:
- Per class - a customer with a normal item and an oversized one pays the sum of both rates
- Per order - they pay one rate, the highest one present in the cart
Which you want depends on whether you genuinely ship it as two parcels or one. The most common customer complaint comes from exactly here: they add a small item to a large order and the delivery cost doubles with no explanation.
Note: if a method has a general cost defined but no cost for the class attached to a product in the cart, that method can fail to appear at all. It is one of the more frequent reasons shipping vanishes from checkout.
The free shipping threshold
Free shipping is a separate method with its own trigger condition. You get four: a valid free shipping coupon, a minimum order amount, a minimum amount or a coupon, a minimum amount and a coupon.
Three things to decide deliberately, because the defaults surprise people:
- Net or gross. Which figure the threshold compares against depends on your tax settings. Check it with a test cart right at the threshold instead of assuming - the difference can be significant enough to produce an email from a customer
- Before or after discounts. The method settings contain a switch deciding whether the minimum is applied before coupon discounts. If you issue discount codes, set it on purpose - otherwise a 10% code can quietly take the customer’s free shipping away
- Whether free shipping hides the paid methods. By default a customer over the threshold still sees paid options. That is usually right, because some people will pay for faster delivery - but if you want only free shipping to remain, that has to be forced separately
How to set the threshold. Not by feel and not by copying a competitor. Look up your average order value in the store reports and set the threshold 20-30% above it. Too low and you are giving delivery away to people who would have bought anyway. Too high and nobody reaches it, so the threshold does nothing. After a month, compare average order value with the period before; if it has not moved, the threshold is wrong.
Also check the threshold covers your real shipping cost. Free delivery from 199 PLN on a 15% margin with an 18 PLN courier fee is subsidising your own sales.
”You are 40 away from free delivery”
The threshold does nothing if the customer does not know about it. A cart message showing how much is missing is one of the cheapest things to implement and one of the more measurable - it raises basket value among people who are already buying.
Where it belongs:
- In the cart - the most important spot, that is where the decision to add something happens
- In the mini-cart in the header - if the store has one
- On the product page - a static “free delivery over 250” line under the price, without dynamic calculation
What not to do: do not show that message at checkout. The customer has already decided there, and suggesting they go back to shopping is a direct route to an abandoned cart - in the piece on the technical reasons carts get abandoned I set out how easily you lose people on the final step.
A related setting: the shipping calculator in the cart (Shipping → Shipping options). Switched on, it lets people learn the cost before reaching checkout, which removes the most common buying worry. Switched off, it hides the cost until an address is entered - and that is a setting that statistically costs orders.
Cash on delivery is a payment method, not a shipping one
A frequent misunderstanding during setup: in WooCommerce cash on delivery is a payment method, not a shipping method. You will find it in the payments settings.
Two things follow directly:
- You can restrict it to selected shipping methods - the gateway settings contain a field listing them. Sensible when a courier supports it but local pickup does not
- A surcharge for it is not configured in shipping. Core WooCommerce has no “add a fee to this payment method” field - that needs a plugin or an explicitly named extra shipping method
Whether to offer it at all is a business decision, not a technical one. It raises order counts, because some customers will not buy any other way, and it raises the number of unclaimed parcels you pay for in both directions. Which payment methods are worth having alongside it I set out in the piece on WooCommerce payment methods.
”No shipping methods available” - the causes
Ticket number one. Five causes, in order of frequency:
- The customer’s address matches no zone and the default zone is empty. Check whether they entered a country outside your zones
- The zone exists but contains no methods - the classic after adding a new zone and forgetting the second step
- A product carries a shipping class with no cost defined in that method
- Every product in the cart is virtual - WooCommerce then shows no shipping at all, and that is correct behaviour
- A plugin conflict where something adds rules to shipping - if the problem appeared suddenly with no config changes, check what was updated recently
Diagnosis takes a few minutes: add one ordinary product to the cart, enter your own address and see whether methods appear. If they do, the problem is with a specific product or a specific address rather than the whole configuration.
International shipping
Three things to decide before you enable a single country:
- A separate zone with real rates. An international courier costs several times a domestic one; carrying your domestic free shipping threshold over to the EU is the fastest way to lose money on every parcel
- VAT on sales to consumers in the EU. Above the EU distance selling threshold you account for VAT at the customer’s country rate, usually through the OSS scheme. That is a conversation to have with your accountant before the first order arrives, because it affects the rates charged in the store
- Returns and complaints. The cost of a return from abroad can exceed the order value; it is worth calculating and stating in your terms
The test before you go live
Shipping configuration is not verified in the admin, it is verified in the cart. The eight cases I run before every launch:
- One cheap product, a domestic address - do all the methods appear
- A cart just below the free shipping threshold - is delivery charged and is the shortfall visible
- A cart just above it - did free shipping appear
- A cart with a discount code dropping it below the threshold - does it behave the way you configured
- A product with a shipping class, alone and alongside a normal one - does the total make sense
- Local pickup - does it appear only where it should
- A foreign address - does it land in the right zone
- A virtual product - does shipping disappear
The whole test takes fifteen minutes and catches everything that otherwise comes back as a phone call. Worth repeating after every larger plugin update - it is one of the checks I keep in ongoing store maintenance.
Frequently asked questions
Why does WooCommerce show no shipping methods? Usually because the customer’s address matches no zone and the default “Locations not covered by your other zones” is empty. The second common cause: a product carries a shipping class with no cost defined in that method. Check by adding an ordinary product to the cart and entering your own address.
How do I set free shipping over a certain amount? Add the “Free shipping” method to the zone and set the “minimum order amount” requirement. Decide two things deliberately while you are there: whether the minimum applies before coupon discounts (there is a separate switch) and whether the compared figure is net or gross, which depends on your tax settings and is best confirmed with a test cart.
What amount should the free shipping threshold be? Start from your average order value in the store reports and set the threshold 20-30% above it. Too low means giving delivery away to customers who would have bought anyway; too high means nobody reaches it. After a month, compare average order value with the previous period - no change means the threshold is set wrong.
What is the difference between shipping zones and shipping classes? A zone is a geographic area and the list of methods available in it - it decides what the customer sees at all. A shipping class is a product label that lets you charge delivery differently for part of your range, for example oversized items. The zone answers “where to”, the class answers “what”.
How should shipping be charged when a cart mixes shipping classes? In the method settings you choose the calculation type: per class, meaning the sum of the rates for every class in the cart, or per order, meaning a single highest rate. The choice should reflect reality - if you ship it as one parcel, per-class charging will look inexplicable to the customer.
Running a store where something does not work the way it should? I build and rebuild WooCommerce stores - from a single fix to reworking the whole sales flow. Tell me what you are dealing with and I will send back a scope and a price.