Description
Expired stock costs you twice: once when you throw it away, and again when a customer receives something past its date. Sellinor Expiration Dates for WooCommerce puts a date on every product that needs one, shows you what is about to run out, and takes expired products off sale on its own.
Call it an expiration date, an expiry date, a best before or use by date — it works the same way. It is made for grocery and food shops, bakeries and fresh produce, dairy and meat, drinks, supplements, cosmetics, pharmacy and medical supplies, and anything else with a shelf life.
How it works
- Set a date. Open a product’s Expiration tab — right after Inventory — pick a date, or tap +1 week, +1 month, +6 months or +1 year. Variations can each have their own date.
- Choose what happens. When a product expires, hide it from the shop, mark it out of stock, or both — on the day itself or a few days early.
- Let it run. The plugin checks every hour. Expired items are kept out of carts and removed at checkout, and every action is written to the activity log.
Features
Dates on every product
- Expiration dates on simple and variable products, with a separate date per variation or one default date for all of them.
- Quick-set buttons in the product editor, plus quick edit and bulk edit from the product list.
- A sortable, colour-coded Expiration column and an « Expired / No date » filter in the product list.
- Optionally show the date on the product page, with your own label (« Best before », « Use by », …) and only when it is getting close.
Automatic protection
- Hide expired products, set them out of stock, or both — with an optional number of days before the date.
- Cart and checkout protection: expired items cannot be added to the cart and are removed at checkout.
See what is coming
- An Expirations overview with Expiring soon and Expired lists, search, sorting, a value-at-risk column and an expiration calendar.
- A dashboard widget with the products that expire next.
- An activity log of every automatic action and date change, with filters, search and CSV export.
Bulk work and developers
- CSV import and export of expiration dates for every product and variation.
- Data & cleanup tools: clear dates in bulk, or move long-expired products to the trash — both preview exactly which products match first.
- REST API: an
edfw_expiration_datefield on WooCommerce products and variations, and filters to list products expiring within a date window — for syncing with an ERP, POS or warehouse system. - WP-CLI:
wp edfw get | set | clear | listfor scripts, scheduled jobs and migrations. - Compatible with WooCommerce High-Performance Order Storage (HPOS). Translation-ready.
Pro add-on
This plugin is complete on its own. For stores that manage a lot of perishable stock, a separate Pro add-on is available from sellinor.dev:
- Batch & lot tracking (FEFO) — several batches per product, each with its own date; orders take stock from the earliest-expiring batch first, and the lot number appears on orders and emails.
- Automatic expiry discounts — tiered discounts as the date gets closer, with an optional « Expiring soon » badge.
- Clearance category — short-dated, discounted products gather in a storefront category that keeps itself up to date.
- Per-category rules & shelf life — different actions and lead times per category, and a shelf life that dates restocked products automatically.
- Waste, recovery & forecast reports — value written off vs. recovered, trends by month and category, and what expires in the next 7, 30 and 60 days.
- One-click date changes & write-offs — select products on the Overview and extend, re-date or write them off in one go.
- Email alerts & digests, event webhooks (Slack, Zapier, Make or any URL), and an Expiration date column in WooCommerce’s own product import/export.
Pro is a separate plugin; nothing in this plugin is locked or time-limited.
Documentation
Guides for every feature: sellinor.dev/docs/product-expiration-dates/.
Screenshots












Installation
- Install the plugin from Plugins Add New, or upload the
sellinor-expiration-dates-for-woocommercefolder to/wp-content/plugins/. - Activate it. WooCommerce must be installed and active.
- Go to Products Expirations Settings and choose what should happen when a product expires.
- Edit a product, open the Expiration tab and set a date.
FAQ
-
Can I use it for best before, use by or sell by dates?
-
Yes. The plugin stores one date per product or variation and acts on it — what you call that date is up to you. You can also set the label customers see on the product page, for example « Best before ».
-
What happens when a product expires?
-
You choose in the settings: hide it from the shop, set it out of stock, both, or do nothing and handle it yourself. You can also have the action run a number of days before the date. Hiding and out-of-stock also stop expired items from being bought: they cannot be added to the cart, and any already in a cart are removed at checkout.
-
Does it work with variable products?
-
Yes. Each variation can have its own date, or you set one default date on the parent that every variation without its own date uses. A variable product is only hidden once all of its variations have expired.
-
Can I import expiration dates in bulk?
-
Yes. Products Expirations Import / Export downloads every product with its current date; edit the file and upload it again. Developers can also use the REST API or WP-CLI.
-
Will it show the date to customers?
-
Only if you want it to. Turn on the product-page display in the settings, pick a label, and optionally show the date only when it is within a certain number of days.
-
Can I get an email when products are about to expire?
-
The free plugin shows everything expiring soon on the Expirations overview and in a dashboard widget. Scheduled email digests are part of the Pro add-on.
-
Does it support batches or lots with different dates?
-
The free plugin tracks one date per product or variation. If you receive the same product in batches with different dates, the Pro add-on tracks each batch separately and sells the earliest-expiring one first (FEFO).
-
Is it compatible with WooCommerce HPOS?
-
Yes. The plugin declares full compatibility with WooCommerce High-Performance Order Storage.
-
What does the activity log record?
-
Every automatic action (a product hidden or set out of stock), date changes made in the editor, by bulk edit, import, the REST API or WP-CLI, and the cleanup tools. Entries older than 90 days are removed automatically.
-
Will my data be removed when I uninstall?
-
Only if you ask for it. By default your dates, settings and activity log are kept in case you reinstall. Turn on « Delete all plugin data » in Settings Data & cleanup for a full cleanup.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Sellinor Expiration Dates for WooCommerce” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Sellinor Expiration Dates for WooCommerce” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.7.3 – 2026-09-28
- Maintenance release alongside the Pro add-on; no changes to the free plugin.
1.7.2 – 2026-09-27
- Improved: the Pro Features page describes the Pro email digest’s 30-day summary as optional.
1.7.1 – 2026-09-27
- Improved: the Expiration column in the products list is wide enough for long dates such as « September 24, 2026 » to stay on one line.
1.7.0 – 2026-09-27
- Improved: the product editor’s Expiration tab now sits right after Inventory, with the date and its quick-set buttons (+1 week, +1 month, +6 months, +1 year) together. « +1 month » is now a calendar month rather than 30 days.
- Improved: Expirations sits directly under « Add new product » in the Products menu.
- Improved: on the Overview, hovering a value shows how it is calculated (e.g. « 48 × $10.39 (on sale, regular $12.99) »), and the search sits in its own toolbar row.
- Improved: status labels such as « 7 days left » no longer wrap onto two lines on narrower screens.
- Added: a short, dismissible note on WooCommerce’s own Products Export and Import screens about including expiration dates.
- Improved: the Import / Export button that downloads your products with their current dates is now labelled « Download template » (it said « empty template »).
- Improved: clearer wording and spacing on the Pro Features page.
- Improved: plugin description, FAQ and screenshots refreshed.
- Dev: new
edfw_page_header_actionsaction for adding buttons to the Expirations page header. - Fixed: a stray empty file was included in the 1.6.0 package.
1.6.0 – 2026-09-20
- Added: a « Data & cleanup » section in Settings gathering the tools that change your data in one place — clear expiration dates in bulk (every dated product, or only those already expired), and move expired products to the trash. Both preview how many products match and let you see exactly which ones before you commit.
- Added: an « Include out of stock » toggle on the Overview filter bar, carried across tabs.
- Added: a dismissible notice after activation pointing at the Expirations screen.
- Added: a link to the Pro features page from the plugin’s row on the Plugins screen.
- Improved: out-of-stock products are now treated the same way everywhere — the product list, the calendar, the counts and the dashboard widget no longer disagree with each other.
- Improved: a far-off expiration now reads « ~8 months left » or « ~2 years left » rather than a raw day count.
- Improved: Settings subsections no longer scroll off-screen when several add-ons are active; System Info stays last and Data & cleanup sits after any add-on sections.
- Improved: the settings-saved notice moved to WordPress’s standard position and can be dismissed.
- Improved: Overview layout — Recent activity above Plugin status, activity-log actions grouped, sentence-case headings and assorted spacing fixes.
- Fixed: an Overview calendar day could show a different count from the list it links through to.
- Fixed: report statistics are cached separately per out-of-stock filter, so switching the toggle no longer briefly shows the other filter’s numbers.
- Dev: translation template regenerated (409 strings).
1.5.4 – 2026-09-12
- Tested up to WordPress 7.1.
- Refreshed the plugin directory assets: new screenshots, banner and icon.
1.5.3 – 2026-07-05
- Fixed: a momentary product-load failure during the hourly expiry sweep no longer skips a variable product’s expired variations for the rest of the day — it retries on the next run.
- Improved: the Overview « inventory at risk » estimate now consistently excludes variable products whose variations use batch/lot tracking (Pro) from the single-date sum, since those lots are already valued precisely.
1.5.2 – 2026-07-05
- Fixed: batch/lot-tracked products (Pro) could be hidden from the catalog while later lots were still sellable — the derived visibility dates now respect batch tracking everywhere and clear themselves.
- Fixed: expiration-date writes to batch-tracked products via quick edit, CSV imports, the REST API, and WP-CLI are now cleanly skipped or rejected instead of being silently reverted by the next batch sync.
- Fixed: the Overview « inventory at risk » figure now values batch-tracked products by their actually-expiring lots instead of their entire stock.
- Fixed: quick-set date preset chips now compute from the store’s timezone rather than the browser clock.
- Security: CSV exports (Activity Log, Pro Waste & Recovery) now neutralize spreadsheet formula injection in free-text cells.
- Performance: the hourly expiry sweep no longer re-scans every previously-expired variable product on every run.
- Performance: the Products-list expiration column and the Overview calendar each dropped their per-row/per-page query overhead on large catalogs.
- Improved: the Pro features page, comparison table, and settings previews now describe the full current Pro feature set; screen-reader labels on the waste/recovery trend cards.
- Dev: uninstall cleanup now covers the event-webhook options and the waste-sweep cron.
1.5.1 – 2026-07-04
- Improved: a report search with no matches on the current tab now links straight to the matches on the other tab (« Found 2 in Expired ») instead of dead-ending at zero.
1.5.0 – 2026-07-04
- Added: search the Overview report by product name or SKU, and sort it by product name or expiration date (click the column headers).
- Added: the WooCommerce REST API products endpoint accepts edfw_expires_before / edfw_expires_after filters, so external systems can pull everything expiring in a window in one call.
- Added: WP-CLI commands — wp edfw get / set / clear / list (with expiring-window flags and table/csv/json/ids/count output) for hosting automation and bulk scripting.
- Added: product-editor quick-set date chips (+1 week / +1 month / +3 months / +1 year) and, on variable products, one-click « apply this date to all variations » / « clear all variation dates » tools (batch-tracked variations are respected and skipped).
- Added: export the Activity Log as CSV, respecting the on-screen filters.
- Added: a maintenance tool that previews and moves long-expired products to the trash (reversible; variable products only qualify when every variation has long expired), with each product logged.
- (With the Pro add-on) the digest email now includes the value at risk in the next 7/30 days alongside its waste summary, and a new event webhook POSTs signed JSON (Slack/Zapier-compatible, batched per request) whenever expiry events happen.
- Improved: the Activity Log lists entries in a fully deterministic order, and search/sort/filters carry correctly across pagination.
1.4.0 – 2026-07-04
- Added: a getting-started guide on the Overview for new installs — choose your expiry action, add your first dates (product editor, quick edit, or CSV import), and track everything from the dashboard. It disappears on its own once real data exists (dismissible per user, and controllable via the edfw_show_onboarding filter).
- Added: the expiration date is now a first-class field (edfw_expiration_date) on the WooCommerce REST API products and variations endpoints, so POS/ERP systems and scanner workflows can read and write dates programmatically. The field appears in the endpoint schema, invalid dates are rejected with a clear error on every route (batch endpoints included), null or an empty string clears the date, and every change is recorded in the Activity Log as « API: date set/cleared ».
- Improved: the Activity Log filter now offers every recorded action type (including stock write-offs), and API entries carry their own icon.
- (With the Pro add-on, the Reports tab additionally gains a 6-month waste-vs-recovery trend, a per-category loss breakdown, and a CSV export of the raw waste and recovery events.)
1.3.0 – 2026-07-04
- Added: the Activity Log now records expiration-date changes made via quick edit and on individual variations (previously only product-editor edits were logged), with the edit source stored on every entry.
- Added: extension points that let add-ons set per-product expiry behaviour — an effective-policy filter consulted by purchasability, cart validation, the out-of-stock sweep and the catalog hide logic, a per-product frontend display filter, page-tab registration, and Overview hooks for extra report cards. (These power the Pro add-on’s new per-category rules, clearance category, waste reporting and Reports tab; without the add-on, behaviour is unchanged.)
- Improved: catalog hiding now uses a precomputed per-product « hide from » date (maintained automatically and backfilled on update), keeping shop queries fast and exact — including for variable products — and self-healing hourly if it ever drifts.
- Improved: related-products filtering now uses the exact same hide date as the shop catalog, so the two can never disagree.
- Improved: the Overview products card no longer reserves excess empty space below short filtered lists.
- Hardening: includes all WordPress.org review hardening from 1.2.2–1.2.4 (fully prepared activity-log queries, plugin-API-based add-on detection, broadened input sanitization and output escaping). No change to features or behavior.
1.2.4 – 2026-06-28
- Hardening: rewrote the activity-log queries to use fixed, fully prepared statements (no interpolated SQL), switched plugin-presence detection to WordPress’s plugin API instead of filesystem path construction, and clarified that the Pro add-on is a separate plugin with no license check in the free plugin. No change to features or behavior.
1.2.3 – 2026-06-19
- Hardening: broadened input sanitization (file uploads, request URI, settings POST), output escaping, and prepared-statement coverage on the activity-log queries, and switched to FILE-based path resolution, for WordPress.org review compliance. No change to features or behavior.
1.2.2 – 2026-06-13
- Maintenance: version kept in sync with the separately distributed Pro add-on release; no functional changes in the free plugin. (The Pro add-on’s one-click « install the free base plugin » helper now falls back to the publisher-hosted download when the WordPress.org listing isn’t reachable.)
1.2.1 – 2026-06-13
- Maintenance: version kept in sync with the separately distributed Pro add-on release; no functional changes in the free plugin.
1.2.0 – 2026-06-13
- Added: theme-proof on-product display — when a customized theme doesn’t fire the standard product summary hook, the expiration date now renders via the add-to-cart form area instead (never duplicated on standard themes).
- Added: an [edfw_expiration_date] shortcode for manual placement in page builders and fully bespoke templates (optional id attribute; suppresses the automatic placement on that product’s page; works even with the display toggle off).
- Improved: the « Show on product page » setting now explains placement and points to the shortcode for heavily customized themes.
1.1.15 – 2026-06-13
- Improved: consistent wording across the Pro hints — every mention now says « the Pro add-on » instead of a bare « Pro » as the sentence subject (product editor, Overview hint, Import/Export note, Pro Features page).
1.1.14 – 2026-06-13
- Improved: clearer wording on the Overview email hint (« Get this report by email — Pro sends you an expiring-products digest daily, weekly, or monthly. »).
1.1.13 – 2026-06-12
- Improved: the page title and header Upgrade button are now centered by flex layout instead of pixel offsets, so the header renders identically regardless of other plugins’ admin styles, fonts, or zoom level.
1.1.12 – 2026-06-10
- Added: an
edfw_hide_single_date_fieldfilter so add-ons that derive the expiration date themselves can start the manual date field hidden in the product editor.
1.1.11 – 2026-06-10
- Maintenance: version kept in sync with the separately distributed Pro add-on release; no functional changes in the free plugin.
1.1.10 – 2026-06-10
- Fixed: the help « ? » icon next to the expiration date field is now vertically centered with the input (WooCommerce’s default tip offset is sized for its shorter fields).
1.1.9 – 2026-06-10
- Improved: every « Upgrade to Pro » button now renders at exactly the same size as the header upgrade button — the preview-panel and Pro Features page buttons previously used larger WordPress button sizes.
1.1.8 – 2026-06-10
- Improved: the Pro preview panels (Notifications/Discounts) now span the full content width and start flush with the tab bar, exactly like the regular settings cards — previously they were capped at 640px and offset 16px lower.
1.1.7 – 2026-06-10
- Improved: wider, hard-enforced equal tabs in the settings navigation (200px minimum on every tab, asserted with priority so nothing can shrink the Pro preview tabs below the others).
1.1.6 – 2026-06-10
- Fixed: the settings tabs now keep their equal widths at every window size — below 960px wide they previously collapsed back to unequal natural widths; the tab rail now scrolls horizontally instead when space runs out.
1.1.5 – 2026-06-10
- Fixed: the equal-width settings tabs now render identically in every browser — the previous approach relied on a CSS grid behavior that differs between Chrome, Safari, and Firefox.
1.1.4 – 2026-06-10
- Improved: the settings tabs now render as a segmented control — every tab has the same width with a centered label, on free and Pro installs alike (natural-width pills wrap on small screens).
1.1.3 – 2026-06-10
- Improved: the settings tab row now keeps every tab at the same height (the PRO preview pills no longer sit ragged against the plain tabs), and the Pro panel icon chip and buttons share the header button’s corner radius for a consistent look.
1.1.2 – 2026-06-10
- Improved: polished the Pro preview panels (icon now sits inline with the section title in a gradient chip), the header Upgrade button aligns with the page title, and all upsell buttons keep their gradient on hover instead of falling back to the admin color scheme.
1.1.1 – 2026-06-10
- Improved: button icons (Copy, Download, Clear all logs) are now inline SVGs instead of icon-font glyphs — exact geometric centering on every display, no more font-baseline alignment drift.
1.1.0 – 2026-06-10
- Improved: all admin button icons now render on the Dashicons-native 20px grid with flex centering — sub-native sizes landed glyphs on fractional pixels, which read as misalignment (System Info, Activity Log, and settings buttons).
1.0.99 – 2026-06-10
- Improved: crisper button icons on the System Info and Activity Log screens (straight « copy » glyph, consistent sizing and optical alignment).
1.0.98 – 2026-06-10
- Maintenance: version kept in sync with the separately distributed Pro add-on release; no functional changes in the free plugin.
1.0.97 – 2026-06-10
- Fixed: the Overview’s « inventory at risk » query no longer depends on a relaxed MySQL mode, so it works on hosts that enforce ONLY_FULL_GROUP_BY.
- Fixed: changing the « expiring soon » threshold for the first time now refreshes the cached Overview counts immediately.
- Improved: dropping a CSV onto the import box now stages the file for review — the import runs when you click Import CSV, never on the drop itself.
- Improved: the activity-log clear action fails quietly on a missing security token instead of stopping the whole page.
1.0.96 – 2026-06-10
- Improved: the Overview statistics are now cached briefly and the inventory-value calculation is bounded, so the dashboard loads noticeably faster on large catalogs.
- Improved: dropping a CSV onto the import box now submits through the standard form flow, which is more reliable across browsers.
- Improved: clearing the activity log now redirects after the action, so refreshing the page can no longer re-submit it.
- Security: the CSV importer now also inspects the uploaded file’s content (not just its extension) and rejects files that are clearly not CSV.
- Fixed: the uninstall cleanup matches the plugin’s own post meta exactly and skips WooCommerce-specific cleanup when WooCommerce’s tables are already gone.
- Added: preview pages for the Pro add-on’s Notifications and Discounts settings sections (shown only when the separate Pro add-on is not installed).
1.0.95
- Fixed: the admin « Site timezone » status now reads correctly (e.g. « UTC » or « America/New_York ») instead of a doubled « UTCUTC », and the « expiring soon threshold » status reads « 1 day » instead of « 1 days ».
1.0.94
- Added: the on-product expiration date now also displays on block themes that use WooCommerce’s block-based single-product template (for example the default Twenty Twenty-Four / Twenty Twenty-Five themes) — it appears just after the product price. Classic WooCommerce themes are unchanged.
1.0.93
- Security: the « Expiring products » dashboard widget is now shown only to users who can manage WooCommerce, so other roles can no longer see product stock levels.
- Maintenance: a malformed import row’s date value is now truncated in the error notice, removed some dead admin CSS, and minor internal cleanups.
1.0.92
- Fixed: the « Clear all logs » confirmation prompt now works in translated languages whose text contains an apostrophe (previously the confirmation could be skipped in, for example, French).
- Improved: the dashboard widget skips impossible stored dates, and the active tab and settings section are announced to screen readers.
- Maintenance: small internal cleanups.
1.0.91
- Improved: the System Info report and the dashboard « with dates »/ »expired » counts now ignore impossible stored dates (e.g. a corrupt « 2025-02-29 »), so every screen agrees.
- Improved: a variation whose stored date is corrupt now shows no date rather than a wrong one on the product page, consistent with the rest of the plugin.
- Maintenance: refreshed the translation template, removed dead code, and fixed a misleading code comment.
1.0.90
- Fixed: upgrading from a much older version now reliably carries a previously enabled « automatically hide expired products » setting over to the current expiry-action control.
- Maintenance: documentation, internationalization, and accessibility polish.
1.0.89
- Fixed: changing a variable product to a simple product now clears its leftover synced expiration date so it no longer shows a date it doesn’t really have.
- Improved: a clearer cap on long import error lists; small accessibility, consistency, and security-log refinements.
- Maintenance: removed dead code and consolidated duplicated logic across the plugin.
1.0.88
- Improved: corrupt stored dates are handled consistently across display, reports, and import; the weekday initials in the calendar header now translate independently per day.
- Maintenance: accessibility, internationalization, security, and documentation polish; removed dead code and consolidated duplicated logic.
1.0.87
- Improved: dashboard report counts and the calendar load more efficiently and consistently exclude impossible stored dates.
- Improved: a corrupt stored date can no longer produce a wrong reformatted date or an empty badge; recipient and settings values are validated and clamped defensively.
- Maintenance: accessibility (announced toasts), documentation, and security log-hygiene fixes; removed dead code.
The full changelog, including the separate Pro add-on, is available at sellinor.dev.
