Theme or Style WordPress Message pages

That screen is essentially a conditional display of the wp-login.php screen. It’s wp-login.php?action=logout, so to style it you have to simply enqueue a stylesheet (preferred) or inline code with your own style rules. So create your style-login.css file, put it in your theme/child theme (depending on if you’re building from scratch or just adding to an existing theme) and use your developer tools to look at the elements that are rendered on that page and writing style rules for them.

You’d put this code into your functions.php file:

function my_custom_login_stylesheet() {
    wp_enqueue_style( 'custom-login', get_stylesheet_directory_uri() . '/style-login.css' );
}
add_action( 'login_enqueue_scripts', 'my_custom_login_stylesheet' );

There’s a full tutorial on this stuff over here that has a lot of extra info:

https://premium.wpmudev.org/blog/customize-login-page/

UPDATE / ADDENDUM:
The following is a detailed breakdown on how to add custom templates and assign pages to replace the default WP admin screens, as requested in the comments:

function notices_enqueue_front() {
    global $pagenow, $typenow, $post;
    /* In my plugin, I actually have this part set up as plugin settings.
     * In the plugin settings you assign which page you want as the login page and which one you
     * want as the registration page.  For the purpose of this example though, we'll just hard code
     * the page IDs.  You can extrapolate this list for every one of the screens available.
     * So you can add one for the Forgot Password screen, error screens, etc. 
     *
     * You have to create pages in WordPress, then get the page IDs.  You don't have to publish the pages yet.
     */
    $loginPage              = 723;
    $registrationPage       = 748;
    if( $loginPage == $post->ID ) {
        /* So if your LOGIN page ID matches the ID of the page being viewed, it will enqueue the custom login css. */
        wp_enqueue_style( 'custom-login', plugins_url( 'css/custom-login-front.css', __DIR__ ), array(), 'x.x' ); //update x.x as version
    }
    if( $registrationPage == $post->ID ) {
        /* So if your REGISTRARION page ID matches the ID of the page being viewed, it will enqueue the custom login css. */
        wp_enqueue_style( 'custom-registration', plugins_url( 'css/custom-registration-front.css', __DIR__ ), array(), 'x.x' ); //update x.x as version
    }
    /* I have the CSS in separate files, but you could just do one single file and re-use it, if that's the case, you can abandone the lines above and
     * just use the following 3 lines, uncommented, instead: */
    //if( $registrationPage == $post->ID || $loginPage == $post->ID ) {
        //wp_enqueue_style( 'custom-notices', plugins_url( 'css/custom-notices-front.css', __DIR__ ), array(), 'x.x' );
    //}
}
add_action( 'wp_enqueue_scripts', 'notices_enqueue_front', 100 );

/* The next step is to include the templates into the theme as options that can be assigned to a page.
 * Because I built this as a plugin, it doesn't happen just by including them in the theme directory the way it does with a theme.
 * If you're doing all of this in a functions.php file in a child theme, you can skip/leave out the next part.
 */
function notices_page_template( $page_templates, $theme, $post ) {
    /* You would simply include all of your different templates in this list following the same pattern.
     * This ensures that when you're making a Page, these templates are available to be loaded into the Template drop down. */
    $page_templates['template-login.php']       = 'Login Page';
    $page_templates['template-register.php']    = 'Registration Page';
    return $page_templates;
}
add_filter( 'theme_page_templates', 'notices_page_template', 10, 3 );
function notices_load_page_template( $template ) {
    global $post;
    /* Again, repeat this set-up for each of the custom templates you make. */
    $login_template_slug        = 'template-login.php';
    $register_template_slug     = 'template-register.php';
    $page_template_slug         = get_page_template_slug( $post->ID );
    if( $page_template_slug == $login_template_slug ) {
        /* I have my templates in a 'templates' directory, make sure you match the correct directory path here. */
        return plugin_dir_path( __DIR__ ) . 'templates/' . $login_template_slug;
    }
    if( $page_template_slug == $register_template_slug ) {
        /* I have my templates in a 'templates' directory, make sure you match the correct directory path here. */
        return plugin_dir_path( __DIR__ ) . 'templates/' . $register_template_slug;
    }
    return $template;
}
add_filter( 'template_include', 'notices_load_page_template', 99 );
/* Reminder:  Both of the functions above are if you have a plugin.
 * If you have a theme, you can just drop your templates in the main theme folder and they will load. */


/* This next section is where we capture users navigating to the default WordPress screens in question and re-direct them to our assigned pages instead. */
function notices_template_redirects() {
    global $pagenow;
    /* As with the first function, this leverages something I set up as plugin settings - we'll just hard-code the page IDs here though. 
     * You'll want to repeat this process for each of the pages you want to redirect to a custom template. */
    $loginPage              = 723;
    $loginPageURL           = get_the_permalink( $loginPage );
    $registrationPage       = 748;
    $registrationPageURL    = get_the_permalink( $registrationPage );
    /* Now, I have special rules for what to do with different user levels and if users are logged in or not.
     * You can strip this down to a basic process for everyone.
     * Or even adjust and add other levels to the rules. */
    if( !is_user_logged_in() ) :
        /* $pagenow returns the actual file, like 'login.php'.
         * But it excludes the query parameters, like '?action=whatever', so you'll see how I address that. */
        if( !empty( $loginPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) ) : /* No query parameters. */
            wp_redirect( $loginPageURL );
        endif;
        /* The WP registration page's URL is 'login.php?action=register', so here's how I check for that: */
        if( !empty( $registrationPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) && ( strtolower( $_GET['action'] ) == 'register' ) ) :
            wp_redirect( home_url( $registrationPageURL ) );
        endif;
    else :
    /* But if the users ARE logged in, I still want the admins to:
     * A) be redirected to the WP Dashboard
     * B) still be able to view the registration form, for testing and for guiding users through the registration process. */
        if( current_user_can( 'administrator' ) ) :
            if( !empty( $loginPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) ) :
                wp_redirect( admin_url() ); /* To WP Dashboard */
            endif;
            if( !empty( $registrationPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) && ( strtolower( $_GET['action'] ) == 'register' ) ) :
                wp_redirect( home_url( $registrationPageURL ) ); /* Redirects to the custom Registration page. */
            endif;
        else :
            /* But for all other user levels, if you're already logged in, accessing the login screen takes you to the home page. */
            if( !empty( $loginPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) ) :
                wp_redirect( home_url() );
            endif;
            /* And if non-admin user tries to access the registration, while logged in, it redirects them to the home page. */
            if( !empty( $registrationPage ) && ( strtolower( $pagenow ) == 'wp-login.php' ) && ( strtolower( $_GET['action'] ) == 'register' ) ) :
                wp_redirect( home_url() );
            endif;
        endif;
    endif;
}
add_filter( 'init', 'notices_template_redirects' );
/* In the above function, you'll basically have to create a unique redirect rule for each of the default WP pages you want to address.
 * So you'll need one for the 'forgot password', another for any 'error' notices, etc. */

Next, create a file and call it template-login.php. In a plugin, place it in the appropriate directory you specified above in the notices_load_page_template() function. This will make sure that your plugin can find the file. If you’re doing this in your theme/child theme using functions.php just create the file in the main theme folder.

In the template-login.php file, add the following code:

<?php
/**
 * Template Name: Login Page (The 'Template Name:' comment line must remain in the file, WP needs it.  You can remove my note and the note below.)
 * Displays front end, user friendly, non-WP login dialogue
 */
    get_header(); 
    /* This will load the theme's default header.  You can actually create multiple headers for your theme, but that's a whole other thing. */
?>
            <!-- the following is basic WP login code you can delete this comment -->
            <div class="login-modal">
                <form name="loginform" id="loginform" action="<?php echo home_url( 'wp-login.php' ); ?>" method="post">
                    <h2><?php the_title(); ?></h2>
                    <p>
                        <label for="user_login">Username or Email Address <span class="required">*</span></label>
                        <input type="text" name="log" id="user_login" aria-describedby="login_error" class="input" value="" size="20" autocomplete="username" />
                    </p>
                    <p>
                        <label for="user_pass">Password <span class="required">*</span></label>
                        <input type="password" name="pwd" id="user_pass" aria-describedby="login_error" class="input" value="" size="20" autocomplete="current-password" />
                    </p>
                    <p class="submit">
                        <input type="submit" name="wp-submit" id="wp-submit" class="button alt" value="Log In" />
                        <input type="hidden" name="redirect_to" value="<?php echo esc_url( home_url() ); ?>" />
                    </p>
                </form>
            </div>
<?php
    /* This will load the theme's default footer.  You can actually create multiple footers for your theme, but that's a whole other thing. */
    get_footer();
    /* It's important to note that you HAVE TO put in the content for each of these pages.
     * Since you're replacing the default WP login.php function/file, it won't know what content to display, you have to provide that.
     * You can actually hard code the content in each template.  Something like "Error:  You don't have access to this page."
     * Or you can type it in as content in the WP editor and then call the content with the_content();.
     * So before you start replacing the the WP defaults, make note of what is displayed and write out what you want it to be.
     * That way you don't end up with blank pages loading instead of notices, logins, etc. */ 
?>

I apologize if my answer was overly verbose, I just wanted to make sure I explained everything I was doing with the code so you could make adjustments as needed. The way I’ve built this for use with a custom web application I’m building for an organization that’ll have 1500-3000 members registering 3 times a year means there’s a specific way mine needs to work, and your set up may not need that.

Leave a Comment