Code

Build a custom WP-CLI command

A scenario for a bulk CSV user-import command that handles batching, idempotent re-runs, and progress reporting the way a real ops script needs to.

Works with Claude / GPT620 uses 4.1

The prompt

code-custom-wp-cli-command
I need a WP-CLI command `wp myplugin import-users <file.csv>` that reads a CSV with
columns [email, first_name, last_name, role] and creates WordPress users, run by our
ops team against a site with roughly 40,000 rows.

CONTEXT: [this will be run more than once as ops re-uploads corrected files, and the
host times out long-running SSH sessions after 10 minutes]

Write this as a senior dev handling a real migration script, in order:
1. Show the full class extending `WP_CLI_Command`, registered via `WP_CLI::add_command()`,
   with the command accepting the file path as a positional arg and an optional
   `--dry-run` flag.
2. Process the CSV in batches (not all 40,000 rows in one `wp_insert_user()` loop) and
   explain why: memory growth from object cache and postmeta caching across a long-running
   CLI process, and how to periodically call `wp_cache_flush()` inside the loop to avoid
   WP-CLI itself running out of memory on huge imports.
3. Make it idempotent: check `email_exists()` before creating, and on a second run with
   a corrected file, update the existing user's name/role instead of erroring out or
   creating a duplicate.
4. Use `WP_CLI::log()`, `WP_CLI\Utils\make_progress_bar()`, and `WP_CLI::success()` /
   `WP_CLI::error()` appropriately, and make sure a single bad row (malformed email)
   logs a warning and continues rather than aborting the whole batch.
5. Note the edge case: role names in the CSV might not match actual registered roles
   (typos, or a role from a plugin that isn't active on this environment), and the
   command should validate against `wp_roles()->roles` before assigning, falling back
   to `subscriber` with a warning.

Swap in your actual command name, CSV columns, and batch size.

Idempotency is the detail that separates a script ops can safely re-run from one that silently doubles up data on a retry. Always ask for the --dry-run flag explicitly: it’s cheap to add and saves a real incident the first time someone uploads the wrong file.