WP-CLI
Five commands, all driving the same objects the admin screens drive. An import started on the command line appears in Importundo → History and can be rolled back from either place.
Importing needs --user
importundo import refuses to run without it, and that is deliberate.
WordPress blanks the slug of a pending post when the current user cannot publish_posts, and strips markup when they cannot post unfiltered HTML. An import running as nobody therefore writes something different from the same file run through the wizard. Naming the user keeps the two paths identical.
wp --user=1 importundo import products.csv
wp --user=editor@example.com importundo import products.csv
wp --user=jane importundo import products.csv
A user ID, a login or an email address all work. rollback and retry take --user too, but do not require it: without one they run as the user who created the import.
importundo import
Import a CSV file. The file may be a path on the server, or — with Importundo Pro — an https:// address to download it from, because the reason to run this from cron is usually a supplier feed, and a supplier feed lives at an address rather than on disk.
wp --user=<user> importundo import <file> [--post-type=<post-type>] [--template=<template>]
[--map=<pairs>] [--match=<field>] [--on-match=<behaviour>] [--write-unchanged]
[--dry-run] [--allow-failures] [--porcelain]
| Option | What it does |
|---|---|
<file> | Path to the CSV file. With Importundo Pro, an https:// address to download it from also works. |
--post-type | Post type to import into. Default: post. |
--template | Apply a saved mapping template, by ID or by name (Importundo Pro). Without one, columns are mapped automatically by header name. |
--map | Map columns explicitly, as column:target pairs separated by commas. Overrides automatic mapping for the columns named.--map="sku:meta.sku,Name:post.post_title" |
--match | What identifies an existing post, so a second run updates instead of duplicating. Accepts post.ID, post.post_name, post.post_title or meta.<key>. A column of the same name is mapped to it automatically when nothing else is. |
--on-match | What to do with a row that matches: update, skip or fail. Default: update. |
--write-unchanged | Write every matched row even when nothing about it has changed. Off by default, which is what makes a no-op re-import cheap. |
--dry-run | Work out what the file would do and report it. Writes nothing. |
--allow-failures | Exit zero even when some rows failed. |
--porcelain | Print the import ID and nothing else. |
What a run looks like
$ wp --user=1 importundo import products.csv --post-type=product --match=meta.sku --dry-run +---------+---------+-----------+---------+--------+ | created | updated | unchanged | skipped | failed | +---------+---------+-----------+---------+--------+ | 2104 | 1388 | 2916 | 0 | 4 | +---------+---------+-----------+---------+--------+ 4 rows: Date could not be read e.g. row 88, row 212, row 4471 First 4 of 4 failures: row 88: Value not accepted in column "price": expected a number Success: Nothing was written. Run it for real with: wp importundo import <file> (import 11 was the check) $ wp --user=1 importundo import products.csv --post-type=product --match=meta.sku Success: Import 12 finished. Undo it with: wp importundo rollback 12
An import run this way is driven to completion in the one process — no loopback, no cron, no time budget. A CLI process has none of the limits the background dispatcher exists to work around.
importundo list
List imports, newest first. Dry runs are hidden unless you ask for them.
wp importundo list [--all] [--format=table|csv|json|yaml]
Columns: id, mode, file, status, created, updated, unchanged, failed, started.
importundo status
Show what one import did — the same counts, warning summary and first failures the import itself reported.
wp importundo status <id>
importundo rollback
Undo an import: created posts deleted, updated posts restored field by field. Asks for confirmation unless you pass --yes.
wp importundo rollback <id> [--yes]
The rollback reference covers exactly what is and is not restored.
importundo retry
Re-run only the rows that failed, against the same mapping. Useful when the cause was transient — a slow image host, a term that has since been created.
wp importundo retry <id>
Running from cron
A nightly supplier feed, checked before it is trusted:
# Refuse to import if the feed would fail more rows than usual.
0 3 * * * cd /var/www/site && \
wp --user=1 importundo import https://supplier.example.com/feeds/products.csv \
--post-type=product --match=meta.sku --template="Supplier feed" \
--porcelain >> /var/log/importundo.log 2>&1
Without --allow-failures the command exits non-zero when any row failed, so cron mail — or whatever watches your exit codes — tells you on the morning it matters. --porcelain prints only the import ID, which is what you need to roll it back.