Stronger than dirt… I mean Ajax

I first learned about Ajax at a WordCamp (yay!), but I didn’t fully grasp how to implement it. There was a helper script provided, and I figured out how to make it work for my plugins, but all I really knew was copy & paste.

It was at least a good 6 months before I dug in and looked at the WordPress Ajax API. Getting a closer look helped me understand what I was writing, and how I could simplify and/or make improvements when necessary.

So let’s start.

I always use jQuery, so for this post, feel free to familiarize yourself with the basics of the jQuery Ajax API

There are 3 basic things we’ll need to plug into $.post.

  1. URL: Where we’re POSTing to (or GET, I tend to lean toward POST)
  2. Data: Our post-data, at a minimum, we have to send the name of a particular action (more on this later)
  3. Callback function: What to do with with the ajax response
$.post( url, dataObject, callbackFunction );

For the URL, here’s what I seen some people use: plugins_url('some-file-in-the-plugin.php', __FILE__);, then in some-file-in-the-plugin.php they’ll do something like require_once( '../../../wp-load.php'); so they can have access to core functions and such.

DO NOT DO THIS.

WordPress offers a nice file to use here, wp-admin/admin-ajax.php. It’s not a big file, feel free to look at it.

Okay, so how do we use that URL in the Javascript? Let’s assume our plugin is using 2 files, ajax-plugin.php and ajax-plugin.js.

We’ll first want to enqueue our js file in our plugin.

<?php
//Plugin Name: Ajax Plugin

add_action( 'wp_enqueue_scripts', 'ap_wp_enqueue_scripts' ); //front end
add_action( 'admin_enqueue_scripts', 'ap_wp_enqueue_scripts' ); //back end
function ap_wp_enqueue_scripts() {
	wp_enqueue_script( 'ajax-plugin', plugins_url( 'ajax-plugin.js', __FILE__ ), array('jquery') );
}

To give our Javascript the info it needs (like the location of admin-ajax.php), we’ll use the lovely wp_localize_script. This function lets us create a Javascript object that will be available for use in the javascript file it’s paired with.

wp_enqueue_script( 'ajax-plugin', plugins_url( 'ajax-plugin.js', __FILE__ ), array('jquery') );
wp_localize_script( 'ajax-plugin', 'ajaxPlugin', array(
	'ajaxUrl' => admin_url('admin-ajax.php')
) );

The first argument must be the same as the script handle, the second will be the name of the javascript object, and the third is all that data assigned to the object. This means that the admin-ajax.php file will be available as ajaxPlugin.ajaxUrl.

Back to the admin-ajax.php file. There’s some stuff for core actions in there, but the important thing is at the end (comments removed for brevity).

if ( is_user_logged_in() ) {
	do_action( 'wp_ajax_' . $_REQUEST['action'] );
} else {
	do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] );
}
die( '0' );

These are the hooks we’ll use. One for logged in users, and one for logged out users. Depending on what you’re doing, you may have to use both.

See $_REQUEST['action']? This is some of that data we’ll have to send send over in the Javascript.

That brings our javascript here:

jQuery(document).ready( function($) {
	dataObject = {
		action: 'the_name_of_our_action'
	};
	$.post( ajaxPlugin.ajaxUrl, dataObject, callbackFunction );
});

And we’ll need the corresponding hook(s).

add_action( 'wp_ajax_the_name_of_our_action', 'ap_the_name_of_our_action' );
function ap_the_name_of_our_action() {
}

Of course, ‘the_name_of_our_action’ is horrible, and there are separate hooks for users logged in and out.

add_action( 'wp_ajax_ajax_plugin_action', 'ap_ajax_plugin_action' );
add_action( 'wp_ajax_nopriv_ajax_plugin_action', 'ap_ajax_plugin_action' );
function ap_ajax_plugin_action() {
}

Breath.

Everything that gets echoed out from that callback function (actually, the entire admin-ajax.php file), will be the data that’s handed back to the javascript callback function. Let’s go ahead and prep that.

$.post( ajaxPlugin.ajaxUrl, {
	action: 'ajax_plugin_action'
}, function( response ) {
} );

You’ll notice that in admin-ajax.php, there’s a die( '0' ); at the end. That can really screw with things sometimes. So we’ll want to make sure we die() in our php callback.

Quick test time.

If we have this:

add_action( 'wp_ajax_ajax_plugin_action', 'ap_ajax_plugin_action' );
add_action( 'wp_ajax_nopriv_ajax_plugin_action', 'ap_ajax_plugin_action' );
function ap_ajax_plugin_action() {
	echo 'Hi there';
	die();
}

And this:

$.post( ajaxPlugin.ajaxUrl, {
	action: 'ajax_plugin_action'
}, function( response ) {
	alert( response );
} );

We’ll get an alert that says “Hi there.” Follow? I hope so.

A little handier than just dieing, especially in case of wanting to send back more than just a string or an error, are two nice functions, wp_send_json_success() and wp_send_json_error().

These will send data back organized like so

$response['success'] = true; // or false on if using the error function
$response['data'] = $data; // whatever was passed to the function

Everything is then nicely json-ified.

In the javascript, you can then check the response like this

if ( response.success ) {
	// success, do something with response.data
} else if ( ! response.success ) {
	// error, you can still do something with response.data
}

You can pass more data around in that data object.

$.post( ajaxPlugin.ajaxUrl, {
	action: 'ajax_plugin_action',
	extra: 'Howdy'
}, function( response ) {
	alert( response );
} );
add_action( 'wp_ajax_ajax_plugin_action', 'ap_ajax_plugin_action' );
add_action( 'wp_ajax_nopriv_ajax_plugin_action', 'ap_ajax_plugin_action' );
function ajax_plugin_action() {
	die(  strip_tags( $_POST['extra'] ) );
}

Naturally, this above example is kinda dumb, no reason for ajax. Now seems like a good time to put it all together and do a little demo. Below is an example that puts everything together and enables front-end title editing on the Twenty Fourteen theme.

Leave a Reply

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

%d bloggers like this: