WooCommerce Expiry Date Tracking: What Product Data Holds
WooCommerce tracks stock per product, not per batch. See what an expiry field or plugin can hold, where FEFO breaks, and how to run a daily CSV expiry check.
ShelfLifePro Editorial Team
Inventory management insights for retail and pharmacy
Two batches, one stock number
Picture a small online shop that sells supplements, specialty snacks or pet treats on WooCommerce. A new carton of the bestselling protein powder arrives while a few tubs from the last delivery are still on the shelf. Someone updates the stock quantity, the product page says "In stock", and orders keep coming in.
What the store just lost is the fact that those tubs carry two different best before dates. WooCommerce now holds one number for the product. The older tubs are still in that count, and nothing on the screen tells the packer which ones to grab first.
That's not a bug. It's how the data model works, and it's worth understanding before you buy a plugin to fix it.
How WooCommerce stores stock
In WooCommerce, stock lives on the product. Turn on stock management for a simple product and you get one quantity field. On a variable product (sizes, flavours, pack counts) each variation can hold its own quantity. That's as deep as the core stock model goes.
Core has no batch, lot or expiry concept. A batch in the warehouse sense, meaning units that arrived together and share a date, has nowhere to live. When an order comes in, WooCommerce takes one off the product or variation count. It doesn't know or care which physical tub went in the box.
So the real question for WooCommerce expiry date tracking isn't "where's the expiry setting?" It's "where can a date be attached at all?"
What a custom field or plugin adds
There are two common ways to get a date onto a product:
- Custom fields (product meta). You add a field like `best_before` to each product, through a custom-fields plugin or a code snippet. It shows up in the admin, and you can show it on the product page too.
- A WooCommerce expiration date plugin. What you get depends on the plugin. It might be a date field on the product or variation, an admin list sorted by date, an email when a date gets close, or a setting that hides the product once the date passes.
Both work well in one situation: when every unit in stock shares a single date. Think a limited drop, a pre-order, or a bakery box baked fresh for the week. One date per product is enough there.
What the product data can't hold
Things go wrong once a product has more than one date in stock at the same time, and any item you restock will get there.
- One field, several dates. A single best before field holds either the old batch's date or the new one's. Whichever you enter, you're wrong about part of the stock.
- No quantity per date. Some plugins let you list several batches. Check whether each sale actually comes off a specific batch. If it doesn't, the batch quantities stop matching reality after the first day of orders.
- No FEFO view. First-expiry-first-out needs every batch in the store on one list, sorted by date, with quantities. A field on each product scatters those dates across product pages. You don't get a pick list.
- No sales speed next to the date. A date that's close is fine if the product sells fast. A date months away is a problem if it barely moves. The product record holds the date and the count, but it can't answer the question that matters: will these units sell before then?
- No cost at risk. Without cost per unit next to the date, you can't tell which problem is worth fixing first.
It's the same gap covered in why inventory systems leave expiry tracking out. A stock count is built to answer "can I sell this?", not "which of these goes off first?"
Get the free expiry-tracking spreadsheet
Batch-level rows, days-left and status formulas, colour-coded alerts, and a live value-at-risk summary. Works in Excel and Google Sheets. See what's inside.
Instant download. No spam, unsubscribe in one click.
Splitting batches into variations
The usual workaround is to make each batch its own variation: "Protein powder, vanilla, BB March" next to "Protein powder, vanilla, BB August". Now each date has its own quantity. That's WooCommerce batch tracking, sort of.
You pay for it elsewhere. Customers see dates as options, or you hide them and fight with default selections. Every delivery means creating one variation and retiring another. Reviews and sales history get split across variations. And someone still has to decide which variation sells first, because the store won't steer buyers to the older batch on its own.
It's fine for a few high-value items. Try it across the whole catalogue and the admin work buries it.
Exporting products and stock to CSV
Whatever you store on the product, you can get it out again. WooCommerce has a built-in product exporter (Products → Export in the admin) that writes a CSV with SKU, name, stock quantity, price and more. If your dates live in custom fields, tick the option to export custom meta and they come out as extra columns.
These are the columns a daily expiry check needs:
- SKU and product or variation name
- Stock quantity
- Expiry or best before date, from the meta column or a separate batch sheet
- Unit cost, joined in from your purchase records if it isn't stored in WooCommerce
- Units sold over a recent window, from your orders or analytics export
If batch dates don't live in WooCommerce at all, keep a simple batch sheet with SKU, date and quantity received, and fill it in when stock arrives. The expiry-tracking spreadsheet template is set up for exactly that. The date has to be written down at receiving, because nothing later in the process can recover a date nobody recorded. If the products you stock carry a mix of date types from different manufacturers, this guide to date wording explains what each one means.
A daily expiry check from the export
Suppose you have 40 tubs of vanilla protein powder. 15 are from an older batch with a best before 21 days away, and the other 25 don't expire for months. The product sells about 0.5 tubs a day. Over 21 days that's roughly 10 tubs sold, even if every sale comes from the older batch first. So about 5 of the 15 won't clear in time. At a worked-example cost of $18 a tub, that's $90 at risk on one SKU, and you can see it three weeks ahead instead of on the day it expires.
Here's the routine, run on the export each morning:
- Sort the batch rows by date, earliest first.
- For each near-dated row, divide units on hand by daily sales to get days to clear.
- Flag any row where days to clear runs past the date.
- Rank the flagged rows by units that won't clear times unit cost.
- Decide on each one: move it to the front of the pick, bundle it, mark it down, return it to the supplier, or donate it.
The 2-page FEFO cheatsheet covers the picking side, and pricing near-expiry products covers how deep a markdown should go.
A spreadsheet can do all of this. Its weak spot is the person running it. The export goes stale if nobody pulls it, the sales window needs refreshing, and the check stops when whoever built it is away. Shops on Shopify run into the same wall, as the Shopify version of this problem shows, and so do stores working from a till, covered in tracking expiry with your existing POS.
Where a daily agent fits
ShelfSense by ShelfLifePro is a daily inventory agent that runs this check alongside the system you already have. Once a day it reads your stock, batch, cost and expiry records. Then it lists what to mark down, clear or reorder, ranked by money at risk, with the math shown for every call. It recommends and you approve. It never changes a price or places an order on its own, and when it isn't sure, it says nothing.
For WooCommerce, you export to CSV today, and a direct connection is available on request. ShelfSense's free audit reads one CSV export, no account needed. If you'd like to see what your current export shows, start free on the ShelfSense page.
ShelfLifePro Editorial Team
The ShelfLifePro editorial team covers inventory management, expiry tracking, and waste reduction for pharmacies, supermarkets, and retail businesses worldwide.
See what batch-level tracking actually looks like
ShelfLifePro tracks expiry by batch, automates FEFO rotation, and sends markdown alerts before stock expires. 14-day free trial, no credit card required.
The monthly expiry-tracking brief
One short email a month, only when there is something worth reading. FEFO tactics, markdown math, and real-world waste-reduction wins. Unsubscribe anytime.
No spam. Unsubscribe in one click.