Importundo

Reference · since 1.1.0

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]
OptionWhat it does
<file>Path to the CSV file. With Importundo Pro, an https:// address to download it from also works.
--post-typePost type to import into. Default: post.
--templateApply a saved mapping template, by ID or by name (Importundo Pro). Without one, columns are mapped automatically by header name.
--mapMap columns explicitly, as column:target pairs separated by commas. Overrides automatic mapping for the columns named.
--map="sku:meta.sku,Name:post.post_title"
--matchWhat 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-matchWhat to do with a row that matches: update, skip or fail. Default: update.
--write-unchangedWrite every matched row even when nothing about it has changed. Off by default, which is what makes a no-op re-import cheap.
--dry-runWork out what the file would do and report it. Writes nothing.
--allow-failuresExit zero even when some rows failed.
--porcelainPrint the import ID and nothing else.

What a run looks like

dry run, then the real thing
$ 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.