Getting Started

Mapping hierarchical and multi-path taxonomies

Published · Last updated

WordPress and WooCommerce use taxonomies to group posts and products – categories, tags, brands, attributes, custom taxonomies. SSI maps a CSV column to a taxonomy, but real-world CSVs do clever things: nested category paths, multi-category assignments, mixed separators. This article covers how to map all of them correctly.

The basics – one term per row

Simplest case. CSV has one term per row in a column:

SKU,Name,Tag
ABC-001,Widget A,featured
ABC-002,Widget B,best-seller

Map Tag → product_tag. Each row gets one product tag.

Hierarchical taxonomies – the > separator

WooCommerce categories, custom hierarchical taxonomies (brand hierarchies, location hierarchies, etc.) live as trees: Electronics has children Phones, Laptops, Tablets; each child may have grandchildren. Your CSV expresses a row’s position in the tree by joining the path with a separator.

The conventional separator is >:

SKU,Name,Categories
ABC-001,iPhone Case,Electronics > Phones > Accessories
ABC-002,Wireless Mouse,Electronics > Laptops > Peripherals

Configure the taxonomy mapping for product_cat:

  • Source: Categories (the CSV column name)
  • Separator: >

On import, SSI:

  1. Splits Electronics > Phones > Accessories into ["Electronics", "Phones", "Accessories"] (trimming whitespace around the >).
  2. Walks the path, creating each level as a term if it doesn’t exist already, parented to the previous level.
  3. Assigns the product to every level of the path – Electronics, Phones, AND Accessories – so the product shows up on parent category pages too. (This is the new-import default; you can switch back to leaf-only. See Which category levels get assigned below.)

After the import, your category tree looks like:

Electronics            ← iPhone Case is in here (default: all levels)
├── Phones             ← iPhone Case is in here (default: all levels)
│   └── Accessories    ← iPhone Case is in here (always — the leaf)
└── Laptops            ← Wireless Mouse is in here (default: all levels)
    └── Peripherals    ← Wireless Mouse is in here (always — the leaf)

Spaces around the > are optional but recommended for human readability. SSI trims them. Both A > B > C and A>B>C work.

Which category levels get assigned

When you import a hierarchical path, SSI can attach the product to every level of that path or only to the deepest (leaf) term. This is controlled per-import by the Assign every category level (not just the deepest) option in Additional Options.

  • ON – a product in Men > T-Shirts is assigned to BOTH Men AND T-Shirts (every level of the path). Parent category pages (/product-category/men/) list the product, breadcrumbs render the full path, and layered-navigation filters include parent categories. This matches WP All Import / WooCommerce expectations.
  • OFF – only the deepest (leaf) term is assigned (T-Shirts only). Parent category pages won’t list the product.

New imports default this option ON. Imports created before this option existed keep their original leaf-only behaviour until you tick the box – so re-running an existing import won’t silently change which categories your products belong to. Switch it on (and re-run) when you want the all-levels behaviour on an older import.

The SSI_ADD_ALL_TERMS_FROM_HIERARCHY PHP constant has no effect. Use the Assign every category level option instead.

Choosing a different hierarchy separator

If your CSV uses something other than > (some feeds use /, others use :: ), set the separator field accordingly. Pick a separator that doesn’t appear inside any term name. / is risky if you have terms like “and/or”; > is generally safe.

Multi-path assignments – the | separator

A single product often belongs to MULTIPLE categories. SSI uses | (pipe) to separate independent paths within one cell:

SKU,Name,Categories
ABC-001,iPhone Case,Electronics > Phones > Accessories | Sale > Black Friday

That single row places the product in BOTH:

  • Electronics > Phones > Accessories
  • Sale > Black Friday

Configure the taxonomy mapping:

  • Source: Categories
  • Separator: >
  • Multi-separator: | (this is the default, so usually nothing to do)

SSI splits on | FIRST (giving you the list of paths), then splits each path on > (giving you the hierarchy levels within that path). With the default Assign every category level option, the product ends up assigned to every level of every path; with that option off it’s assigned only to the leaf of each path. See Which category levels get assigned above.

Changing the multi-separator

If | clashes with your data (some product titles contain pipes), set the multi-separator to something else – comma, semicolon, your choice. Pick something that doesn’t appear inside any individual term name AND doesn’t appear inside any path.

Flat (non-hierarchical) taxonomies

Tags, product attributes (pa_color, pa_size), and most custom taxonomies are flat – no parent/child relationships. The separator is still useful here, but only for multi-value assignment:

SKU,Name,Tags
ABC-001,Widget A,featured|best-seller|gift-idea

Map Tags → product_tag with multi-separator |. The product gets all three tags.

For flat taxonomies you can leave the hierarchy separator (>) blank – there’s no hierarchy to express.

WooCommerce attributes – the pa_ prefix

Variable products use product attributes (color, size, material) that double as taxonomies. WooCommerce stores these under the pa_ prefix: pa_color, pa_size, pa_material.

SKU,Name,Type,Color,Size
TSHIRT-001,Cotton T-Shirt,variable,,
TSHIRT-001-RED-S,Cotton T-Shirt — Red / S,variation,Red,Small
TSHIRT-001-RED-M,Cotton T-Shirt — Red / M,variation,Red,Medium
TSHIRT-001-BLU-S,Cotton T-Shirt — Blue / S,variation,Blue,Small

Map Color → pa_color and Size → pa_size, and tick Used for variations on both.

Used for variations tells WooCommerce the attribute distinguishes the variations of the parent product. See the Importing variable products article for the full story.

Default term fallback

For hierarchical taxonomies that the CSV doesn’t map (e.g. you don’t have a product_brand column in your CSV but you’ve set up the product_brand taxonomy with a default term in WordPress), SSI’s upsert-relationships stage assigns the default term to every imported item that has no term in that taxonomy. SSI reads the default from default_category (post categories), default_term_<taxonomy> or default_<taxonomy>; WooCommerce’s Make default link on a product category sets default_product_cat. A taxonomy without a configured default is skipped.

Useful for “Generic” or “Uncategorised” brands you want every product to belong to without populating the CSV.

Common gotchas

Whitespace in term names

"Apparel > Hats " (trailing space inside the hierarchy) is a different term from "Apparel > Hats". SSI trims whitespace around the separator, but NOT inside the term name itself. Clean your CSV.

Mixing separators in one CSV

If some rows use > and others use /, you’ll get a mess. Pick one separator per taxonomy and stick to it. If the CSV is inconsistent, pre-process it to normalise.

Same hierarchy different name capitalisations

WordPress slug-deduplicates terms (Phones and phones both become the slug phones), so casing differences within ONE import collapse together. Across imports they should already be consistent – but if you find one CSV has Phones and another has phones, you may end up with a phones-2 slug. See Handling duplicate term slugs for the policy options.

Multi-path with empty paths

Categories: "A > B ||C > D" produces 3 paths after splitting on |: A > B, an empty path and C > D. The empty one is skipped silently. Watch for accidental double-pipes if your CSV is auto-generated.

Reserved term names

Don’t use 0, null, or parent as standalone term names – WordPress core has edge cases with these. Wrap them in something descriptive: Year 0, Null Category, Top-Level Parent.

Worked example – full WooCommerce category mapping

Source CSV:

SKU,Name,Categories,Tags,Color,Size
WIDGET-001,Cotton T-Shirt,Apparel > Tops > T-Shirts | Sale,unisex|cotton,Red|Blue|Green,S|M|L
WIDGET-002,Wool Hat,Apparel > Hats > Wool,winter,Black,One Size

Mappings:

CSV columnTaxonomyHierarchy separatorMulti-separator
Categoriesproduct_cat>|
Tagsproduct_tag(none)|
Colorpa_color (variable)(none)|
Sizepa_size (variable)(none)|

After import, WIDGET-001 belongs to both the Apparel > Tops > T-Shirts path and the Sale category. With the default Assign every category level option on, it’s attached to Apparel, Tops, T-Shirts AND Sale (so it shows on each of those category pages); with that option off it’s attached only to the leaf terms T-Shirts and Sale. It has tags unisex + cotton, and Color and Size values Red, Blue, Green and S, M, L as attributes. Variations themselves come from variation rows in the file; see Importing variable products.

What’s next

  • Importing variable products – when an attribute taxonomy drives variations.
  • Handling duplicate term slugs – what to do when two CSV spellings collapse to the same WP slug.
  • Choosing your unique identifier – the upstream prerequisite for any re-import.

Written for Super Speedy Imports 2.99.19.

Comments

▲
▼
1/1