| name | theme-init |
|---|---|
| description | Use when the user wants to set up or clean up a WordPress site over the WP Engine SSH gateway using WP CLI. Trigger on requests like "run theme setup", "clean up the WordPress install", "delete the old pages/menus/themes/categories", "deactivate plugins on the site", "update the site title", or any WP Engine SSH + WP CLI cleanup task. Gathers all selections, shows one plan, confirms once, then executes. |
| disable-model-invocation | true |
| argument-hint | [environment] |
| allowed-tools | Bash, AskUserQuestion |
Guided WordPress site cleanup over the WP Engine SSH gateway using WP CLI. Gathers every selection up front, shows ONE consolidated plan of all destructive commands, confirms ONCE, then runs the approved operations.
WP Engine exposes WP CLI through an SSH gateway. Use plain one-shot SSH per call:
SSH="ssh <env>@<env>.ssh.wpengine.net"<env> is the WP Engine install name (same in username and hostname). SSH key auth must already be configured. If a command returns Permission denied (publickey), stop and tell the user their SSH key is not registered with WP Engine. Run each WP CLI command as a single quoted argument (one-shot, non-interactive). Do NOT open an interactive session.
Do NOT use SSH multiplexing (ControlMaster/ControlPath). It is unreliable on Windows OpenSSH (fails with getsockname failed: Not a socket) and the speed gain is negligible once the read pass is collapsed. The performance comes from Step 2's single read pass, not from connection reuse.
- If
$1is provided, use it as the environment name; otherwise ask "Which WP Engine environment? (the install name)".
Run ONE command that fetches everything the menu needs. This also verifies the connection — if it fails, report the exact error and stop.
$SSH "
echo '===PREFIX==='; wp config get table_prefix;
echo '===BLOGNAME==='; wp option get blogname;
echo '===POSTTYPES==='; wp post-type list --_builtin=0 --field=name | grep -v '^acf-';
echo '===CATEGORIES==='; wp term list category --format=count;
echo '===MENUS==='; wp menu list --fields=term_id,name;
echo '===THEMES==='; wp theme list --fields=name,status;
echo '===PLUGINS==='; wp plugin list --fields=name,status --status=active,inactive;
"Split the output on the ===MARKER=== lines. Use <PREFIX> (the real table prefix) everywhere a table name appears — never hardcode wp_.
Use AskUserQuestion to collect every choice before running anything. Max 4 options per question; split across questions if needed.
- Operations (multiSelect): Delete pages, Delete categories, Delete menus, Delete themes, Manage plugins, Update site title. Only ask the follow-ups for operations the user picks.
- Delete pages → always offer builtin
postandpage, plus each custom post type from===POSTTYPES===, each as its own individual option (multiSelect, 4 per question, split as needed).===POSTTYPES===lists custom types only — it may be empty, in which case offer justpostandpage. Build a single-quoted comma list<TYPES>from the picks. Never group into "All". - Delete menus → ask all menus or specific IDs (from
===MENUS===). - Delete themes → present theme slugs (multiSelect) for which to KEEP; everything else is deleted. Active theme can't be deleted.
- Manage plugins → ask action (Delete / Deactivate / Both), then present plugin slugs (multiSelect) for each chosen action.
- Update site title → ask for the new title string.
Print the full set of exact commands that will run, with affected counts, then a single AskUserQuestion (yes/no). Example:
## Plan — <env>
1. Delete pages: types ('post','page') — 14 posts
wp post delete $(wp db query "SELECT ID FROM <PREFIX>posts WHERE post_type IN ('post','page') AND post_status != 'auto-draft'" --skip-column-names) --force
2. Delete categories: 6 terms
wp term delete category $(wp term list category --format=ids)
3. Delete menus: all (3)
wp menu delete $(wp menu list --format=ids)
4. Delete themes: keep twentytwentyfour — deletes 2
wp theme delete $(wp theme list --field=name | grep -v "twentytwentyfour")
5. Plugins: delete akismet hello; deactivate jetpack
6. Site title -> "New Title"
Run all of the above?
Any operation whose preview matched nothing is reported and dropped from the plan. If the user declines, stop — run nothing.
On approval, run each operation as its own command over the shared connection, in this order: pages, categories, menus, themes, plugins (delete then deactivate), title. Capture each result so success/failure is attributable per operation.
$SSH "wp post delete \$(wp db query \"SELECT ID FROM <PREFIX>posts WHERE post_type IN (<TYPES>) AND post_status != 'auto-draft'\" --skip-column-names) --force"
$SSH "wp term delete category \$(wp term list category --format=ids)"
$SSH "wp menu delete \$(wp menu list --format=ids)" # or: wp menu delete 1 2 3
$SSH "wp theme delete \$(wp theme list --field=name | grep -v \"<keep-slug>\")" # multiple: grep -v -e a -e b
$SSH "wp plugin delete slug-a slug-b"
$SSH "wp plugin deactivate slug-c slug-d"
$SSH "wp option update blogname \"<new title>\""WP CLI errors (Error:) — quote them exactly and stop that operation; do not auto-retry.
## Theme Init — <env>
- Pages: <N / skipped> - Categories: <N / skipped> - Menus: <N / skipped>
- Themes: <deleted N, kept X / skipped>
- Plugins: <deactivated / deleted / skipped> - Site title: <set / skipped>
- Destructive and irreversible. Recommend a WP Engine restore point before running.
\$(...)must be escaped so it runs remotely, not locally.- Active theme cannot be deleted; tell the user to activate a keeper first if needed.
- Use
<PREFIX>from the read pass, never a hardcoded table prefix. - Plugin list is filtered to
--status=active,inactive; must-use plugins and dropins are intentionally excluded from the menu.
What this is
theme-initis a Claude Code skill that automates fresh-WordPress-install cleanup over the WP Engine SSH gateway using WP CLI. It's the boilerplate teardown you do at the start of a new build — deleting default pages/posts (and any custom post types), categories, menus, and unused themes; deactivating or deleting plugins; and setting the site title.Its design is "gather first, confirm once": it does a single read pass to verify the connection and populate every menu, collects all your selections up front, prints one consolidated plan of the exact destructive commands (with affected counts), and only runs anything after a single yes/no confirmation. Operations whose preview matches nothing are dropped automatically.
Prerequisites
ssh <env>@<env>.ssh.wpengine.net, where<env>is your install name (it's the same in both the username and hostname).Permission denied (publickey), your key isn't registered on the install — fix that before running.disable-model-invocation: true, so it only runs when you call it explicitly (e.g./theme-init <environment>), not on its own. It takes an optional environment argument; if omitted, it'll ask.A few things to know before running
wp_.