WP-CLI Cheat Sheet for Emergencies and Maintenance
The WP-CLI commands that get a broken WordPress site back: core and plugin checksums, safe-mode flags, user rescue, database repair, search-replace, cron, cache and remote aliases.
WP-CLI is the command line interface for WordPress. When the dashboard is a white screen, a redirect loop or a login you cannot get past, WP-CLI still talks to the files and the database directly, so it is usually the fastest way back. This sheet is grouped by task. Run every command from the WordPress root (the folder that holds wp-config.php) or add --path. Commands that change data are marked, and the recipes near the end chain them together for real emergencies.
Before you change anything: take a database export (wp db export) and, if you can, a copy of the files. Every recipe below assumes you did.
Placeholders used on this sheet
| Placeholder | Replace it with | How to find it |
|---|---|---|
PLUGIN_SLUG |
The plugin folder name, for example woocommerce |
wp plugin list --field=name |
THEME_SLUG |
The theme folder name, for example twentytwentyfive |
wp theme list --field=name |
USER |
A user ID, login name or email address (most user commands accept any of the three) | wp user list |
USER_ID |
The numeric user ID only | wp user list --fields=ID,user_login |
ROLE |
A role slug: administrator, editor, author, contributor, subscriber or a custom role |
wp role list |
VERSION |
A version number, for example 6.8.1 |
The WordPress.org release archive or the plugin changelog |
OPTION_NAME |
A row name in the options table, for example siteurl |
wp option list --search="*PART*" |
HOOK |
A cron event hook name | wp cron event list |
OLD / NEW |
The string to find and the string to put in its place | Usually the old and new site URL |
FILE.sql |
A path to an SQL dump file | Your choice of name |
SITEUSER |
The system (Linux) account that owns the site files | stat -c '%U' wp-config.php |
HOST, PORT, PATH |
SSH host name, SSH port and the WordPress folder on that server | Your hosting control panel |
Global flags (work with any command)
| Flag | What it does | Example | Notes |
|---|---|---|---|
--path=PATH |
Points WP-CLI at a WordPress folder | wp --path=/var/www/site/public_html core version |
Saves a cd. Needed in cron jobs. |
--url=URL |
Sets the site URL WordPress thinks it is serving | wp --url=shop.example.com plugin list |
Required to target one site in a multisite network. |
--user=USER |
Runs the command as that WordPress user | wp --user=admin post create ... |
Matters for commands that check capabilities. |
--skip-plugins |
Loads WordPress without any plugins | wp plugin list --skip-plugins |
Add =PLUGIN_SLUG,PLUGIN_SLUG to skip only some. Must-use plugins still load. |
--skip-themes |
Loads WordPress without the active theme | wp option get home --skip-themes |
Use together with --skip-plugins when a fatal error stops WP-CLI itself. |
--skip-packages |
Does not load installed WP-CLI packages | wp --skip-packages cli info |
For when a package breaks WP-CLI. |
--require=FILE |
Loads a PHP file before running the command | wp --require=fix.php eval '...' |
Handy for one-off patches. |
--exec=PHP_CODE |
Runs PHP code before the command | wp --exec="define('WP_DEBUG',true);" plugin list |
Code runs early, before WordPress loads fully. |
--debug |
Prints WP-CLI debug messages and PHP errors | wp plugin list --debug |
Add =bootstrap or another group name to limit output. First thing to add when a command fails silently. |
--quiet |
Suppresses informational messages | wp cron event run --due-now --quiet |
Errors still print. Good for cron. |
--ssh=TARGET |
Runs the command on a remote server over SSH | wp --ssh=deploy@HOST:PORT/PATH core version |
WP-CLI must be installed on the remote server. |
--allow-root |
Lets WP-CLI run as the root account | Avoid | Files created as root end up owned by root. Switch to the site user instead: su - SITEUSER -c 'cd PATH && wp ...' |
--format=FORMAT |
Output format on list and get commands | --format=json, csv, yaml, ids, count, table |
ids and count are not available on every command. |
--fields=A,B / --field=A |
Chooses output columns, or a single value per line | wp user list --field=user_email |
--field output pipes cleanly into other commands. |
Core: version, integrity, reinstall, update, roll back
| Command | What it does | Example | Notes |
|---|---|---|---|
wp core version |
Prints the installed WordPress version | wp core version --extra |
--extra adds database version, TinyMCE version and locale. |
wp core check-update |
Lists available core updates | wp core check-update --minor |
Read only. |
wp core verify-checksums |
Compares core files against the official WordPress.org checksums | wp core verify-checksums |
Reports changed files and files that should not exist in core folders. A primary hack check. Does not look inside wp-content. |
wp core download --skip-content |
Downloads core without the default themes and plugins | wp core download --skip-content --force --version=VERSION |
Changes files. With --force it overwrites core files in place. It does not delete extra files, so remove anything verify-checksums flags by hand. |
wp core update |
Updates core to the latest release | wp core update |
Changes files. Run wp core update-db afterward if prompted. |
wp core update --version=VERSION --force |
Installs a specific version, including an older one | wp core update --version=6.7.2 --force |
This is the rollback. The database is not downgraded, so test before relying on it. |
wp core update --minor |
Applies only minor (security and maintenance) releases | wp core update --minor |
Lower risk than a major update. |
wp core update-db |
Runs database upgrade routines after a core update | wp core update-db --network |
--network upgrades every site in a multisite. |
wp core is-installed |
Exit code 0 if WordPress is installed, 1 if not | wp core is-installed && echo yes |
Useful in scripts. A failure here often means a database connection problem. |
Plugins and themes
| Command | What it does | Example | Notes |
|---|---|---|---|
wp plugin list |
Lists plugins with status, update and version | wp plugin list --status=active --fields=name,version,update |
Filters: --status=active|inactive|must-use|dropin, --update=available. |
wp plugin list --field=name --status=active |
Prints only the active plugin slugs | wp plugin list --field=name --status=active > active-plugins.txt |
Save this before you deactivate everything so you can restore the set. |
wp plugin deactivate PLUGIN_SLUG |
Deactivates one or more plugins | wp plugin deactivate PLUGIN_SLUG --skip-plugins --skip-themes |
The skip flags let the command run even when that plugin causes a fatal error. |
wp plugin deactivate --all |
Deactivates every plugin | wp plugin deactivate --all --skip-plugins |
Does not touch must-use plugins or drop-ins such as advanced-cache.php and object-cache.php. |
wp plugin activate |
Activates plugins | wp plugin activate $(cat active-plugins.txt) |
Reactivate one at a time to find the culprit. |
wp plugin install PLUGIN_SLUG --version=VERSION --force |
Installs or reinstalls a specific version from WordPress.org | wp plugin install PLUGIN_SLUG --version=VERSION --force |
Changes files. --force overwrites the existing copy. This is how you roll a plugin back. Also accepts a zip path or URL. |
wp plugin update |
Updates plugins | wp plugin update --all --dry-run |
--dry-run shows what would update. --exclude=PLUGIN_SLUG leaves one alone. |
wp plugin verify-checksums |
Checks plugin files against WordPress.org checksums | wp plugin verify-checksums --all |
Only works for plugins hosted on WordPress.org. Premium plugins report as unverifiable. |
wp plugin status PLUGIN_SLUG |
Shows details for one plugin | wp plugin status PLUGIN_SLUG |
Read only. |
wp plugin auto-updates status |
Shows auto-update setting per plugin | wp plugin auto-updates disable PLUGIN_SLUG |
Also enable. Useful when an auto-update keeps reinstalling a broken version. |
wp plugin delete PLUGIN_SLUG |
Deletes plugin files | wp plugin delete PLUGIN_SLUG |
Destructive. Deactivate first. Plugin data in the database usually remains. |
wp theme list |
Lists themes | wp theme list --status=active |
Child themes show their own slug; check the parent is installed. |
wp theme activate THEME_SLUG |
Switches theme | wp theme activate twentytwentyfive --skip-themes --skip-plugins |
The quickest way to rule out the theme. Widgets and menus may need reassigning afterward. |
wp theme install THEME_SLUG --version=VERSION --force |
Installs or reinstalls a theme version | wp theme install twentytwentyfive --activate |
Changes files. |
Users: rescue access, clean up accounts
| Command | What it does | Example | Notes |
|---|---|---|---|
wp user list |
Lists users | wp user list --role=administrator --fields=ID,user_login,user_email,user_registered |
Check for administrators you do not recognize after a hack. |
wp user create LOGIN EMAIL |
Creates a user | wp user create rescue rescue@example.com --role=administrator |
Without --user_pass a password is generated and printed. Delete the account when done. |
wp user update USER --user_pass=NEW_PASSWORD |
Sets a new password directly | wp user update USER --user_pass='NEW_PASSWORD' --skip-email |
The password lands in your shell history. Clear it or use wp user reset-password USER --show-password. |
wp user reset-password USER |
Sets a new random password and emails the user that it changed | wp user reset-password USER --skip-email --show-password |
Changes data. --show-password prints the new password; --skip-email suppresses the notice. |
wp user set-role USER ROLE |
Replaces the user’s role | wp user set-role USER administrator |
Also add-role and remove-role. |
wp user delete USER --reassign=USER_ID |
Deletes a user and gives their content to another user | wp user delete 7 --reassign=1 |
Destructive. Without --reassign their posts are deleted too. |
wp user session list USER |
Lists the user’s active login sessions | wp user session list USER --format=count |
Read only. |
wp user session destroy USER --all |
Logs the user out everywhere | wp user session destroy USER --all |
Do this for every admin after a password reset or suspected compromise. |
wp user meta list USER |
Shows user meta, including capabilities | wp user meta get USER wp_capabilities |
The meta key prefix follows $table_prefix. |
Options: site URL, autoload bloat, settings
| Command | What it does | Example | Notes |
|---|---|---|---|
wp option get OPTION_NAME |
Reads one option | wp option get siteurl and wp option get home |
First check for redirect loops and wrong-domain problems. |
wp option update OPTION_NAME VALUE |
Writes one option | wp option update home 'https://example.com' |
Changes data. WP_HOME and WP_SITEURL in wp-config.php override these if defined. |
wp option list --search=PATTERN |
Lists options by name pattern | wp option list --search="*_transient_*" --format=count |
Wildcards * and ?. |
wp option list --autoload=on --format=total_bytes |
Total size of autoloaded options | wp option list --autoload=on --format=total_bytes |
Autoloaded options load on every request, so a large total slows every page. |
| List the biggest autoloaded options | Shows option sizes, largest last | wp option list --autoload=on --fields=option_name,size_bytes | sort -n -k 2 | tail -n 20 |
Investigate before deleting anything; most belong to plugins. |
wp option get-autoload / set-autoload |
Reads or changes the autoload flag | wp option set-autoload OPTION_NAME off |
Added in WP-CLI 2.8. Accepts on, off, yes, no (support for the WordPress 6.6 autoload values arrived in WP-CLI 2.11). Use instead of update, which will not change autoload if the value is unchanged. |
wp option patch |
Edits one key inside a serialized option | wp option patch update OPTION_NAME KEY VALUE |
Safer than editing serialized data by hand. |
wp option delete OPTION_NAME |
Deletes an option | wp option delete OPTION_NAME |
Destructive. Export the value first with wp option get OPTION_NAME --format=json. |
Note: WordPress 6.6 introduced new autoload values (on, off, auto, auto-on, auto-off) in place of yes and no. A raw SQL query that only looks for autoload = 'yes' will undercount on current sites.
Database
| Command | What it does | Example | Notes |
|---|---|---|---|
wp db export |
Dumps the database with mysqldump | wp db export FILE.sql --add-drop-table |
Use - as the file to stream: wp db export - | gzip > backup.sql.gz. --tables= and --exclude_tables= limit it. |
wp db import FILE.sql |
Imports an SQL file | wp db import FILE.sql |
Destructive to any table in the file. Take an export first. |
wp db check |
Checks tables with mysqlcheck | wp db check |
Read only. |
wp db repair |
Repairs tables with mysqlcheck | wp db repair |
Mainly helps MyISAM tables. InnoDB tables usually report that repair is not supported. |
wp db optimize |
Optimizes tables with mysqlcheck | wp db optimize |
Can lock tables on large sites. Run off-peak. |
wp db query "SQL" |
Runs SQL with the site’s credentials | wp db query "SELECT ID,user_login FROM wp_users" |
Also reads from a file: wp db query < FILE.sql. Use your real table prefix. |
wp db search STRING |
Finds a string anywhere in the database | wp db search 'eval(' --all-tables |
Good for spotting injected scripts and old URLs. |
wp db size |
Shows database size | wp db size --tables --size_format=mb |
--human-readable is an alternative. |
wp db tables |
Lists tables | wp db tables --all-tables-with-prefix |
Shows plugin tables too. |
wp db prefix |
Prints the table prefix | wp db prefix |
Use it to write correct SQL. |
wp db cli |
Opens an interactive MySQL client | wp db cli |
Logs in with the credentials from wp-config.php. |
wp db reset |
Drops every table | Do not use in an emergency | Destructive. Listed only so you recognize it. |
search-replace (moving domains, switching to HTTPS)
| Command or flag | What it does | Example | Notes |
|---|---|---|---|
wp search-replace OLD NEW |
Replaces text across the database, handling serialized data | wp search-replace 'http://example.com' 'https://example.com' |
Changes data. Always run with --dry-run first. |
--dry-run |
Reports what would change without writing | wp search-replace OLD NEW --dry-run |
Shows replacements per table and column. |
--skip-columns=guid |
Leaves a column untouched | wp search-replace OLD NEW --skip-columns=guid |
Post GUIDs are identifiers for feed readers and should not normally change. |
--precise |
Forces PHP processing of every row instead of SQL | wp search-replace OLD NEW --precise |
Slower but catches values the SQL fast path can miss. |
--all-tables-with-prefix |
Includes non-core tables that share the prefix | wp search-replace OLD NEW --all-tables-with-prefix |
Covers plugin tables. --all-tables includes every table in the database, whatever the prefix. |
--export=FILE.sql |
Writes the replaced data to a file and leaves the database unchanged | wp search-replace OLD NEW --export=FILE.sql |
Ideal for preparing a migration dump. |
--network |
Runs across all sites in a multisite | wp search-replace OLD NEW --network |
Needed for network-wide domain changes. |
--report-changed-only |
Lists only tables with changes | wp search-replace OLD NEW --dry-run --report-changed-only |
Shorter output. |
--regex |
Treats OLD as a regular expression | wp search-replace 'https?://(www\.)?example\.com' 'https://example.com' --regex --regex-delimiter='#' |
Much slower. The default delimiter is chr(1), so slashes in the pattern are fine; set --regex-delimiter only if you want a specific one, and escape it if it appears in the pattern. Test on a copy. |
Cron
| Command | What it does | Example | Notes |
|---|---|---|---|
wp cron event list |
Lists scheduled events | wp cron event list --fields=hook,next_run_relative,recurrence |
Many overdue events point to broken WP-Cron spawning. Unknown hooks can be malware. |
wp cron event run HOOK |
Runs an event now | wp cron event run --due-now |
--due-now runs everything overdue. --all runs every event. |
wp cron event delete HOOK |
Unschedules an event | wp cron event delete HOOK |
Changes data. |
wp cron schedule list |
Lists recurrence intervals | wp cron schedule list |
Read only. |
wp cron test |
Tests whether WP-Cron can spawn via a loopback request | wp cron test |
A failure usually means the server cannot reach its own URL (firewall, basic auth, DNS) or DISABLE_WP_CRON is set. |
| System cron line | Runs due events on a real schedule | */5 * * * * cd /PATH && wp cron event run --due-now --quiet |
Pair with define('DISABLE_WP_CRON', true);. Install in the site user’s crontab. |
Cache, transients and rewrites
| Command | What it does | Example | Notes |
|---|---|---|---|
wp cache flush |
Flushes the object cache | wp cache flush |
With Redis or Memcached this can flush every site sharing that cache instance. Page caches (plugin or server) need their own purge. |
wp cache type |
Reports which object cache is in use | wp cache type |
Read only. |
wp transient delete --expired |
Removes expired transients | wp transient delete --expired |
Safe routine cleanup. --all removes every transient (they rebuild). |
wp transient get NAME |
Reads one transient | wp transient get NAME --network |
--network targets site transients. |
wp rewrite flush |
Regenerates rewrite rules | wp rewrite flush |
Fixes 404s on posts after a migration or permalink change. |
wp rewrite flush --hard |
Also rewrites .htaccess |
wp rewrite flush --hard |
Single site only. Apache only, and WP-CLI needs apache_modules: [mod_rewrite] in wp-cli.yml to write the rules. |
wp rewrite structure |
Sets the permalink structure | wp rewrite structure '/%postname%/' |
Flushes rules automatically. |
wp-config.php from the command line
| Command | What it does | Example | Notes |
|---|---|---|---|
wp config get NAME |
Reads a constant or variable | wp config get DB_HOST |
Works even when WordPress cannot connect to the database. |
wp config list |
Lists everything defined in the file | wp config list --fields=name,type |
Values include secrets; do not paste the output anywhere public. |
wp config set NAME VALUE |
Adds or changes a constant | wp config set WP_DEBUG true --raw |
--raw writes the value as PHP (a boolean) rather than a quoted string. |
wp config delete NAME |
Removes a constant | wp config delete WP_DEBUG_DISPLAY |
Changes the file. |
wp config shuffle-salts |
Replaces all keys and salts | wp config shuffle-salts |
Logs every user out. Standard after a compromise. |
wp config path |
Prints where wp-config.php is | wp config path |
WordPress also looks one folder above the root. |
Media, maintenance mode and diagnostics
| Command | What it does | Example | Notes |
|---|---|---|---|
wp media regenerate |
Rebuilds image thumbnails | wp media regenerate --only-missing --yes |
Heavy on CPU. Pass attachment IDs to limit it. |
wp media image-size |
Lists registered image sizes | wp media image-size |
Read only. |
wp maintenance-mode activate |
Puts the site into maintenance mode | wp maintenance-mode activate |
Creates a .maintenance file in the root. |
wp maintenance-mode deactivate |
Ends maintenance mode | wp maintenance-mode deactivate |
Also status and is-active. |
wp profile stage |
Times the bootstrap, main query and template stages | wp profile stage --url=https://example.com/slow-page/ |
A separate package: wp package install wp-cli/profile-command:@stable. |
wp profile hook |
Times callbacks on a hook | wp profile hook init --spotlight |
--all profiles every hook. --spotlight hides near-zero results. |
wp doctor check |
Runs health checks (autoload size, core checksums, cron count, PHP files in uploads and more) | wp doctor check --all |
A separate package: wp package install wp-cli/doctor-command:@stable. wp doctor list shows the checks. |
wp cli info |
Shows WP-CLI, PHP and config details | wp cli info |
Confirms which PHP binary WP-CLI is using. |
Aliases and running over SSH
Aliases live in wp-cli.yml (project folder) or ~/.wp-cli/config.yml (your account). The built-in @all alias runs a command against every alias you have defined.
@prod:
ssh: deploy@example.com/var/www/example/public_html
@staging:
ssh: deploy@staging.example.com:2222/var/www/staging/public_html
@both:
- @prod
- @staging
| Command | What it does | Example | Notes |
|---|---|---|---|
wp @ALIAS COMMAND |
Runs a command against that alias | wp @prod plugin list --update=available |
The alias must come straight after wp. |
wp cli alias list |
Shows configured aliases | wp cli alias list |
Read only. |
wp --ssh=USER@HOST:PORT/PATH |
One-off remote command without an alias | wp --ssh=deploy@HOST:2222/PATH core verify-checksums |
Uses your SSH keys and config. Remote WP-CLI must be on the PATH. |
wp @both core version |
Runs against a group alias | wp @both core version |
Quick version audit across environments. |
Common recipes
1. White screen or critical error right after a plugin update
wp plugin list --skip-plugins --skip-themes --fields=name,status,version,update
wp plugin deactivate PLUGIN_SLUG --skip-plugins --skip-themes
# Not sure which plugin? Save the active list, then turn them all off:
wp plugin list --field=name --status=active --skip-plugins --skip-themes > active-plugins.txt
wp plugin deactivate --all --skip-plugins --skip-themes
# Bring them back one at a time and reload the site after each:
wp plugin activate PLUGIN_SLUG
# Roll the culprit back to the last good version:
wp plugin install PLUGIN_SLUG --version=VERSION --force
If plugins are not the cause, test the theme: wp theme activate twentytwentyfive --skip-plugins --skip-themes. If the error persists with both skipped, look at must-use plugins (wp-content/mu-plugins), drop-ins and the PHP error log.
2. Locked out of wp-admin
wp user list --role=administrator --fields=ID,user_login,user_email
wp user update USER --user_pass='NEW_PASSWORD' --skip-email
wp user session destroy USER --all
# Still blocked? A security plugin may be the problem:
wp plugin deactivate PLUGIN_SLUG --skip-plugins
# Wrong URL causing a login redirect loop:
wp option get siteurl
wp option get home
wp config get WP_HOME
wp config get WP_SITEURL
3. Suspected hack: first look
wp db export pre-cleanup.sql
wp core verify-checksums
wp plugin verify-checksums --all
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
wp cron event list --fields=hook,next_run_relative,recurrence
wp db search '<script' --all-tables
wp option get siteurl
wp option get home
# Replace core files with clean copies of the same version:
wp core download --skip-content --force --version=$(wp core version)
# Then force everyone to log in again:
wp config shuffle-salts
wp user list --field=ID | xargs -I % wp user session destroy % --all
Checksums cannot vouch for premium plugins, themes or uploads. Look for PHP files inside wp-content/uploads: find wp-content/uploads -name "*.php".
4. Move a site to a new domain or to HTTPS
wp db export before-replace.sql
wp search-replace 'http://OLD_DOMAIN' 'https://NEW_DOMAIN' --skip-columns=guid --all-tables-with-prefix --dry-run
wp search-replace 'http://OLD_DOMAIN' 'https://NEW_DOMAIN' --skip-columns=guid --all-tables-with-prefix
wp option get home
wp cache flush
wp rewrite flush
OLD_DOMAIN and NEW_DOMAIN are host names such as example.com. Repeat for www. and for escaped forms (http:\/\/OLD_DOMAIN) if the dry run shows matches in JSON data.
5. Slow admin and a bloated database
wp db size --tables --size_format=mb
wp option list --autoload=on --format=total_bytes
wp option list --autoload=on --fields=option_name,size_bytes | sort -n -k 2 | tail -n 20
wp transient delete --expired
wp cron event list --format=count
wp db optimize
6. Roll back a bad core update
wp db export before-rollback.sql
wp core update --version=VERSION --force
wp core verify-checksums
wp cache flush
7. Stuck on “Briefly unavailable for scheduled maintenance”
wp maintenance-mode status
wp maintenance-mode deactivate
# Or remove the file directly:
rm .maintenance
Then rerun whatever update was interrupted, because it may have left a plugin half installed.
8. Run as the right system user
su - SITEUSER -c 'cd /PATH && wp plugin list'
Gotchas
- Running as root. WP-CLI refuses unless you add
--allow-root, for good reason. Files it creates become owned by root and the web server may then be unable to update them. - Wrong PHP version. The shell’s
phpmay differ from the site’s PHP.wp cli infoshows which binary is in use. A plugin that needs newer PHP can fatal in WP-CLI but not on the web, or the other way round. - Must-use plugins and drop-ins always load.
--skip-pluginsdoes not stopwp-content/mu-plugins,advanced-cache.phporobject-cache.php. Rename the file to rule it out. - Multisite needs
--url. Without it, commands act on the main site only. - wp-config.php constants win.
wp option update homedoes nothing visible ifWP_HOMEis defined inwp-config.php. - Raw SQL breaks serialized data. A plain SQL
REPLACE()changes string lengths inside serialized arrays and corrupts them. Usewp search-replace. - Object cache flushes can be shared. If several sites use one Redis database,
wp cache flushempties it for all of them. core download --forceleaves extra files behind. Malware files added towp-includesorwp-adminstay until you delete them. Rerunverify-checksumsto list them.- Checksums only cover WordPress.org code. Core has
wp core verify-checksumsand plugins havewp plugin verify-checksums, but there is no built-in theme equivalent. Reinstall WordPress.org themes withwp theme install THEME_SLUG --forceand check premium plugins, custom themes and uploads by hand. - Passwords in shell history.
--user_passon the command line is recorded. Clear history or prefix the command with a space if your shell is set to ignore those lines. - Packages are separate.
wp profileandwp doctorare not part of the default install. On shared hosting you may not be allowed to install packages. wp cron event runruns as WP-CLI, not the web server. A job that works here can still fail through WP-Cron if loopback requests are blocked. Usewp cron test.
Did this fix it?
Still stuck? Start again from what you can see in the Emergency Room.
Need the full fix?
Cheat sheets are quick reference. The field guides walk you through each emergency step by step.
Open the Emergency Room