wp-cli/maintenance-mode-command
Enables, disables, and checks WordPress maintenance mode from the command line using WP-CLI. Manage the .maintenance file with simple commands, optionally adding a custom message or retry interval, without touching the dashboard or filesystem manually.
wp maintenance-mode ships in the standard WP-CLI bundle. Confirm it is available, and install it only if your distribution is stripped down:
wp help maintenance-mode
# only if the command is missing:
wp package install wp-cli/maintenance-mode-command
There are three subcommands: activate, deactivate, and status. First use case, wrapping a core/plugin update by hand:
wp maintenance-mode activate
wp core update && wp plugin update --all
wp maintenance-mode deactivate
Where to look first:
wp help maintenance-mode <subcommand> for the authoritative flags.features/*.feature files in the repo are the real contract for output strings and exit codes. The README is generated from the command docblocks, so it lags the code.ABSPATH . '.maintenance' — a tiny PHP file whose only job is to set $upgrading. Verify which file you are touching with wp eval 'echo ABSPATH;'.Deploy wrapper with a trap. The most valuable pattern is guaranteeing deactivation on failure:
#!/usr/bin/env bash
set -euo pipefail
WP="wp --path=/var/www/html"
$WP maintenance-mode activate
trap '$WP maintenance-mode deactivate' EXIT
$WP core update
$WP plugin update --all
$WP db import dump.sql
$WP search-replace 'staging.example.com' 'example.com'
$WP cache flush
The trap ... EXIT fires on both success and error, which is the only sane way to avoid a site stuck in 503 after a failed deploy.
Guard activation with status. Treat activate/deactivate as non-idempotent in automation and branch instead of blindly calling them:
if wp maintenance-mode status | grep -qi 'not active'; then
wp maintenance-mode activate
fi
Check the exit code of status once in your environment before relying on it — if it returns 0 in both states, output parsing (or the wp eval file check below) is what you need.
Remote and staging targets. Use WP-CLI aliases rather than SSH-ing and cd-ing around:
wp @prod maintenance-mode activate --url=https://example.com
wp @prod maintenance-mode deactivate
Define @prod in ~/.wp-cli/config.yml with an ssh: key so --path and the web user are handled by the alias.
Deactivation is not the end of the job. Pair it with cache clearing, because object caches are irrelevant here but page caches and CDNs are not:
wp maintenance-mode deactivate
wp cache flush
wp rocket clean --confirm # or your CDN purge CLI
Multisite. The .maintenance file is per-installation, not per-site. --url changes which site WP boots, not the scope of the toggle — activating affects the whole network. Plan a network-wide change window rather than per-subsite toggles.
Custom maintenance page. The command cannot set a message. WordPress will load a wp-content/maintenance.php drop-in if present, so put your styled standalone HTML there (wp maintenance-mode just creates the triggering file). Keep that drop-in out of version control until you deliberately want it live.
Health check after the window. Confirm the site is actually serving again rather than trusting the command output:
curl -fsS -o /dev/null -w '%{http_code}\n' https://example.com/
ABSPATH, not wp-content. On shared docroots with multiple installs, always pass --path and confirm with wp eval 'echo ABSPATH;'.www-data and you SSH in as a deploy user, activate fails; fix ownership or run via the alias that uses the correct user.wp maintenance-mode deactivate works even while the site is down for visitors. The hard fallback is rm "$(wp eval 'echo ABSPATH;')/.maintenance".wp core update writes its own .maintenance file briefly. Don't run activate concurrently with a core update in another terminal or you'll misread the file's presence.rsync --delete and git clean will happily delete .maintenance, and a committed copy will be restored on every deploy. Add .maintenance to .gitignore and to your sync excludes.wp --debug maintenance-mode status (or WP_CLI_DEBUG=1) and cat the file to see the $upgrading timestamp. A stale, hand-edited file is a common cause of "it says active but the site is up" confusion, and vice versa.Retry-After header, so bots and some clients back off for several minutes after you deactivate — a short window can look longer to external monitoring than it was.wp package install wp-cli/maintenance-mode-command:vX.Y.Z), and keep the three calls behind one shell function or Makefile target so a rename or removal is a one-line change. If it ever disappears, wp eval 'file_put_contents( ABSPATH . ".maintenance", "<?php \$upgrading = " . time() . ";" );' and unlink are complete substitutes.composer behat -- features/<name>.feature, composer phpcs, composer phpstan, and composer phpcbf to autofix style. Use composer behat-rerun after a partial failure rather than re-running the full suite, which reinstalls WordPress per scenario.How can I help you explore Laravel packages today?