Replacing admin-ajax with REST API Endpoints

Sometimes it may be convenient to replace AJAX requests in the admin panel with requests using the REST API. This can make your code more concise and the requests more secure.

Let's consider the following example. Suppose the plugin code adds an admin page. On this page, there is a button and an area for the result of the AJAX request. When the button is clicked, an AJAX request is executed that retrieves the latest posts, and then the titles of these posts are displayed.

Using WP AJAX

In this example, there is no nonce implementation for security, but this must be added in a real plugin.

To start, we need to enqueue our JS script:

add_action( 'admin_enqueue_scripts', 'wp_learn_rest_enqueue_script' );

function wp_learn_rest_enqueue_script() {
	wp_enqueue_script(
		'myscript',
		plugin_dir_url( __FILE__ ) . 'myscript.js',
		[ 'jquery' ],
		false,
		true
	);
}

Now let's write a script to handle the button click event and execute the AJAX request.

/**
 * Handling the AJAX request
 */
jQuery( document ).ready(
	function ( $ ) {
		const loadPostsButton = $( '#ajax-button' );
		if ( loadPostsButton ) {
			loadPostsButton.on(
				'click',
				function ( event ) {
					$.post(
						ajaxurl,
						{
							'action': 'learn_fetch_posts',
						},
						function ( posts ) {
							const textarea = $( '#wp-learn-posts' );
							posts.forEach( function ( post ) {
								textarea.append( post.post_title + '\n' )
							} );
						},
					)
				},
			);
		}
	},
);

Note: Here we use the js variable ajaxurl, which is automatically defined in the admin panel.

Now we need to create a function to handle the AJAX request. For this, we attach a callback to the hook wp_ajax_*

add_action( 'wp_ajax_learn_fetch_posts', 'my_ajax_fetch_posts' );

function my_ajax_fetch_posts() {
	$posts = get_posts();
	wp_send_json( $posts );

	// All AJAX handlers must terminate PHP after completing their work
	wp_die();
}

Using WP REST API

Now let's see how such a task would look if we used the WP REST API.

Now an AJAX request handler is not needed, so we can remove the function my_ajax_fetch_posts and the associated hook.

WordPress comes with a client Backbone JavaScript for making direct requests to the WP REST API.

To ensure that your code can use the Backbone.js client, you simply need to update your plugin's dependency from jquery to wp-api.

This will ensure that your plugin's JavaScript code is loaded only after the REST API JavaScript client is loaded, so you can use it in your js script.

In the JavaScript file, you can first remove the code related to jQuery/Ajax.

Then you will need to register a click event handler for the new button.

const loadPostsByRestButton = document.getElementById( 'wp-learn-rest-api-button' );
if ( loadPostsByRestButton ) {
	loadPostsByRestButton.addEventListener( 'click', function () {
		// do something
	} );
}

Then in the event handler function, you can use the WP API client, getting it from the global wp object, to create a new collection of posts:

const allPosts = new wp.api.collections.Posts();

At this point, "allPosts" is just an empty collection, so you will need to retrieve the posts by calling the "fetch" method on the collection.

allPosts.fetch();

The "fetch" method returns a promise, so you can chain the "done" method to handle the response and implement a callback function that will take the response from the API request. You can specify the posts argument in this callback function to accept the response from the API request.

const posts = allPosts.fetch().done(
	function ( posts ) {
		// do something with the posts
	}
);

Now you can iterate over the posts object using the "forEach" method.

const posts = allPosts.fetch().done(
	function ( posts ) {
		posts.forEach( function ( post ) {
			// do something with the post
		} );
	}
);

Finally, you can add the post title to the response result area. First, you need to create an instance of the textarea before the forEach loop, and then add the post title to the textarea's value property inside the forEach loop.

const posts = allPosts.fetch().done(
	function ( posts ) {
		const textarea = document.getElementById( 'wp-learn-posts' );
		posts.forEach( function ( post ) {
		  textarea.value += post.title.rendered + '\n'
		} );
	}
);

The final code will look something like this:

const loadPostsByRestButton = document.getElementById( 'wp-learn-rest-api-button' );
if ( loadPostsByRestButton ) {
	loadPostsByRestButton.addEventListener( 'click', function () {
		const allPosts = new wp.api.collections.Posts();
		allPosts.fetch().done(
			function ( posts ) {
				const textarea = document.getElementById( 'wp-learn-posts' );
				posts.forEach( function ( post ) {
					textarea.value += post.title.rendered + '\n'
				} )
			}
		);
	} );
}

Conclusion

A major advantage of using the WP REST API and the Backbone.js JavaScript client is that you can use the same client repeatedly. For example, if you want to get users, you can simply create a new user collection and retrieve them. To do this via admin-ajax, you would need either a new admin_ajax handler function or update the existing function to accept a parameter to determine what to retrieve.

Another advantage is that the JavaScript API client handles nonce verification for you. With admin-ajax, you need to specify this yourself and check it in your handler function. Thus, by using the REST API and JavaScript client, your requests become more secure.