undo.studio is a journal about creating a calm, bootstrapped software business from scratch.

by JC

WordPress has a standard way of sending data to PHP on the server from JavaScript in the browser, referred to as WP AJAX.

In this article, I’ll give a complete example of how to set up both the PHP and JavaScript to communicate through this method, using modern JavaScript fetch instead of jQuery, along with nonce verification for security.

Why use WP AJAX?

You may wonder, why use this instead of making your own PHP file that can receive POST data?

WordPress has an admin-ajax.php file through which you can route AJAX requests. It handles many things you’d otherwise have to check on your own. For example, using WP AJAX ensures that when you’re working with data on the PHP side, the WP core files are loaded, so you can query WordPress posts with WP_Query. It can also authenticate the user, if you only want logged-in users to send data.

How this example code is different

Many examples of WP AJAX use jQuery. In this example, I’ll use the modern Fetch API which 97.8% of all browsers support.

The second difference is that I’ll verify a nonce, which WordPress recommends for safeguarding against malicious HTTP requests. If you’re submitting a plugin to WordPress.org, they require that your plugin passes the WordPress Coding Standards (WordPressCS) which enforces nonce verification.

Code snippets you’ll write

  • PHP to load the page with a nonce for the JavaScript to send in a POST request
  • Plain JavaScript fetch to make a POST request to the PHP
  • PHP to handle incoming data

In these examples, you’ll see the dashify prefix (a plugin I’m making!). You should replace this with your own prefix.

The examples below are for a plugin, so it may be slightly different when developing a theme, or if you’re rendering JavaScript with PHP instead of enqueueing it. You’ll also need to adjust file paths for your own project.

Loading the page with a nonce (PHP)

First, we’ll use wp_enqueue_script to load a JavaScript file, and then wp_add_inline_script to pass it a nonce.

wp_enqueue_script(
	'dashify_settings_script',
	plugins_url( '/admin/js/dashify-settings.js', __FILE__ )
);

$nonce = wp_create_nonce( 'dashify_save_settings_nonce' );
$ajax_url = admin_url( 'admin-ajax.php' );

wp_add_inline_script(
	'dashify_settings_script',
	"const dashify = {
		nonce: '$nonce',
		ajaxURL: '$ajax_url',
	};",
	'before'
);

We’re using wp_add_inline_script instead of wp_localize_script, which you may have seen in other examples online, because, as mentioned in the documentation, the latter is designed for translating strings, not passing data. wp_add_inline_script is the official way to pass data after WordPress 4.5, which was released in 2016.

Sending data from JavaScript

On the client side, we’ll create a FormData to which we’ll add the nonce, a unique name for the action, and some data.

The nonce and URL to POST to are available on the page in a global dashify object thanks to the wp_add_inline_script we wrote earlier.

const data = new FormData();
data.append('_ajax_nonce', dashify.nonce);
data.append('action', 'dashify_save_settings');
data.append('dashify_enabled', 'true');

await fetch(dashify.ajaxURL, {
	method: 'POST',
	body: data
});

We’ll leave out getting a response in this example, but know that it’s possible to send a response from the PHP side, receive it here, and continue executing JavaScript.

Handling the incoming data

Back on the PHP side, we’ll use a WordPress action to handle the incoming data.

add_action(
	'wp_ajax_dashify_save_settings',
	'handle_dashify_save_settings'
);

function handle_dashify_save_settings() {
	// If the setting data wasn’t sent, something went
	// wrong, and we shouldn’t do any further processing.
	if ( empty( $_POST['dashify_enabled'] ) ) {
		return;
	}

	// Verify the nonce. If it fails, it will return a
	// 403 response. The value passed in here should
	// match what was passed to wp_create_nonce().
	check_ajax_referer( 'dashify_save_settings_nonce' );

    // In your own project, this is where you handle the
    // incoming data according to your needs. In my project,
    // we’re saving an option.
	update_option(
		'dashify_enabled',
		sanitize_key( $_POST['dashify_enabled'] )
	);

	// Stop execution of PHP and return a response to the
	// browser. This is needed if you’re not already sending
	// back data with wp_send_json() or similar.
	wp_die();
}

Refer to the documentation on the wp_ajax_ hooks for additional detail, like how to allow unauthenticated requests.

Depending on your use case, you’ll need to sanitize and validate data accordingly. In the example above, the WordPress function sanitize_key is sufficient for the value in dashify_enabled, and it passes WordPressCS. As a bonus, it’s shorter than sanitize_text_field( wp_unslash( … which you might end up with after following the suggestions from WordPressCS tool. This WordPressCS page on GitHub describes the different ways to sanitize and validate data.

With those snippets, you should can send data from JavaScript to PHP easily when developing in WordPress!

If you spot any mistakes, feel free to contact me. I’d like to keep this example updated and accurate for as long as possible.

Happy coding!

January 2024 numbers
7 February 2024
Waiting for 51 days
14 January 2024
Analytics aren’t evil
28 February 2023
Bye Linux, hello Mac
27 November 2022