Skip to content

AJAX In Plugins

eswarsaladi edited this page Jan 5, 2023 · 1 revision

AJAX in Plugins

Introduction


  • Ajax - Overview of the technology
  • Writing a Plugin - How to write a plugin
  • Plugin API - Filters and actions - what they are and how to use them How to add HTML to the appropriate WordPress page, post, or screen -- for instance, if you want to add Ajax to administration screens you create, you will need to understand how to add administration menus to WordPress; if you want to add Ajax to the display of a single post, you'll need to figure out the right filters and actions to add HTML to that spot on viewer-facing blog screens. This article does not cover these topics.

Ajax on the Administration Side


Since Ajax is already built into the core WordPress administration screens, adding more administration-side Ajax functionality to your plugin is fairly straightforward.

This short example uses PHP to write our JavaScript in the footer of the page. This script then triggers the AJAX request when the page is fully loaded:

<?php
add_action( 'admin_footer', 'my_action_javascript' ); // Write our JS below here

function my_action_javascript() { ?>
	<script type="text/javascript" >
	jQuery(document).ready(function($) {

		var data = {
			'action': 'my_action',
			'whatever': 1234
		};

		// since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
		jQuery.post(ajaxurl, data, function(response) {
			alert('Got this from the server: ' + response);
		});
	});
	</script> <?php
}
<?php 

add_action( 'wp_ajax_my_action', 'my_action' );

function my_action() {
	global $wpdb; // this is how you get access to the database

	$whatever = intval( $_POST['whatever'] );

	$whatever += 10;

        echo $whatever;

	wp_die(); // this is required to terminate immediately and return a proper response
}

Notice how the 'action' key's value 'my_action', defined in our JavaScript above, matches the latter half of the action 'wp_ajax_my_action' in our AJAX handler below. This is because it is used to call the server side PHP function through admin-ajax.php. If an action is not specified, admin-ajax.php will exit, and return 0 in the process.

You will need to add a few details, such as error checking and verifying that the request came from the right place ( using check_ajax_referer() ), but hopefully the example above will be enough to get you started on your own administration-side Ajax plugin.

Notice the use of wp_die(), instead of die() or exit(). Most of the time you should be using wp_die() in your Ajax callback function. This provides better integration with WordPress and makes it easier to test your code.

Separate JavaScript File


The same example as the previous one, except with the JavaScript on a separate external file we'll call js/my_query.js. The examples are relative to a plugin folder.

jQuery(document).ready(function($) {
	var data = {
		'action': 'my_action',
		'whatever': ajax_object.we_value      // We pass php values differently!
	};
	// We can also pass the url value separately from ajaxurl for front end AJAX implementations
	jQuery.post(ajax_object.ajax_url, data, function(response) {
		alert('Got this from the server: ' + response);
	});
});

With external JavaScript files, we must first wp_enqueue_script() so they are included on the page. Additionally, we must use wp_localize_script() to pass values into JavaScript object properties, since PHP cannot directly echo values into our JavaScript file. The handler function is the same as the previous example.

<?php
add_action( 'admin_enqueue_scripts', 'my_enqueue' );
function my_enqueue($hook) {
    if( 'index.php' != $hook ) {
	// Only applies to dashboard panel
	return;
    }
        
	wp_enqueue_script( 'ajax-script', plugins_url( '/js/my_query.js', __FILE__ ), array('jquery') );

	// in JavaScript, object properties are accessed as ajax_object.ajax_url, ajax_object.we_value
	wp_localize_script( 'ajax-script', 'ajax_object',
            array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'we_value' => 1234 ) );
}

// Same handler function...
add_action( 'wp_ajax_my_action', 'my_action' );
function my_action() {
	global $wpdb;
	$whatever = intval( $_POST['whatever'] );
	$whatever += 10;
        echo $whatever;
	wp_die();
}

Ajax on the Viewer-Facing Side


Since WordPress 2.8, there is a hook similar to wp_ajax_(action):

wp_ajax_nopriv_(action) executes for users that are not logged in. So, if you want it to fire on the front-end for both visitors and logged-in users, you can do this:

add_action( 'wp_ajax_my_action', 'my_action' );
add_action( 'wp_ajax_nopriv_my_action', 'my_action' );

Note 1: Unlike on the admin side, the ajaxurl javascript global does not get automatically defined for you, unless you have BuddyPress or another Ajax-reliant plugin installed. So instead of relying on a global javascript variable, declare a javascript namespace object with its own property, ajaxurl. You might also use wp_localize_script() to make the URL available to your script, and generate it using this expression: admin_url( 'admin-ajax.php' )

Note 2: Both front-end and back-end Ajax requests use admin-ajax.php so is_admin() will always return true in your action handling code. When selectively loading your Ajax script handlers for the front-end and back-end, and using the is_admin() function, your wp_ajax_(action) and wp_ajax_nopriv_(action) hooks MUST be inside the is_admin() === true part.

Ajax requests bound to either wp_ajax_ or wp_ajax_nopriv_ actions are executed in the WP Admin context. Carefully review the actions you are performing in your code since unprivileged users or visitors will be able to trigger requests with elevated permissions that they may not be authorized for.

if ( is_admin() ) {
    add_action( 'wp_ajax_my_frontend_action', 'my_frontend_action' );
    add_action( 'wp_ajax_nopriv_my_frontend_action', 'my_frontend_action' );
    add_action( 'wp_ajax_my_backend_action', 'my_backend_action' );
    // Add other back-end action hooks here
} else {
    // Add non-Ajax front-end action hooks here
}

Here the Ajax action my_frontend_action will trigger the PHP function my_frontend_action_callback() for all users. The Ajax action my_backend_action will trigger the PHP function my_backend_action_callback() for logged-in users only.

The post-load JavaScript Event


Plugins and themes that insert content via Ajax must trigger the post-load event on document.body after content is inserted. Other scripts that depend on a JavaScript interaction after content insertion, such as AddToAny or a jQuery Masonry script, listen for the post-load event to initialize their required JavaScript. When the post-load event is fired from Jetpack's Infinite Scroll, for example, AddToAny displays the share buttons for each post, and jQuery Masonry positions elements on the page.

JavaScript triggering the post-load event after content has been inserted via Ajax:

jQuery( document.body ).trigger( 'post-load' );

JavaScript listening to the post-load event:

jQuery( document.body ).on( 'post-load', function () {
    // New content has been added to the page.
} );

Error Return Values


If the Ajax request fails in wp-admin/admin-ajax.php, the response will be -1 or 0, depending on the reason for the failure. Additionally, if the request succeeds, but the Ajax action does not match a WordPress hook defined with add_action('wp_ajax_(action)', ...) or add_action('wp_ajax_nopriv_(action)', ...), then admin-ajax.php will respond 0.

Debugging


To parse AJAX, WordPress must be reloaded through the admin-ajax.php script, which means that any PHP errors encountered in the initial page load will also be present in the AJAX parsing. If error_reporting is enabled, these will be echoed to the output buffer, polluting your AJAX response with error messages.

Because of this, care must be taken when debugging Ajax as any PHP notices or messages returned may confuse the parsing of the results or cause your JavaScript to error.

One option if you can't eliminate the messages and must run with debug turned on is to clear the buffer immediately before returning your data.

    ob_clean();
    echo $whatever;
    wp_die();

It is also possible to use tools such as FirePHP to log debug messages to your browsers debug console. An alternative approach is to use a debugging proxy such as fiddler.

WPEngineer - FirePHP and Wordpress Fiddler

Further Reading - External Resources


Related References