How to Create Your Own Maintenance Mode plugin

I’m going to teach you how to create your maintenance mode plugin; but first, the back story to how I ended up creating my own:

A few months ago, we started the development phase of a new project. As usual, after the client had bought their domain and hosting, we were going to put up a splash page. I was going to go through the usual process of configuring the domain DNS recordsinstalling WordPress and then installing my go-to plugin WP Maintenance Mode.

Right then Bobbi messaged, “I want to make a custom splash page.”

I kid you not, I was about to hit the Install button when I saw this message pop up in Slack and I paused.

“Sure! Let’s do it!” I typed back.

So then I set about making a small plugin to create a custom splash page. I don’t know why I hadn’t already done this, but it has made life so much easier.

What Maintenance Mode Actually Is

The trick with a splash page plugin (or a coming soon page plugin) is that it’s not actually a maintenance mode plugin.

Maintenance mode makes your entire website inaccessible from the browser for everyone.

But as an industry, we’ve fallen into the (often confusing) habit of calling the splash page maintenance mode.

A splash page like the one I am about to show you how to create is a page that only visitors see. Logged in users (or whomever you grant permission to) can design, code, test, and use their website normally, they don’t see the splash page. Usually when many people say maintenance mode, this is what they actually mean.

Making a custom splash page plugin is very easy. If you’ve never built a WordPress plugin, this is an excellent first-time project.

I’m also going to introduce you to Carbon Fields (CF) – an alternative to Advanced Custom Fields (ACF), and simpler to include in your own plugin. (If you’ve never used Advanced Custom Fields, look out for a future tutorial where I go over just how powerful custom fields can be using ACF or CF.)

Writing a Basic WordPress Plugin

Creating a WordPress plugin has two basic rules:

  1. Your folder plugin name must match the main PHP file inside your plugin folder.
  2. You need the following code at the top of your main PHP file to identify and designate this folder as a plugin:
     * Plugin Name: Wanderoak Maintenance Mode
     * Plugin URI:
     * Description: Displays a maintenance mode page for anyone who's not logged in.
     * Author: Aurooba Ahmed
     * Author URI:
     * @package wo-maintenance-mode

And that’s it! If you have these two things, you’ve built a plugin. Of course, this plugin doesn’t do anything, yet. But that’s what we’re going to get to next.

Here’s the basic file structure of this plugin:

├── assets
│   ├── style.css
├── lib
│   ├── carbon-fields
├── views
│   └── maintenance.php
├── wom_crb.php
└── wswg_maintenance_mode.php

We’re going to build a customizable splash page plugin that comes with a little bit of flexibility. You can get as fancy (or not fancy at all) with your own splash page; this tutorial will give you a solid foundation on how to do that.

Our plugin will have the following settings:

  • Status: Let’s you turn on/off the splash page
  • Header Image: Let’s you add a header image
  • Page Title
  • Content: A simple WYSIWG text editor
  • Social Media: So you can add social media platforms
  • MailChimp Form: Because email is king, right?

Creating the Plugin Settings Page

First we’re going to include the Carbon Fields library in our plugin. Download the Carbon Fields repository and save it in your plugin folder. I have a folder called /lib/ where I saved it.

Next, you’re going to include the library in your plugin PHP file like so:

require(dirname(__FILE__) . '/lib/carbon-fields/carbon-fields-plugin.php');

You’re going to create a new file where you will register your custom fields. My file is called wom_crb.php. One of the reasons I enjoy Carbon Fields so much is because I don’t have to use a GUI to create Custom Fields, I can do it all in code, and it can be much faster.

Here’s a link to the Carbon Fields documentation. It’s well written and pretty straightforward, however, I will walk you through the basic fields we’re going to create.

Here’s what our finished page is going to look like:

maintenance plugin settings - we start with good

Before we tackle the individual fields, we have to create the page that will hold our plugin settings. In Carbon Fields, this means creating a container. In your new file, include the Carbon Fields classes for Containers and Fields:


use Carbon_Fields\Container;
use Carbon_Fields\Field;

Next, we’re going to create the container itself:

Container::make('theme_options', 'WO Coming Soon')

In Carbon Fields, the tabs and arrows are pretty important. So make sure to keep your document nice and clean. Here we’ve created a theme options container called WO Coming Soon, we’ve made it a child page of the Settings page in WordPress (because cluttering up the menu is a big no-no), and it’s only available to administrators or those roles that are allowed to edit themes.

The next line is where we start adding fields:

// your fields will go here.

Radio Field

The first field we’re going to create is the Splash Page status toggle, so that it’s easy to turn the splash page on or off.

You’re going to notice that the way different fields work in Carbon Fields is very standardized. I’ve added comments throughout so that it’s easy to read the code.

// this initializes the field type and gives it a name
Field::make('radio', 'crb_womm_status', 'Coming Soon/Maintenance Mode Status')
// these are the radio options for this field, simple key/value pairs
        'true' => 'On',
        'false' => 'Off',
// the following options are optional, but adding help text is always a good idea
    ->help_text('You may turn the coming soon page on or off. Turning off the page deletes all the information in the fields.')
// we're setting the status to false by default so that we have to manually turn it on

Once you add the last option for the field, then you add the comma. This signifies the end of this field.

Image Field

The image field is added like this:

Field::make( 'image', 'crb_header_image', 'Header Image' )
    ->set_value_type( 'url' )
        'relation' => 'AND', 
            'field' => 'crb_womm_status',
            'value' => 'true', 
            'compare' => '=', 

In the rest of the fields, you’ll notice the set_conditional_logic option. We want the rest of the options to show up only when the Splash Page status is toggled on.

Text Field

Next we’ll create a field for the Page Title:

Field::make('text', 'crb_title', 'Page Title')
// here we're specifying a width for the field so that it looks more reasonable
        'relation' => 'AND',
            'field' => 'crb_womm_status',
            'value' => 'true', 
            'compare' => '=',

Rich Text Field

Then we’ll create a WYSIWG field to add the content for the page:

Field::make('rich_text', 'crb_page_content', 'Page Content')
        'relation' => 'AND', 
            'field' => 'crb_womm_status',
            'value' => 'true', 
            'compare' => '=', 

Complex Field (In ACF this is the Repeater field)

Now we’re going to create a Complex Field, which is a field where you specify more fields within one row. And you can add as many rows as you want. This is super handy for something like social media, where it’s always the same fields (social media type and URL), and you need multiples of them:

complexfield example - we start with good
Field::make( 'complex', 'crb_social', 'Social Media' )
// here we're adding the fields each row will have, a select field and a text field for the URL
    ->add_fields( array(
        Field::make( 'select', 'crb_social_media', 'Social Media Platform' )
            ->add_options( array(
                'fb' => 'Facebook',
                'twitter' => 'Twitter',
                'instagram' => 'Instagram',
            ) ),
// since we're not adding any special options for the text field, all we need is the first line that specifies the type and gives it a unique name. super handy!
        Field::make( 'text', 'crb_social_url', 'Full URL' ),
    ) )
        'relation' => 'AND',
            'field' => 'crb_womm_status',
            'value' => 'true', 
            'compare' => '=',

I’ll be using Font Awesome to add the social media icons, so I’ve included the font awesome library in the lib folder. But you’re welcome to use whatever you want to use.

Now all that’s left is to add the MailChimp fields, which are just a radio field and a text field. Use the screenshot of the finished plugin settings page as a reference when creating it. 🙂 Once you toggle the MailChimp status on, there’s just a single text field called Form Action URL. (Curious how this works? Here you go.)

Registering the fields

Next you’re going to actually register your fields in the main plugin file like so:

add_action('carbon_register_fields', 'crb_womm');
function crb_womm() {
    include_once(dirname(__FILE__) . '/wom_crb.php');

Building the Splash Page ‘view’

Creating the actual splash page is as simple as creating a regular page template in WordPress, except it’s not a page template, it’s just a page in PHP, complete with a header and footer. I’m assuming you have a decent handle on PHP and HTML in the WordPress ecosystem, so I’m just going to include a commented code snippet here:

 * Maintenance mode template that's shown to logged out users.
 * @package wo-maintenance-mode
    // Here I'm grabbing all the fields I need and putting them in variables. This makes for easier to read code, in my opinion. The key thing to notice here is that since these are theme options the function we're using to grab the fields is carbon_get_theme_option( 'field_key' )
    $himage = carbon_get_theme_option('crb_header_image');
    $message = carbon_get_theme_option( 'crb_page_content' );
    $mcstatus = carbon_get_theme_option( 'crb_mc_status' );
    $mcid = carbon_get_theme_option( 'crb_mcid' );
    $social = carbon_get_theme_option( 'crb_social', 'complex' );
    $pagetitle = carbon_get_theme_option('crb_title');

<!DOCTYPE html>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- to grab the proper path for your assets, you use plugins_url( 'the path within the folder to your file ', dirname(__FILE__)) -->
	<link rel="stylesheet" href="<?php echo plugins_url( 'assets/style.css', dirname( __FILE__ ) ); ?>">
	<!-- Here we're adding the Page Title into the Title meta -->
	<title><?php echo $pagetitle; ?> | <?php echo esc_html( get_bloginfo( 'name' ) ); ?></title>
    <!-- Here I'm loading Font Awesome 5 Pro, but you can load whatever it is that you will use for social media icons -->
    <script defer src="<?php echo plugins_url( '/assets/brands.min.js', dirname( __FILE__ ) ); ?>"></script>
    <script defer src="<?php echo plugins_url( '/assets/fontawesome.min.js', dirname( __FILE__ ) ); ?>"></script>
<!-- Honestly, the rest of this is a simple html file with the necessary information being pulled in using PHP -->
    <div class="header-image">
        <img src="<?php echo $himage; ?>" />
    <div class="actual">
            <h1><?php echo $pagetitle; ?></h1>

            <?php echo $message; ?>
        <?php if ($mcstatus == 'true') : ?>
        <!-- Begin MailChimp Signup Form. This is the standard embed code MailChimp gives you. This is a universal piece of code. The only unique part is the Form Action URL, which you can grab from your MailChimp account. -->
        <div id="mc_embed_signup">
        <form action="<?php echo $mcid; ?>" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
            <div id="mc_embed_signup_scroll">
        <div class="mc-field-group">
            <input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL" placeholder="email address">
            <div id="mce-responses" class="clear">
                <div class="response" id="mce-error-response" style="display:none"></div>
                <div class="response" id="mce-success-response" style="display:none"></div>
            </div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
            <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_d1111f5d43491b616846d9d71_834d091b2d" tabindex="-1" value=""></div>
            <div class="clear"><input type="submit" value="Sign Up" name="subscribe" id="mc-embedded-subscribe" class="button"></div>

        <!--End mc_embed_signup-->
        <?php endif; ?>
        <div class="social">
                // Okay this is the part that may be new to you. Since the Complex Field creates an array of arrays, we'll use a for loop to loop through all of them and grab the information to display. I'm checking which social media platform was chosen, and then displaying the appropriate icon from Font Awesome for it with the link they added.
                foreach ( $social as $link ) {
                    if ($link['crb_social_media'] == 'fb') :
                        echo '<a href="' . esc_url( $link['crb_social_url'] ) . '" target="_blank">' . '<i class="fab fa-facebook"></i>' . '</a>';
                    elseif ($link['crb_social_media'] == 'twitter') :
                        echo '<a href="' . esc_url( $link['crb_social_url'] ) . '" target="_blank">' . '<i class="fab fa-twitter"></i>' . '</a>';
                    elseif ($link['crb_social_media'] == 'instagram') :
                        echo '<a href="' . esc_url( $link['crb_social_url'] ) . '" target="_blank">' . '<i class="fab fa-instagram"></i>' . '</a>';


I have this page saved in a folder called /views/ because I have multiple variations of splash pages. This way, when I’m adding it to a project, I can just select the one that’s appropriate in that particular situation.

Now here’s the tiny bit of logic we’re going to employ:

If the user is not an Administrator and/or is not logged in, we want to serve up our splash page, but ONLY when the Splash Page status is toggled on.

So first we’re going to create a function called wo_maintenance_mode to serve up our splash page to anyone who is NOT an Administrator or is NOT logged in:

function wo_maintenance_mode(){
    if(!current_user_can('edit_themes') || !is_user_logged_in()){
//this is where I would choose a different view to pull depending on the situation        
        if ( file_exists( plugin_dir_path( __FILE__ ) . 'views/maintenance.php' ) ) {
			require_once( plugin_dir_path( __FILE__ ) . 'views/maintenance.php' );


We’re going to write a simple if statement to check whether the Splash Page status is toggled on or off; if it’s on, then we will call the function we just created above:

$status = carbon_get_theme_option('crb_womm_status');

if ( $status == 'true' ) :
    add_action('get_header', 'wo_maintenance_mode');

And there you have it. You have a simple Maintenance Mode plugin you can install on any of your websites – it’s customizable, you can add more fields and logic to it if you want, and it has an easy to use interface.