WooCommerce Sales Report from MySQL (wc_order_stats Guide)
Build a WooCommerce sales report from MySQL using wc_order_stats: net sales, orders, items, AOV and returning customers, with the status and refund gotchas.
Summary
WooCommerce stores order analytics in the MySQL table wp_wc_order_stats (your prefix may differ). Summing net_total for real orders gives net sales; num_items_sold, returning_customer and date_created add the rest of a sales report. Connect the store database to Better Analyst read-only and ask for the report in plain English.
On this page
Who this report is for
WooCommerce store owners, developers and agencies who want sales reporting beyond the built-in Analytics screens, such as custom periods, cohorts or joins with other data.
What the report includes
| Metric | Source field | Why it matters |
|---|---|---|
| Order date | wp_wc_order_stats.date_created | Store-local timestamp for daily, weekly and monthly sales (date_created_gmt also exists). |
| Net sales | wp_wc_order_stats.net_total | total_sales minus tax and shipping; WooCommerce Analytics' net sales is SUM(net_total). |
| Gross sales | wp_wc_order_stats.total_sales | Order total including tax and shipping. |
| Items sold | wp_wc_order_stats.num_items_sold | Units per order and in total. |
| Order status | wp_wc_order_stats.status | Stored with a wc- prefix (wc-completed, wc-processing); filter out cancelled and failed orders. |
| Refund rows | wp_wc_order_stats.parent_id | Refunds are separate rows with a non-zero parent_id and negative totals; count orders where parent_id = 0. |
| Returning customer | wp_wc_order_stats.returning_customer | Splits sales between new and returning buyers. |
How to build it in Better Analyst from MySQL
- Create a read-only MySQL user for the WordPress database and, if your host restricts remote access, allowlist the Better Analyst IP ranges from the MySQL connector docs.
- In Better Analyst, open Connectors, choose Add Connector, then MySQL, and enter host, port (3306 by default), database, username and password, with SSL if your host supports it.
- Test the connection and save. Optionally restrict the AI to the WooCommerce tables with data access controls.
- Add a Data Context note with your table prefix and which statuses count as sales, for example wc-completed and wc-processing.
Questions to ask
- “Show net sales, orders and items sold by month for 2026 from wc_order_stats, counting only completed and processing orders.”
- “What's our average order value for new versus returning customers?”
- “How much was refunded each month?”
- “Show me all orders from the last 30 days over $500.”
Sample output
Sample data for illustration, not real account data.
| Month | Orders | Net sales | Items sold | AOV (net) | Returning customer share |
|---|---|---|---|---|---|
| Jul 2026 | 1,284 | $71,890 | 2,951 | $55.99 | 38.2% |
| Aug 2026 | 1,342 | $76,420 | 3,104 | $56.94 | 39.5% |
| Sep 2026 | 1,197 | $69,310 | 2,803 | $57.90 | 41.0% |
Charts to use
- Net sales and orders by month (Combo chart): Net sales as columns with order count as a line.
- New vs returning sales (Stacked column chart): Monthly net sales split by returning_customer.
Keep it up to date
Schedule a weekly sales summary by email every Monday, and add an alert if daily orders drop to zero, which often means checkout or payments are broken.
Further reading
Frequently asked questions
Why don't my totals match WooCommerce Analytics?
Check three things: the status filter (statuses carry a wc- prefix), refunds (separate rows with a parent_id), and whether you used net_total or total_sales. WooCommerce Analytics also lets you choose which statuses count.
Is customer_id the WordPress user ID?
No. In wc_order_stats, customer_id refers to wc_customer_lookup.customer_id, which also covers guest customers. Join through wc_customer_lookup to get email or user details.
Is wc_order_stats always populated?
It's maintained by WooCommerce Analytics. If you imported historical orders or disabled analytics, rows can be missing; WooCommerce can re-import historical data from its Analytics settings.