Learning To Master The Basics Of AJAX

Posted on September 30, 2014 by in Tips & Tricks | 8 comments

Learning To Master The Basics Of AJAX

Last week I introduced you to the magic of AJAX and showed you how to use a few plugins to easily “AJAXify” your WordPress site. By “AJAXify” I mean using AJAX to change the page, already loaded in the browser, without refreshing the page. You can’t do that using pure PHP, the language that WordPress uses to turn a template into a page view, since PHP runs on your server not in the browser.

Since AJAX is run using the JavaScript library jQuery, which does run in the browser, it can be used to make a separate request for data from the server. Once that request is complete, that data can be used in the current page with some simple jQuery.

Today I’m going to show you some basic patterns for using AJAX to get new data and use it in a page that is already loaded. I will cover how the request works, and how to insert the response into the page using jQuery. In addition I will show you how to connect the AJAX request to a WordPress hook, so you can control what data is returned using PHP. Most importantly we will talk about how to do it securely.

Before we begin, I should say that this is not a beginner topic. It’s not too hard, but you should have a basic idea of what AJAX is, which I explained last week, how hooks work in WordPress, which I wrote about a few weeks ago and a basic knowledge of jQuery.

Anatomy Of An AJAX Request

Before diving into the specifics of how this all works, let’s begin by touching briefly on each of the steps in the process of making an AJAX request and getting the data into the browser. I’ll address each of these steps in depth, but its helpful to have an overview of the process before going into the individual parts in detail.

When you make a request, it’s usually triggered by a JavaScript event, for example, when a specific link is clicked. That means we will need a JavaScript file added to our theme that we can write the jQuery for both making the AJAX requests and for putting the response of the request onto the page.

Once the request is made, the browser needs to know where the file in WordPress that it can use to process the request is. That means we’ll need to make the URL for that file available. We’ll also want to make sure that the action can’t be triggered by a third-party so we’ll need to add a nonce as well.

Once the request is triggered WordPress will attempt to do an action, so we will need to hook a callback function to that action. We’ll also need to write that callback. Once that callback function is processed it will send data back to the browser, which we call the response. We’ll need to write a little jQuery to do something with that data, for example display it on the current page.

I know that sounds like a lot, but we can break it down into 3 steps.

Preparing To Use jQuery

The first step is to add our JavaScript file and make sure it has everything it needs. What it needs is to have jQuery available, the URL for WordPress’ AJAX processor and a nonce to use for security. We can do all of that inside of a function hooked to wp_enqueue_scripts().

In our callback function we will need to do 2 things. The first is enqueue our JavaScript file. The second is use wp_localize_script to add our nonce and the AJAX URL.

add_action( 'wp_enqueue_scripts', 'slug_ajax_scripts' );
function slug_ajax_scripts() {
   if ( ! is_admin() ) {
       wp_enqueue_script( 'slug-ajax', get_stylesheet_directory_uri() . 'js/slug-ajax.min.js', array ( 'jquery' ), false, true );
       $jp = array(
           'nonce' => wp_create_nonce( 'nonce' ),
           'ajaxURL' => admin_url( 'admin-ajax.php' ),
       ); 
       wp_localize_script( 'slug-ajax', 'jp', $jp ); 
   }
}

Thanks to what we’ve done with wp_localize_script(), whenever our JavaScript is loaded, an object will be available to all JavaScript. In this case it’s called “jp” since that’s the second argument we passed to wp_localize_script(). Its contents are from the PHP array in the third argument. That means in our JavaScript we will be able to use ‘jp.nonce’ and ‘jp.ajaxURL’.

You will also need to make sure to create that file in your theme or child theme. In the new JavaScript file, for now, just add a no conflict wrapper:

jQuery(document).ready(function($) {

});

This will allow everything inside of it to use $ as an alias for jQuery and to run when the page is loaded.

Building An Ajax Request

For now, let’s build a simple AJAX request that will run whenever a link with the ID “ajax-trigger” is clicked on and return a specific post’s title into a container with the ID of “ajax-target”. Later on I’ll show you how to pass variables with the request so we can make it more dynamic, but let’s start simple.

Before we begin, make sure on the page you have has the trigger link and an empty container to load the results into. That means this HTML must be present:

<a href="#" id="ajax-trigger">trigger</a>
<div id="ajax-target"></div>

Now in your JavaScript file, let’s write a basic AJAX request:

$.get(
       jp.ajaxURL, {
           'action': 'jp_ajax_test',
           'nonce' : jp.nonce,
       },
       function( response ) {
             $( '#ajax-target' ).append( response );
       }
   );
}

This request, right now will send two things to the URL defined in jp.ajaxURL, which is the URL for WordPress’ AJAX processor, which we set up in the last step. The first is the WordPress action to trigger, “jp_ajax_test” and the second is the nonce stored in jp.nonce, which is the nonce we setup in the last step.

The second half is the callback function that works with the response. Inside of it, we just take the response and use jQuery’s append method to add it to the “#ajax-target” container.

You might have noticed already that this code needs to be attached to an event, which is the next step, so it’s not actually going to ever run. We can use jQuery’s click() method to easily set this to run when “#ajax-trigger” is clicked. So let’s put our code inside of that. While we’re add it let’s add a console.log() before the AJAX to make sure the click event works properly, since we haven’t actually set up the response yet.

$( "#ajax-trigger" ).click(function() {
 console.log( 'clicked!' );
 $.get(
       jp.ajaxURL, {
           'action': 'jp_ajax_test',
           'nonce' : jp.nonce,
       },
       function( response ) {
             $( '#ajax-target' ).append( response );
       }
   );
 }
});

Now, if you click on “#ajax-trigger”, you should see ‘clicked’ in your console. Depending on your server configuration, you’ll either see a “0” or nothing in the target container, since right now AJAX isn’t sending anything back.

The Server-Side

So far we’ve worked totally client-side, IE in the browser. In order to have anything to load, we’ll need to send some data back. For that we need to hook a function to the action triggered by the AJAX request.

In our JavaScript file, we set the action to “jp_ajax_test”. As a result whenever this runs it will trigger one of two hooks in WordPress: “wp_ajax_jp_ajax_test” and “wp_ajax_nopriv_jp_ajax_test”. The first one will only run when triggered by a logged in user, while the second will only run only when a non-logged in user triggers the action. This allows us to send different responses based on if the user is logged in or not, or to not send anything in one case or the other. For now, let’s hook the same callback to both.

In your theme or child theme’s functions.php let’s create the hooks and an empty callback:

add_action( 'wp_ajax_jp_ajax_test', 'slug_ajax_callback' );
add_action( 'wp_ajax_no_ppriv_jp_ajax_test', 'slug_ajax_callback' );
function slug_ajax_callback() {

}

Now we have something for WordPress to do when it retrieves this request. AJAX callback functions are a little different then most functions, because the data isn’t passed into the function directly. Instead we need to get it from the HTTP request. The other thing that is different is that we need to tell PHP when to “die”–to stop execution and send back data.

The first thing we need to do though is check our nonce. For this we can use the function check_ajax_referer(). Referrer is intentionally misspelled by the way. It’s a long story, just trust me. This will verify that our nonce is correct. It accepts two parameters, the name of the nonce and the part of the request its in. Here’s what our callback looks like with the nonce check:

add_action( 'wp_ajax_jp_ajax_test', 'slug_ajax_callback' );
add_action( 'wp_ajax_no_ppriv_jp_ajax_test', 'slug_ajax_callback' );
function slug_ajax_callback() {
	if ( check_ajax_referer( 'jp', 'nonce' ) ) {
		//we'll handle this next
	}
	else{
		wp_die( 'Nonce error' );
	}
}

Now the callback checks the nonce and if it passes, does nothing, for now. If it fails it will return an error message. Notice that we put what we wanted to return inside of wp_die() instead of using echo or return. That tells PHP to send back our message and then die. We’ll do the same thing in a second with our successful response.

As I said, we’re going to return the title of a specific post. That’s unexciting but I’m trying to show you a basic pattern. We’ll spice it up in the next section when I show you how to get variables from the browser into PHP. The point right now is to illustrate that you can use any PHP function or functions in your callback. Here’s the complete example code for now:

add_action( 'wp_ajax_jp_ajax_test', 'slug_ajax_callback' );
add_action( 'wp_ajax_no_ppriv_jp_ajax_test', 'slug_ajax_callback' );
function slug_ajax_callback() {
	if ( check_ajax_referer( 'jp', 'nonce' ) ) {
		//make sure you set the ID of a post that exists here
		wp_die( get_the_title( 1 ) );
	}
	else{
		wp_die( 'Nonce error' );
	}

}

Now in the browser if you click the link, you should see the title of that post in your target container.

Passing Variables To The Server

That’s it. That’s the basic pattern. Of course to make this useful, we’ll want to be able to pass some variables from the browser to the request. To illustrate this, lets elaborate on our previous example. In this case let’s return a custom field for the current post. Create a new post and add a custom field called “date” using the custom field UI in the editor or using update_post_meta().

Now in the template file for single posts, add this inside the loop:

<?php
echo '<a id="get-date" href="#" post_id="' . esc_attr( get_the_id() .'">Get Date</a>';
echo '<div id="date"></date>';
?>

Now in your JavaScript file let’s add a second request that’s similar to the last example, but with 2 new additions so we can pass the HTML attribute post_id back to the server. Take a look:

$( "#get-date" ).click(function() {
  var post_id =$(  '#get-date' ).attr( 'post_id' );
  $.get(
       jp.ajaxURL, {
           'action': 'jp_get_date',
           'nonce' : jp.nonce,
           'post_id' : post_id,
       },
       function( response ) {
             $( '#date ).append( response );
       }
   );
 }
});

Now we get the post ID from the HTML attribute and add it our request so it will be available to us in the PHP callback function.

Let’s take a look at how that works. Again, the callback and action is almost the same, notice that since the AJAX action has a different name, the hooks we use have a different name to match:

add_action( 'wp_ajax_jp_get_date', 'slug_get_date_ajax_callback' );
add_action( 'wp_ajax_no_priv_jp_get_date', 'slug_get_date_ajax_callback' );
function 'slug_get_date_ajax_callback() {
	if ( check_ajax_referer( 'jp', 'nonce' ) ) {
		//make sure you that the post_id is in the request and it's a number
		if ( isset( $_GET( 'post_id' ) && intval( $_GET( 'post_id' ) > 0  ) {
		$date = get_post_meta( $_GET( 'post_id' ), 'date', true );
		if ( $date ) {
			wp_die( $date );
		}
		
		wp_die( 'No date set.' );
		
	}
	else{
		wp_die( 'Nonce error' );
	}

}

This new callback function is similar to our first one, but we need to add a few additional safety checks for security and to prevent errors. The first thing we do is make sure that ‘post_id’ is in the current request. If so, we check that it’s a number, or a string representing a number. If it’s not, than something has gone wrong, and that could be something malicious so we need to abort.

If those tests pass, we can can use the post_id to get the meta field get_post_meta(). Then we can test if that data is a valid, ie there is a value and return it. If not we will return a message.

Mastering The AJAX

In this article I’ve shown you the basic pattern of using AJAX in WordPress to send simple data to the server, use it in a PHP function and return the response to the browser. It’s up to you to use your creativity to apply this pattern to your own needs. Once you’ve learned this, the next step is to learn how to make post requests to save data into your database, but that’s a topic for another day.

Article thumbnail image by sam_ding / shutterstock.com

8 Comments

  1. Nice post Josh, hope there’s more AJAX related content on it’s way.

  2. Nice post. Please is there any simple plugin that can make Ajax work with WordPress? The steps provided can easily throw novice like me into confusion.

    Thanks.

    • Hi Jim. We had a great post last week about ajax plugins that you might want to check out.

  3. Good post. There are some minor issues ‘wp_ajax_nopriv` instead ‘wp_ajax_no_ppriv`.
    In my practice I use $.ajax and new FormData which I can send files.

    Greetings!

  4. Great! Hope to see more posts to improve coding skills.

  5. Sweet!

    I already use Ajax in lot of my custom plugins but no one actually use nonce as I was unable to understand how to use it correctly.
    Until now! What a great tutorial we got here! Thank you so much Josh!

    Now is time to update my codes.

  6. Hi,
    I would assume that copy-pasting would 95% get me started up. There seem to be errors like (brackets):
    $( “#ajax-trigger” ).click(function() {
    console.log( ‘clicked!’ );
    $.get(
    jp.ajaxURL, {
    ‘action’: ‘jp_ajax_test’,
    ‘nonce’ : jp.nonce,
    },
    function( response ) {
    $( ‘#ajax-target’ ).append( response );
    }
    );
    }
    });

    Fixing it did not get me on the right path either. After some time spent on this, I would say that the code will not work with “reasonable modifications needed for proper function, such as paths.”

    If you don’t agree, please post template files….

  7. Hey Josh,

    I think I’ve got it all setup properly, but I’m getting “-1” back instead of the post title. I’ve included the top most portion of your sample source code along with the bit you said to write into the functions.php, assuming that goes there as well… also assuming the -1 means I’m not passing something correctly, though the console.log is reporting that the entire JS is being read. Any thoughts?

500,591 Customers Are Already Building Amazing Websites With Divi. Join The Most Empowered WordPress Community On The Web

We offer a 30 Day Money Back Guarantee, so joining is Risk-Free!

Sign Up Today
www.maxformer.com

вход в личный кабинет альпари

別れさせ屋 福岡

Pin It on Pinterest