Admin UX PHP Intermediate

Simple Maintenance Mode for Non-Admin Users

Last updated: May 6, 2026

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.

functions.php
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;
} );

Built by Nahnu Plugins

Need something more powerful than a snippet?

Our commercial plugins go further, built for serious WordPress sites with full support, updates, and documentation included.

Browse All Plugins →

This website uses cookies to enhance your browsing experience and ensure the site functions properly. By continuing to use this site, you acknowledge and accept our use of cookies.

Accept All Accept Required Only