Skip to content

Margin Report

wp-admin → WooCommerce → Margin Report is the operations team's view of how much money each order, period, and product is actually making. It pairs the per-product _fruitplug_cost_gbp cost data (set on the Fruit Costs page) with the revenue of every fulfilled Woo order.

What it counts

The report includes orders with status wc-completed or wc-processing. Drafts, cancelled, failed, on-hold, and pending orders are excluded.

For each order line item:

  • Revenue = WC_Order_Item_Product::get_total() — i.e. the line subtotal after order-level discounts and before tax. This matches what the customer actually paid for the fruit (shipping and fees are excluded — they're not margin-bearing).
  • Cost = unit cost × quantity, where unit cost is sourced in this priority:
    1. _fruitplug_cost_gbp on the line item meta (snapshot taken at checkout). Currently never populated — Cart\CustomBoxPricing does not copy product cost onto order items. See "Known gaps" below.
    2. _fruitplug_cost_gbp on the product post meta (live lookup at report-run time). This is the active path today.
  • Margin = revenue − cost. Margin % = margin / revenue.

Filters

  • Date range presets: today, last 7 days, last 30 days, this month, last month, custom (from / to ISO dates).
  • The form pins to whatever preset you select; "custom" exposes the from/to date inputs.

Summary card

Field Meaning
Orders Count of orders matching the range and statuses.
Revenue (£) Sum of all line totals (post-discount, pre-tax).
Cost (£) Sum of all line costs.
Margin (£) Revenue minus cost.
Margin % Margin ÷ Revenue, expressed as a percentage.
Avg / order Margin ÷ order count.

Per-order table

One row per order in the range, capped at 500 per page (the Calculator paginates underneath the admin UI). Each row links to the standard Woo order edit screen.

Per-product table

Roll-up of every product slug touched in the range, sorted by margin (£) descending. This is the screen ops uses to spot which fruits are pulling the most absolute margin and which look weak.

CSV export

The "Export CSV (orders)" button on the filter bar streams a CSV of the per-order table for the current range. The button is nonce-protected (fruitplug_margin_report_csv) and the download endpoint re-checks manage_woocommerce. Columns:

Order ID, Date, Status, Customer, Revenue (GBP), Cost (GBP), Margin (GBP), Margin (%)

The export streams via php://output so memory usage stays flat regardless of order count.

Edge cases

  • Refunds. Woo records refunds as shop_order_refund posts attached to the parent. The calculator subtracts WC_Order::get_total_refunded() from revenue, then reduces cost proportionally (refund items don't carry per-line cost detail, so we approximate). For partial refunds this is "close enough" — confirm against Woo's native refund report if it really matters.
  • Subscription renewals. Counted as standard orders — they show up under their own order ID with status wc-completed.
  • Tax & shipping. Excluded. The report is a margin-on-fruit view, not a P&L.
  • Missing cost data. If a product has no _fruitplug_cost_gbp set, that line's cost is treated as £0 → margin overstated. Set every product's cost on the Fruit Costs page.

Known gaps

  • Cost not snapshotted at checkout. Cart\CustomBoxPricing does not currently copy _fruitplug_cost_gbp from product to line item, so every report runs against the current product cost. If a supplier price changes between order time and report time, the historical margin shifts. Fix: add a woocommerce_checkout_create_order_line_item hook to stamp the cost on the line item.
  • HPOS off only. The calculator queries wp_posts and wp_postmeta directly. When HPOS (Custom Order Tables) is enabled on production, the report will return zero results — the queries need swapping for the WC data-store API at that point.

What "healthy" margin looks like

TBD — pending review of a full month of completed orders. The healthy band will be added here once we have data.