Title: Food Products for WooCommerce
Author: Mac
Published: <strong>September 3, 2026</strong>
Last modified: September 3, 2026

---

Search plugins

![](https://ps.w.org/mfood-products-for-woocommerce/assets/banner-772x250.png?rev
=3679253)

![](https://ps.w.org/mfood-products-for-woocommerce/assets/icon.svg?rev=3679253)

# Food Products for WooCommerce

 By [Mac](https://profiles.wordpress.org/macvej/)

[Download](https://downloads.wordpress.org/plugin/mfood-products-for-woocommerce.1.1.1.zip)

 * [Details](https://wordpress.org/plugins/mfood-products-for-woocommerce/#description)
 * [Reviews](https://wordpress.org/plugins/mfood-products-for-woocommerce/#reviews)
 *  [Installation](https://wordpress.org/plugins/mfood-products-for-woocommerce/#installation)
 * [Development](https://wordpress.org/plugins/mfood-products-for-woocommerce/#developers)

 [Support](https://wordpress.org/support/plugin/mfood-products-for-woocommerce/)

## Description

**Food Products for WooCommerce** turns your WooCommerce shop into a food shop. 
It adds two
 new product types – **Food Simple Product** and **Food Variable Product**–
that work exactly like WooCommerce’s own Simple and Variable products, with everything
a food or grocery shop needs on top: a nutrition declaration table, expiry dates,
batch and supplier tracking, and automatic handling of stock that is about to go
off.

Nothing is replaced or overridden: your existing products, themes and payment gateways
carry
 on untouched. You choose the new product type only on the products that need
it.

#### Nutrition declaration table

Every food product gets a **Nutrition** tab: a label/amount/unit table declared 
per 100 g or
 per 100 ml (pre-filled with the EU-mandatory energy / fat / carbohydrate/
protein / salt rows, all editable) that is shown to shoppers as its own tab on the
product page. Rows can be reordered, renamed, indented as sub-nutrients, added and
removed. Food Variable Products can share one table across every variation, or let
a single variation override it with its own.

#### Ingredient list

An **Ingredients** tab holding the ingredients in declaration order, each with an
optional
 percentage, sub-ingredients and one of the 14 EU-declarable allergens.
The product page prints the list as one sentence with allergens in bold, plus a “
may contain” line. Per-variation overrides work the same way as for nutrition.

#### Expiry dates and batch tracking

The **Expiry & Tracking** tab stores one row per batch, each with an expiry date,
quantity,
 batch number, batch date and supplier – so you always know which delivery
a unit of stock came from and when it goes off. Food Variable Products track batches
per variation, matching how WooCommerce already tracks stock. Every sale takes a
unit off the batch closest to its date, and a refund puts it back, so the table 
reads as what is still on the shelf.

Optionally, the closest upcoming expiry date is shown to shoppers on the product
page – always,
 or only once it falls within a number of days you choose.

#### Expiry Dashboard and write-off

An admin screen listing every batch row across every food product in one place, 
sorted by
 closest expiry date first, colour-coded by urgency, filterable by date
range and exportable as a CSV file for your stock takes and audits. A batch that
has expired can be written off from there or from the product itself, taking what
is left of it out of the sellable stock – or you can have that happen automatically
every night at an hour you choose.

#### The batch table is the stock

Once a product tracks batches, its batch table _is_ its stock. WooCommerce’s own
stock
 management is switched off for it and stays off; the product is in stock 
while a batch in date has units left, “N in stock” on the product page is the batch
total, and a shopper cannot buy more than the batches hold. Every sale comes off
a batch – a full-price sale off the freshest batch first, so the batch nearest its
date is kept for the reduced offer – and a refund puts the units back. Stock past
its best-before date is not sold at all unless you say so (see below).

#### Automatic Markdown

Offer a discount on the batch closest to its date, on a ladder of steps you set (
for example
 15% a week out, 30% three days out, 50% on the last day). The product’s
own price is never changed: the shopper opts into the reduced batch on the product
page, the discount applies to that cart line only, and the offer withdraws itself
once the batch is sold out or expired. A cap on units per batch, a price floor, 
a catalogue badge and a choice of whether a product with nothing left to sell stays
listed or is hidden are all yours to set, and any product can opt out. Where the
law allows it, you can also choose to keep selling batches past their best-before
date: that adds a fixed last step to the ladder with its own discount and wording,
and those units count as sellable stock. A **Markdown Earnings** screen reports 
what each marked-down batch sold, what it brought in, what the discount cost, and
how much expired unsold anyway.

#### Email when expired

A scheduled digest email listing every batch that has reached its expiry date – 
or is about to,
 within a window you choose – sent to the shop users you pick, daily,
weekly, every 2 weeks or every 3 weeks. Each batch is only ever mailed once, every
send is recorded in an Email Log, and a “Send Notification Email Now” button lets
you run it on demand. Individual products can opt out.

#### Automatic category switching

Have WooCommerce move stock for you: categories you choose (for example “Clearance”
or “Last
 chance”) are added to a product as it nears its closest expiry date, and
categories are removed – or every category stripped – once that date has passed.
If a fresh, later-dated batch pushes the expiry date back out, both changes are 
reversed automatically, and categories you assigned by hand are never touched. An
optional **Switching Log** screen records every move the nightly run makes, with
the product, the direction and the batch that caused it.

#### Built for real shops

 * Fully translation-ready, with a choice of date formats for the dates it prints.
 * WooCommerce **HPOS** (High-Performance Order Storage) and **Cart & Checkout Blocks**
   
   compatible.
 * No account, no subscription, no external service: the plugin never contacts a
   remote server
    and sends no analytics or telemetry of any kind. Everything runs
   on your own site.
 * No bundled third-party libraries – it uses the copies of jQuery and Select2 that
   WordPress
    and WooCommerce already ship.
 * Every file shipped is unminified, human-readable source. There is no build step.

#### Requirements

WooCommerce must be installed and active. The plugin will not activate without it,
and
 deactivates itself with an explanatory notice if WooCommerce is later disabled.

## Screenshots

[⌊A Food Simple Product on the shop front end, with the nutrition declaration table,
the
ingredient list with allergens in bold, and the expiry date shown to the shopper.⌉⌊
A Food Simple Product on the shop front end, with the nutrition declaration table,
the
ingredient list with allergens in bold, and the expiry date shown to the shopper
.⌉[

A Food Simple Product on the shop front end, with the nutrition declaration table,
the ingredient list with allergens in bold, and the expiry date shown to the shopper.

[⌊The Nutrition tab in the product editor: the label/amount/unit table declared 
per 100 g or
100 ml, pre-filled with the EU-mandatory rows and reorderable by drag.⌉⌊
The Nutrition tab in the product editor: the label/amount/unit table declared per
100 g or
100 ml, pre-filled with the EU-mandatory rows and reorderable by drag.⌉[

The Nutrition tab in the product editor: the label/amount/unit table declared per
100 g or 100 ml, pre-filled with the EU-mandatory rows and reorderable by drag.

[⌊The Ingredients tab: ingredients in declaration order, each with an optional percentage,

sub-ingredients and one of the 14 EU-declarable allergens.⌉⌊The Ingredients tab:
ingredients in declaration order, each with an optional percentage,
sub-ingredients
and one of the 14 EU-declarable allergens.⌉[

The Ingredients tab: ingredients in declaration order, each with an optional percentage,
sub-ingredients and one of the 14 EU-declarable allergens.

[⌊The Expiry & Tracking tab: the batch table with expiry date, quantity, batch number
and
supplier, which doubles as the product's stock.⌉⌊The Expiry & Tracking tab: 
the batch table with expiry date, quantity, batch number and
supplier, which doubles
as the product's stock.⌉[

The Expiry & Tracking tab: the batch table with expiry date, quantity, batch number
and supplier, which doubles as the product’s stock.

[⌊The Automatic Markdown settings, where you set the discount steps that reduce 
a batch as its
expiry date gets closer.⌉⌊The Automatic Markdown settings, where 
you set the discount steps that reduce a batch as its
expiry date gets closer.⌉[

The Automatic Markdown settings, where you set the discount steps that reduce a 
batch as its expiry date gets closer.

[⌊The Markdown Earnings dashboard, showing what marked-down stock sold for against
what it
would otherwise have been written off for.⌉⌊The Markdown Earnings dashboard,
showing what marked-down stock sold for against what it
would otherwise have been
written off for.⌉[

The Markdown Earnings dashboard, showing what marked-down stock sold for against
what it would otherwise have been written off for.

[⌊The Expiry Dashboard: every batch row from every food product in one list, closest
expiry
first, filterable by date range and exportable as CSV.⌉⌊The Expiry Dashboard:
every batch row from every food product in one list, closest expiry
first, filterable
by date range and exportable as CSV.⌉[

The Expiry Dashboard: every batch row from every food product in one list, closest
expiry first, filterable by date range and exportable as CSV.

## Installation

 1. **Install and activate WooCommerce**, if it isn’t already. This plugin adds product
    types to WooCommerce and will refuse to activate without it.
 2. **Install this plugin.** Either upload the plugin’s zip file under **Plugins > 
    Add New > Upload Plugin**, or upload the extracted folder to `/wp-content/plugins/`
    over FTP/SFTP, then activate it.
 3. **Create a product** the normal WooCommerce way (**Products > Add New**), and choose**
    Food Simple Product** or **Food Variable Product** from the **Product data** type
    dropdown.
 4. **Open Food Products > Settings** in the wp-admin menu to configure the date format,
    expiry email notifications, the Expiry Dashboard and automatic category switching.

## FAQ

### Does this require WooCommerce?

Yes. The plugin adds WooCommerce product types and will not activate without it.

### Does it work with my existing products?

Yes. Existing Simple and Variable products are left exactly as they are. The food
features
 appear only on products you switch to Food Simple Product or Food Variable
Product, and you can switch a product back at any time.

### Can I track expiry dates per variation?

Yes. Food Variable Products keep their own batch table per variation, since expiry
dates and
 quantities are physical stock facts and WooCommerce already tracks stock
per variation. Nutrients work the other way round: one shared table for the whole
product, which any single variation can override.

### What is the Expiry Dashboard?

An admin screen listing every batch row from every food product’s Expiry & Tracking
table in
 one place, sorted by closest expiry date first, filterable by date range
and exportable as CSV. It can be turned off on the Settings page.

### Can I get emailed when a product expires?

Yes. Turn on “Email when expired” on the Notification Email tab and choose recipients
and a
 frequency (daily, weekly, every 2 weeks or every 3 weeks). Each expiring 
batch row is emailed once and logged. Set an “upcoming expiry window” to be warned
a few days ahead instead of only after the fact.

### Does the plugin call any external service?

No. It makes no remote requests, requires no account or API key, and collects no
analytics or
 telemetry.

### Does Automatic Markdown work with the block-based product page?

The reduced-batch choice is a field in WooCommerce’s classic add-to-cart form, so
it appears on
 the classic single product template and in the Add to Cart form block
that renders that form. The Cart, Mini Cart and Checkout blocks all show the batch
and offer a reduced line was bought under.

### Will automatic category switching mess up my categories?

No. It records exactly what it added or removed on each product and reverses only
that. Any
 category you assigned by hand is left alone, and individual products 
can opt out of category switching entirely on their Expiry & Tracking tab.

### What happens to my data if I delete the plugin?

Deleting the plugin removes only its own settings (`fpwc_generel_settings_options`),
the email
 log and the category switching log. Nutrition, ingredient and Expiry &
Tracking data saved on your products, and the batch a marked-down order line was
bought from, are left untouched, so reinstalling picks up exactly where you left
off.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Food Products for WooCommerce” is open source software. The following people have
contributed to this plugin.

Contributors

 *   [ Mac ](https://profiles.wordpress.org/macvej/)

[Translate “Food Products for WooCommerce” into your language.](https://translate.wordpress.org/projects/wp-plugins/mfood-products-for-woocommerce)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/mfood-products-for-woocommerce/),
check out the [SVN repository](https://plugins.svn.wordpress.org/mfood-products-for-woocommerce/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/mfood-products-for-woocommerce/)
by [RSS](https://plugins.trac.wordpress.org/log/mfood-products-for-woocommerce/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.1.1

 * The plugin is now called “Food Products for WooCommerce” wherever its name is
   shown.
 * Automatic Markdown now offers every batch that is close enough to its date, each
   at its own
    step, instead of only the one closest to expiry. The shopper picks
   the date they want.
 * The Expiry Dashboard’s columns can be sorted by clicking their headings, and 
   the CSV export
    follows the same order.
 * The product page stylesheets now inherit the theme’s font, size and colours, 
   so the nutrition
    table, ingredient list, best-before line and batch picker read
   correctly on dark and light themes alike without custom CSS.
 * Stylesheets and scripts are only loaded on the pages that use them: a non-food
   product page
    loads none of them, and the markdown stylesheet no longer loads
   on every page of the site.

#### 1.1.0

 * The batch table is now a tracked product’s stock. Switching “Track expiry dates
   and batches” on
    turns WooCommerce’s own stock management off for that product
   or variation (and for the parent of a variable product) and hides the option;
   the product is in stock while a batch in date has units left, the product page
   shows the batch total as “N in stock”, and a shopper cannot buy more than the
   batches hold. A product that was managing stock shows what WooCommerce held, 
   so those units can be entered as batches.
 * A full-price sale now comes off the freshest batch first, keeping the batch nearest
   its date for
    the reduced offer. A reduced sale still comes off the batch the
   shopper picked.
 * Stock past its best-before date is no longer sold at any price unless “When a
   batch passes its
    best-before date” under Products is set to keeping it on sale,
   which adds a fixed last step to the Automatic Markdown ladder for it with its
   own discount and wording. The ladder’s own steps now start at one day out.
 * “When every batch has expired” is now “When nothing is left to sell”, with two
   choices: show the
    product as out of stock, or hide it. The old “keep selling
   at full price” choice no longer applies and falls back to out of stock.
 * What happens to a batch past its date is now one choice under Products – write
   it off by hand,
    write it off nightly, or keep it on sale at a discount – rather
   than two toggles on two tabs that ruled each other out.
 * New **Automatic Markdown**: discount a batch automatically as its best-before
   date approaches,
    on a ladder of steps you set, with a live preview of what a
   shopper would be offered, a cap on how many units go on offer, a price floor,
   and a choice of what happens once every batch has expired.
 * New **Markdown Earnings** screen: what each marked-down batch sold, what it brought
   in, what
    the discount cost, and how much expired unsold anyway.
 * New **Switching Log** screen: every category move the nightly run makes, with
   the product, the
    direction and the batch that caused it.
 * New **Ingredient list**, with allergens picked out in bold, shown as its own 
   tab on the
    product page.
 * New nightly write-off, and a write-off button on each batch, taking what is left
   of an expired
    batch off WooCommerce stock so the shop stops selling it. Pick
   the hour it runs at, on your shop’s own clock; it starts at midnight. It never
   takes stock below zero.
 * Batch quantities now follow every sale, not only the reduced ones: a sold unit
   comes off the
    batch closest to its best-before date, the way the shelf is emptied,
   and a refund puts it back on the batch it came off. Stock you have not put a 
   date on is sold last. The Expiry Dashboard and the batch table therefore read
   as what is still on the shelf rather than what was put there, and an expiring
   batch is no longer written off stock that was already sold.
 * Split the settings into a General tab and a new Products tab. Each dashboard 
   is switched on
    directly under the feature it reports on, and is only offered
   while that feature is on: Expiry Dashboard and Switching Log on the Products 
   tab, Markdown Earnings on the Automatic Markdown tab. The General tab is left
   with the date format.
 * The Markdown Earnings and Switching Log screens now open on the last year, and
   their date filters
    are labelled From and To.
 * The markdown plumbing an order line carries – the batch it came from and the 
   amount saved – is no
    longer listed on the order screen. The Best before date
   and the Offer it was sold under still are, and the money is on the Markdown Earnings
   screen.
 * Rewrote the option names, labels, tooltips and messages across every screen in
   plain English,
    with one term per thing throughout.
 * The write-off and delete buttons on the Expiry Dashboard now name themselves 
   on hover, so an
    icon-only action says what it does before it is clicked.
 * Every switch in the Expiry & Tracking tab now carries a help tip saying what 
   it does, on both a
    Simple Food Product and each variation of a Variable Food
   Product.
 * The Best before date and the Offer a reduced line was bought under now sit on
   a line each in the
    basket, mini-basket and checkout, instead of running together
   into one sentence.
 * Fixed a Variable Food Product adding its parent to the cart instead of the variation
   the shopper
    picked. WooCommerce chooses how to handle an add-to-cart by product
   type and only knows its own, so the chosen variation was being dropped – which
   also made a marked-down variation come back as “the reduced units have just sold
   out”, the batch having been looked for on the parent.
 * Nutrient table rows can be dragged by their grip again – jQuery UI was cancelling
   every drag
    because the grip is a button.
 * Fixed the “Declared per” choices stacking on top of each other in the product-
   level Nutrient
    tab, so 100 g and 100 ml can be picked again.
 * Dropped “Serving” as a declaration basis. EU FIC 1169/2011 wants the declaration
   itself per
    100 g or per 100 ml, so a serving size is now simply printed alongside
   whichever of those is chosen, on both the product page and per variation. Products
   that had saved “Serving” fall back to per 100 g and keep showing their serving
   size.
 * Fixed the Unit select being taller than the fields beside it, in both the product
   tab and the
    variation panels.
 * Fixed the nutrient row buttons sitting top-left instead of centred inside variation
   panels.
 * Removed the nutrient row counter and the customer preview from the editor.
 * Nutrient tables inside variation panels are drag-sortable again. The handler 
   that set them up
    listened on the wrong element for WooCommerce’s “variations
   loaded” event, so it never ran.

#### 1.0.2

 * Renamed the plugin display name to “MFood Products for WooCommerce” so it matches
   the
    assigned plugin slug, as asked for in the plugin review. Nothing you have
   set up changes.

#### 1.0.15

 * Renamed the plugin slug and text domain from `food-products-for-woocommerce` 
   to
    mfood-products-for-woocommerce, as asked for in the plugin review. The plugin
   name, its settings and all data saved on your products are unchanged.

#### 1.0.1

 * Prefixed every remaining global name (options, meta, hooks, cron schedule keys,
   script
    handles, page slugs, CSS classes) and removed the dynamic prefix concatenation.
 * Fixed an unbalanced closing tag on the settings screens.
 * Guarded product category lookups against an error result.
 * Guarded a missing quantity value when building the notification email.
 * Batched the email log writes into a single option update.
 * Passed fputcsv() its delimiter, enclosure and escape explicitly, for PHP 8.4.
 * Removed unused code and corrected documentation.

#### 1.0.0

 * Initial release.

## Meta

 *  Version **1.1.1**
 *  Last updated **6 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.8 or higher **
 *  Tested up to **7.1**
 *  PHP version ** 8.1 or higher **
 * Tags
 * [expiry date](https://wordpress.org/plugins/tags/expiry-date/)[food](https://wordpress.org/plugins/tags/food/)
   [nutrition](https://wordpress.org/plugins/tags/nutrition/)[woocommerce](https://wordpress.org/plugins/tags/woocommerce/)
 *  [Advanced View](https://wordpress.org/plugins/mfood-products-for-woocommerce/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/mfood-products-for-woocommerce/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/mfood-products-for-woocommerce/reviews/)

## Contributors

 *   [ Mac ](https://profiles.wordpress.org/macvej/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/mfood-products-for-woocommerce/)