Authorization and registration on Ajax in WordPress

The use of “Ajax” is one of the most common methods of creating and working with user interfaces.

Using this technology allows you to perform invisible background processing of data (without reloading the page), which greatly improves the process of user interaction with the site.

As an example, the work of Ajax in WordPress can be seen in the admin panel if you open the browser console and go to the tab “Network”, but, as elsewhere, in WordPress has its own features of working with asynchronous JavaScript and in this article we will look at them.

The theory of using Ajax in WordPress

Since the bearded version of the kernel 2.8, WordPress allows you to create your own events using built-in Ajax, but it is worth understanding that there are a number of rules that must be followed:

  • All requests must be passed using the admin-ajax.php file, no need to write your own handlers.
  • The rights to use events processing asynchronous requests must be properly delimited.
  • The use of nonce (Hash, with a defined life cycle), greatly reduces the likelihood of misuse of the event.
  • The event should end with wp_die(), not die() or exit(). Third-party developers often use filtering function wp_die(), do not deprive them of this possibility. Besides, this function is useful to debug your code.
  • As you can see, the rulebook is quite short and does not have any critical limitations.

Practicing Ajax in WordPress

The first thing we have to do is to create HTML markup for registration/authorization forms and style them.

<div class="wpz_flex wpz_holder">
	<div class="wpz_login">
		<p class="wpz_heading">Authorization</p>
		<form data-type="authorization" autocomplete="false">
			<div class="wpz_flex">
				<div>
					<label>Login or E-mail</label>
					<input type="text" name="wpz_login" placeholder="Login" required="">
				</div>
				<div>
					<label>Password</label>
					<input type="password" name="wpz_password" placeholder="******" autocomplete="false" required="">
				</div>
			</div>
			<input type="submit" name="wpz_submit" value="Log in"><span class="wpz_loading">Processing...</span>
			<div class="wpz_alert"></div>
		</form>
	</div>
	<div class="wpz_registration">
		<p class="wpz_heading">Registration</p>
		<form data-type="registration" autocomplete="off">
			<div>
				<label>Desired login</label>
				<input type="text" name="wpz_login" placeholder="Username" aria-required="">
				<label>E-mail address</label>
				<input type="email" name="wpz_email" placeholder="E-mail">
			</div>
			<div>
				<label>Password</label>
				<input type="password" name="wpz_password" placeholder="Password" required="">
			</div>
			<input type="submit" name="wpz_submit" value="Sign up"><span class="wpz_loading">Processing...</span>
			<div class="wpz_alert"></div>
		</form>
	</div>
</div>

It’s worth keeping in mind that your theme’s style sheet may partially overlap the styles of the forms we are working with.

To begin, we suggest that you don’t change the HTML markup used in this tutorial, but simply copy and paste it into the body of the page using the HTML element in the Block Editor.

The scripts in this tutorial will rely on this markup.

JS script initialization event

Insert this code into functions.php of your theme (preferably a child theme):

// Add an event to the JS scripts initialization process.
add_action( 'wp_enqueue_scripts', 'wpz_ajax_enqueue' );

// Describe the event.
function wpz_ajax_enqueue() {

	// Connect the js file of the script.
	wp_enqueue_script(
		'wpz-ajax', // Name.
		get_stylesheet_directory_uri() . '/scripts/wpz-ajax.js', // Path to JS file.
		array('jquery') // In the jquery array.
	);

	// Use the wp_localize_script function to pass variables to the JS script.
	wp_localize_script(
		'wpz-ajax', // Where do we pass it on to.
		'wpz_ajax_obj', // The name of the array that will contain the data to be transferred.
		array(
			'ajaxurl' => admin_url( 'admin-ajax.php' ), // Array element containing the path to admin-ajax.php
			'nonce'   => wp_create_nonce('wpz-nonce') // Create a nonce.
		)
	);
}

The first thing we do is hook the scripts initialization event to register our own *.js.

Note that we use get_stylesheet_directory_uri() function to specify path to new JS file as we work in child theme. If you work in parent theme use function get_template_directory_uri().

Thanks to function wp_localize_script(), and in file /scripts/wplb-ajax.js, there will be available an object with data that we send from PHP. Keep in mind that you can use this method to send any kind of data, both static data from the database and the results of loops.

Initial body of the plugged in script

To begin, the contents of the file wplb-ajax.js, which should be located in the wp-content/my_theme/scripts folder, will be

jQuery(document).ready(function ($) {
	'use strict';
	'esversion: 6';

	// Function for sending forms.
	$('.wpz_holder').on('submit', 'form', function (ev) {
		// Determine which form the user filled out.
		let this_is = $(this);

		// Define the button.
		let button = $(this).find('input[type="submit"]');

		// Define the type of form.
		let type = $(this).attr('data-type');

		// Send an Ajax request to WordPress.
		$.ajax({

			// Path to file admin-ajax.php.
			url: wpz_ajax_obj.ajaxurl,

			// Create an object containing sending parameters.
			data: {

				// The event to which we are going to refer.
				'action': 'wpz_ajax_request',

				// Передаём тип формы.
				'type': type,

				// Passing the values of the form.
				'content': $(this).serialize(),

				// We use nonce for protection.
				'security': wpz_ajax_obj.nonce,

				// Before sending Ajax to WordPress.
				beforeSend: function () {}
			}
		})
		.always(function() {
			// Run after each Ajax request.

		})
		.done(function(data) {
			// Function for working with processed data.

		})
		.fail(function(errorThrown) {
			// We will read the errors in the console if something does not go according to plan.

			console.log(errorThrown);
		});

		// Prevent an action that is embedded in the default form.
		ev.preventDefault();
	});

});

Note that two directives are used:

  • use strict – this is the so-called “strict mode”, which markedly limits the syntax you can use. Thanks to this you can be 100% sure that the script will work properly in all browsers.
  • esversion: 6 means that we use ECMAScript version 6 syntax, which was released in 2015, so there is no doubt about browser compatibility. You can also use newer versions up to version 11 (Release Date: June 2020), but at your own risk. It is not recommended to downgrade.

You may have noticed that the .on() function is used, like this:

$('.wpz_holder').on('submit', 'form', function (event) {});

Instead of the simple and familiar:

$( "form" ).submit(function( event ) {});

The point is that the .on() function allows you to refer to elements dynamically added to the DOM (Document Object Model).

If you imagine that as a result of some event a new block element with a link appeared on the page:

<div id="wpz_new_element">
	<a href="#" id="wpz_read_more">Read more..</a>
</div>

If the link is to be clicked, then:

// It won't work that way:
$('#wpz_read_more').click(function(event){});

// This is how it will work:
$('#wpz_new_element').on('click', '#wpz_read_more', function (event) {});

The design of the $.ajax({}) function itself is quite simple, and we have added comments for each line. But it’s worth noting that we use the wplb_ajax_obj object, which we created when we initialized the script itself.

The event that will handle Ajax in WordPress core, in our case is called wplb_ajax_request.

Let’s create it.

Ajax processing event in WordPress

Back in functions.php add the following code:

// Create an Ajax processing event in a WordPress theme.
add_action( 'wp_ajax_nopriv_wpz_ajax_request', 'wpz_ajax_request' );
// add_action( 'wp_ajax_wpz_ajax_request', 'wpz_ajax_request' );

// Describe the function itself.
function wpz_ajax_request() {

	// The $_REQUEST variable contains all the data of the forms that have been filled out.
	if ( isset( $_REQUEST ) ) {

		// Check the nonce, and if something went wrong, we interrupt the function.
		if ( ! wp_verify_nonce( $_REQUEST[ 'security' ], 'wpz-nonce' ) ) {
			wp_die( 'Basic protection not passed' );
		}

		// Let's introduce a variable that will contain an array with the result of the event.
		$result = array( 'status' => false, 'content' => false );

		// Create an array that contains the values of the fields of the filled form.
		parse_str( $_REQUEST[ 'content' ], $creds );

		switch ( $_REQUEST[ 'type' ] ) {
			case 'registration':
				/**
				 * The registration form is filled out.
				 */
				break;
			case 'authorization':
				/**
				 * Filled out the authorization form.
				 */
				break;
		}

		// Convert the array with the processing results and send it back as a string in JSON format.
		echo json_encode( $result );

	}

	// Finishing the Ajax job.
	wp_die();
}

To create the event itself the hook wp_ajax_action_name is used, where action_name is the name of the event, in our case wplb_ajax_request, but the prefix can be two:

  • wp_ajax_nopriv_wplb_ajax_request, the event will only be available to unauthorized users (guests).
  • wp_ajax_wplb_ajax_request – only for authenticated users.

It turns out that if we need Ajax that will work for both guests and authorized users of the WordPress site, we need to create both events at the same time!

We also introduced a variable $result, which will contain an array with the results of processing, and the array itself is converted to JSON format string and sent back to the browser.

It’s time to start working with users.

User Registration

When the form is submitted, the serialize() function will write all data from completed form into global variable $_REQUEST and as an array element.

Let’s start with the registration form, which means we are interested in the “registration” case where we use the switch operator.

Insert the following code:

case 'registration':
	/**
	 * The registration form is filled out.
	 */

	// Try to create an object with a user.
	$user = username_exists( $creds[ 'wplb_login' ] );

	// Check to see if there is already such a user.
	if ( ! $user && false === email_exists( $creds[ 'wplb_email' ] ) ) {
		// The user does not exist.

		// Create an array with the data for registering a new user.
		$user_data = array(
			'user_login'   => $creds[ 'wplb_login' ], // Login.
			'user_email'   => $creds[ 'wplb_email' ], // Email.
			'user_pass'    => $creds[ 'wplb_password' ], // Password.
			'display_name' => $creds[ 'wplb_login' ], // Display name.
			'role'         => 'subscriber' // Role.
		);

		// Adding a user to the database.
		$user = wp_insert_user( $user_data );

		// Check for errors.
		if ( is_wp_error( $user ) ) {

			// Unable to create a user, write the result to an array.
			$result[ 'status' ]  = false;
			$result[ 'content' ] = $user->get_error_message();

		} else {

			// Create an array for authorization.
			$creds = array(
				'user_login'    => $creds[ 'wplb_login' ], // User login.
				'user_password' => $creds[ 'wplb_password' ], // User Password.
				'remember'      => true // Remember.
			);

			// Trying to authorize a user.
			$signon = wp_signon( $creds, false );

			if ( is_wp_error( $signon ) ) {

				// It did not work to authorize it.
				$result[ 'status' ]  = false;
				$result[ 'content' ] = $signon->get_error_message();

			} else {

				// Authorization is successful, set the necessary cookies.
				wp_clear_auth_cookie();
				clean_user_cache( $signon->ID );
				wp_set_current_user( $signon->ID );
				wp_set_auth_cookie( $signon->ID );
				update_user_caches( $signon );

				// Write the results to an array.
				$result[ 'status' ] = true;
			}

		}
	} else {

		// Such a user already exists, registration is not possible, write data to the array.
		$result[ 'status' ]  = false;
		$result[ 'content' ] = esc_html__( 'The user already exists', 'wplb_ajax_lesson' );
	}
	break;

It’s simple enough. If the circumstances are favorable, the user will be registered and authorized, and if not, thanks to the error handler built into WordPress, we’ll know exactly what went wrong.

Simply put, the result of the processing will return to the wplb-ajax.js file 100% of the time.

Let’s see what we can do with the data received back.

User authorization

We have described the authorization process in a block related to registration, and since we’re not going to multiply Ajax requests in WordPress, we’ll just copy and paste a piece of code in the right place:

case 'authorization':
	/**
	 * Filled out the authorization form.
	 */

	// Create an array for authorization.
	$creds = array(
		'user_login'    => $creds[ 'wplb_login' ], // User login.
		'user_password' => $creds[ 'wplb_password' ], // User Password.
		'remember'      => true // Remember.
	);

	// Пробуем авторизовать пользователя.
	$signon = wp_signon( $creds, false );

	if ( is_wp_error( $signon ) ) {

		// It did not work to authorize it.
		$result[ 'status' ]  = false;
		$result[ 'content' ] = $signon->get_error_message();

	} else {

		// Authorization is successful, set the necessary cookies.
		wp_clear_auth_cookie();
		clean_user_cache( $signon->ID );
		wp_set_current_user( $signon->ID );
		wp_set_auth_cookie( $signon->ID );
		update_user_caches( $signon );

		// Write the results to an array.
		$result[ 'status' ] = true;
	}

	break;

That’s the end of the input data processing, let’s go back to the JavaScript file and work with the data that came back.

Response processing in js

Before we do anything with the data we have processed and sent back, let’s see what we can do before we send it out in the first place.

We describe the beforeSend: function () {}):

// Before sending an Ajax request to the WordPress core.
beforeSend: function () {

	// Let's hide the button and show the user that the script works.
	button.hide();
	this_is.find('.wpz_alert').hide();
	this_is.find('.wpz_loading').show();
}

It’s simple, we hid the form submit button and showed a pseudo-spinner to visualize the process.

Now let’s describe the process of visualizing the returned data:

.done(function(data) {
	// Function for working with processed data.

	// The variable $reslut will store the result of processing.
	let $result = JSON.parse(data);

	// Проверяем какой статус пришел.
	if ( $result.status == false ) {

		// An error came, hide unnecessary elements and return the button.
		this_is.find('.wpz_alert').addClass('wpz_alert_error').html($result.content).show();

		button.show();

	} else {

		// The user is authorized, let's show him the message.
		$('.wpz_holder').addClass('wpz_alert wpz_signon').html('<p style="margin-bottom:3px;"><strong>Welcome!</strong></p>Ajax has done its job, you\'re in! Reload the page and make sure.');
	}

})

Since the code is very simple and contains comments, there is no point in describing it.

Afterword and the source code

As you can see, using Ajax in WordPress is very simple, but keep in mind that within this tutorial we have omitted several important points and offer you to deal with them yourself:

  • Automatic password generation or a second field to enter the password.
  • Sending a notification of new user registration with all the data for authorization.
  • Implementation of the logout process.
  • Implementation of the process of restoring or resetting the password.

For this lesson, we have prepared all the sources, and form wrapped in shortcode for more convenient use. You can download it here.

Instructions:

  • Add the contents of the functions.php file from the archive to the end of the file with the same name (functions.php) of your theme.
  • Copy the wplb_ajax_template.php file into the root folder of your WordPress theme.
  • In the root folder of your theme, create a scripts folder and put the wplb-ajax.js file there
  • Paste this shortcode into the body of the page, any method you like, removing any extra spaces:
[wpz_ajax_example]

How useful is the publication?

Click on a star to rate it!

Average score 5 / 5. Number of grades: 1

No ratings yet. Rate it first.

Similar posts

WordPress Template Hierarchy full guide

A guide to the template hierarchy in WordPress All modern WordPress themes consist of templates, style sheets, javascript, and images. Together, these files determine how your site will look to users. Templates with specific names affect certain areas of your website. Generally, a WordPress theme should contain templates for displaying categories, dates, archives, individual posts,…
Read more

What are plugins in WordPress and how do they work?

If you’re new to WordPress, you’re probably asking yourself: “What are plugins in WordPress?” This is a fairly common question because, in addition to introducing one of many new terms into your vocabulary, WordPress plugins are also an important building block of every single WordPress site. This article will answer your question, and then we’ll…
Read more

How to install a plugin on WordPress – a step-by-step guide for beginners

Installing plugins on WordPress using the admin panel is so easy that you’ll probably never need the skills to manually install plugins via FTP/SFT or using WP-CLI. But the technical part can be useful if the WordPress plugin directory is overloaded or not available at all. Installing plugins on WordPress from a repository The easiest…
Read more