WooCommerce Inventory Management
Core stock control is a number that goes down when an order is placed. Everything that makes inventory hard — variations, bundles, multiple channels, returns — is what happens around that number.
WooCommerce stock is one integer per item, decremented on order. That is the entire core model, and it is sufficient for a single-channel shop selling simple products. Every inventory problem that follows comes from a situation the integer cannot describe.
The settings that decide behaviour
Four store-level options do most of the work, and they are worth setting deliberately rather than accepting:
- Manage stock globally, then per product. Without it, nothing is tracked at all.
- Hold stock for unpaid orders, in minutes. This is why quantities drop without a sale.
- Low stock and out of stock thresholds, which drive notifications and visibility.
- Out of stock visibility, deciding whether sold-out items disappear from the catalogue or stay visible.
That last one is a merchandising decision disguised as a technical setting. Hiding sold-out products keeps the catalogue clean and destroys the URLs' search value; keeping them visible retains the ranking and needs a clear "back soon" state. For anything seasonal, keep them and say when they return.
Variations are where accuracy is won or lost
A product in four sizes and three colours is twelve physically separate things. Stock belongs on each of them.
Managing at the parent level is the most common inventory mistake in WooCommerce: the product shows as in stock because two sizes remain, a customer orders the sold-out size, and you are issuing a refund and an apology. Adding product variations covers the mechanics; the discipline is to enable stock management on every variation and give each one its own SKU.
Bundles and grouped products complicate this further, because selling a bundle should decrement several underlying items. Core does not do that — see product bundles for what actually handles it.
Held stock, and the abandoned checkout
When a customer reaches checkout, WooCommerce reserves the quantity so two people cannot buy the last one simultaneously. If payment does not complete, the hold expires and the stock returns.
Two failure modes:
- A hold period that is too long makes popular items look sold out during a busy sale.
- A hold period that is too short allows the same unit to be sold twice while the first payment is still processing.
Fifteen to sixty minutes suits most stores. If stock seems to vanish and return on its own, this is the mechanism, and the cancelled orders list will show why. Orders stuck in a pending state are a related symptom worth reading alongside checkout not working.
Where the numbers actually break
| Cause | What goes wrong |
|---|---|
| Selling on another channel | Overselling, because core sees only your site |
| A CSV import overwriting stock | Yesterday's numbers restored on top of today's |
| Manual edits during a sale | Two people writing the same field |
| Refunds without restock | Returned goods never come back into stock |
| Cancelled orders in bulk | Stock restored for items never dispatched |
The import case is the quiet one. A CSV product import that includes a stock column will overwrite live quantities with whatever was in the file — which is correct behaviour and almost never what the person running it intended. Import without the stock column unless you are deliberately resetting counts.
Backorders, honestly
Backorders let people buy what you do not have. The choice is between three positions: not allowed, allowed silently, or allowed with the customer notified.
"Allowed silently" is the setting to avoid. A customer who discovers after paying that the item ships in three weeks is a support ticket and often a refund. If you accept backorders, say so on the product page and in the confirmation email, and give a date.
When inventory should leave WordPress
At a certain point the store should stop being the system of record.
Move to a dedicated inventory system when you sell the same stock through more than one channel, when purchasing and supplier lead times need tracking, when goods move between locations, or when someone is reconciling spreadsheets weekly. From then on WooCommerce receives stock levels rather than deciding them, and the store becomes one channel among several — which is also the moment B2B and wholesale pricing and point of sale start to matter, since both are additional channels drawing on the same numbers.
Synchronisation is not free. Expect a sync interval, expect conflicts, and decide explicitly which system wins.
Common mistakes
- Stock managed at the parent product instead of the variation.
- Importing a CSV with a stock column during trading hours.
- No SKUs, which makes every reconciliation manual.
- Refunds without restocking, so returns are lost from the count.
- Hiding out-of-stock products and losing the search value of their URLs.
- Believing the number without a physical count — every real inventory drifts.
Verify
Place a test order for a variation, confirm the correct variation's stock decremented, then refund it with restock and confirm the number returns. Reach checkout without paying and watch the hold appear and expire. Run a low-stock product to zero and check what a customer sees on the product page, the shop archive and search — the three views often disagree, and products not showing is usually that disagreement rather than a bug.
Frequently asked
- Because unpaid orders hold stock. When a customer reaches checkout and does not pay, the quantity is reserved for a configured hold period so it cannot be oversold, and it is released when the order is cancelled.
- Per variation whenever variations are physically separate items, which is almost always. Managing at the parent level means a size that has sold out still shows as available, which produces refunds rather than orders.
- Not on its own. Core knows only about orders placed on your site, so a marketplace or a physical till selling the same items will oversell unless something synchronises them — usually an inventory system that owns the numbers.