WooCommerce product CSV import: shaping a supplier file to the built-in importer’s columns and rules
WooCommerce’s built-in importer takes a CSV whose columns follow its product schema, and a supplier’s spreadsheet almost never arrives in that shape. Categories need a > between levels, weights need a bare number in the store’s unit, and Yes has to become 1. Here are the columns that matter, what Update existing products matches on, and how to shape a supplier file so the importer creates what you meant.
Have a supplier file like this? Send it exactly as it arrived and see the same products before and after.
What the WooCommerce importer expects
A supplier’s spreadsheet arrives with a Category column reading Kitchen/Cookware/Frying Pans on one row and Cookware; Frying pans on the next, for two pans that belong on the same shelf. Neither is what a WooCommerce product CSV import expects. The importer reads > between the levels of a category path and a comma between separate categories, so the path it wants is Kitchen > Cookware > Frying pans.1
The importer is built in, under Products > All Products, then Import. It takes a CSV or TXT file, matches the columns it recognises to product fields, and adds or updates the products the rows describe; any column it does not recognise is not imported by default.1 So the work is not the upload. It is shaping the supplier’s file to WooCommerce’s product CSV import schema.12
The file should be UTF-8, with 1 and 0 for true and false and commas between multiple values in a cell.1 Excel is not among the editors WooCommerce recommends, and the page warns that spreadsheet applications “can change formatting or character encoding”, so check the saved CSV before importing it.1 The whole job is one platform’s version of product data enrichment: take the file as it arrived and return one the store will accept.
The columns, and the values each one accepts
Only two columns are marked required, SKU and Name, and even a missing SKU is not refused: WooCommerce “generates one if this value is omitted”.1 The rest are optional in that the import runs without them, not in that the product which appears is the one you meant.
| Column | Accepts | What to watch |
|---|---|---|
| ID | an existing product’s ID | Cannot be set for a new product |
| Type | simple, variable, grouped, external, variation, virtual, downloadable | Several are separated by commas |
| Published | 1, 0, -1, 2, true, false | 0 is private, but false is draft |
| In stock? | 1 or 0 | Not Yes, No or In Stock |
| Stock | a number, parent, or blank | A blank turns stock management off |
| Regular price, Sale price | a price, such as 24.99 | No currency symbols or formulas |
| Weight, Length, Width, Height | numbers only | The unit is the store’s setting |
| Categories | paths with >, separated by commas | A comma inside a name takes a backslash |
| Images | URLs, or file names already in the Media Library | First is featured; no redirect scripts |
| Parent | the parent’s SKU, or its ID as id:123 | Variation rows only |
| Attribute 1 value(s) | values separated by commas | A variation row takes one |
| meta: plus a key | plain text | No JSON or serialised data |
Measurements need the closest look. The schema’s only instruction for Weight, Length, Width and Height is “Parse only numbers.”1 The unit belongs in the header, not the cell: the schema names the column Weight (unit), and WooCommerce’s own sample file has Weight (lbs) and Length (in).3 The unit itself is a store setting, one for weight and one for dimensions, chosen under WooCommerce > Settings > Products > General.5
One more rule sits behind the table: a product with no category goes into the default category, Uncategorized unless someone has renamed it or chosen another.7
What Update existing products matches on
One option on the upload screen decides what a repeat import does. With Update existing products selected, the importer looks up each row’s ID or SKU in the store: “Existing products that match by ID or SKU are updated. Products that do not exist are skipped.”1 With it unselected, rows whose IDs or SKUs already exist are skipped instead.1
That makes the SKU the key to the file. A row without one is not rejected, but the SKU WooCommerce generates for it is one the supplier’s next file cannot match.1 WooCommerce’s advice for repeat imports is to “keep stable IDs or SKUs”: for a supplier file, a SKU on every row that will not change between deliveries.1
The trap is a supplier column headed ID. The mapping screen maps recognised columns automatically, and ID is one of the schema’s own names.1 But the ID column “Identifies an existing product to update”, and the schema on GitHub is blunter: “Defining this will overwrite data for that ID on import.”12 With Update existing products selected, a supplier’s 1482 that happens to match one of your product IDs updates that product with the supplier’s row.1 A supplier’s own code belongs in SKU or a meta: column, never in ID.
Where supplier files break it
Supplier files are built for a buyer or a warehouse, not for this importer. Five things in them break it.
- Separators. Categories arrive with slashes or pipes, or split across columns such as Department and Range, where the importer wants one path per category with > between levels.1 And because WooCommerce “treats commas as field separators”, a comma inside a single value, in a category name or an attribute value, needs a backslash: a category called Places, People, Cities is written Places\, People\, Cities.1 Mapping supplier categories onto your own tree comes first; the syntax comes second.
- Units in the cell. 1200 g, 1.2 kg and 1.2kg in one Weight column. The importer parses only numbers, so it cannot turn grams into kilograms for you: convert every row to the store’s unit first.15
- Words where the importer wants numbers. Yes, No and In Stock in columns that take 1 and 0, and prices written as £24.99. WooCommerce’s advice for a supplier file is to remove “formulas, currency symbols, extra whitespace, and unsupported formatting”.1
- Image links that do not load. A bare file name, a cloud-storage link behind a redirect script, or a link that has died since the sheet was made. WooCommerce copies each image into the Media Library during the import, so it must be directly accessible then; a file name works only for an image already there.1 On one of our recent jobs, for a musical instrument retailer, we fetched all 12,015 image links on the catalogue before the file was built, and 3,566 came back broken or blocked. Nearly a third of them. The import never saw one.
- HTML in descriptions. On some servers, WordPress can mistake a CSV containing HTML for another file type and refuse it with “Sorry, this file type is not permitted for security reasons.” The documented way round is to upload the file to the site’s uploads directory and enter its server path under Show advanced options.1
One supplier row, before and after
Here is one row for a frying pan as a supplier sent it, set against the importer’s columns. Bold is the value the importer gets; amber is a flag for a person, because no rule settles it.
| WooCommerce column | Supplier sent | After |
|---|---|---|
| Type | blank | simple |
| SKU | FP-28 (with a leading space) | FP-28 |
| Name | FRYING PAN 28CM NON STICK | 28 cm non-stick frying pan |
| Published | Yes | 1 |
| Regular price | £24.99 | 24.99 |
| Weight (kg) | 1200 g | 1.2 |
| Categories | Kitchen/Cookware/Frying Pans | Kitchen > Cookware > Frying pans |
| In stock? | In Stock | 1 |
| Stock | Plenty | No quantity given |
| Images | fp28.jpg | A file name, not a URL |
| Attribute 1 name | Colour: Black | Colour |
| Attribute 1 value(s) | Colour: Black | Black |
Weight is the row to check twice, because it can go wrong without looking wrong: strip the g from 1200 g without converting and the pan weighs 1,200 kg. Stock is the honest flag. Plenty is not a number, and a blank Stock cell turns stock management off.1 Choosing between that and an invented quantity is a decision for a person, not a rule.
Variable products: parent and variation rows
A variable product is one product in several versions, and each variation “can have its own price, SKU, stock level, and other attributes”.6 In the CSV, that is one parent row and one row per variation.
The parent row has Type set to variable, its own SKU and every value in Attribute 1 value(s). Each variation row has Type set to variation, its own unique SKU and Name, the parent’s SKU (or its ID, written id:123) in Parent, and only its own value; given more than one, WooCommerce uses the first.1 Attribute 1 global is 1 for an attribute already set up under Products > Attributes and 0 for one that belongs to the product alone.17 Generally, WooCommerce says, “it’s preferable to define attributes globally”.7
| Type | SKU | Parent | Attribute 1 name | Attribute 1 value(s) | Attribute 1 global | Regular price | Stock |
|---|---|---|---|---|---|---|---|
| variable | KT-100 | blank | Colour | Black, Cream, Red | 1 | blank | blank |
| variation | KT-100-BLK | KT-100 | Colour | Black | 1 | 39.99 | 12 |
| variation | KT-100-CRM | KT-100 | Colour | Cream | 1 | 39.99 | 0 |
| variation | KT-100-RED | KT-100 | Colour | Red | 1 | 42.99 | 5 |
Whether the variations then appear comes down to spelling and price. The importer page says “Keep the attribute name and value spelling identical in the parent and variation rows”, and its own example of what to normalise is L, l and Large, turned into the single value you want.1 A variation without a price does not show in the store.4
Spelling also decides what shoppers see, because each spelling of a value is one more option in the store’s filters. The fix is the same for the filter and the import: normalise attribute values before the file is built.
WooCommerce 11.1 changed two things. With Update existing products selected, a simple product already in the store can become variable in one import if its parent row comes first; earlier versions, or files whose row order is uncertain, need two.1 And an update can add a variation: a row matching no product becomes a new variation if its Parent is an existing variable product and the row has a SKU and attribute values the parent already has.1
How to prepare the file, step by step
Eight steps, in an order that stops each one undoing the last. Work on a copy and keep the supplier’s original untouched, as supplier data onboarding sets out.
- Start from an export. Export a few of your own products and use the file as the template, since a WooCommerce export “already follows the required schema”.1
- Decide whether the file adds or updates. New products need no ID column; an update needs each product’s SKU or ID as the store has it, with Update existing products selected.1
- Rename the headers and fill the gaps. Use the schema’s exact names (Weight (kg), not Wt), move any column with no home to meta: or drop it, and give every row a Type and a Published value.1
- Make every value the importer’s. Yes and No become 1 and 0, currency symbols and formulas come out, and weights and dimensions are converted to the store’s unit before the unit is removed.15
- Rewrite categories as paths, with > between levels, commas between categories and a backslash before any comma inside a name.1
- Split attributes into their columns, with one value on each variation row and one spelling everywhere.1
- Check every image link. Each must be a direct URL that loads, or a file already in the Media Library, with the featured image first. Add alt text after the import; the importer cannot.1
- Save as UTF-8 and test small. Back up the store, import a handful of rows on a staging site and read the skipped-row report, then import the rest in batches, staying on the page while each runs.1
What to do next
Most of that list is not WooCommerce work. It is the shaping every channel asks of a supplier file: one value per cell, one spelling per value, one unit per column, and links that load. RefynData’s product data enrichment service does it before the import: each SKU matched to the real product, items filed into your own category tree, spelling variants folded onto one canonical word, measures converted to one unit and image links fetched, with every value keeping a link to its source. You get a Google Sheet or Excel file, one tab per category, with a quality score that warns but never blocks the export.
Start from an export of your own products, and give every row a SKU that will not change. Test a handful of rows on staging before the rest goes in. Then keep each fix as a rule for that supplier, because the next delivery will arrive with the same slashes, the same grams and the same Yes.
Questions
How do I import products into WooCommerce from a CSV file?
Go to Products > All Products and select Import, then choose a UTF-8 CSV whose headers follow WooCommerce’s product CSV import schema. Check the column mapping screen and run the importer, staying on the page until it finishes. Rows whose SKU or ID already exists are skipped unless you select Update existing products.
Which columns does the WooCommerce CSV importer require?
Only SKU and Name are marked required, and WooCommerce generates a SKU if the cell is empty. The rest are optional, but a product with no category goes into the default category, and a variation with no price does not show in the store. Columns the importer does not recognise are not imported unless you map them.
How do I import variable products into WooCommerce with a CSV?
Give the parent a row with Type set to variable, its own SKU and every attribute value. Give each variation a row with Type set to variation, a unique SKU, the parent’s SKU in Parent, one attribute value and a price. Spell each attribute name and value identically in every row, or the variations may not be created.
Does a WooCommerce CSV import overwrite existing products?
Only with Update existing products selected, and only for rows whose ID or SKU matches a product already in the store; other rows are skipped, though from WooCommerce 11.1 a new variation of an existing variable product can be created. With the option unselected, rows whose ID or SKU already exists are skipped instead. Never map a supplier’s own ID column to ID.
How do I set categories and subcategories in a WooCommerce product CSV?
Write the full path with > between levels, such as Kitchen > Cookware > Frying pans, and separate categories with commas. Put a backslash before any comma that is part of a category name, so the importer keeps the whole name.
Why are my product images not importing from the CSV?
Each image URL must be directly accessible when the import runs, because WooCommerce copies the file into the Media Library. Links behind redirect scripts, such as some cloud storage links, are not supported, and a bare file name works only if the file is already in the Media Library. The importer cannot set alt text, so add it afterwards.
Sources
- WooCommerce documentation. Product CSV Importer and Exporter. Read .
- WooCommerce on GitHub. Product CSV Import Schema. Read .
- WooCommerce on GitHub. sample_products.csv (WooCommerce sample data). Read .
- WooCommerce documentation. Variable Products. Read .
- WooCommerce documentation. Products Settings. Read .
- WooCommerce documentation. Adding and Managing Products. Read .
- WooCommerce documentation. Managing Product Categories, Tags and Attributes. Read .