My product genuinely costs zero, so why is it listed as missing a cost?
WooCommerce deletes the cost value on an order line when it is zero, so a free sample and a product nobody costed end up as the same absence in the database.
The short answer
Because on an order line, WooCommerce deletes the cost value when it is zero instead of storing a zero. A free sample and a product nobody has costed therefore look exactly the same in the database: no value at all.
Rather than guess which of the two it is, Merchgain always says no cost data and never cost 0. Free samples, giveaways and downloadable extras will show up on the missing-cost list, and there is no way for any plugin to tell them apart from genuine gaps.
What WooCommerce actually does
When order item data is saved, the cost goes through this:
$cogs_value = (float) $cogs_value;
if ( 0.0 === $cogs_value ) {
$this->order_item_data_store->delete_metadata( $item->get_id(), '_cogs_value', '' );
} else {
$this->order_item_data_store->update_metadata( $item->get_id(), '_cogs_value', $cogs_value );
}
Zero deletes the row. And a product with no cost entered returns 0 from
get_cogs_total_value(), so both paths arrive at the same delete.
There is an asymmetry worth knowing: on the product, a cost of 0 is stored, because the
product data store only deletes empty strings and empty arrays. So at product level, zero and
missing are distinguishable. At order-line level they are not.
What to do about it
- Accept the listing for genuine freebies. They are on the list because the data cannot say otherwise, and a report that hid them would be inventing information.
- If the item does have a cost, enter it. A promotional mug still cost you something to buy and print; the honest number is that, not zero.
- Read coverage as “revenue with a known cost”, not as a score to get to 100%. A shop that gives away 6% of its revenue in samples will sit at 94% forever, and that is the correct answer.
How Merchgain reports it
Two different sources, deliberately. The list of products with no cost is read at product level, where zero and missing can be told apart. The coverage percentage is read at order-line level, where they cannot — so it answers the only question that data can answer: how much of this revenue has a cost recorded against it.
The note about deliberate zeroes sits inside the missing-cost block, next to the list, so the first person who sees their free samples there gets the explanation in the same screen.
Related answers
Disagrees with what you see in your shop? Write to us — every message is read. contact@merchgain.com