Whenever you upgrade a plugin, theme or WordPress itself through the WordPress dashboard, WordPress will put itself in maintenance mode and all your visitors will see the maintenance mode notice “Briefly unavailable for scheduled maintenance. Check back in a minute.”

By default, WordPress will also output headers that tell browsers and search engines that the page is temporarily unavailable (HTTP header status code 503), and a Retry-After HTTP header which tells the browsers to reload the page after 600 seconds (aka 10 minutes).

It is really easy to customize the maintenance mode page. All you have to do is to drop a file called maintenance.php in your wp-content directory, and WordPress will show this page to your users instead of the standard page.

Example maintenance.php file:

<?php
wp_load_translations_early();

$protocol = wp_get_server_protocol();
header( "$protocol 503 Service Unavailable", true, 503 );
header( 'Content-Type: text/html; charset=utf-8' );
header( 'Retry-After: 30' );
?>
<!DOCTYPE html>
<html>
<head>
    <title><?php _e( 'Maintenance' ); ?></title>
</head>
<body>
    <h1><?php _e( 'Maintenance' ); ?></h1>
    <p><?php _e( 'Briefly unavailable for scheduled maintenance. Check back in a minute.' ); ?></p>
</body>
</html>

If you look at the code above, you’ll notice that we’re now telling the browser to try to reload after just 30 seconds, instead of the default 10 minutes. The upgrade process usually only lasts for a few seconds anyways.

To try it out, you can place a file called .maintenance (notice the first dot) in your document root (where your index.php file is) with the following content:

<?php $upgrading = 9999999999999;

Now, for most of our users we can enhance this even further. As the page is returning a HTTP 503 status code, we can do an AJAX HEAD request to the same URL, which polls at a set interval of e.g. 3 seconds. When the AJAX request receives a HTTP 200 status code instead of 503, we’ll do a page refresh to show the page to the user:

<script>
var maintenance_check = function() {
    var request = new XMLHttpRequest();
    request.open( 'HEAD', window.location, true );

    request.onload = function() {
        if ( this.status >= 200 && this.status < 400 ) {
            // Maintenance mode ended. Reload page.
            window.location.reload();
        } else {
            // Still in maintenance mode. Try again in 3 seconds.
            setTimeout( maintenance_check, 3000 );
        }
    };

    request.onerror = function() {
        // Connection error. Try again in 3 seconds.
        setTimeout( maintenance_check, 3000 );
    };

    request.send();
};
maintenance_check();
</script>

To finish off, we can show the user something like a spinner to indicate to them that something is happening in the background and that the page will reload automatically when it is ready.

You can find some nice, easy-to-implement pure CSS spinners here.

Here is a Gist with a full maintenance.php with AJAX loader, spinner and some additional minimal styling.