Menu

WordPress AJAX Login Without a Plugin – The Right Way

When doing anything AJAX-based with WordPress you need to make sure you are doing it right. In this article you will come across several techniques that are considered to be the best way of doing AJAX, as described on the Codex and many other websites.

One thing to keep in mind is that WordPress has a tone of functions that you can use to make your job a lot easier. For painless user login feature these functions will be used in this article:

By following this article you will be able to create a nice login box that pops out on click and checks for user credentials.

Login concepts

First off, there's a couple of ways that you can implement login on your website. You could create a special Page called "Login" and display the form on an empty page with page-login.php template (kind of what you have by default when visiting /wp-admin). Second option is to keep the login form visible all the time above the header or in the sidebar. Third option is to call a login box when you click on a "Login" button/link. This is the option that's going to be described in this article but you can easily apply this technique on any Login concept you want.

HTML markup

Form has to be placed anywhere inside the <body> tag and for this article it is preferred you put it right at the beginning. The tag is usually found in header.php file of your theme.

header.php
<body>
    <form id="login" action="login" method="post">
        <h1>Site Login</h1>
        <p class="status"></p>
        <label for="username">Username</label>
        <input id="username" type="text" name="username">
        <label for="password">Password</label>
        <input id="password" type="password" name="password">
        <a class="lost" href="<?php echo wp_lostpassword_url(); ?>">Lost your password?</a>
        <input class="submit_button" type="submit" value="Login" name="submit">
        <a class="close" href="">(close)</a>
        <?php wp_nonce_field( 'ajax-login-nonce', 'security' ); ?>
    </form>
    ...

At the end of the form there is a wp_nonce_field function which creates a hidden field with ID "security" and value "ajax-login-nonce" but in hashed form. If you refresh your page after applying the code above you will see an ugly HTML form on top. We also need a login button, so place that anywhere you want.

header.php
<?php if (is_user_logged_in()) { ?>
    <a class="login_button" href="<?php echo wp_logout_url( home_url() ); ?>">Logout</a>
<?php } else { ?>
    <a class="login_button" id="show_login" href="">Login</a>
<?php } ?>

That's the HTML part, let's go ahead and style it so the form only shows up when user clicks the login link.

Styling the login box

This is the minimum required CSS that you can put inside your style.css. Use this as a starting point for your styling or if you want a fully styled form just click "expand code" in the bottom right.

style.css
form#login{
    display: none;
    background-color: #FFFFFF;
    position: fixed;
    top: 200px;
    padding: 40px 25px 25px 25px;
    width: 350px;
    z-index: 999;
    left: 50%;
    margin-left: -200px;
}

form#login p.status{
    display: none;
}

.login_overlay{
    height: 100%;
    width: 100%;
    background-color: #F6F6F6;
    opacity: 0.9;
    position: fixed;
    z-index: 998;
}
expand code +
form#login{
    display: none;
    background-color: #FFFFFF;
    border-radius: 8px;
    font-family: Arial, Helvetica, sans-serif;
    box-shadow: 0 0 6px rgba(0, 0, 0, 0.2);
    position: fixed;
    top: 200px;
    padding: 40px 25px 25px 25px;
    width: 350px;
    z-index: 999;
    left: 50%;
    margin-left: -200px;
    color: #878787;
    font-size: 11px;
}

form#login h1{
    color: #333333;
    font-family: 'Georgia', 'Times New Roman', Times, serif;
    font-size: 27px;
    font-weight: 100;
    text-align: center;
    line-height: 1;
    margin: 0 0 30px 0;
}

form#login input#username,
form#login input#password{
    border: 1px solid #EDEDED;
    border-radius: 3px 3px 3px 3px;
    box-shadow: 0 0 3px rgba(0, 0, 0, 0.1) inset;
    color: #333333;
    font-size: 15px;
    padding: 10px 10px 10px 13px;
    width: 325px;
    margin: 7px 0 30px 0;
    background-color: #F9F9F9;
    font-family: 'Georgia', 'Times New Roman', Times, serif;
}

form#login input#username:focus,
form#login input#password:focus{
    background-color: #FFF;
}


form#login input.submit_button{
    font-size: 13px;
    color: #FFF;
    border: 1px solid #b34336;
    background-color: #e25c4c;
    border-radius: 3px;
    text-shadow: 0 1px 0 #ba3f31;
    padding: 9px 31px 9px 31px;
    background: -moz-linear-gradient(top, #ea6656, #df5949);
    border-top: 1px solid #bb483a;
    border-bottom: 1px solid #a63b2e;
    float: right;
    box-shadow: 0 1px 0 #E87A6E inset;
}

form#login a{
    text-decoration: none;
}

form#login a.close{
    color: #DCDCDC;
    position: absolute;
    right: 15px;
    top: 15px;
}

form#login a.lost{
    color: #B4B2B2;
    float: left;
    margin: 10px 0 0 0;
}

form#login p.status{
    text-align: center;
    margin: -25px 0 20px 0;
    display: none;
}

a.login_button{
    font-family: Arial, Helvetica, sans-serif;
    padding: 5px 7px 5px 7px;
    background-color: #FFF;
    border-radius: 3px;
    border: 1px solid #DCDCDC;
    color: #333;
    text-decoration: none;
    font-size: 11px;
}

.login_overlay{
    height: 100%;
    width: 100%;
    background-color: #F6F6F6;
    opacity: 0.9;
    position: fixed;
    z-index: 998;
}

Sending user info via AJAX

When the user fills out the form with his username and password we need to send that data to the server, see if the inserted data is correct and, based on the fact , notify the user that the login was successful and perform the login or just notify him that his data is incorrect.

All of the server-side checking code will be placed inside of theme's functions.php file. We'll create a function that will include our JS file, create a new JS object called ajax_login_object and enable the users with no privileges (not logged in) to call our function.

functions.php
function ajax_login_init(){

    wp_register_script('ajax-login-script', get_template_directory_uri() . '/ajax-login-script.js', array('jquery') ); 
    wp_enqueue_script('ajax-login-script');

    wp_localize_script( 'ajax-login-script', 'ajax_login_object', array( 
        'ajaxurl' => admin_url( 'admin-ajax.php' ),
        'redirecturl' => home_url(),
        'loadingmessage' => __('Sending user info, please wait...')
    ));

    // Enable the user with no privileges to run ajax_login() in AJAX
    add_action( 'wp_ajax_nopriv_ajaxlogin', 'ajax_login' );
}

// Execute the action only if the user isn't logged in
if (!is_user_logged_in()) {
    add_action('init', 'ajax_login_init');
}

Notice the wp_ajax_nopriv_ajaxlogin hook, it's the most important part. If you leave out "nopriv" and use wp_ajax_ajaxlogin then only users that are logged in can access the function. We continue by making a function which collects the data received from POST method, checks if the nonce is valid and then tries to perform user login with the received data.

functions.php
function ajax_login(){

    // First check the nonce, if it fails the function will break
    check_ajax_referer( 'ajax-login-nonce', 'security' );

    // Nonce is checked, get the POST data and sign user on
    $info = array();
    $info['user_login'] = $_POST['username'];
    $info['user_password'] = $_POST['password'];
    $info['remember'] = true;

    $user_signon = wp_signon( $info, false );
    if ( is_wp_error($user_signon) ){
        echo json_encode(array('loggedin'=>false, 'message'=>__('Wrong username or password.')));
    } else {
        echo json_encode(array('loggedin'=>true, 'message'=>__('Login successful, redirecting...')));
    }

    die();
}

All that's left is making the "login" button show our form and sending the form data with AJAX to the function above. Create a file called "ajax-login-script.js" and place it inside your theme's folder.

ajax-login-script.js
jQuery(document).ready(function($) {

    // Show the login dialog box on click
    $('a#show_login').on('click', function(e){
        $('body').prepend('<div class="login_overlay"></div>');
        $('form#login').fadeIn(500);
        $('div.login_overlay, form#login a.close').on('click', function(){
            $('div.login_overlay').remove();
            $('form#login').hide();
        });
        e.preventDefault();
    });

    // Perform AJAX login on form submit
    $('form#login').on('submit', function(e){
        $('form#login p.status').show().text(ajax_login_object.loadingmessage);
        $.ajax({
            type: 'POST',
            dataType: 'json',
            url: ajax_login_object.ajaxurl,
            data: { 
                'action': 'ajaxlogin', //calls wp_ajax_nopriv_ajaxlogin
                'username': $('form#login #username').val(), 
                'password': $('form#login #password').val(), 
                'security': $('form#login #security').val() },
            success: function(data){
                $('form#login p.status').text(data.message);
                if (data.loggedin == true){
                    document.location.href = ajax_login_object.redirecturl;
                }
            }
        });
        e.preventDefault();
    });

});

That's it! You have a nice looking AJAX login form now. Article covered the best way to do AJAX in WordPress but you should also consider adding a frontend validation to the form.

Comments? Questions? Feedback is welcome!