Choosing your unique identifier

June 5, 2026

The unique identifier is the CSV column (or PHP function) Super Speedy Imports uses to decide whether a row should UPDATE an existing post or INSERT a new one. Get this right and re-imports are clean. Get it wrong and every re-import creates duplicates.

This is the single most important decision when setting up an import.

What it does

On every run, SSI’s match-existing stage looks at each CSV row and asks: “Does WordPress already have a post with this unique identifier value?”

  • Yes → store that post’s ID on the batch row → the later update-posts / update-postmeta stages will UPDATE that post.
  • No → leave the post_id blank → insert-posts / insert-postmeta will create a new post.

Without a unique identifier, every re-import would duplicate every row.

The fallback — _sku

If you don’t set an explicit unique identifier, SSI falls back to the _sku postmeta key — but only when _sku is actually mapped. This is what WooCommerce stores SKUs under, so for a typical product import where you’ve mapped a SKU column it Just Works:

"post_meta": {
    "_sku": "SKU",
    "_regular_price": "Regular_Price"
}

With this config, the value in your CSV’s SKU column becomes the _sku postmeta — and, since no explicit unique identifier is set and _sku is mapped, SSI uses that as the unique identifier automatically.

If neither an explicit unique identifier nor a _sku mapping is present, this fallback does not apply — you must set the unique identifier explicitly (see below).

Constraint: SKU values must be unique across all products. If two CSV rows have the same SKU, SSI dedups them at load time by appending -2, -3, etc. (Watch the CLI output for the Fixed N duplicate post_name values count.)

Explicit unique identifier

For non-product post types (or products where you want to match on something other than SKU), set the unique identifier explicitly in Additional Options → Unique item identifier.

Two ways to provide it:

1. A CSV column

Pick any column whose values are unique across all your rows. Common examples:

  • A vendor’s internal product ID
  • A barcode
  • An imported-from URL
  • A combined key like vendor:vendor_id that you build in the CSV

When the import runs, SSI writes that value to a hidden _ssi_unique_item_id postmeta on each post and uses it on subsequent runs to find the same post again.

2. A PHP function

For composite identifiers (e.g. “ISBN if present, otherwise title + year”), supply a PHP snippet in the function editor below the field. The snippet runs once per row and returns the identifier string.

// Receives $data (the raw CSV row as an associative array)
// Returns the identifier value as a string.
if (!empty($data['ISBN'])) {
    return $data['ISBN'];
}
return strtolower($data['Title']) . '-' . $data['Year'];

PHP-function identifiers are powerful but require trusting whoever wrote the snippet — see the Troubleshooting article on security if you’re auditing a third-party import config.

What happens with a blank identifier

SSI treats a blank unique identifier as a fatal data-quality issue. Any CSV row with a blank value in the configured identifier column makes the import abort during load-csv:

Import aborted — 5 row(s) have a blank unique identifier.
Every row must have a non-empty value in column 'SKU'.

Row 12: blank value in unique identifier column 'SKU'
Row 47: blank value in unique identifier column 'SKU'
...

The abort is by design — silently inserting rows with blank identifiers would create posts that can’t be matched on the NEXT re-import, leading to duplicates forever. Fix the CSV (fill in the missing identifiers or remove the rows) and re-run.

Things to watch for

Don’t change the unique identifier between runs

If your first import used SKU as the identifier, every post got _ssi_unique_item_id = <sku-value> attached. If you then change the identifier to a different column and re-import, match-existing will look for the NEW identifier — won’t find anything — and INSERT every row as a new post. Duplicate catalog.

If you genuinely need to switch identifiers, plan a migration: bulk-update the existing _ssi_unique_item_id postmeta to the new scheme via SQL or WP-CLI before the first re-import on the new identifier.

Trim whitespace in your CSV

SSI matches identifiers byte-for-byte. A SKU "ABC-123 " (trailing space) and "ABC-123" are different identifiers. Most spreadsheet exports preserve trailing whitespace; check your CSV.

Case sensitivity depends on your DB collation

abc-123 and ABC-123 may or may not match depending on whether your WordPress database uses a case-sensitive collation. Default WP collation (utf8mb4_unicode_520_ci) is case-insensitive, so they’ll match. Custom collations may not. When in doubt, normalise to one case in your CSV.

SSI’s behaviour on duplicate identifiers within ONE CSV

If your CSV has two rows with the same SKU (a real data bug, but it happens), SSI’s load-csv finalisation dedups by appending -2, -3, etc. to the duplicates’ identifier values. Both rows get imported, but with slightly different identifiers — which means each becomes a separate WP post. Watch the CLI’s Fixed N duplicate post_name values line after load-csv. A non-zero count indicates a CSV that should be cleaned up.

Summary checklist

  • ✓ Pick a column whose values are stable, unique, and present on every row.
  • ✓ If you don’t have a natural unique column, build one (vendor:id, or a PHP function combining title+year).
  • ✓ NEVER change the unique identifier between runs without a migration plan.
  • ✓ Trim whitespace and normalise case before importing.
  • ✓ Watch for the “blank unique identifier” abort on first run — fix the CSV, don’t bypass the check.

What’s next

  • Quick start — importing products: shows where this fits in the bigger setup flow.
  • How imports work — the stage pipeline: explains why match-existing runs WHEN it does and what depends on it.
  • Stage selection presets: lets you run just the matching+update flow without re-doing the full pipeline.
×
1/1