Putting a site into maintenance mode is a common need during deployments, design updates, content migrations, and plugin upgrades. WordPress’s built-in maintenance mode only activates automatically during core updates and is not designed for extended use. This snippet adds a controlled maintenance mode that you can toggle with a single constant, serves a clean maintenance page to visitors, returns the correct HTTP status code for search engines, and keeps full access for administrators.
The Code
Add this to your functions.php or a site-specific plugin. Toggle maintenance mode by changing the NSL_MAINTENANCE_MODE constant between true and false. No plugin activation or database change is required.
The 503 Status Code
Returning a 503 Service Unavailable status is critical for SEO during maintenance. A 503 tells search engine crawlers that the unavailability is temporary, Google will not de-index your pages in response to a 503 the way it would to a 404 Not Found. It will simply retry the URL later. The Retry-After: 3600 header provides a hint suggesting Googlebot check back in one hour, which helps it schedule its retry efficiently.
Never put a site into maintenance mode using a redirect to another URL without a 503, this can cause search engines to treat the redirect as permanent and update their index accordingly, potentially harming rankings.
Administrator Access
The current_user_can( 'manage_options' ) check allows administrators to browse the front end normally while maintenance mode is active. This is essential for reviewing changes before taking the site out of maintenance. The is_admin() check ensures the admin backend is always accessible, allowing you to manage the site, run updates, or disable maintenance mode without needing to temporarily remove the snippet.
The Maintenance Page
The snippet includes a minimal inline maintenance page with clean styling. Customise the heading, body text, and styles directly in the HTML block. You can add your logo using an <img> tag with an absolute URL, add estimated downtime information, or include a contact email for urgent enquiries. Keep the page simple, it doesn’t load WordPress’s full template stack, so all styles must be inline.
wp-config.php Alternative
For deployments where you want maintenance mode active before WordPress fully loads, for example during a database migration, define the constant in wp-config.php instead of functions.php. Adding define( 'NSL_MAINTENANCE_MODE', true ); there ensures the maintenance check runs as early as possible in the request lifecycle.
define( 'NSL_MAINTENANCE_MODE', true ); // Set to false to disable
add_action( 'template_redirect', function() {
if ( ! defined( 'NSL_MAINTENANCE_MODE' ) || ! NSL_MAINTENANCE_MODE ) return;
if ( is_admin() ) return;
if ( current_user_can( 'manage_options' ) ) return;
// Return a 503 Service Unavailable with Retry-After header
http_response_code( 503 );
header( 'Retry-After: 3600' ); // Hint to bots to retry in 1 hour
header( 'Content-Type: text/html; charset=utf-8' );
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Under Maintenance — <?php bloginfo( 'name' ); ?></title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; color: #0f172a;
display: flex; align-items: center; justify-content: center;
min-height: 100vh; padding: 24px; }
.card { background: #fff; border: 1px solid #e2e8f0; border-radius: 16px;
padding: 48px; max-width: 480px; text-align: center;
box-shadow: 0 4px 24px rgba(0,0,0,0.06); }
h1 { font-size: 24px; font-weight: 700; margin-bottom: 12px; }
p { color: #64748b; font-size: 16px; line-height: 1.65; }
</style>
</head>
<body>
<div class="card">
<h1>Under Maintenance</h1>
<p>We're making some improvements and will be back shortly. Thank you for your patience.</p>
</div>
</body>
</html>
<?php
exit;
} );
