Specification

A WooCommerce CSV can be internally incomplete and look entirely well-formed.

The structural model, measured on a real WooCommerce export rather than read from documentation — and a straight account of why we have not shipped a writer for it.

Not built

We do not export WooCommerce files, and this page is not a roadmap.

Shopify is built and round-trips through our own validator with zero blockers. WooCommerce is not built, and is deliberately blocked on a real WooCommerce install — we will not write a target grammar from documentation again. We did that twice, and the documentation was wrong both times.

What follows is what we have actually measured. It is published because it is useful on its own, and because a specification we are confident about is a different thing from one we have tested — and you are entitled to know which one you are reading.

Woo declares the tree; Shopify infers it

This is the whole difference and everything else follows from it. Shopify groups rows by a repeated Handle and works the structure out. WooCommerce states it outright: every row carries a Type, and a variation carries an explicit Parent pointer.

Measured on a 101-record, 17-column export produced by WooCommerce’s own exporter: 2 simple rows, 13 variable rows, 86 variation rows.

The scope split is the same one that costs people their catalogue on Shopify, wearing different column names. A variable row declares the option set — all 13 carried a multi-valued attribute, one to six values each. A variation row declares exactly one value, all 86 times. Getting that backwards is the most likely mistake anyone reading the documentation will make; we made the equivalent mistake on Shopify and it produced 200 blockers on a 204-row file that imports cleanly.

Two more measured facts that are opposites of Shopify’s behaviour, and so are exactly where a Shopify-shaped assumption breaks. Price lives on the variation, never on the parent — 0 of 13 parents carried a regular price, 81 of 86 variations did. And every variation carries a Name, all 86 of them, where Shopify puts the title only on the first row of a group.

The measured export

101 records
17 columns, from WooCommerce’s own exporter.
2 / 13 / 86
simple / variable / variation rows.
0 of 13
Parent rows carrying a price.
81 of 86
Parent references that resolve to nothing. See below — this is the finding.

The finding: 81 of 86 parent references point at nothing

In that export, Parent on a variation row points at its parent by id. Only 5 of the 86 references resolve to a row inside the file. The other 81 point at products that are not in the export at all.

It is a partial export, and it is the single most useful thing we have learned about this format: a WooCommerce CSV can be internally incomplete and look entirely well-formed. Nothing about the file announces it. Imported into a fresh store, 81 variations arrive with no parent — which is the same shape as a row belonging to no product, in Woo’s vocabulary, and it is the first rule we will write once there is something real to check it against.

It is also a constraint on any writer we build. Documentation says Parent also accepts the parent’s SKU, resolved against products in the same file. If that is true it is the only form we could ever use, because we do not have and cannot invent WooCommerce post ids — and a multi-variant product whose parent row has no SKU could not be written at all. It would have to be reported rather than guessed at. Inventing an identifier is precisely what the rest of this system is built to refuse.

Note the word “if”. That claim comes from documentation and we have not measured it, which is the whole reason this page is a description and not a rule set.

Why a writer without a validator is worse than no writer

Validation gates export. An export is never produced from rows that failed a check — that rule is what makes the output worth anything. A WooCommerce writer shipped today would have nothing to be gated by, because our validator implements the Shopify grammar and only that. It would hand you a file under our name with no check of any kind behind it.

An undetected failure is the only true defect in this product. Shipping one deliberately, at the last stage, to close a milestone, is not a trade we are willing to make.

The other half is that we have written import rules from documentation before, twice, and both times the documentation was wrong in a way only a real store revealed. Rules written now would be hypotheses presented to you as findings.

What unblocks it is the same thing that unblocked Shopify: a real target to measure against. The methodology page describes what that looked like the first time.

What a Woo install has to answer

  • Does Parent genuinely resolve by SKU within the same file, or only by post id?
  • What happens to a variation whose parent is missing — refused, or imported orphaned and silent?
  • What does the importer do with a price on a variable row, where the export never puts one?
  • Which of the 17 columns are actually required, as opposed to merely always present in an export?

Every one of those is a question a document could answer confidently and wrongly.

The Shopify half is built, and it is free to try.

If you are moving a catalogue to Shopify, every rule we have is running today. The full grammar is here.

Check a file free