Adding login AJAX form to your WordPress

Usually when building pages like web shops or specialized blogs with user base, you want to have the register or log in form on your page. A CMS like WordPress has all the functionality for logging in and registering embedded in it, but if you were to use just

<a href="<?php echo wp_login_url(); ?>" title="Login">Login</a>

you’d get redirected to a well known WordPress log in screen

WordPress login screen

WordPress login screen — a bit boring and not that user friendly.

But what if you want a bit better user experience? Wouldn’t it be better to stay on the page while logging in?

HTML preparations

First you’ll need to decide where you want your login button. For me it seems logical that that button is in the header, above the menu. For Twenty Sixteen theme, you can open header.php and add this code right under the begging of the header tag

<div class="top_bar">
<div class="container">
<div class="ajax_login">
<form id="login" action="login" method="post">
<h1><?php esc_attr_e('User login','yourtheme') ?></h1>
<p class="status"></p>
<input id="username" type="text" name="username" placeholder="<?php esc_attr_e('Username','yourtheme') ?>">
<input id="password" type="password" name="password" placeholder="<?php esc_attr_e('Password','yourtheme') ?>">
<div class="forgotten_box">
<a class="lost" href="<?php echo esc_url(wp_lostpassword_url()); ?>"><?php esc_attr_e('Lost your password?','yourtheme') ?></a>
<input class="submit_button" type="submit" value="Login" name="submit">
<?php wp_nonce_field( 'ajax-login-nonce', 'security' ); ?>
<div class="ajax_login_overlay"></div>
<?php if (is_user_logged_in()):?>
<a class="login_button" href="<?php echo wp_logout_url( home_url() ); ?>"><?php esc_attr_e('Logout','yourtheme') ?></a>
<?php else: ?>
<a class="login_button" id="show_login" href=""><?php esc_attr_e('Login','yourtheme') ?></a>
<?php endif; ?>

We’ve just added a top bar with our log in form — if you’re logged in a log out button appears, if you’re not, a log in button appears. Currently, without any styling we’ll get a visible form and button, and we want it to be a bit nicer, no? In your style.css add

/*------------------------ AJAX login -------------------------*/
text-align: right;
font-family: Montserrat, "Helvetica Neue", sans-serif;

.top_bar .ajax_login{
display: inline-block;
margin-right: 10px;

.top_bar .ajax_login_overlay{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgb(0,0,0);
background: rgba(0,0,0,0.5);
display: none;
cursor: default;
z-index: 101;
transform: translateZ(1px);

display: none;
background-color: #FFFFFF;
position: fixed;
top: 50%;
margin-top: -117px;
z-index: 999;
left: 50%;
margin-left: -200px;
cursor: default;
padding: 0 0 20px 0;

#login h1{
color: #fff;
background: #1a1a1a;
font-weight: 700;
text-transform: uppercase;
font-size: 15px;
padding: 8px 20px;
text-align: left;
margin-bottom: 25px;

#login p.status{
display: none;
padding: 0 20px;
margin-bottom: 12px;

#login input#username,
#login input#password{
margin: 10px 20px;
width: 400px;
display: block;
background: #f7f7f7;
background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0));
border: 1px solid #d1d1d1;
font-family: Montserrat, "Helvetica Neue", sans-serif;

#login .forgotten_box{
display: inline-block;
padding: 3px 20px 0 20px;

#login .forgotten_box .lost{
display: block;
padding: 5px;
padding-left: 0;
margin-bottom: 0;
-webkit-transition: all 180ms ease-in;
-moz-transition: all 180ms ease-in;
-o-transition: all 180ms ease-in;
transition: all 180ms ease-in;

#login input.submit_button{
padding: 15px;
margin-right: 20px;
float: right;
cursor: pointer;
-webkit-transition: all 180ms ease-in;
-moz-transition: all 180ms ease-in;
-o-transition: all 180ms ease-in;
transition: all 180ms ease-in;

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

.top_bar .ajax_login .login_button{
display: inline-block;
color: #0c0f0b;
font-size: 12px;
font-weight: 700;
line-height: 30px;
-webkit-transition: all 180ms ease-in;
-moz-transition: all 180ms ease-in;
-o-transition: all 180ms ease-in;
transition: all 180ms ease-in;

.top_bar .ajax_login .login_button:hover{
color: #d84949;

You’ve got yourself a nice button

Login button

Login button — great, now what?

And it would be nice if that button did anything :D Right now not much happens. You’ll need to set up AJAX call, and some JavaScript to manipulate the toggling of the login form, and you’ll need to set up the callback function for the log in as well.

Functions.php code

In our functions.php we’ll add

/********* AJAX Login ***********/
function yourtheme_ajax_login_init(){
wp_register_script('ajax-login-script', get_template_directory_uri() . '/js/ajax-login-script.js', array('jquery') );
wp_localize_script( 'ajax-login-script', 'ajax_login_object', array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'redirecturl' => home_url(),
'loadingmessage' => esc_html__('Sending user info, please wait...', 'yourtheme')
// 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', 'yourtheme_ajax_login_init');
if (!function_exists('ajax_login')) {
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'=> esc_html__('Wrong username or password.', 'yourtheme')));
} else {
echo json_encode(array('loggedin'=>true, 'message'=> esc_html__('Login successful, redirecting...', 'yourtheme')));

We need to enqueue our scripts and localizations first. We need our trusty admin-ajax.php , a redirect link that will point to our home page, and a loading message that will be displayed while the log in process is happening. Next, we want to execute the login action, only if we’re not logged in — it doesn’t do us much good if we have the functionality if we’re logged in already, we want it to execute when we need it — and that’s when we’re logged out.
 And lastly, our AJAX callback function that is checking the nonce, storing the login info into an array and then signs us up using wp_signon() function.


Now for the fun part. In our ajax-login-script.js that we placed in the js/ folder add the following code

jQuery(document).ready(function($) {
"use strict";

// Show the login dialog box on click
$('a#show_login').on('click', function(e){

$('.ajax_login_overlay').on('click', function(e){
$('.ajax_login .status').html('');
$('form#register_form .field input').val('');

// Perform AJAX login on form submit
$('form#login').on('submit', function(e){
$('form#login p.status').show().text(ajax_login_object.loadingmessage);
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;


First thing we wrote is what will happen when we click our log in box — a modal window will show with username and password — our login form. A bit of simple fading in and out. And on the ‘log in’ button press on the form we’ll execute our AJAX call. Also notice that when you click outside of the modal that your modal will close.

And that’s it. Simple no? Now you’ve got a fully functional AJAX login form that you can style how ever you like.

Log in form

A login form that you can style any way you want :)

If you have any questions let me know in the comments below. I’m planning to add a register functionality next, so stay tuned for that one :) Happy coding!

Originally published at Made by Denis.

Show your support

Clapping shows how much you appreciated Denis Žoljom’s story.