WordPress AJAX

Asynchronous JavaScript and XML, commonly known as AJAX plays an important role in designing functional WordPress plugins. It allows WordPress plugins to download data without refreshing the page each time for fetching data from the server. It does this by transferring data in the backend.

References

Example

In this example plugin, consider how wp_ajax has been used to mix PHP and JavaScript, then provide functionality similar to the Heartbeat API to update with a random color and random words from a proxied remote HTTP API every 3 seconds.

Note in the example use of apply_filters() to unify data sent to wp_localize_script() (initialData) and $.getJSON() (newData).

<?php
/**
 * Plugin Name: AJAX Enqueue Script Example
 * Description: Set a random background color from values calculated in PHP. Load random words from a remote API. Update every 3 seconds.
 *
 * @see https://gist.github.com/pdclark/5570bb145a1aa5f63f98b6bfd0783a9a
 *      For a version using WP REST API.
 */

/**
 * Data sent in JSON via wp_localize_script() for initialData and wp_ajax action for update_data.
 */
add_filter(
	'aese/data',
	function( $a ){
		return array_merge( $a, [
			'date' => date( 'Y-m-d' ),
			'microtime' => microtime(),
			'update_url' => admin_url( 'admin-ajax.php?action=update_data' ),
			'bg_color' => [
				'r' => rand( 0, 255 ),
				'g' => rand( 0, 255 ),
				'b' => rand( 0, 255 ),
				'a' => ( rand( 0, 100 ) / 100 ),
			],
			'random_words' => json_decode(
				wp_remote_retrieve_body(
					wp_remote_get( 'https://random-word-api.herokuapp.com/word?number=10' )
				)
			),
		] );
	}
);
/**
 * Enqueue a wp_ajax action as a JavaScript.
 */
add_action(
	// Enqueue on front-end and backend.
	// Else see template_redirect or admin_init.
	'init',
	function(){
		wp_enqueue_script(
			'ajax_enqueued_script',
			// This script address will load PHP and WordPress again.
			admin_url( 'admin-ajax.php?action=ajax_enqueued_script' ),
			// Script dependencies.
			// @see https://developer.wordpress.org/reference/functions/wp_register_script/#core-registered-scripts
			[ 'jquery' ],
			1,
			true
		);
		wp_localize_script(
			'ajax_enqueued_script',
			// If the above address has been changed to a static file,
			// this object will send initial PHP values to JavaScript in an "initialData" object.
			'initialData',
			apply_filters( 'aese/data', [] )
		);
	}
);
/**
 * Serve JSON from filter via wp_ajax action.
 */
add_action(
	// Unauthenticated users.
	'wp_ajax_nopriv_update_data',
	function() {
		do_action( 'wp_ajax_update_data' );
	}
);
add_action(
	// Authenticated users.
	'wp_ajax_update_data',
	function() {
		header( 'Content-Type: application/json' );
		echo wp_json_encode(
			apply_filters( 'aese/data', [] )
		);
		exit;
	}
);
/**
 * PHP-powered JavaScript.
 * Could also be moved to static file because of wp_localize_script().
 */
add_action(
	// Unauthenticated users.
	'wp_ajax_nopriv_ajax_enqueued_script',
	function() {
		do_action( 'wp_ajax_ajax_enqueued_script' );
	}
);
add_action(
	// Authenticated users.
	'wp_ajax_ajax_enqueued_script',
	function() {
		header( 'Content-Type: text/javascript' );
		?>
		jQuery( document ).ready( function( $ ) {
			<?php // This can be done because WordPress and PHP are loaded. ?>
			console.log( 'Inline PHP Date: <?php echo esc_js( date( 'Y-m-d' ) ); ?>' );
			<?php // This, wp_localize_script() is a way to send PHP values to JavaScript that works for static scripts as well. ?>
			console.log( 'wp_localize_script() initialData', initialData );

			updateBackgroundColor(
				initialData.bg_color.r,
				initialData.bg_color.g,
				initialData.bg_color.b,
				initialData.bg_color.a
			);
			addWords( initialData.random_words );

			setInterval(
				function(){
					$.getJSON( initialData.update_url, function( newData ){
						updateBackgroundColor(
							newData.bg_color.r,
							newData.bg_color.g,
							newData.bg_color.b,
							newData.bg_color.a
						);
						addWords( newData.random_words );
					});
				},
				3000
			);

			function updateBackgroundColor( r, g, b, a ){
				$( 'body' ).css(
					'background-color',
					'rgba( ' + r + ', ' + g + ', ' + b + ', ' + a + ' )'
				);
			}

			function addWords( words ) {

				for ( let i = 0; i < words.length; i++ ) {
					setTimeout(
						function(){
							$( 'body' ).prepend( words[i] + ' ' );
						},
						i * ( 3000 / words.length )
					)
				}
			}
		} );
		<?php
		exit;
	}
);

In contrast, notice the difference in this version of the plugin, where the REST API is used instead of wp_ajax for newData. Notice especially line 71, where wp_json_encode() is no longer called for data output by the REST API — JSON encoding is handled automatically. Also notice use of get_rest_url() on line 16 — this resolves the path to /wp-json/ even if the JSON endpoint has been modified with the rest_url_prefix filter.

<?php
/**
 * Plugin Name: AJAX Enqueue Script with REST API Example.
 * Description: Set a random background color from values calculated in PHP. Load random words from a remote API. Update every 3 seconds.
 */

/**
 * Data sent in JSON via wp_localize_script() for initialData and wp_ajax action for update_data.
 */
add_filter(
	'aese/data',
	function( $a ){
		return array_merge( $a, [
			'date'         => gmdate( 'Y-m-d' ),
			'microtime'    => microtime(),
			'update_url'   => get_rest_url( null, 'aese/v1/random' ),
			'bg_color'     => [
				'r' => rand( 0, 255 ),
				'g' => rand( 0, 255 ),
				'b' => rand( 0, 255 ),
				'a' => ( rand( 0, 100 ) / 100 ),
			],
			'random_words' => json_decode(
				wp_remote_retrieve_body(
					wp_remote_get( 'https://random-word-api.herokuapp.com/word?number=10' )
				)
			),
		] );
	}
);
/**
 * Enqueue a wp_ajax action as a JavaScript.
 */
add_action(
	// Enqueue on front-end and backend.
	// Else see template_redirect or admin_init.
	'init',
	function(){
		wp_enqueue_script(
			'ajax_enqueued_script',
			// This script address will load PHP and WordPress again.
			admin_url( 'admin-ajax.php?action=ajax_enqueued_script' ),
			// Script dependencies.
			// @see https://developer.wordpress.org/reference/functions/wp_register_script/#core-registered-scripts
			[ 'jquery' ],
			1,
			true
		);
		wp_localize_script(
			'ajax_enqueued_script',
			// If the above address has been changed to a static file,
			// this object will send initial PHP values to JavaScript in an "initialData" object.
			'initialData',
			apply_filters( 'aese/data', [] )
		);
	}
);
/**
 * Serve JSON from filter via REST endpoint.
 *
 * @see https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/
 */
add_action(
	'rest_api_init',
	function() {
		register_rest_route(
			'aese/v1',
			'/random/',
			[
				'methods'  => 'GET',
				'callback' => function() {
					return apply_filters( 'aese/data', [] );
				},
			]
		);
	}
);
/**
 * PHP-powered JavaScript.
 * Could also be moved to static file because of wp_localize_script().
 */
add_action(
	// Unauthenticated users.
	'wp_ajax_nopriv_ajax_enqueued_script',
	function() {
		do_action( 'wp_ajax_ajax_enqueued_script' );
	}
);
add_action(
	// Authenticated users.
	'wp_ajax_ajax_enqueued_script',
	function() {
		header( 'Content-Type: text/javascript' );
		?>
		jQuery( document ).ready( function( $ ) {
			<?php // This can be done because WordPress and PHP are loaded. ?>
			console.log( 'Inline PHP Date: <?php echo esc_js( gmdate( 'Y-m-d' ) ); ?>' );
			<?php // This, wp_localize_script() is a way to send PHP values to JavaScript that works for static scripts as well. ?>
			console.log( 'wp_localize_script() initialData', initialData );

			updateBackgroundColor(
				initialData.bg_color.r,
				initialData.bg_color.g,
				initialData.bg_color.b,
				initialData.bg_color.a
			);
			addWords( initialData.random_words );

			setInterval(
				function(){
					$.getJSON( initialData.update_url, function( newData ){
						updateBackgroundColor(
							newData.bg_color.r,
							newData.bg_color.g,
							newData.bg_color.b,
							newData.bg_color.a
						);
						addWords( newData.random_words );
					});
				},
				3000
			);

			function updateBackgroundColor( r, g, b, a ){
				$( 'body' ).css(
					'background-color',
					'rgba( ' + r + ', ' + g + ', ' + b + ', ' + a + ' )'
				);
			}

			function addWords( words ) {

				for ( let i = 0; i < words.length; i++ ) {
					setTimeout(
						function(){
							$( 'body' ).prepend( words[i] + ' ' );
						},
						i * ( 3000 / words.length )
					)
				}
			}
		} );
		<?php
		exit;
	}
);