5 min read

How to Export WooCommerce Orders to CSV (HPOS-Safe)

An order export often begins with a simple request: “Can you send me the sales from last quarter?” It becomes less simple when the file is empty, misses recently placed orders, or contains totals without enough detail to explain them.

The usual problem is not the CSV format. It is how the exporter reads WooCommerce. Modern stores can keep orders in High-Performance Order Storage (HPOS), while older installations may still use legacy order storage. An exporter that assumes every order is a WordPress post can quietly stop seeing the full picture.

Shirely uses WooCommerce order queries and order objects, so the same workflow supports HPOS and legacy storage. You can choose a useful slice of the order history, download one row per order, and inspect the result before it goes anywhere else.

Start with the question the file needs to answer

Do not export the entire store by habit. A smaller, well-defined file is easier to review and safer to share.

Before running the export, decide whether you need:

  • orders in a particular status, such as processing or completed;
  • a start date, an end date, or both;
  • a migration sample rather than the full history;
  • a reconciliation file for a specific accounting period.

Choose Orders, apply the relevant status and date filters, then run the export on demand. For a migration, start with a narrow date range. It gives you a realistic file for testing without making the first round difficult to inspect.

What the order CSV contains

The exporter writes one row per order. The columns are:

order_id, origin_ref, status, currency, date_created, customer_id, customer_email,
billing_first_name, billing_last_name, billing_company, billing_address_1, billing_address_2,
billing_city, billing_state, billing_postcode, billing_country, billing_email, billing_phone,
shipping_first_name, shipping_last_name, shipping_company, shipping_address_1, shipping_address_2,
shipping_city, shipping_state, shipping_postcode, shipping_country, payment_method,
payment_method_title, transaction_id, customer_note, total, line_items, refunds

That makes the file useful for more than a revenue total. It preserves the order status and currency, billing and shipping context, payment references, the customer note, and the data needed to understand what was purchased.

The file also contains personal and transaction-related information. Treat it as sensitive business data. Keep access limited, store it according to your own retention policy, and avoid leaving copies in shared download folders.

How line items and refunds fit into one row

A single order can contain several products and several refunds, but a CSV row still needs to remain a single row. Shirely packs those repeated values into two fields.

Line items use this structure:

SKU:quantity:total

When an order has more than one item, entries are separated with a pipe (|). Refunds use amount:reason, with the same pipe separator for multiple entries.

This representation is deliberately compact. It keeps the export readable in a spreadsheet and supplies the matching order importer without pretending that a flat CSV is a relational database. If you intend to transform these fields in another tool, test a few multi-item and refunded orders first so the separator is handled correctly.

Why HPOS support matters

HPOS changes where WooCommerce stores order data. Code written around a generic posts-table query may work on a legacy store and return incomplete or empty results after HPOS is enabled.

Shirely avoids that assumption by working through WooCommerce's order layer. You do not need a different export template for an HPOS store, and you do not need to turn HPOS off to produce the file.

That does not remove the need for a sanity check. Compare the number of rows with the order count for the same status and date range in WooCommerce. Then open a few orders with different shapes: a guest order, a registered customer, several line items, and a refund if you have one.

Keep migration identifiers intact

For reporting, order_id is useful because it identifies the order in the current store. For a store-to-store round trip, preserve both order_id and origin_ref.

WordPress IDs are local to an installation. An order numbered 1050 on one store is not automatically the same record as order 1050 on another. The import side uses provenance to avoid treating an accidental ID collision as permission to overwrite the wrong order.

The practical workflow is:

  1. Export a small representative range.
  2. Keep the identifier columns unchanged.
  3. Import it into staging.
  4. Check customer links, addresses, totals, line items, refunds, and order notes.
  5. Only then prepare the wider migration.

If you are moving more than orders, load the dependencies in a sensible sequence. Products and customers should be available before the order history that refers to them.

A quick verification checklist

Before you hand off or archive the CSV, check:

  • the row count matches the filters you selected;
  • the oldest and newest dates are in the expected range;
  • statuses and currencies look plausible;
  • several orders contain the expected billing and shipping values;
  • multi-item orders have every item in line_items;
  • refunded orders contain the expected refund entry;
  • the file still includes order_id and origin_ref if it will be imported;
  • access to the file is limited to people who need the customer data.

This takes a few minutes and catches the kind of quiet mismatch that otherwise appears much later in an accounting or migration review.

Frequently asked questions

Does the export support HPOS?

Yes. Shirely reads orders through WooCommerce order queries and objects rather than assuming they are stored as ordinary WordPress posts.

Can I export only a date range or one status?

Yes. The order export supports an order-status filter plus start and end dates. Use them to keep the file aligned with the task at hand.

Does each product get a separate CSV row?

No. The export uses one row per order. Products are stored in line_items as SKU:quantity:total, with a pipe between several items.

Are passwords or payment card details included?

No customer passwords are part of this export. The file contains order and payment-reference fields such as the payment method and transaction ID, not raw payment-card credentials.

Do I need WPML or Matrix Mode?

No. Orders are store records, not translated catalog rows. This workflow does not require Matrix Mode.

When you are ready to test the other half of the workflow, read how to import WooCommerce orders from CSV. The documentation covers the wider import and export process, while pricing explains the available Shirely licenses.