Change Password using AJAX and jQuery in WordPress Front-End

Recently, a client asked me to add a feature where users will be forced to change their passwords the first time they log-in into their account. The structure of the project website is a bit different because the client wants to be the one creating the accounts and give them to people. That was why the force change-password feature was needed.

Of course the feature is easy to do using just plain PHP and HTML, but if you are like me who wants to take small bits of modules into the next level then you might probably want to check out this tutorial on how to create an ajaxified Change Password that runs on the Front-end.

So why use AJAX on the client-side instead of PHP? – AJAX allows web pages to be updated asynchronously by exchanging small amounts of data with the server behind the scenes. This means that it is possible to update parts of a web page, without reloading the whole page. Classic web pages, (which do not use AJAX) reloads the entire page for the content to change, which, in my opinion, is slower. So that is why I prefer AJAX for client-side processing.

So let’s start building the form where people will be inputting their new password.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Change Password Form -->
<article class="change-password-content">          
    <div class = "change-password-messages">
        <p>You must change your password before you can access any part of our website.</p>
    </div>
    <div class = "change-password-form">
        <label for="password"><?php _e('New Password'); ?></label><br />
        <input type="password" class="form-control password1" />
       
        <label for="password2"><?php _e('Re-enter New Password'); ?></label><br />
        <input type="password" class="form-control password2" />
       
        <input type="submit" name="change-password" value="<?php _e('Change Password'); ?>" class="btn-change-pass" />  
    </div>
</article>

If you notice, the above code is not really a form. This is basically because we are submitting the inputs using AJAX and values on fields will be pulled out using jQuery. Although there is an AJAX Form plugin that can be used in actual forms, but we are not really going to use that on this tutorial since I want to demonstrate how you can achieve an ajaxified change password form using best practices in WordPress.

Now lets check out the script bellow which we will be using for client-side processing. (Explanations are on the codes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<script>
$(document).ready(function() {
    // Define admin-ajax for front-end usage
    var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
   
    // Inlcude the jquery-ui.min.js to be able to use this form validation function
    function cvf_form_validate(element) {
        element.effect("highlight", { color: "#F2DEDE" }, 1500);
        element.parent().effect('shake');
    }
   
    // Detect if button with a class "btn-change-pass" was clicked
    $('body').on('click', '.btn-change-pass', function(e) {
       
        // Validate empty fields or mismatched passwords
        if ($('.change-password-form .password1').val() === '') {
            cvf_form_validate($('.password1'));
        } else if ($('.change-password-form .password2').val() === '') {
            cvf_form_validate($('.password2'));
        } else if ($('.change-password-form .password2').val() !== $('.change-password-form .password1').val()) {
            $(".change-password-messages").html('<p class = "bg-danger"><span class = "glyphicon glyphicon-remove-circle"></span>&nbsp; Passwords do not match</p>');
        } else {
            // if everything is validated, we're ready to send an AJAX request
           
            // Defining your own loading gif image
            $(".change-password-messages").html('<p><img src = "<?php bloginfo('template_url'); ?>/images/loading.gif" class = "loader" /></p>');
           
            // Define the ajax arguments
            var data = {
                'action': 'cvf_ngp_change_password',
                'cvf_action': 'change_password',
                'new_password': $('.change-password-form .password2').val()
            };
           
            $.post(ajaxurl, data, function(response) {
                // Detect the recieved AJAX response, then do the necessary logics you need for each specific response
                if(response === 'success') {
                    $(".change-password-messages").html('<p class = "bg-success">Password Successfully Changed <br /><a href = "<?php echo home_url(); ?>">Click here to continue</a></p>');
                    $('.change-password-form').hide(); 
                } else if (response === 'error') {
                    $(".change-password-messages").html('<p class = "bg-danger"><span class = "glyphicon glyphicon-remove-circle"></span>&nbsp; Error Changing Password</p>');
                    $('.change-password-form').show(); 
                }
            });
        }
    });
});
</script>

Basically what the above code does is it validates the user inputs, all of this is happening on the client-side. If all the inputs are correct then we can start sending the value of either the first or second input field which contains the password. In my case, I am sending the value of the second input field and I retrieved it by simply using the .val() function as seen bellow:

1
$('.change-password-form .password2').val()

If you notice, other parameters are also sent: “action” and “cvf_action”. “action” is a required parameter which is used by the admin-ajax.php of WordPress to identify the PHP function that will handle the request, in my case I used the cvf_ngp_change_password() function. while the “cvf_action” is just something I use to check if the post has been received on the server side.

Finally, let’s take a look at the server side processing script using PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
add_action('wp_ajax_cvf_ngp_change_password', array('NGP_Users', 'cvf_ngp_change_password') );
add_action('wp_ajax_nopriv_cvf_ngp_change_password', array('NGP_Users', 'cvf_ngp_change_password') );

function cvf_ngp_change_password() {
       
    global $current_user;
   
    if(isset($_POST['cvf_action']) && $_POST['cvf_action'] == 'change_password') {
       
        //Sanitize received password
        $password = sanitize_text_field($_POST['new_password']);
       
        // Define arguments that will be passed to the wp_update_user()
        $userdata = array(
            'ID'        =>  $current_user->ID,
            'user_pass' =>  $password // Wordpress automatically applies the wp_hash_password() function to the user_pass field.
        ); 
        $user_id = wp_update_user($userdata);
       
        // wp_update_user() will return the user_id on success and an array of error messages on failure.
        // so bellow we are going to check if the returned string is equal to the current user ID, if yes then we proceed updating the user meta field
        if($user_id == $current_user->ID){
            update_user_meta($current_user->ID, 'ngp_changepass_status', 1);
            echo 'success';
           
        } else {
            echo 'error';
        }  
    }
    // Always exit to avoid further execution
    exit();
}

So what we did on the above code is we simply received the password that was sent by our client script, then we sanitize the field to make sure that we are safe from any possible SQL injections. After that we proceeded to the updating of the password using the function wp_update_user() which returns the ID of the user on success and an array of errors on failure. We then checked if the returned ID and the current user id are the same(or updated succesfully), if yes we update the user meta status to 1 which we can use later on to verify if the user has already changed their password or not.

If you want to force your users to change their password, include the code bellow before the get_header() function of your page template.

1
2
3
4
5
6
7
8
global $current_user;

$changepass_status = get_user_meta($current_user->ID, 'ngp_changepass_status', true);

if (!is_super_admin() && $changepass_status != 1) {
    wp_redirect(home_url('/change-password/'));
   
}

The above code will check if the “ngp_changepass_status” meta key exists or not equal to 1 (0 or empty means the password hasn’t been changed yet). If not existing or not equal to 1, we redirect them to our Change Password page.