You need WordPress maintenance mode without a plugin: visitors should see a short “back soon” page while you work, and you, logged in as an administrator, should keep seeing the real site. This snippet does that with a proper 503 Service Unavailable status, so search engines treat the downtime as temporary instead of indexing the maintenance message.
The snippet
<?php
/**
* Maintenance mode: visitors get a 503 page, administrators see the site.
*/
add_action( 'template_redirect', 'dpc_maintenance_mode', 1 );
function dpc_maintenance_mode(): void {
if ( current_user_can( 'manage_options' ) ) {
return;
}
if ( ! headers_sent() ) {
header( 'Retry-After: 3600' );
}
wp_die(
'<h1>' . esc_html__( 'Maintenance', 'dpc' ) . '</h1><p>' . esc_html__( 'This site is under scheduled maintenance. Please check back later.', 'dpc' ) . '</p>',
esc_html__( 'Maintenance', 'dpc' ),
array( 'response' => 503 )
);
}
How it works
template_redirectfires on every front-end request just before WordPress picks a template, in classic and block themes alike. The older One-Click Import version hooked intoget_header, which block themes never call, so their sites stayed public.current_user_can( 'manage_options' )lets administrators through. It returnsfalsefor logged-out visitors, so no separate login check is needed.wp_die()with'response' => 503sends the status code and no-cache headers. TheRetry-Afterheader tells crawlers to come back in an hour; it is only sent when headers are still open, so it never raises a warning.- The message is escaped and translatable, and the status is an integer, as
wp_die()expects. - wp-admin, wp-login.php, the REST API, admin-ajax and WP-Cron never fire
template_redirect, so you can still log in and scheduled tasks keep running.
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor and publish. Leave Action/Hook empty. The function is attached to template_redirect and only runs there, when WordPress already knows who is logged in. To end maintenance, disable the code block; there is nothing to clean up.
The same code also works unchanged in a small plugin or an mu-plugin.
Customise it
- Let editors in too: change the capability to
edit_posts. - Longer work: raise
3600(seconds) in theRetry-Afterheader. - Keep one page public, such as a contact page: add
if ( is_page( 'contact' ) ) { return; }after the capability check. - Own design: replace the
wp_die()call withstatus_header( 503 );,nocache_headers();, your own markup andexit;.
To also keep wp-admin closed to everyone but you while you work, combine it with Lockdown Admin Backend to your IP.
Gotchas
- Page caches: a caching plugin or host cache may keep serving cached pages to visitors. Purge the cache after you enable the code block, and again after you disable it.
- Keep it short. A 503 is fine for hours; weeks of 503 responses can still cost you indexed pages, and then a real maintenance plugin with a scheduled end is the better tool.
- Logged-in users without
manage_options(customers, subscribers) see the maintenance page too. That is intended. - WordPress’s own
.maintenancefile, written during core updates, is a separate mechanism and is not affected.
In the Scripts Organizer library Import it with one click from Scripts Organizer.