How to make jQuery ajax (JSON) requests in WordPress

Overview & Preparation

Making jQuery ajax calls in WordPress to return JSON data to your client-side Javascript is an invaluable application that is only going to become more popular in the next few years. What’s the significance of using jQuery ajax to get JSON data from a WordPress site? Doing this (the right way) essentially allows you to request server-side information from your WordPress database, then have it returned to your client-side in one quick, extremely lightweight, and simple swoop. Ping the server, return the information you need. No page reload, no bulky parsing needed.

Luckily, there are some built-in utilities within WordPress that can be leveraged for this purpose.

Applications

Say you want to…

  • Populate a div with links to the 10 most recent posts after the page loads, or on a button click.
  • Allow the user to filter posts by tag, and return the results without reloading the page.
  • Load the comments for a post only if the user explicitly asks for them (clicks “show comments”, etc)

You get the point. Any time we want to get server data without reloading the page is a good application to use jQuery ajax to return JSON from the server.

The wrong (tempting) way

You might be familiar with using the jQuery.ajax() or jQuery.load() functions to return HTML data from other pages in your WordPress theme. However, using these functions to return bulky HTML data (as in when these functions return the contents of a particular div from a URL) when all you need is some text or an object to work with on the client side is an expensive process that requires lots of loading, rendering, and parsing.

To summarize:
Bad: Making ajax requests that ping arbitrary theme URLs, then parse and return bulky HTML data.

The right(er) way

Instead, we can get the necessary text or data structure from the server using JSON, which is much quicker, lightweight, and ultimately easier to work with on the client-side. Also, WordPress has a built-in utility to handle such requests, although developers often aren’t aware of it. Instead requesting the ajax data from another URL in the WordPress theme, we will pass the request to the file wp-admin/admin-ajax.php. This is a native file within WordPress whose job is specifically to handle such ajax requests and return lightweight results. All you’ll get back from this URL is your data, in JSON format. This way, you don’t have to parse through loads of HTML just to get the data you want.

Good: making ajax requests that ping WordPress’ built-in ajax utilities (wp-admin/admin-ajax.php) and return lightweight JSON data.

Requirements

To follow along with this completely you’ll need:

  • A jQuery-enabled WordPress site to play with. Anything 3.0+ will be fine
  • Google Chrome developer tools (makes this much more palatable)
  • Access to following 2 files:
    • wp-content/your-theme/functions.php (here we’ll add the handler functions for the server-side request).
    • wp-content/your-theme/js.js, or some other custom Javascript file to work with. Just make sure it’s loaded correctly in your theme so that the code will execute properly.

The data flow

Before getting started, let’s take a look at how our data is going to flow from beginning to end:

  1. User event on the client-side (button click)
  2. Javascript (js.js) click handler recognizes the click and initiates the jQuery ajax call.
  3. The jQuery ajax function makes a server side request at the URL that is given (remember, we will be using wp-admin/admin-ajax.php)
  4. The URL considers the request, and runs the appropriate function (this will be specified in functions.php)
  5. The function encodes the data to JSON format, then prints it out as its response
  6. The jQuery ajax function accepts this response as a Javascript object, and returns it to its success handler
  7. The success handler function (sub-function of the jQuery ajax function) uses the response data to perform an action on the client-side

The tutorial!

Security Considerations

I am not a security expert (ie, I’m sorry, but not responsible, if something undesirable happens to your site when you use a variant of this technique).

Most practical uses of admin-ajax.php provide an avenue for interacting with the WordPress database. However, there are a few simple things you can do to mitigate security concerns:

  • Pick secure names for your functions and “action” parameter (for simplicity, I use ‘do_ajax’ in this example; this could obviously be much more secure.)
  • Don’t provide methods for altering or deleting data in the hooked-in PHP function.
  • Validate all values passed to your PHP function to minimize the risk of injection.
  • If you don’t feel comfortable using admin-ajax, don’t use it.

That said, happy admin-ajaxing, and on to the good stuff.

Create a WordPress entry to interact with

First thing’s first; we’ll need an HTML document to interact with in order to attach this JSON-fetching process to a user event. You could also create your own HTML elements in a WordPress template, then create a new page and assign it your custom template — however, in the name of simplicity I’ll just create a regular WordPress post.

Go ahead and create a post; nothing too special. I’ll title mine “JSON Test.” I’ll also give it a unique a tag element that we can attach the click handler to; let’s call it

<a id="json_click_handler" href="#">
     Click here to do JSON request! We'll get the 10 most recent posts as JSON
</a>

One last thing: create a div that we can put the JSON results into once we process the request and get the results. I called it

<div id="json_response_box"></div>

Create the Post | How to do Jquery AJAX / JSON requests in WordPress

Step 1: Create the post

Create the the Javascript click handler in js.js.

In your custom Javascript file, make a click handler for the new link. Inside this click handler, we’ll put the AJAX request, and the response (success) function.

If you’re not familiar with jQuery.ajax(), read up here.

Here are the different components of our jQuery.ajax() call:

url
The url parameter should be set to the location of your admin-ajax.php file, which is part of the WordPress core within the wp-admin directory. So, the path should be www.yourwpdirectory.com/wp-admin/admin-ajax.php. This file exists specifically to process ajax requests like the one we are about to make!

dataType
This should be set to ‘JSON’, indicating that we want the data returned in JSON format.

data
The data parameter represents the array of REQUEST (GET;POST) parameters that are passed to the remote URL (admin-ajax.php). So, any value we enter under the data parameter of the ajax call will be available as a REQUEST variable in admin-ajax.php. For instance, if we pass

ourVar: 'someValue'

as part of the ajax data parameter, it will be available at the remote URL (admin-ajax.php) as

$_REQUEST['ourVar']

This is part of the magic of making jQuery ajax calls. for our purposes we’ll pass three parameters within data:

  • ‘action’:'do_ajax’ (the action parameter is REQUIRED BY WORDPRESS in order to tell the remote URL which function to hook into. It doesn’t have to be called ‘do_ajax’, but it does have to match the action hook we will write just a bit later. This way, whenever an AJAX request has an action parameter that matches our WordPress action hook, it will do the function that we specify in that hook.)
  • ‘fn’:'get_latest_posts’ (this will be used to tell admin-ajax.php which server-side function we want it to run, once the ‘do_ajax’ process has begun)
  • ‘count’: 10

This way, admin-ajax.php will have two REQUEST variables available during this call,

$_REQUEST['fn']

and

$_REQUEST['count']

success
In the success parameter, we specify a success function that will run if our AJAX request is successful. Let’s create this function, but leave it blank for now. Creating the success handler will be one of the last steps.

error
Similar to the success function, the error parameter specifies a function to run if there is an AJAX error. We shouldn’t get any errors, but if we do, it’s useful to know what’s going on here.

Here’s the complete click handler with jQuery ajax call, in js.js

jQuery(document).ready(function(){
     jQuery('#json_click_handler').click(function(){
          doAjaxRequest();
     });
});
function doAjaxRequest(){
     // here is where the request will happen
     jQuery.ajax({
          url: 'http://www.yourwpdirectory.com/wp-admin/admin-ajax.php',
          data:{
               'action':'do_ajax',
               'fn':'get_latest_posts',
               'count':10
               },
          dataType: 'JSON',
          success:function(data){
                 // our handler function will go here
                 // this part is very important!
                 // it's what happens with the JSON data 
                 // after it is fetched via AJAX!
                             },
          error: function(errorThrown){
               alert('error');
               console.log(errorThrown);
          }
          

     });

}

Test that the click handler and remote URL are working properly.

Open up the Chrome developer tools, and click the Network tab. This will show all of the network requests that happen, which will include the AJAX request we’ve just written.

Refresh everything, then go ahead and click the link you made at first in the ‘JSON test’ post, which now has the click handler attached to it.

Now, watch the network results. IF you’ve specified the correct location for the URL of admin-ajax.php, you will see a response like this:

Successful Ajax Call

Notice that the URL, admin-ajax.php, returns a Status code:200 OK. This is good, it means the the function is working, hitting the correct URL.

Also, notice that the key/value pairs that we specified in the jQuery.ajax() “data” parameter are now available at the remote URL as Query String Parameters. This is key, because it means we can use these values on the server-side.

Otherwise, if the URL isn’t right, you’ll see this:

Unsuccessful AJAX call

(You’ll also see the error alert that we wrote as the error response to our jQuery.ajax() function).

If you don’t see any such AJAX requests being processed when you click the button, then your click handler, or resulting AJAX function has not been attached properly.

Hopefully, you saw case #1, a successful AJAX request. If so, we can move on to setting what happens once admin-ajax.php receives this request!

Add action hooks to functions.php to sync the client- and server-side AJAX mechanisms, and start making a server-side (PHP) handler function

Now that the client-side jQuery.ajax() call is successfully sending the AJAX request to admin-ajax.php, it’s time to determine what happens with this data once the remote URL is hit.

Even though the action is happening at admin-ajax.php, we don’t have to edit this file at all. Instead, open up functions.php from within your WordPress theme, and we will write functions that hook into actions on admin-ajax.php from here. This way, we’re not messing with any source code; just hooking into it from within our own theme.

We need to add 3 components to functions.php:

  • 2 actions hooks that tell admin-ajax.php to run a certain function, depending on the ‘action’ parameter that the AJAX request sends.
  • The resulting function to run

So, the code should look like this:

add_action('wp_ajax_nopriv_do_ajax', 'our_ajax_function');
add_action('wp_ajax_do_ajax', 'our_ajax_function');
function our_ajax_function(){
     // now we'll write what the server should do with our request here
}

Notice that the suffix of the ‘wp_ajax_nopriv_’ and ‘wp_ajax_’ action hooks match the action parameter sent from the jQuery.ajax() call, which was ‘do_ajax’.

This means whenever admin-ajax.php receives an AJAX call, it will see what the ‘action’ parameter is. If the ‘action’ parameter is set to ‘do_ajax’, it will run ‘our_ajax_function’. Sounds good!

Build the PHP handler function

We just started building the AJAX request handler function, ‘our_ajax_function’. Now, let’s add to it and make it actually work.

Before getting started, let me explain my philosophy about this function. I recommend making ‘our_ajax_function’ into a mini AJAX switchboard that handles all AJAX calls — because, although we only have one ajax call now, we might have any number in the future. In other words, doing it this way scales well. Then, this switchboard can check the accompanying parameter ‘fn’, and invoke specific functions according to the value of that argument.

Why don’t we just use the ‘action’ parameter to determine which function to run, isn’t that what it’s for? Sort of, yes. But that means you’d have to write a WordPress action hook for every single AJAX function you wanted to run; that’s a pain. Instead, I like to send every AJAX call to the switchboard function, ‘our_ajax_function,’ by setting ‘action’:'do_ajax’ in the jQuery.ajax() call. Then, we can call more specific functions depending on what value is passed for the ‘fn’ parameter.

So, in functions.php

function our_ajax_function(){

   // the first part is a SWTICHBOARD that fires specific functions
   // according to the value of Query Var 'fn'

     switch($_REQUEST['fn']){
          case 'get_latest_posts':
               $output = ajax_get_latest_posts($_REQUEST['count']);
          break;
          default:
              $output = 'No function specified, check your jQuery.ajax() call';
          break;

     }

   // at this point, $output contains some sort of valuable data!
   // Now, convert $output to JSON and echo it to the browser 
   // That way, we can recapture it with jQuery and run our success function

          $output=json_encode($output);
	     if(is_array($output)){
		print_r($output);	
	     }
	     else{
		echo $output;
	     }
	     die;

}

As you can see, this switchboard is now going to call one more function, ‘ajax_get_latest_posts’, because the ‘fn’ parameter of our jQuery.ajax() call matches the first case on the switch statement. So, we need to make this specific function, ‘ajax_get_latest_posts’, to, well, get the latest posts, and return the results as an array of PHP objects. So, also in functions.php

function ajax_get_latest_posts($count){
     $posts = get_posts('numberposts='.$count);
     return $posts;
}

So, running through the PHP code in ‘our_ajax_function’, this is what happens:

  • The switch statement starts, checking the value of $_REQUEST['fn']
  • The first check is true, $_REQUEST['fn'] == ‘get_latest_posts’, so the first case will fire
  • ajax_get_latest_posts($_REQUEST['count']); runs, and returns an array of the latest 10 posts.
  • Back in function ‘our_ajax_function’, $output now == the result of ajax_get_latest_posts. So, $output is an array of the 10 latest posts.
  • To conclude ‘our_ajax_function’, the value of $output is converted to JSON via PHP’s json_encode method, and echoed, in order for the original jQuery function to access it.

Where are we now? We’re back to the success function of the jQuery.ajax() function, and the “data” argument contains the server-side output. In other words, “data” in our jQuery.ajax() success function now holds the contents of what was just $output in our PHP function.

That was the magic. Now let’s DO something with that response.

Andrew Peters

Andrew is a user experience developer from Carnegie Mellon's School of Computer Science in Pittsburgh, PA, who uses a variety of web languages to produce intuitive sites and applications.

More Posts

25 Responses to How to make jQuery ajax (JSON) requests in WordPress

  1. Hi, I liked your explanation and currently I’m using this methods here but my manager told me he is going to remove access to the wp-admin folder because it is the safest way.

    So I ask, there any way of doing this without admin-ajax file?

    and about security, it is or it isnt’ safe to use Ajax trough wp-admin folder?

    Thanks in advance!!

    bye

    • Hi Thiago,

      You can do this type of Ajax processing at a different URL of your choice, but it makes sense to use admin-ajax, since WordPress provides this utility for that exact purpose. If you did this with a different URL, you would need to set it up to accept ajax requests, process the request, and return JSON. Admin-ajax already does all this.

      To address your security concerns: again, I am not a security expert. Don’t use admin-ajax.php unless you feel comfortable with the security of the technique. The following is nothing more than my amateur, semi-informed speculation about the security of this method. That said, I imagine processing ajax requests with admin-ajax is probably more secure than the alternative for a few reasons:

      First, a random user/hacker cannot do anything with admin-ajax unless they know the name of the corresponding hook in functions.php. In this example I used ‘do_ajax,’ but you can imagine using a more secure name that would be increasingly difficult to guess/access. You can choose whatever name you want, just remember that the name of the filter hook in functions.php must match the ‘action’ parameter of your jQuery.ajax() request.

      Second, even if somebody accessed your admin-ajax and figured out the ‘action’ (filter hook name) to pass, all they can do is run the functions that are connected to that hook (our_ajax_function, in this example). If you check that part of the example, you can see that the only thing our_ajax_function can do is return an object of the latest posts. IF your hooked-in function allowed more dangerous actions, such as deleting or altering posts, then it would be a more pressing security concern.

      So, to summarize, a user needs to know your ‘action’ parameter to get any access to admin-ajax. If this is a concern, you can make this very secure. If they figure out your ‘action’ parameter, they can only access the functions that are associated with that hook in functions.php. If there only benign functions associated with this, the risk is limited.

      Essentially, if you have a secure ‘action’ parameter, it’s probably easier for a malicious user to actually crack your WordPress login than it is to infiltrate admin-ajax. And cracking the login (and get total access) would be much more attractive to them than trying to figure out your purposefully complex admin-ajax hooks.

      Good luck & happy coding.

  2. You should validate $_REQUEST['count'] before use, otherwise random user/hacker could pass a string like ’10&post_type=any&post_status=any’ or similar and read unwanted data. This is not a tested PoC, but you should get the idea…

    • Point taken random user/hacker (ha), this is indeed a concern. I didn’t initially write with utmost security in mind, but it is obviously an important consideration. I’ll edit the writeup to reflect your suggestion.

      Or maybe you can for me, by hacking my admin-ajax.php :)

      • No problem. Your example was nevertheless helpful to understand the concept of frontend ajax with WP.

  3. Hi!
    Thanks a lot for the great tutorial. Everything worked great from the first run, except one thing.

    If my ajax_get_latest_posts($count) function returns an array, and back in the jQuery I do something like alert(data) it outputs this : [object Object].

    If the function returns anything else (string, integer) everything works fine.

    Any ideas why this would happen?

    • Hi Kay,

      Yes, what you’ve described makes sense: If your PHP function returns an array, then “data” in your Javascript will also be an array. Since alert can’t tell you much about arrays, you might try console.log(data), which outputs to the Chrome console, or to Firebug if you’re using Firefox.

      Then, you can iterate through “data” in your javascript with a for loop to do something with each of the array’s elements.

  4. Thanks a lot. Checking the console showed that the information is making it through to the jQuery data. So how do you iterate though data?

    Theoretically shouldn’t something like print_r(data) work since i know this is an array?

    And the weird part is that I get 2 error jQuery windows after clicking on the link.

    • Well, since print_r() is a PHP method it won’t do much good in the context of Javascript. That’s why I suggest examining it in the Chrome console with console.log(data) — the information that gives you is similar to what you get from print_r() in PHP.

      As far as iterating through your data object, you can do that with standard Javascript looping. There are a few different approaches that will work; I prefer

      for(var i in data){
      // do something with data[i]...
      }

      http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript

      • My bad with the print_r. A little embarrassed of that. I was trying everything, it was a mess.
        So if I return an array the
        “data” itself becomes an array.
        All makes sense now. Thanks a LOT for everything.

  5. I found the answer, but now I have a bigger problem. I need to use this method for a big function with a lot of data, would having that function in functions.php slow down the website or hurt it in anyway?

    • Simply having the function in functions.php won’t hurt much — it won’t run until it’s called. Just focus on making the PHP and JS functions as efficient as possible. If there’s unnecessary overhead (too many loops, database queries, etc) in the PHP or, more likely, the Javascript function, it could get slow. Just make sure the function’s performance is acceptable to you, and call it only when necessary in order to lighten the load. Work on making the functions more efficient to speed them up!

  6. Hi, Andrew.

    Thanks a lot for your nice presentation.

    I tried your code and it worked perfectly.

    However,when I tried again to tweak it, by returning the $output from the following function , I get a “0″ or blank page. Could you help giving some hints?

    • Seems like this would be an issue with your PHP, not the AJAX process. I would try echoing your sql string back before executing the query — does it contain a well-formed query that would produce results if run directly on the database? If not, you may have to debug your query construction.

  7. Hello, imagine I only want to load all the content of a post using AJAX, how would the functions.php part look?

    I use thumbnails and would like to load the content my posts using AJAX and I have a hard time finding a solution.

    Check out my Question at stackoverflow.com

    Many thanks

    • I can’t say exactly, but you may want to look at get_post(). You can pass this function an ID and get a single post object. This object will have a property ->post_content, which you could echo back to your client-side JS.

      Edit: looks like you solved your question on StackOverflow — but we were on the same page!

  8. Pingback: Wordpress How to | Pearltrees

  9. Pingback: How to do damn near anything with WordPress – Stephanie Leary

  10. Pingback: Ajax | Pearltrees

  11. Hello Andrew,

    Thanks a lot for the post with the detailed steps, it really makes a difference! Now I’ve got a better understanding of AJAX magic :)

    A quick question, if I want to return an HTML markup do I need to do anything differently? I’m still using the code that json_encode() the output, however I don’t know if that’s the correct way to go on when I’m returning HTML markup. I’m not so good at understanding json.

    Many thanks,
    Dasha

    • To return standard html, do a couple things differently. in the jQuery.ajax() call, in the data parameter, set dataType:'html' instead of dataType:'json'. Then, in the php, you don’t have to json_encode(). Just echo some html output.

  12. Just wanted to drop you a line saying thanks. This helped me get the basics and create a ajax login form for wordpress. Took me a few more hours than I planned but I am vastly better person for it. Thanks and congrats!!!

    • No problem! Once you get this down it’s a very versatile addition to your WP arsenal.

  13. Pingback: Tweet parade (no.08 Feb 2013) | gonzoblog

  14. Pingback: GraphicRiver – Fall Festival Event Flyer Template

Leave a Reply

Your email address will not be published. Required fields are marked *

Please type the characters of this captcha image in the input box

Prove your humanity: please type the 3 letters in this image:

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>