How to use Ajax with your WordPress Plugin or Theme?

How to use Ajax with your WordPress Plugin or Theme?

What is Ajax?

Ajax is the technology that allows interaction on a website without the website needing to reload each time. It stands for Asynchronous JavaScript and XML. However, many different technologies can be used and today it is common for JSON objects to be used instead of XML. Ajax is one of the ways you can make your WordPress website interactive and deliver dynamic content.

Where might you want to use Ajax on your WordPress site?

A common use of Ajax is to load information based on user input. For example, a store finder interface would likely use Ajax. The user would input the zipcode and then Ajax is used to retrieve the nearby stores from the database.

Contact forms, newsletter sign-up forms, and surveys are also common uses of Ajax. If you have a large amount of information, Ajax can be used to retrieve only the data that the user is interested in.

How to use wp_ajax?

WordPress has a hook called wp_ajax that should be used for adding Ajax functionality to your WordPress plugin or theme. It’s a good idea to use the wp_ajax hook instead of using your own php file to handle the backend request for both security and functionality.

Wp_ajax loads the WordPress core, which means that you can do anything that you would normally do in a plugin or theme. You may want to check user capability, update options, access post meta data, or use WordPress variables like $wpdb for interacting with the database. You can even use the WordPress HTTP API to interact with an external service, like the Facebook or Twitter API.

Tutorial: Complete wp_ajax Example

Here are step-by-step instructions on how to use wp_ajax.  We are going to use a simple example where we ask for user feedback and record their response as post meta data.  This is what it looks like:

Here is the php code that creates that question and the buttons.

echo 
"<p>Was this post helpful?
 <button class='post_feedback' id='post_feedback_yes' post='" . get_the_ID() ."'>Yes</button>
 <button class='post_feedback'  id='post_feedback_no' post='" . get_the_ID() ."'>No</button>
<span id='post_feedback_status'></span></p>";

You can add that code to the relevant theme template file. If you are not the creator of the theme, you may want to create a child theme rather than editing the theme directly since updates to the theme will overwrite your changes.

Although this is a small amount of code, it sets up the stage for our Javascript.  Note that I gave the buttons unique IDs and the same class names. Not only does this make styling them with CSS easy, but also the ID names make it easy for us to query the DOM for those elements with Javascript.  Also, the empty Span tag is where the response of “Thank you” will appear.

You will also notice that I coded the post ID into the button as a custom attribute.  This post ID is going to be transmitted to the server with the Ajax post request.

The next step is to write the Javascript file which makes the buttons interactive and sends the Ajax request. Here is what that looks like:

jQuery(document).ready(function () {

    jQuery("#post_feedback_no").click(function (event) {
        var post_id = jQuery(this).attr('post');
        jQuery(".post_feedback").attr('disabled','disabled');
        sendFeedback('action=post_feedback&response=no&post_id=' + post_id);
        return false;
    });

    jQuery("#post_feedback_yes").click(function (event) {
        var post_id = jQuery(this).attr('post');
        jQuery(".post_feedback").attr('disabled','disabled');
        sendFeedback('action=post_feedback&response=yes&post_id=' + post_id);
        return false;
    });

    function sendFeedback(data) {
        jQuery.post(ajaxurl, data, function(result) {
            var response = JSON.parse(result);
            if(response.feedback_success==1) {
                jQuery("#post_feedback_status").html("Thank you!");
            } else {
                jQuery("#post_feedback_status").html("Error Occurred.");
            }

        });
    }
});

For the Javascript, I used jQuery because it takes care of browser compatibility issues and it’s easy to write. jQuery is built into WordPress so all you have to do is tell WordPress that jQuery is a dependency for your script when you enqueue it.

The jQuery is pretty straightforward.  When a button is clicked, both buttons are disabled to prevent further clicks. An HTTP post request is sent with the name of the action, the response (yes or no), and the post ID.  The action string is what wp_ajax looks at to determine what function should be called to handle the post request.

To enqueue your Javascript, put this in your theme’s functions.php file:


 function post_feedback_scripts() {
	wp_enqueue_script(
		'post_feedback',
		get_stylesheet_directory_uri() . '/post_feedback.js',
		array( 'jquery' )
	);
}
add_action( 'wp_enqueue_scripts', 'post_feedback_scripts' );

The last parameter of the wp_enqueue_script function is an array of dependencies, which is just jQuery in our case.

Before that Javascript file will work, you will also need to add this to your functions.php file:

add_action('wp_head','pluginname_ajaxurl');
function pluginname_ajaxurl() {
	?>
	<script type="text/javascript">
		var ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
	</script>
	<?php
}

Basically, this defines the Javascript variable ajaxurl. If you were using wp_ajax on the admin side only, then ajaxurl would already be defined, but on the frontend, you have to define it.  Putting this definition in the head of the document will ensure that it is defined before your script runs.

Here is the final piece of code for your functions.php file that brings this altogether:


add_action( 'wp_ajax_post_feedback', 'post_feedback' );
add_action( 'wp_ajax_nopriv_post_feedback', 'post_feedback' );
function post_feedback() {
	if(!isset($_POST['response']) || !isset($_POST['post_id'])) {
		echo json_encode(array('feedback_success'=>0));
		wp_die();
	} else {
		$response_safe = filter_var($_POST['response'], FILTER_SANITIZE_STRING);
		$post_safe = filter_var($_POST['post_id'], FILTER_SANITIZE_NUMBER_INT);
		if($response_safe=='yes') {
			$yes_count = get_post_meta ( $post_safe, 'feedback_yes', true );
			update_post_meta($post_safe, 'feedback_yes', ++$yes_count);
			echo json_encode(array('feedback_success'=>1));
			wp_die();
		} else if ($response_safe=='no') {
			$no_count = get_post_meta ( $post_safe, 'feedback_no', true );
			update_post_meta($post_safe, 'feedback_no', ++$no_count);
			echo json_encode(array('feedback_success'=>1));
			wp_die();
		} else {
			echo json_encode(array('feedback_success'=>0));
			wp_die();
		}
	}
}

The function post_feedback will be called whenever admin-ajax.php receives an HTTP request with an action of post_feedback.  My code first checks to see if the two required $_POST variables are set.  If they are not set, I return a JSON data response of feedback_success = 0 which my Javascript interprets as an error.

It is important to treat all $_POST data as potentially unsafe because it can be changed by a malicious user.  Therefore, I use best security practices and use filter_var to sanitize the $_POST data before using it.  I also name my sanitized variables so that the name specifies that they are safe. This is to avoid confusion.  Then the code increments the yes or no count, depending on which button the user clicked on, and then saves the new value into the post’s custom field.

Common WordPress Ajax Errors and How to Solve Them

The tool that I rely on most often to troubleshoot Ajax issues is Google Chrome Developer Tools. Ctrl+Shit+I will open up the Chrome tools. If you select the “Network” tab, you can view all of the XHR requests and see the server response.

Fixing this Error: WordPress admin-ajax.php returns 0

This can be a puzzling error, but usually the solution is easy. Your PHP function for handling the ajax must call wp_die(). If you forget and call exit() instead, your PHP script will not work correctly.

Diagnosing and Solving PHP Errors

Strangely enough, PHP errors at first glance might look like some strange Javascript error, such as: “Uncaught SyntaxError: Unexpected token {” This is because the Javascript is expecting a JSON (or XML) response and instead it got a PHP error that it’s trying to parse. If you have WP_DEBUG turned on, you should see the PHP errors in the Chrome Developer Tools.

Problem: Ajax Only Works on the Admin Side

There are two things you have to do to get wp_ajax to work on the frontend. One, you have to define ajaxurl (see above). And two, you have to use the wp_ajax_nopriv_ hook.

Conclusion

There are a lot of different parts that go into programming an Ajax request for a WordPress theme or plugin, but the finished product is a dynamic and interactive website.