Using front-end AJAX requests in your WordPress plugins

Although it is fairly uncommon to be adding AJAX functionality to your WordPress plugins, it can be necessary for it to be added. Luckily it is quite easy and straight forward to integrate the required components as and when they are required.

To help explain how this can be achieved, we will be creating a plugin called “Ajax Example“, stored in the folder “ajax-example” inside the plugin directory of your WordPress install.

Further information on creating a WordPress plugin can be found on WordPress.org and other resources, so won’t go into too much detail here.

First we need to create a file called “index.html” and copy the following into this file:

<?php
/*
Plugin Name: Ajax Example
Plugin URI: http://wp.me/pWbfz-dB
Description: Simple example of how to integrate front-end ajax requests via your plugin.
Version: 0.1
Date: 2011-09-01
Author: Steve Whiteley
Author URI: http://flav36rs.com
*/

class Ajax_Example
{
	public function __construct()
	{
		// ...
 	}
}

$ajaxExample = new Ajax_Example();

?>

We will be using the OOP structure for this plugin instead of the prefixed function format, however could be converted with ease. This class provides the skeleton structure of our plugin, you should save this file to our “ajax-example” folder before we start to add more functionality.

The next step is to include the JavaScript file that performs the AJAX request, which is called by the “init” action hook added to the class constructor method:

add_action( 'init', array( &$this, 'init' ) );

Then we add the init function to the plugin, which includes calls to insert the JavaScript file (wp_enqueue_script) and set the parameters required by the external file (wp_localize_script).

public function init()
{
	wp_enqueue_script( 'ajax-example', plugin_dir_url( __FILE__ ) . 'ajax.js', array( 'jquery' ) );
	wp_localize_script( 'ajax-example', 'AjaxExample', array(
		'ajaxurl' => admin_url( 'admin-ajax.php' ),
		'nonce' => wp_create_nonce( 'ajax-example-nonce' )
	) );
}

Additional parameters can be added to array if they are required, the two mentioned should be the minimum that are required.

While we’re here, we should add the function that handles the response generated by the AJAX request. Notice here that we check the nonce value that is defined in the function above and set the content type before returning the encoded JSON array.

public function ajax_call()
{
	if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( $_REQUEST['nonce'], 'ajax-example-nonce' ) )
		die ( 'Invalid Nonce' );
	header( "Content-Type: application/json" );
	echo json_encode( array(
		'success' => true,
		'time' => time()
	) );
	exit;
}

Create “ajax-example/ajax.js” and copy the following snippet into this file. In order to perform the AJAX request, we use the jQuery .getJSON() method. Alternative methods could be used depending on the type of request you are performing.

jQuery.getJSON(
    AjaxExample.ajaxurl,
    {
        action: 'ajax-example',
        nonce: AjaxExample.nonce
    },
    function( response ) {
    	alert( response.success );
    }
);

Unfortunately this won’t actually do anything until we add two hooks to extend the built in AJAX functionality. These are added to the class constructor, the first (wp_ajax_nopriv_ajax-example) provides access for logged in users, the second (wp_ajax_ajax-example) for anonymous / non-logged in visitors.

if ( is_admin() ) {
	add_action( 'wp_ajax_nopriv_ajax-example', array( &$this, 'ajax_call' ) );
	add_action( 'wp_ajax_ajax-example', array( &$this, 'ajax_call' ) );
}

Please be aware that when using these hooks, they are called from within is_admin(), otherwise they are not correctly set.

The full contents of the plugin file “ajax-example/index.php” should be as follows:

<?php
/*
Plugin Name: Ajax Example
Plugin URI: http://wp.me/pWbfz-dB
Description: Simple example of how to integrate front-end ajax requests via your plugin.
Version: 0.1
Date: 2011-09-01
Author: Steve Whiteley
Author URI: http://flav36rs.com
*/

class Ajax_Example
{
	public function __construct()
	{
		if ( is_admin() ) {
			add_action( 'wp_ajax_nopriv_ajax-example', array( &$this, 'ajax_call' ) );
			add_action( 'wp_ajax_ajax-example', array( &$this, 'ajax_call' ) );
		}
		add_action( 'init', array( &$this, 'init' ) );
	}

	public function init()
	{
		wp_enqueue_script( 'ajax-example', plugin_dir_url( __FILE__ ) . 'ajax.js', array( 'jquery' ) );
		wp_localize_script( 'ajax-example', 'AjaxExample', array(
		    'ajaxurl' => admin_url( 'admin-ajax.php' ),
		    'nonce' => wp_create_nonce( 'ajax-example-nonce' )
		) );
	}

	public function ajax_call()
	{
		if ( ! isset( $_REQUEST['nonce'] ) || ! wp_verify_nonce( $_REQUEST['nonce'], 'ajax-example-nonce' ) )
			die ( 'Invalid Nonce' );
		header( "Content-Type: application/json" );
		echo json_encode( array(
			'success' => true,
			'time' => time()
		) );
		exit;
	}

}

$ajaxExample = new Ajax_Example();

?>

Other things to consider when using the example code provided above are that you should probably ensure jQuery is loaded and possibly only add the the scripts to the pages that they are required, rather than globally.

This functionality was tested with WordPress 3.2.1, it may however change and be simplified in future releases.

16 Replies to “Using front-end AJAX requests in your WordPress plugins”

  1. Great article.

    One constructive criticism though :
    You don’t need:

    add_action( ‘wp_ajax_nopriv_ajax-example’, array( &$this, ‘ajax_call’ ) );

    within the is_admin call since the “nopriv” part stands for “no privileges” and is for anybody that is NOT logged in, which of course, will never be the case within an admin page. So ajax requests within the WordPress admin only require calls like :

    add_action( ‘wp_ajax_ajax-example’, array( &$this, ‘ajax_call’ ) );

    I have one question for you as well, since yours is the only reference I have found online (so far) using WordPress ajax and classes.

    Any idea how to get WordPress ajax calls working in an OOP environment that is using multiple classes within the plugin? Reason being is that the plugin I am developing is fairly extensive so I wanted to break the frontend and the admin sides of the plugin into separate classes. The main file for the plugin then does a simple :

    if ( is_admin() ) {
    // instantiate My_Admin class
    } else {
    // instantiate My_Frontend class
    }

    On the frontend of the site I want to make some ajax calls to functions that are within the Frontend class, but can’t get WordPress to find the functions. I have tried:

    add_action(‘wp_ajax_my_function’, array( ‘My_Frontend’, ‘eq_add_attendee’ ));

    I have set a variable upon instantiation like this:
    $frontend = new My_Frontend;
    add_action(‘wp_ajax_my_function’, array( $frontend, ‘eq_add_attendee’ ));

    I have tried static calls:
    add_action(‘wp_ajax_my_function’, ‘My_Frontend::eq_add_attendee’ );

    and initially I had the main plugin file as an object itself, with the other objects set as properties (which is what I would like to go back to)
    $this->frontend = new My_Frontend;
    add_action(‘wp_ajax_my_function’, array( $this->frontend, ‘eq_add_attendee’ ));

    none of these work.

    it seems as if WordPress will only recognize classes or functions that are actually within the plugin’s file.

    Any ideas???

    Thank you in advance for your time, effort, and talent.

    Like

    1. Great question bc,

      Class instances need to be passed by reference, so adding a “&” to the front of “$frontend” in the add_action call should do the trick:

      $frontend = new My_Frontend();
      add_action (‘wp_ajax_my_function’, array( &$frontend, ‘eq_add_attendee’ ) );

      Hope that helps…

      Like

      1. Hi Randy,

        Thanks for the response. I was actually already passing by reference, cuz normally I would be using &$this for the CLASS name within my classes, but simply forgot to type that into my comment post.

        On a side note:
        I’m not sure how far the passing by reference has to be taken. I’m instantiating my frontend and admin classes using a singleton type constructor. So I have a private constructor, coupled with a public method named “instance” that checks if the class object exists yet, instantiates it if it does not, and then passes that by reference. So you can only ever create one frontend object. Additional attempts to instantiate a new object will simply pass the already existing one. But I’m not sure whether you have to pass by reference something that is already being passed by reference! Considering how intelligent computers actually are, you probably DO have to continually pass things by reference. But I don’t know for certain.

        Anyways, back to the main attraction:

        Just to be certain I hadn’t overlooked something like forgetting to pass by reference, I tried it again, and it still didn’t work.

        BUT!!!!

        I discovered that the culprit preventing my ajax from working was the “is_admin” conditional:

        so Ajax calls work with this:

        if ( is_admin() ) {
        // instantiate My_Admin class
        require_once( My_Admin.class.php’ );
        $this->admin = new My_Admin();
        }

        require_once( My_Frontend.class.php’ );
        $this->frontend = new My_Frontend();
        add_action (‘wp_ajax_my_function’, array( &$this->frontend, ‘eq_add_attendee’ ) );

        …but NOT this:

        if ( is_admin() ) {
        // instantiate My_Admin class
        require_once( My_Admin.class.php’ );
        $this->admin = new My_Admin();
        } else {
        require_once( My_Frontend.class.php’ );
        $this->frontend = new My_Frontend();
        }

        add_action (‘wp_ajax_my_function’, array( &$this->frontend, ‘eq_add_attendee’ ) );

        ( this results in a callback not found error )

        …nor this:

        if ( is_admin() ) {
        // instantiate My_Admin class
        require_once( My_Admin.class.php’ );
        $this->admin = new My_Admin();
        } else {
        require_once( My_Frontend.class.php’ );
        $this->frontend = new My_Frontend();
        add_action (‘wp_ajax_my_function’, array( &$this->frontend, ‘eq_add_attendee’ ) );
        }

        ( WP just doesn’t even see the ajax hooks with this, so my jQuery ajax functions simply return “-1” )

        I just can’t even wrap my head around the fact that the is_admin conditional is bunging things up !!!

        Anybody smarter than me have any ideas regarding this???

        Like

      2. Found my own answer.

        Because all WP ajax calls go through admin-ajax.php, they are considered part of the admin side of things.

        Therefore all ajax functionality has to be done from functions/methods with admin visibility.

        So now I have to ALWAYS load my frontend class so that it’s ajax functionality is visible from within the admin.

        Don’t think I like that :

        Like

  2. Steve, thanks for the great example of Ajax on WordPress. I am trying to use this code to send the navigator.geolocation.getCurrentPosition back to my plugin. It works, but it doesn’t finish until the page is fully loaded. Unfortunately, this is too late for my plugin to finish it’s work. Firebug just shows admin-ajax.php waiting, displaying it last in the NET tab. I have thrown in some alerts and the ajax script is ran before any part of the page is displayed. Any ideas?

    Like

  3. Not sure if it’s just the partiuclar theme I’m working on but it you also might need to add `do_action()` function to get WordPress to response to the Ajax calls. I just used the following in functions

    if(isset($_REQUEST[‘action’])) {
    do_action(‘wp_ajax_’.$_REQUEST[‘action’]);
    do_action(‘wp_ajax_nopriv_’.$_REQUEST[‘action’]);
    }

    Like

  4. Just a question, when using ‘wp_ajax_ajax-example’, can admin users also access this. I’m making a script which should be accessed on both the admin as well as the frontend pages to retrieve a piece of data (token). Common sense tells me that a function for anonymous users should aso be accessible by higher authentication levels, but i’m not sure because i could find documentation on this.

    Like

    1. Yes admin users would be able to access that function/method as would any other logged in user.

      It’s non-logged in site visitors that would NOT be able to utilize that AJAX functionality.

      In order to make your AJAX calls available to non-logged in users, you need an additional action like:

      add_action( ‘wp_ajax_nopriv_ajax-example’, array( &$this, ‘ajax_call’ ) );

      the “nopriv” bit means “no privileges” meaning NOT logged in.

      so if you want AJAX functionality for BOTH logged in AND non-logged in users you need BOTH actions:

      add_action( ‘wp_ajax_ajax-example’, array( &$this, ‘ajax_call’ ) );
      add_action( ‘wp_ajax_nopriv_ajax-example’, array( &$this, ‘ajax_call’ ) );

      Like

  5. Great post! This is the only reference I could find on this subject.

    I have one question:
    How would I pass data to the callback function? If I want to run a database query using a user input, how would I pass the input back to the callback function?

    Thank you!

    Like

    1. most likely through $_POST, but it depends on how you are setting things up.

      I always use $_POST because it is more secure than other request methods.

      So you would use JS to gather the form info you want to send, which can be as easy as serializing the entire form in question, then sending that via POST while performing the AJAX call.

      Then your callback function simply checks the $_POST array for the data.

      Like

  6. Thanks, this was very interesting.

    I ran it and it brings up a dialog that display the word “true” when the page loads. Is that what is supposed to happen.

    I was looking for a way of continuously displaying a live update of a counter (global population) on a wordpress page.

    How could I modify this example to display the time parameter that is used, in a wordpress widget, for example?

    Like

Leave a comment