Website Guider

The Ultimate Resource for WPadmins and Geeks

Create a Custom Login Page for WordPress (Without Plugin)

Do you want to show your users a custom login page?

By choosing a custom page, users can log in to the WordPress dashboard using the page you have set as default.

Creating a custom login page for WordPress isn’t a tough task.

In this updated tutorial, I will walk you through the code by which you can create a simple login form for your users.

Also, the previous code I used was deprecated, so there was a need to update this post. The code I will present to you is fully compatible with the latest version of WordPress.

Why You Need Custom Login Page

Of course, there are various reasons for it.

Few of us don’t like the default WordPress login page due to its interface or copyright links. Many of us would like to send the user to a different page where the user can log in to the website without accessing the main default login page.

If you want to create a front-end login page for WordPress, this tutorial will surely help you.

Remember, I didn’t style this login page because different people have different opinions. So you have to style it manually as per your needs. Also, you don’t need to be good at designing.

If you know CSS you are good to go.

You can use this code for any website. Few tweaks to code will take this login form to the next level.

Another reason for using the custom login page is that if you have a membership site, then you need one. So you can easily create a client login page in WordPress.

Creating a User Login Page in WordPress

This tutorial is all about creating a custom login page in WordPress; we will create a plugin.

We will create a few functions and a specific shortcode. In the previous version of this tutorial, we used the template system to show our login page in the front.

But, we will no longer use that. Instead, we will use shortcode.

You might ask why are you switching from template to shortcode?

I have a reason for this. When writing this tutorial, it is hard to create a template in the Block editor or so-called Gutenberg. Creating a template in Gutenberg is beyond the scope of this tutorial.

Tip: If you don’t know how to write a plugin or don’t know how to create files. Please don’t proceed. It is a must that you follow all the steps in this tutorial and read them carefully. Now without wasting more time, let’s jump into it.

Creating a Plugin

Firstly, we will create a plugin and name it Custom Login. Create a file and call it custom-login.php.

Inside, paste this code.

<?php
/**
 * Plugin Name: Custom Login
 * Description: This plugin lets you add the custom login  feature on any post or page by using shortcodes.
 * Plugin URI: https://websiteguider.com
 * Author: WebsiteGuider
 * Author URI: https://websiteguider.com
 * Version: 1.0.0
 * License: GPL2
 * Text Domain: custom-login
 * 
 */

I wouldn’t go into detail like what’s here going on. There are plenty of tutorials already on Google.

Adding some titbits to custom-login.php

Once the plugin is in the list in the backend, we can insert a few code lines to custom-login.php. Put these lines of code after the plugin information.

/**

/**
 * Enqueue scripts
 *
 * == main.js ==  This file adds client side checking to our login and register pages.
 */
function custom_enqueue_scripts() {
    wp_enqueue_script( 'main-js', plugins_url() . '/custom-plugin/js/main.js', array( 'jquery' ), false, false );
}
add_action( 'wp_enqueue_scripts', 'custom_enqueue_scripts' );

// Define constants so we can use them as shortcuts
define("SHORTCODES_PATH", plugin_dir_path( __FILE__ ) . 'shortcodes');
define("FUNCTIONS_PATH", plugin_dir_path( __FILE__ ) . 'functions');

// Include the required Files
require_once SHORTCODES_PATH . '/login-shortcode.php';
require_once FUNCTIONS_PATH . '/login-functions.php';
require_once FUNCTIONS_PATH . '/custom-login-functions.php';

Here we are adding a JavaScript file, few constants we will use later, and few files we require.

Tip: you can also add a CSS file if you need to style the login form.
Warning: Please don’t activate the plugin yet. Once you do all the things, then activate and see results.

Creating our folders

To make the code easier to maintain, we will create three folders such as

  • Shortcodes: Inside this, we will store our shortcode file.
  • Functions: This folder will hold a few files related to custom functions.
  • JS: All the JavaScript files will go inside this folder.

 Creating files

Now we will start playing with code. Are you ready to get your hands dirty with code? Let’s begin.

Firstly, we will start with the Functions folder. Inside the Functions folder, create a file custom-login-functions.php. Inside this file, put this code.

<?php


/**
 * Log-in the User
 *
 * This function accepts various parameters that are used for checking whether the user exists or not.
 *
 * @since 1.0.0
 *
 * @param int $user_id The ID of the user.
 * @param string $user_login The users username/email.
 * @param string $user_pass Password of the user.
 * @param boolean $user_remember Whether to remember the user credentials or not.
 *
 * @return void Return early if the user doesn't exist.
 * @author WebsiteGuider
 **/

function custom_log_userin($user_id, $user_login, $user_pass, $user_remember = false ) {
    if( ! absint( $user_id ) || $user_id < 1 ) {
        return;
    }
    
    wp_set_auth_cookie( $user_id, $user_remember );
    wp_set_current_user( $user_id, $user_login );
    do_action( 'wp_login', $user_login, get_userdata( $user_id ) );
}
function custom_error_set( $id, $value ) {
    global $error_json;
    
    if( is_null($value) ) {
        unset($error_json);
        return;
    }
    
    $id = sanitize_key( $id );
    
    if( is_array($value) ) {
        $error_json[ $id ] = wp_json_encode( $value );
    } else {
        $error_json[ $id ] = esc_attr( $value );
    }
    
    return $error_json;
}

function custom_error_get( $id ) {
    global $error_json;
    
    $maybe_decode_json = json_decode($error_json[ $id ]);
    
    if( ! is_null( $maybe_decode_json ) && ! is_array($maybe_decode_json) ) {
        $maybe_decode_json = json_decode($error_json[ $id ], true);
    } else {
        $maybe_decode_json = FALSE;
    }
    return $maybe_decode_json;
}
function custom_get_errors() {
    return custom_error_get('custom-errors');
}
function custom_output_error($id, $value) {
    $errors = custom_get_errors();
    if( ! $errors ) {
        $errors = array();
    }
    $errors[ $id ] = $value;
    custom_error_set('custom-errors', $errors);    
}

function custom_print_errors() {
    $errors = custom_get_errors();
    if( ! empty($errors) ) {
        ?>
        <div class="custom-error">
        <?php
        foreach( $errors as $error_id => $error ) {
            echo '<p class="error_' . $error_id .'"><strong>Error:</strong> ' . $error . '</p>';
        }     
        ?>
        </div>
        <?php
    }
}

You can see there are six functions. But I will discuss custom_log_userin(). I wouldn’t consider others because what they do is printing the error on the front login page.

Let’s come to our function, which is an essential function for creating a custom login page. This function logs the user in once he enters his/her Information. Inside this function, we first check for, $user_id which should hold an absolute integer value. Otherwise, the code wouldn’t run.

After that, if the $user_id meets our requirement, then the user is logged in.

Wait a minute, why would you user login if you haven’t checked the credentials yet? Don’t panic; we haven’t yet logged him in. We will use this function inside other functions where he will be able to log in.

Ok, let’s do that.

Create another file in the same folder and name it login-functions.php. Copy and paste this code inside the file.

<?php

/**
 * Generate the HTML markup of the form
 *
 * @since 1.0.0
 *
 * @param string $custom_redirect The URL where the user should be redirected after submitting the form.
 *
 * @return void Return early if the user is logged in.
 * @author WebsiteGuider
 **/

function custom_html_login_form( $custom_redirect ) {
    if( ! is_user_logged_in() ) {
        ?>
        <form method="post" class="custom-login-form">
        <style type="text/css">
			.custom-error {
				margin-bottom: 10px;
				padding: 10px;
    			background-color: #d64646;
    			color: white;
    			border-radius: 5px;
			}
            .custom-error p {
                margin: 0;
            }
		</style>
            <?php custom_print_errors(); ?>
            <p>
                <label for="custom-user"><?php _e('Username', 'custom-login-register'); ?></label>
                <input type="text" name="custom_user" id="custom-user" placeholder="Type Username or Email" />
            </p>
            <p>
                <label for="custom-pass"><?php _e('Password', 'custom-login-register'); ?></label>
                <input type="password" name="custom_pass" id="custom-pass" placeholder="Type the password" />
            </p>
            <p>
            <label for="remember-me">
                <input type="checkbox" name="remember_me" id="remember-me"/>
                <?php _e('Remember Me', 'custom-login-register'); ?>
            </label>
            </p>
            <p>
                <a href="<?php echo wp_lostpassword_url(); ?>"><?php _e('Lost Password', 'custom-login-register'); ?></a>
            </p>
            <p>
                <input type="hidden" name="custom_login_nonce" value="<?php echo wp_create_nonce('custom-login-nonce'); ?>" />
                <input type="hidden" name="custom_redirection" value="<?php echo esc_url( $custom_redirect ); ?>"/>
                <input type="submit" name="submit_custom_login" value="<?php _e('Login', 'custom-login-register'); ?>" />    
            </p>
        </form>
        <?php
    } else {
        _e("You are logged in", 'custom-login-register');
    }
}

add_action( 'init', 'process_custom_login_form' );

/**
 * Process the Log-In form
 *
 * This callback function is called before any headers are sent. 
 * With this function you can validate the user details submitted by him using our log-in form.
 *
 * @since 1.0.0
 *
 * @return void
 * @author WebsiteGuider
 **/

function process_custom_login_form( ) {
    // Validate the username or email field before submitting
    if ( isset($_POST['custom_user'])) {
        $custom_user =  trim($_POST['custom_user']);
    }
    
    // Validate password field before submitting
    if ( isset($_POST['custom_pass']) ) {
        $custom_pass = trim($_POST['custom_pass']);
    }

    if( wp_verify_nonce( (isset($_POST['custom_login_nonce']) ? $_POST['custom_login_nonce'] : ''), 'custom-login-nonce' ) ) {
        $user_info = get_user_by( 'login', $custom_user );
        
        if( ! $user_info ) {
            $user_info = get_user_by( 'email', $custom_user );
        }
        
        if( $user_info ) {
            $user_id = $user_info->ID;
            if( wp_check_password( $custom_pass, $user_info->user_pass, $user_id ) ) {
                if( isset($_POST['remember_me']) ) {
                    $_POST['remember_me'] = true;
                } else {
                    $_POST['remember_me'] = false;
                }
                
                custom_log_userin($user_id, $custom_user, $custom_pass, $_POST['remember_me']);
                wp_redirect($_POST['custom_redirection']);
                die;
            } else {
                custom_output_error('wrong_password', 'The password you entered is incorrect.');
            }
        } else {
            custom_output_error('wrong_username', 'The username you entered is incorrect.');
        }
    }
}

You can notice two functions. The first one has HTML inside it, and the other has PHP code which does all the things of backend.

Our function custom_html_form() also has a check, which is whether the current user is logged in or not. If he is already logged in, notifies him, else show the HTML form.

This function has one parameter $custom_redirect. This parameter is used for redirecting the user after he successfully logs in. You can set this in a shortcode where we will use this functionality.

In my case, I will redirect the user to the home page, but you can send him directly to the admin page, which I will show you later on how to do that.

This function also uses other functions as well like custom_get_errors()(shows an error if found), wp_lostpassword_url()(lost password functionality), wp_create_nonce()(for security purposes).

Now let’s come to another function. process_custom_login_form() Processes our HTML form to the backend. It sends and receives data for verification.

To better understand this function, I created a simple mockup. I think this way you will understand it better.

illustration of custom login form

We are near to conclusion, stay tuned.

Please create a new file inside the shortcode folder and name it login-shortcode.php. Inside this file, put this code.

<?php


/**
 * Shortcode for showing Sign In form.
 *
 * Use [custom_login] shortcode in page, post, or widget to display the log-in form.
 *
 * @since 1.0.0
 *
 * @param array $atts The list of attributes passed when calling the shortcode.
 *
 * @return Return the login form using output buffering.
 * @author WebsiteGuider
 **/

function shortcode_custom_login( $atts ) {
    if(isset($atts['redirect'])) {
    $custom_redirect = $atts['redirect']; }
    
    if( empty($atts['redirect']) ) $custom_redirect = home_url();
    
    // Start Output buffering
    ob_start();
    // Output the HTML form here
    custom_html_login_form( $custom_redirect );
    // End Output buffering by returning it
    return ob_get_clean();
}
add_shortcode( 'custom_login', 'shortcode_custom_login' );

Here I am creating a shortcode custom_login. This shortcode accepts the redirect parameter. Also, this function uses our custom_html_form() to show HTML form to our user.

Using the shortcode on the frontend

 We will create a simple page in our backend and name it Login. Now use the in-built Gutenberg shortcode block. Put this inside the block.

[custom_login redirect="http://yoursite.com/wp-admin"]

Do you see something different? I am talking about redirect. I am redirecting a user to the dashboard after he/she successfully logs in. Be sure to replace yoursite.com with your website name.

Conclusion

I hope everything is clear now. It was all about how to create a custom login page in WordPress? If you doubt or face any issues, I am ready to help put your message in the comment box below.

Now, I want your support. Please do share this tutorial if it helped you, also. Don’t forget to subscribe to our YouTube channel and like our Facebook page.

Raashid Din Dar

Raashid Din Dar is a web developer and designer. He specialises in WordPress Theme and Plugin development. Also, Web Designing is what he loves.He loves to read books and play with friends.

36 thoughts on “Create a Custom Login Page for WordPress (Without Plugin)

  1. This was just what I was looking for!

    I had to add some { } around your last media query and your .site-inner CSS caused some display issues on my site so I removed it. But other than those changes I was able to cut and paste your solution and it worked.

    Thanks for making this available.

  2. Works like a Charm I was looking for such a Nice and Perfect Article.Highly Recommended Keep Posting.Thanks a Million

  3. I am getting the following error when I try to use the script in WordPress 4.9.8:
    “Cannot modify header information – headers already sent by (output started at \Root\htdocs\class.wp-style.php)…

    Any thoughts?

    1. Hello Brian,
      I tested the code in 4.9.8 but i am not getting any error. It maybe problem with php opening and closing tags like you may be calling the tags inside the already opened tags. Please share the line number also, so i can figure it out.
      Hope this helps. If there is anything, please don’t hesitate to share.

  4. I am thankful to websiteguider.com Mr.Raashid. Perfect login page!

    On a few things need to get focused:
    Instead of using directly @media only screen and (max-width: 768px)
    .site-inner {
    padding: 5% 5% 5%!important;
    }

    Use this:
    @media only screen and (max-width: 768px){
    .site-inner {
    padding: 5% 5% 5%!important;
    }
    }

    At this stage, the only thing left to do is to set redirections to ultimately eliminate the default login page of WordPress. Do so by placing these lines at the end of your functions.php file:

    /* Main redirection of the default login page */
    function redirect_login_page() {
    $login_page = home_url(‘/login/’);
    $page_viewed = basename($_SERVER[‘REQUEST_URI’]);

    if($page_viewed == “wp-login.php” && $_SERVER[‘REQUEST_METHOD’] == ‘GET’) {
    wp_redirect($login_page);
    exit;
    }
    }
    add_action(‘init’,’redirect_login_page’);

    /* Where to go if a login failed */
    function custom_login_failed() {
    $login_page = home_url(‘/login/’);
    wp_redirect($login_page . ‘?login=failed’);
    exit;
    }
    add_action(‘wp_login_failed’, ‘custom_login_failed’);

    /* Where to go if any of the fields were empty */
    function verify_user_pass($user, $username, $password) {
    $login_page = home_url(‘/login/’);
    if($username == “” || $password == “”) {
    wp_redirect($login_page . “?login=empty”);
    exit;
    }
    }
    add_filter(‘authenticate’, ‘verify_user_pass’, 1, 3);

    /* What to do on logout */
    function logout_redirect() {
    $login_page = home_url(‘/login/’);
    wp_redirect($login_page . “?login=false”);
    exit;
    }
    add_action(‘wp_logout’,’logout_redirect’);

  5. Thanks for this code. This is wonderful. However, while implementing this, I found some issues.

    1. The login page was not redirecting to admin dashboard
    2. However, the admin login bar was visible. But, when trying to access the admin dashboard, it was again redirecting to wp-login.php page.

    These two were the major issues and I have fixed those two and it works simply perfect now. Now it works like a cham and I enjoy this a lot.

    Thanks for sharing this code.

    1. Thanks for kind words.
      The answer to your issues.
      1. As this is custom login page so we don’t know how the user will use it like if he wants to redirect the customer to main dashboard or any other file.
      2. The code successfully logs you in to WordPress dashboard. But in code you change the behaviour.
      Thanks again.

  6. Hi, unfortunately I get 5 errors of the same type:
    Warning: Cannot modify header information

    When I log in correctly.

    While if the mistake on purpose everything works correctly.

    Why does this happen?
    Thanks a lot.

    Sincerely,
    Feduzi Matteo.

    1. Hello,
      Be sure you aren’t writing the PHP tag.
      Also, I am rewriting this tutorial.
      Thanks for stopping.

  7. $username = $wpdb->escape($_REQUEST[‘username’]);
    $password = $wpdb->escape($_REQUEST[‘password’]);
    $remember = $wpdb->escape($_REQUEST[‘rememberme’]);
    $wpdb->escape is deprecated since version 3.6’
    how to solve it?
    thanks for this tutorial

  8. I am Facing one issue, The login page is redirecting to the Home page and when I trying to access the admin dashboard, it was again redirecting to wp-login.php page

    1. Hi,
      Sorry for inconvenience.
      I am rewriting this tutorial please consider checking the article again, once it is updated.
      Thanks

  9. Hi

    I have wordpress wbesite, I want something like mentioned below:
    1st step: User login with UserName and Password (Traditional WP login form) – Its working well.
    Issues and not able to do below steps:
    2nd Step: User want to post or comments then a popup will come and ask DoB or mobile number etc(from usermeta table) to verify the user. If information is correct, he can post and if information is not correct show error message.

    Is it possible? If so, please help me.

    Reg.

    1. Hi,
      It is a long process. It is not possible to write this long tutorial. You can hire a developer (best option).
      Thanks

  10. Thank you for your post.
    I should like to keep the whole style of my website’s theme (footer, button style, etc).
    I have yet create a page with Elementor with a login form.
    How can I define this page as login page ?
    Thank you by forehand.

    1. Hi,
      Firstly, you can avoid adding the styles.
      Secondly, I am not a big fan of page builder plugins, so don’t know how the elementor works.
      I created the tutorial for general audience.
      Otherwise if you need any help with code please don’t hesitate to ask.
      Thanks.

  11. How to add login with Google to this custom login page.please tell.as I want to apply my styles to those button so plugins can’t be used

    1. Hi,
      Thanks for leaving a valuable comment. I will update the tutorial ASAP to adress the request made.

  12. thanks, Raashid for the tutorial, but I feel some parts are missing: for example, in the code, we are enqueuing some javascript scripts that are not in the tutorial… what do you think about creating a GitHub project or gist with all the code? I’ve followed the tutorial and I think a logout link could be useful too:
    I’ve implemented that one after line 56 in login-functions.php

  13. When I active plugin then show the error.
    The plugin could not be activated because it triggered a fatal error.

    Warning: require_once(/home/workdemo/public_html/walrus/wp-content/plugins/custom-plugin/shortcodeshttp://workdemo.me//walrus/wp-content/plugins/custom-plugin/login-shortcode.php): failed to open stream: No such file or directory in /home/workdemo/public_html/walrus/wp-content/plugins/custom-plugin/custom-login.php on line 26

    Fatal error: require_once(): Failed opening required ‘/home/workdemo/public_html/walrus/wp-content/plugins/custom-plugin/shortcodeshttp://workdemo.me//walrus/wp-content/plugins/custom-plugin/login-shortcode.php’ (include_path=’.:/opt/cpanel/ea-php74/root/usr/share/pear’) in /home/workdemo/public_html/walrus/wp-content/plugins/custom-plugin/custom-login.php on line 26

    1. Hi,
      Thank you for commenting.
      Please give me five minutes, I will provide the solution.
      Thanks

Leave a Reply

Your email address will not be published.

Back to top