Maintenance Mode Snippet Generator
Put a site into maintenance mode with a real 503 and Retry-After header, while letting logged-in users, an IP allowlist and the login page through.
<?php
/**
* Maintenance mode.
*
* Sends 503 with a Retry-After header rather than a 200 page saying "back
* soon": a 200 tells search engines the maintenance page is the page.
*/
/**
* Decides whether this request should see the site.
*
* @return bool
*/
function my_site_maintenance_bypass() {
if ( is_user_logged_in() ) {
return true;
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
return true;
}
return false;
}
/**
* Shows the maintenance page to everyone else.
*/
function my_site_maintenance_mode() {
if ( ! defined( 'MY_SITE_MAINTENANCE' ) || ! MY_SITE_MAINTENANCE ) {
return;
}
// The login screen and admin-ajax stay up: locking yourself out of the
// login page is how a ten minute maintenance window becomes an afternoon.
if ( is_admin() || wp_doing_ajax() ) {
return;
}
global $pagenow;
if ( 'wp-login.php' === $pagenow ) {
return;
}
if ( my_site_maintenance_bypass() ) {
return;
}
header( 'Retry-After: ' . ( 60 * MINUTE_IN_SECONDS ) );
wp_die(
esc_html__( 'We are making a few changes and will be back within the hour.', 'my-site' ),
esc_html__( 'Back shortly', 'my-site' ),
array(
'response' => 503,
'back_link' => false,
)
);
}
add_action( 'template_redirect', 'my_site_maintenance_mode' );
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
Put the site behind a maintenance page without losing your search rankings or locking yourself out. The generated snippet sends a real 503 with a Retry-After header, and leaves the login page up.
How to use
- Switch it on with a constant in
wp-config.php. A constant cannot be flipped by a plugin, or by someone who got into the admin. - Set Retry-After to an honest estimate. It is what tells search engines to come back rather than to drop the page.
- Decide who gets through. Logged-in users is the convenient answer; a capability is the right one on a site with customer accounts.
- Leave WP-Cron running unless you have a reason not to. Scheduled jobs that pile up for an hour all fire at once when you come back.
- Test it in a private window before you announce anything. A maintenance page that is showing to you and nobody else is the usual outcome.
Example
The check that decides who sees the site:
function acme_maintenance_bypass() {
if ( is_user_logged_in() ) {
return true;
}
if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
return true;
}
return false;
}
The wp-login.php exception in the generated code matters more than it looks: without it, an unlucky logout during maintenance means the only way back in is over SSH.
Pitfalls
- A maintenance page served with a 200 status tells search engines this is the page. Repeated over days, the real page drops out of the index. 503 is the correct status.
- Without
Retry-After, a crawler decides for itself when to return, which can be much later than you would like. - Blocking
wp-login.phplocks you out the moment your session expires. - An IP allowlist matches
REMOTE_ADDR, which behind Cloudflare or any proxy is the proxy’s address. The allowlist then matches nobody, or everybody. template_redirectdoes not run for the REST API or for direct file requests, so a headless front end may keep working whether you want it to or not.- Page caching serves the maintenance page after you turn it off, and serves the real page during. Purge the cache at both ends.
wp_die()output is not a themed page. If the maintenance page has to look like the brand, render a template instead.- Leaving maintenance mode on for weeks is a real ranking risk. Google treats a long 503 as a site that is gone.
Compatibility
template_redirect, wp_die() with a response code, and is_user_logged_in() have been stable since WordPress 3.0. This is a code snippet, not WordPress’s own .maintenance file, which core creates during updates and which takes the whole site down including the admin. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.
Frequently asked questions
Why 503 and not a normal page?
Will I be locked out?
wp-login.php and the admin up. Signing in restores the site for you.How do I turn it on and off?
wp-config.php, or flip the option if you chose that mode.Does this work with a caching plugin?
Can I show a designed page instead?
wp_die() call with your own template and keep the status code and the header.