WooCommerce will never print "€29.90/kg" next to "€8.97" on its own: core has no unit-price concept, and the only weight it stores is the shipping weight, which lives under the product's Shipping tab and is never related to price. You have three ways to change that — type the figure into each product by hand, compute it from the weight field with a filter on woocommerce_get_price_html, or use a plugin that renders it on every surface that shows a price. The one thing all three have to get right is which weight they divide by, and that is where most implementations quietly go wrong.
That division is the reason this ended up being a module inside By-Weight Pricing for WooCommerce rather than a snippet we shipped in a docs page. Below is the formula, the code that works, the two places core actively fights you, and the placement rules that decide whether the result is legally usable. Core behaviour was read from WooCommerce trunk in July 2026; the Google feed requirements come from Merchant Center's own attribute documentation, checked the same month.
Why doesn't WooCommerce show a price per kg?
Because the product weight field is a shipping input, not a pricing input. WooCommerce's own documentation places weight and dimensions under the Shipping tab, where they feed carrier rate calculations — nothing in core multiplies, divides or displays price against that number, and there is no separate unit-price field anywhere in the product data panel.
That gap is one layer of a larger one. Price display, decimal input and weight-based stock are separate problems in WooCommerce, and how to sell by weight in WooCommerce maps which of them you actually need to solve. If all you need is the per-kilogram figure beside an ordinary pack price, this page is the whole job.
How do you calculate the unit price?
Divide the price actually charged by the pack's net quantity, then express it per 1 kg or per 100 g. The arithmetic is trivial; the discipline is in the word charged.
| Pack | Price | Per kg | Per 100 g |
|---|---|---|---|
| 300 g | €8.97 | €29.90/kg | €2.99 |
| 500 g | €13.90 | €27.80/kg | €2.78 |
| 1.2 kg | €28.68 | €23.90/kg | €2.39 |
| 250 g, on sale at €5.60 (was €6.90) | €5.60 | €22.40/kg | €2.24 |
The last row is the one that kills hand-typed unit prices. Derived from the regular €6.90 the figure would read €27.60/kg while the customer pays €22.40/kg — a number that is not merely stale but wrong in the direction that gets noticed. Both German and EU rules tie the base price to the price actually charged, and Great Britain makes reduced unit prices during promotions explicit from 6 April 2026.
Which weight should you divide by?
The net content weight, not the shipping weight — and WooCommerce only gives you the second one. Directive 98/6/EC defines the unit price as the final price for one kilogram of the product, which means the declared net quantity: 250 g of coffee, not 250 g of coffee plus a valve pouch, a box and a desiccant sachet.
A store that fills the weight field honestly for carrier rates has entered gross weight. Take that 250 g coffee bag at €5.60 with 40 g of packaging: divide by the shipping weight of 0.29 kg and you print €19.31/kg instead of €22.40/kg — a figure understated by nearly 14%, on a page whose entire purpose is letting shoppers compare accurately. Nothing in the code errors; it just publishes a wrong number on every product. Made-to-order goods have the mirror-image version of this problem, where the delivered weight is lower than the ordered weight rather than higher — selling meat by weight online works through the trim and yield side of it.
There are only three honest ways out, and you have to pick one before writing any code:
- Keep the weight field net and let shipping absorb the difference through packaging rules or a handling fee. Simplest, and fine for light packaging.
- Store the net weight separately in a custom field or a plugin's own field, and divide by that while shipping keeps the gross figure. Correct, and the only option that scales to a mixed catalog.
- Restrict the display to products where packaging is negligible, and leave everything else without a unit price. Legal only if those products genuinely fall outside the obligation.
What does the code snippet look like, and what does it miss?
Every displayed price in WooCommerce passes through woocommerce_get_price_html, which WC_Product::get_price_html() applies to the finished markup, so a filter there can append a unit price computed from the current price:
add_filter( 'woocommerce_get_price_html', function ( $html, $product ) {
if ( ! $product->is_type( 'simple' ) ) {
return $html;
}
// NOTE: get_weight() is the SHIPPING weight. Substitute your net-weight
// field here if your packaging is not negligible.
$weight = (float) $product->get_weight();
$price = (float) $product->get_price(); // current price — already sale-aware
if ( $weight <= 0 || $price <= 0 ) {
return $html;
}
// woocommerce_weight_unit only ever holds one of these four values.
$to_kg = array( 'kg' => 1, 'g' => 0.001, 'lbs' => 0.45359237, 'oz' => 0.0283495 );
$unit = get_option( 'woocommerce_weight_unit' );
if ( ! isset( $to_kg[ $unit ] ) ) {
return $html;
}
$per_kg = $price / ( $weight * $to_kg[ $unit ] );
return $html . ' <span class="unit-price">' . wc_price( $per_kg ) . '/kg</span>';
}, 100, 2 );
The sale-price behaviour comes free: get_price() returns the active price, so a promotion produces a reduced unit price without any extra work. The four weight units in that map are the complete set — WooCommerce's settings screen offers exactly kg, g, lbs and oz for woocommerce_weight_unit, so any other value means something has been filtered and the filter bails out rather than guessing.
What it does not handle is worth being blunt about. Products with no weight silently show nothing, and nobody tells you which ones those are. A per-100 g convention, or the French requirement to use one unit consistently per product category, means more branching. Other plugins filter the same hook, so ordering and double-appending become yours to debug. And variable products break it outright.
Why do variable products break the snippet?
Because the string your filter receives for a variable product is a price range, not a price. WC_Product_Variable::get_price_html() compares the cheapest and dearest variation and, when they differ, builds the markup with wc_format_price_range( $min_price, $max_price ) before handing it to woocommerce_variable_price_html and then to woocommerce_get_price_html. Appending "€23.90/kg" to "€4.50 – €18.00" produces a figure that corresponds to nothing the customer can buy.
Doing it properly means three separate pieces of work: filter woocommerce_variable_price_html rather than the generic hook so you are operating on the variable product deliberately, inject each variation's own per-kilogram figure through woocommerce_available_variation so the display updates when the customer switches, and decide what replaces the range itself on shop and category pages. Our own display module replaces it with the smallest-weight variation's price, the weight it buys and its per-kilogram equivalent — "€7.20 / 200 g" above "€36.00/kg" — because a range with no unit price is exactly the shop-loop gap that leaves an otherwise compliant store non-compliant on its category pages.
Where does the unit price have to appear?
Next to the selling price, on every surface that shows a price, in ordinary body type. Directive 98/6/EC requires both prices to be "unambiguous, easily identifiable and clearly legible" (Article 4(1)), and Great Britain adds an explicit font requirement — "clear and of reasonable size" — when the amended Price Marking Order commences on 6 April 2026.
- Same price block as the selling price. Not a tab, a tooltip, an accordion or text baked into the product image.
- Product pages, shop and category loops, and search results — anywhere a price is rendered.
- Any advertisement that mentions the price, which Article 3(4) puts squarely in scope, including product feeds.
- The unit your market actually requires: 1 kg or 1 L for packaged goods in Germany, one consistently chosen unit per category in France. The jurisdiction-by-jurisdiction detail is in unit pricing laws for online stores.
How do you show a price per kg on Google Shopping?
With two feed attributes, and for a large part of the world they are not optional. Merchant Center requires unit_pricing_measure for products sold by weight, volume, length or area advertised in the EU, EFTA countries, the UK, Australia and New Zealand; unit_pricing_base_measure is optional but is what fixes the denominator Google displays.
- unit_pricing_measure
- What the pack contains — a positive number plus unit, e.g. "300 g". Required for weight, volume, length and area products in the EU, EFTA, UK, Australia and New Zealand.
- unit_pricing_base_measure
- The denominator you want shown, e.g. "100 g". A whole number plus unit; the allowed multipliers are 1, 2, 4, 8, 10 and 100.
- Unit consistency
- Use the same family of units in both attributes, and match the base unit to the one your market's law requires on-site.
- UK targeting
- Submit metric values. Google reads floz, pt, qt and gal as US imperial, which are not the same as UK imperial units.
On-site display never reaches a Shopping listing, and feed attributes never reach your product page. Both have to be filled.
Which method should you use?
Manual entry is only defensible for a frozen catalog; the snippet is right for simple products with one weight convention; a plugin earns its place the moment variations, shop loops or multiple markets are involved.
| Manual | Snippet | Plugin | |
|---|---|---|---|
| Correct after a price change | |||
| Reduced unit price during a sale | |||
| Shop and category loops | Partial | ||
| Per-variation figure, no misleading range | |||
| Net weight separate from shipping weight | Custom field | ||
| Per-100 g or per-market unit | Manual | Custom code | |
| Setup effort | High and recurring | One file | Trivial |
One case sits outside that table entirely: products where the customer chooses the weight. There the per-kilogram price is the price rather than a comparison aid, which is a different build again — and if you are tempted to solve it by putting fractions in the quantity box, what happens when you put decimals in the quantity field is worth reading before you do.
FAQ
How do I display a price per kg in WooCommerce?
Either filter woocommerce_get_price_html to divide the product's current price by its weight converted to kilograms, or use a plugin that renders the figure storewide including variations, sale prices and category loops. WooCommerce core has no unit-price feature at all — the only weight it stores is the shipping weight, and nothing in core relates it to price.
Should I divide by the WooCommerce weight field?
Only if that field holds the net content weight rather than the gross shipping weight. Directive 98/6/EC defines the unit price as the price for one kilogram of the product, so packaging must be excluded — a 250 g coffee bag with 40 g of packaging entered as 0.29 kg produces €19.31/kg instead of the correct €22.40/kg, understating the figure by nearly 14%.
Does the price per kg update when a product goes on sale?
It has to, because the base price is legally derived from the price actually charged. Any implementation that reads the product's current price through get_price() updates automatically, while unit prices typed into a product title or description do not — which is why manual entry fails compliance the first time a promotion runs.
How do I show a price per kg on Google Shopping?
Add unit_pricing_measure and unit_pricing_base_measure to your product feed — the pack content, for example "300 g", and the denominator you want displayed, for example "100 g". Merchant Center requires unit_pricing_measure for products sold by weight, volume, length or area advertised in the EU, EFTA countries, the UK, Australia and New Zealand.
