Launch pricing: Lock in Pro at $79/yr before prices go up View pricing →

Stop losing money to expired stock in WooCommerce

If you sell anything with a shelf life — food, supplements, cosmetics, medical or veterinary supplies — your inventory has a clock on it that WooCommerce can’t see. Core WooCommerce manages quantity beautifully but has no concept of time: no field for a best-before date, nothing to stop an expired item being bought, and no view of what’s about to go off. The result is the quiet, recurring cost of perishable retail — stock written off at the back, the occasional past-date item shipped to a customer, and money tied up in inventory you can’t see expiring.

This guide covers the full workflow for managing perishable inventory in WooCommerce: recording expiry dates, rotating stock with FEFO, pulling expired items automatically, discounting short-dated stock to recover revenue, and keeping lot traceability. Some of it is free; some needs the Pro add-on. We’ll be clear about which is which.

1. Record an expiration date on every perishable product

Everything starts with a date. The free Sellinor Product Expiration Dates plugin adds an Expiration tab to the product editor where you set a best-before or use-by date with a date picker. Variations each get their own date, and you can set a default on the parent that dateless variations inherit — useful when most sizes share a shelf life and one or two differ.

For a real catalog you won’t edit products one at a time. From the Products list you can use Quick Edit for a single inline change or Bulk Edit to apply one date across a selection. For larger jobs, the Import / Export page imports dates from a CSV matched by product ID or SKU in YYYY-MM-DD format — start from the Download template button, which pre-fills every product with its current date. Details are in Getting started and Import & export.

2. Decide what happens automatically on expiry

A date is only useful if something acts on it. Under Products → Expirations → Settings → General you choose the expiry action:

  • Hide from catalog — the product disappears from shop, category, and search pages. Its page still exists so existing links don’t break. This applies immediately.
  • Set to out of stock — the item can still show in your catalog but can’t be bought. This runs on an hourly background check, so it can take up to an hour to appear.
  • Both — neither browsable nor purchasable.
  • Do nothing — the default, leaving you in manual control.

You don’t have to wait for the exact date. A days before setting fires the action early — set it to 3 and items are pulled three days ahead, giving you a buffer to clear or discount them. And whenever any action other than “do nothing” is on, the cart is guarded immediately: an expired item can’t be added, and if something expires while already in a cart it’s removed at checkout. That cart protection kicks in instantly, even before the hourly out-of-stock sweep runs. See Expiry actions for the full behaviour.

This single step — dates plus an automatic action — is enough to stop expired products being sold on most stores, and it’s entirely free.

3. Rotate stock with FEFO, not guesswork

Pulling expired stock is reactive. The way to avoid reaching that point is correct rotation. For dated goods the right method is FEFO — First Expired, First Out: ship the unit closest to expiring first, regardless of when it arrived. It differs from the more familiar FIFO (First In, First Out) whenever a newer delivery carries a shorter shelf life than stock already on the shelf — which happens often, and is exactly how good stock quietly expires behind newer boxes.

Core WooCommerce can’t do FEFO because it tracks one stock number per product. The Pro add-on adds batch tracking: you record each shipment as a batch with a quantity, an expiration date, and an optional batch reference or lot number. When an order comes in, the plugin deducts from the batch that expires soonest, moving to the next batch only when one runs out. If the batches can’t cover the order, it’s placed on hold with an order note rather than overselling stock you don’t physically have. The mechanics live in Batch tracking, and there’s a dedicated FEFO for WooCommerce walkthrough.

Batch totals stay in sync with WooCommerce’s stock field automatically, so you manage stock by editing batches and never touch the quantity box directly.

4. Discount short-dated stock instead of writing it off

Even with good rotation, some stock will approach its date faster than it sells. Writing it off is the worst outcome; discounting it to move it is almost always better. The Pro add-on applies automatic tiered discounts by days-until-expiry — for example:

Days until expiryDiscount
14 days10% off
7 days25% off
3 days50% off

The discount applies in real time through WooCommerce’s price filters, steps up as the date approaches, and can show an “expiring soon” badge on shop and product pages to draw attention to the deal. Set tiers that still protect your margin — a gentle nudge early, steeper cuts only in the final days. Full setup is in Automatic discounts.

One thing to know: because the discount is dynamic rather than written as a sale price, discounted items don’t appear in WooCommerce’s “on sale” loops like the [sale_products] shortcode. The price, strikethrough, badge, and totals on the products themselves are all correct.

5. Keep lot traceability for recalls and refunds

For regulated categories — supplements, cosmetics, food — knowing which batch a customer received isn’t optional. With batch tracking, the lot used to fulfil an order is recorded on the order and in the customer’s email. Refunds and cancellations return stock to the correct batch, not just a generic quantity, and every batch action — created, deducted with the order number, adjusted, swapped, expired, or deleted — is written to the Activity Log. If you ever need to trace or recall a specific lot, you have the per-product, per-order history to do it.

6. Watch what’s expiring across the whole catalog

Managing perishable inventory is a continuous job, so you need a view that doesn’t require opening products. The free Overview dashboard at Products → Expirations gives you stat cards — products tracked, expiring soon, expired, and the value at risk (the stock value of inventory inside your expiring-soon window) — plus a filterable product table and a month calendar showing how many products expire each day. Click a day to see exactly what’s due. The Products list also gains a sortable Expiration column, and your WordPress dashboard gets an Expiring products widget. See Reports & calendar.

To stay ahead without logging in, the Pro add-on can send a scheduled email digest (daily, weekly, or monthly) of products entering your threshold — see Email notifications.

Putting it together

A solid perishable-inventory setup in WooCommerce is really five habits: record a date on everything, act on it automatically, rotate by FEFO, discount what’s short-dated, and keep an eye on the calendar. The first two are free and stop expired products being sold today. FEFO, automatic discounts, lot traceability, and email digests are the Pro add-on, and they’re what turn “don’t ship expired stock” into “barely write anything off.”

If you sell groceries or fresh food specifically, the WooCommerce food & grocery expiry dates guide goes deeper on that workflow. Otherwise, start with the free install, get your dates in, and decide on your expiry action — that’s the foundation everything else builds on.

Frequently asked questions

What is perishable inventory management in WooCommerce?

It's the practice of managing stock that has an expiration or best-before date — food, supplements, cosmetics, medical supplies — so nothing is sold past its date and as little as possible is written off. Core WooCommerce only tracks a stock quantity with no concept of time, so you add a date field, an automatic action when that date arrives, and ideally batch tracking and short-dated discounting on top. The free Sellinor Expiration Dates plugin adds the date field and automatic expiry actions; its Pro add-on adds batch tracking with FEFO and automatic discounts.

Does WooCommerce track expiration dates by default?

No. Core WooCommerce has no field for an expiration or best-before date and no way to act on one — it only tracks a single stock quantity per product. You add the capability with a plugin. The free Sellinor Expiration Dates for WooCommerce plugin adds an Expiration tab to the product editor, a sortable date column to the products list, and automatic actions when a product reaches its date.

How do I stop expired products from being sold?

Set an expiry action under Products → Expirations → Settings → General. You can hide expired products from the catalog, set them to out of stock, or both, and trigger the action a set number of days before the date. With any action other than 'do nothing' enabled, expired items also can't be added to the cart and are removed at checkout, so a product that expires while sitting in someone's cart never gets bought.

What is FEFO and why does it matter for perishable stock?

FEFO stands for First Expired, First Out: you sell the unit closest to its expiration date first, regardless of when it arrived. It matters because deliveries don't always arrive in date order — a newer shipment can have a shorter shelf life — so selling oldest-received first (FIFO) can leave soon-to-expire stock unsold. With the Sellinor Pro add-on, each product holds dated batches and orders deduct from the earliest-expiring batch automatically.

How can I reduce waste from short-dated products?

Discount short-dated stock automatically before it expires. The Sellinor Pro add-on lets you set tiered discounts by days-until-expiry — for example 10% off at 14 days, 25% at 7 days, 50% at 3 days — applied automatically with an 'expiring soon' badge on the storefront. This recovers revenue from stock that would otherwise be written off, while still pulling anything that does reach its date.

Can I keep a record of which batch shipped on each order?

Yes, with the Pro add-on's batch tracking. Each batch carries a quantity, an expiration date, and an optional batch reference or lot number. When an order is fulfilled, the batch used is recorded on the order and the customer's email, refunds and cancellations return stock to the correct batch, and every batch action is written to the activity log — giving you per-product, per-order lot traceability.

Get expiry tracking into your store today

Install the free Sellinor Expiration Dates plugin from WordPress.org, set your first best-before date, and let WooCommerce hide or out-of-stock expired items automatically.

See plans & download free

Or read the documentation.