Every profit figure depends on one boring job: telling WooCommerce what each product costs you. It is the step most shops start and never finish, usually because the tools make it slow or a little risky. This guide covers the ways to do it, which one suits which situation, and the decisions to make before you type the first number.
Before you start: three decisions
Where the cost will live
Recent WooCommerce versions have a built-in Cost of Goods Sold field. Use it unless you have a strong reason not to: a cost stored in WooCommerce’s own field survives a change of reporting plugin, whereas a cost stored in a plugin’s private field leaves with the plugin. Turn it on under WooCommerce → Settings → Advanced → Features → Cost of Goods Sold. The guide on the built-in COGS field explains what it stores and where it stops.
Which number counts as the cost
Normally it is the price your supplier charges for one unit. If you buy in packs, divide: a case of 12 at €30 is €2.50 a unit. If freight, duty or packaging are a meaningful share of what a product costs you and you want them reflected in its margin, add an average per-unit share to the figure yourself. The field holds one number per product, and neither WooCommerce nor most cost plugins will apportion a freight invoice for you.
Including or excluding VAT
The cost field has no idea whether the number includes VAT. Pick one convention and apply it to every product. If your business reclaims VAT on purchases, entering costs excluding VAT is the natural choice, because revenue in a profit report should also exclude VAT. If supplier invoices are easier to copy with VAT included, that is fine too, as long as whatever calculates profit knows, and strips the right rate per product; a shop selling at several VAT rates cannot use one flat percentage.
Option 1: one product at a time
Open the product, go to the General tab, and fill in Cost of goods. This is fine for a new product or a correction, and slow for a catalogue.
Variable products
The cost on the parent product is a default that every variation inherits. Open a variation to give it a cost of its own; WooCommerce also has a bulk action to remove individual variation costs so they all fall back to the parent’s.
A useful pattern:
- If all variations cost the same, enter the cost once on the parent and leave the variations empty.
- If one size or colour costs more, override only that variation.
- If every variation costs something different, give each its own cost and treat the parent value as a safety net, not the answer.
Option 2: from the product list
With the feature on, the product list gains a Cost column, and both Quick Edit and Bulk Edit get a cost field.
- Quick Edit is good for working down a list: filter by category, then edit costs row by row without opening each product.
- Bulk Edit in WooCommerce sets every selected product to the same cost. That suits a range bought at one price, and not much else.
Two things to watch. Bulk Edit in core only sets a value; it cannot raise every selected cost by 5% after a supplier price increase. And a cost field left blank is easy to misread: check afterwards that the products you meant to leave alone still have their cost.
Caltru Ledger, a free plugin, takes over these screens rather than adding new ones. Its product-list column shows the cost next to the margin it implies, coloured against a target margin you set, and for variable products the range their variations cover and how many still need a cost. Bulk Edit gets six modes: change to, increase by or decrease by, each as an amount or a percentage. Products with no cost are skipped by the relative modes rather than treated as zero, and an empty Quick Edit field no longer clears a cost. The details are in entering costs.
Option 3: by spreadsheet
For more than a few dozen products, a spreadsheet is usually fastest, especially if the supplier sends a price list you can paste from.
WooCommerce’s own product exporter and importer support the cost field: export the products, fill in the cost column, and import the file with the option to update existing products. It works, but there is no preview of which costs will change before the import runs, and a mismatched row is easy to miss among hundreds.
Whatever tool you use, the round trip goes wrong in the same places:
- Variations missing from the file. On a variable product, variations are often where the costs actually differ. Make sure they are in the export.
- Matching rows. Match by product ID, or by SKU when IDs differ between sites. A row whose SKU matches nothing should be an error, not quietly skipped.
- Decimal separators. In locales that write decimals with a comma, Excel saves CSV files with semicolons. A tool that expects commas will misread every row.
- Blank cells. Decide whether a blank means “no change” or “remove the cost”. Treating blank as remove turns a partial edit into a mass deletion.
- Inherited costs. If the file writes a variation’s inherited cost into its own row, re-importing gives every variation a fixed cost and ends the inheritance from the parent.
Caltru Ledger’s spreadsheet workflow is built around those failure points. The download includes variations and drafts, uses the separator your spreadsheet software will write back, and writes each row’s own cost rather than the one it inherits. On upload it shows a preview first, such as 12 new, 3 changed, 480 unchanged, 2 with a problem, numbered by line, before anything is saved. A blank cell leaves the product alone. See the spreadsheet workflow.
Which method to use when
| Situation | Best fit |
|---|---|
| A new product, or one wrong cost | The product editor |
| A category, working through by eye | Quick Edit in the product list |
| A supplier price rise across a range | Bulk Edit, by percentage if your tool supports it |
| First-time entry for a whole catalogue | Spreadsheet |
| A supplier’s new price list | Spreadsheet, with a preview before saving |
What about orders you already have?
Entering a cost today does not, by itself, make last year’s profit known. In WooCommerce, an order’s line cost is worked out when the order is placed, so orders placed before you entered a cost carry a cost of zero, or none at all if the feature was off at the time.
There are two honest ways to handle the past:
- Leave it unknown. Report profit only from the date costs were complete.
- Estimate it. Apply today’s costs to older orders, and label them as estimates, because supplier prices may have been different then.
Caltru Ledger does the second, on request, and keeps the label: a tool records past orders at the costs you have now, each marked as an estimate, and estimates can be excluded from every report. When you enter a cost for a product that has already sold without one, the earlier lines are filled in the same way, never overwriting a real recorded figure. If you are moving from WPFactory Cost of Goods, SkyVerge Cost of Goods or ATUM, it imports their costs and, where those plugins kept what a past order cost at the time, uses that figure in preference to today’s price. See setup and migration.
Knowing when you are finished
Most catalogues are never completely costed, and they do not need to be on day one. What matters is knowing where the gaps are and how much they distort the result. Start with the products that sell most, since a missing cost on a bestseller overstates profit far more than one on a product that sold twice last year.
Caltru Ledger measures that directly: it shows how much of the last 90 days’ revenue is standing on lines with no cost, and lists the gaps worst-first, ranked by how much profit each one is overstating, with a box to type the missing cost in. That list is described on the data quality page.
Checklist
- Cost of Goods Sold enabled under Advanced → Features.
- One VAT convention, written down, applied everywhere.
- Unit cost, not pack cost.
- Variable products: parent default plus overrides only where variations differ.
- Bulk changes checked afterwards for products that lost a cost.
- Spreadsheets matched by ID or SKU, with variations included and blanks meaning “no change”.
- Past orders either excluded or clearly marked as estimates.