Web Development Tutorials

Programming

Handle AJAX Requests in WordPress

Handling AJAX requests in WordPress lets the browser talk to your server without reloading the page — a like button, a load-more link, a live search. You handle AJAX requests in WordPress by routing them through admin-ajax.php: the browser posts an action, and WordPress fires your wp_ajax_{action} hook. This tutorial wires up a like button end to end — enqueuing the script, passing a nonce, writing the handler — and shows the real JSON that comes back.

Requirements to handle AJAX requests in WordPress:

  • WordPress 6.0 or newer (tested on WordPress 7.0.2). Both admin-ajax.php and jQuery ship in core.
  • Administrator access to install a plugin.
  • Basic jQuery — the request below uses $.post(), though fetch() works the same way.

How To Handle AJAX Requests in WordPress.

The objective is to send a request from the browser, verify it with a nonce on the server, update a value, and return JSON — all through WordPress’s own AJAX entry point.

Step 1.

First, create a plugin and enqueue a script. The browser needs two things your PHP knows but your JavaScript does not: the URL of admin-ajax.php, and a security nonce. Pass both with wp_localize_script(), which prints them as a JavaScript object before your script runs.

<?php
/**
 * Plugin Name: NdrieL Like Button
 * Description: An AJAX like button routed through admin-ajax.php.
 * Version:     1.0.0
 */
if (!defined('ABSPATH')) {
    exit;
}

add_action('wp_enqueue_scripts', function () {
    wp_enqueue_script(
        'ndriel-like',
        plugins_url('like.js', __FILE__),
        array('jquery'),
        '1.0.0',
        true
    );
    wp_localize_script('ndriel-like', 'ndrielLike', array(
        'url'   => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('ndriel_like'),
    ));
});

Step 2.

Next, write the front-end script — like.js, beside the plugin file. On click it posts to ndrielLike.url with two fields WordPress needs: the action, which selects your handler, and the nonce. The handler’s JSON reply arrives as the response argument.

jQuery(function ($) {
    $('#ndriel-like').on('click', function () {
        $.post(ndrielLike.url, {
            action: 'ndriel_like',
            nonce:  ndrielLike.nonce
        }, function (response) {
            if (response.success) {
                $('#ndriel-like-count').text(response.data.count);
            }
        });
    });
});

The action value — ndriel_like — is the whole routing mechanism: WordPress turns it into the hook name in the next step. You would attach this to a button with id="ndriel-like", the same way you handle events with jQuery anywhere else.

Step 3.

Then, write the server handler. WordPress builds two hooks from your action: wp_ajax_ndriel_like for logged-in users and wp_ajax_nopriv_ndriel_like for logged-out visitors. Hook the same callback to both if the action is public. Inside, check_ajax_referer() validates the nonce — on failure it stops with -1 and a 403 — then wp_send_json_success() returns JSON and exits cleanly.

add_action('wp_ajax_ndriel_like',        'ndriel_ajax_like');
add_action('wp_ajax_nopriv_ndriel_like', 'ndriel_ajax_like');

function ndriel_ajax_like() {
    check_ajax_referer('ndriel_like', 'nonce');

    $count = (int) get_option('ndriel_like_count', 0);
    $count++;
    update_option('ndriel_like_count', $count);

    wp_send_json_success(array('count' => $count));
}

Step 4.

Finally, activate the plugin and trigger the request. In a browser the button click posts the form; to prove the round trip on its own, post to admin-ajax.php with a valid nonce, then with a bad one to see the guard reject it.

curl -X POST http://ndriel.local/wp-admin/admin-ajax.php \
     --data "action=ndriel_like&nonce=4872e0a303"

Result of the AJAX request in WordPress.

A valid request returns a success envelope whose data holds the new count; each call increments it. A missing or wrong nonce never reaches your logic — check_ajax_referer() answers -1 with HTTP 403. This is the real output from WordPress 7.0.2:

# first click
{"success":true,"data":{"count":1}}      HTTP 200

# second click
{"success":true,"data":{"count":2}}      HTTP 200

# bad / missing nonce
-1                                       HTTP 403

AJAX request in WordPress: two admin-ajax.php calls returning success JSON with an incrementing count, and a bad nonce rejected with -1 and HTTP 403.

Notes on AJAX requests in WordPress:

  • Every AJAX action needs a nonce. Create it with wp_create_nonce(), pass it via wp_localize_script(), and check it with check_ajax_referer(). Without it, any site could post to your endpoint.
  • Register both hooks deliberately. wp_ajax_ only fires for logged-in users; skip wp_ajax_nopriv_ and logged-out visitors get a silent 0. Add it only when the action really should be public.
  • Always end the handler with a wp_send_json_* call (or wp_die()). They exit for you; a plain return leaves WordPress to append a trailing 0 to your response.
  • The action string is the routing key — it must match between the JavaScript and the hook suffix exactly, or nothing fires.
  • For a public, cacheable, read-only feed, a JSON file loaded with jQuery or a custom REST route is a lighter choice than admin-ajax.php, which always bootstraps WordPress.

References:

//

Featured tutorial

Leave a comment

Your email address will not be published. Required fields are marked *