Stock management in WooCommerce is a setting per product and a set of behaviours that follow from it. Most stock problems are not the software being wrong; they are stock tracked at the wrong level, or a backorder setting nobody chose deliberately.
Turn it on where you need it
Under WooCommerce inventory settings, enable stock management globally, then per product where it applies.
A digital product does not need it. A physical one usually does, because the alternative is selling something you cannot ship.
Variable products track stock per variation
This is the mistake that causes real problems, and it is easy to make.
On a variable product you can set stock at the parent level or per variation. Setting it at parent level means WooCommerce knows you have twelve of something without knowing which sizes, so a customer can buy a size you have none of.
Track per variation. It is more entries to maintain and it is the only arrangement that reflects reality.
Decide the backorder behaviour deliberately
Three options per product, and the default is not always right.
Do not allow. The product becomes unpurchasable at zero. Correct when you genuinely cannot supply it.
Allow. Customers keep buying with no indication of a wait. This produces complaints, because they had no reason to expect a delay.
Allow, but notify the customer. They can buy and they are told it is on backorder. This is usually the right setting for something you will restock, and it is the one that gets left on the default instead.
Low stock notifications
Set a threshold and WooCommerce emails you when a product drops below it.
Send those to an address someone actually reads, and not one on the domain the store runs on, if the site has a problem, the notification goes with it.
Set the threshold against your restock time rather than picking a round number. If a supplier takes two weeks, being told at two units is too late.
Stock is reserved at checkout, briefly
WooCommerce holds stock for orders in pending payment for a configurable period, then releases it.
Too short and a customer completing a slow bank transfer loses their item mid-payment. Too long and abandoned carts make products appear out of stock when they are not.
Sixty minutes is a reasonable default. If you take payment methods that settle slowly, extend it.
Stock says zero and you have some
Three causes, in order.
Stock at parent level on a variable product while variations also track it. The two disagree and the customer sees the wrong one.
Held stock from abandoned orders. Cancel stale pending orders and the stock returns.
A refund that did not restock. WooCommerce can restock on refund and it is not automatic, refunding without ticking it leaves the item recorded as sold. This is the most common quiet cause of drift between the store and the shelf.
Bulk updates
The products list supports bulk stock changes, which is enough for a small catalogue.
For larger changes, the CSV importer updates existing products when the SKU matches. Export first, edit, import back, and test on a handful before running it across everything, because a spreadsheet mistake applied to two thousand products is a restore instead of an undo.
This is the argument for giving everything a SKU, including each variation. For that, see adding and managing products.
Reconcile against reality
Whatever the store says, count the shelf occasionally.
Drift accumulates from refunds that did not restock, orders cancelled by hand, breakages and returns processed outside the system. None of those are software faults and all of them make the number wrong.
A store that oversells because its stock figures drifted loses more than the sale. It loses the customer who was told the item was available.
Where the numbers actually live
Stock is stored per product or per variation, and on older stores it is held in metadata rows rather than in a dedicated column. That has two consequences worth knowing.
Filtering or sorting by stock is expensive, which is why an admin list of a large catalogue is slow. And a plugin writing stock directly to the database rather than through WooCommerce's own functions can leave the displayed figure and the stored one disagreeing.
Newer versions keep this in dedicated tables and both problems largely go away. There is more on that change and why it is a migration rather than a setting in WooCommerce database growth.
Two channels selling the same stock
The moment stock exists in more than one place: the website and a till, or the website and a marketplace; the question stops being about WooCommerce and becomes about which system is authoritative.
Pick one. Every other system reads from it and none of them writes independently, or the two drift and neither figure can be trusted.
Synchronisation between two writing systems is the arrangement that produces overselling, and it fails most often at exactly the busy moments when it matters. Preparing your store for a sales peak sets out that period.
What a restore does to stock
Restoring a backup moves stock counts backwards to whatever they were when the backup ran, while the orders placed since have already shipped.
The result is a catalogue claiming to have items that are gone. It is not visible in any error and it is discovered by customers ordering things you cannot send.
So a restore on a store needs a stock reconciliation afterwards, in the same way it needs an order reconciliation against the payment provider. Backing up a store that takes orders continuously walks through building that step into the recovery procedure rather than improvising it.
Auditing without stopping the shop
wp wc product list --field=id --status=publish | head -50
Export the catalogue with its stock figures and compare against a physical count, on a schedule rather than after a problem.
The discrepancies that matter are systematic rather than random: one supplier's products always low, one category always high. That pattern points at a process: a return that is not recorded, a bundle that decrements the wrong item, and fixing the process is what stops the drift returning after every count.