Back to Blog
Lesson 35 of the WordPress Plugin Development: Foundations (PHP & MVC) course
WordPressJune 25, 20263 min read

Handling AJAX Requests: A Guide to Asynchronous WordPress

Learn to handle AJAX requests in WordPress securely. Master wp_ajax hooks, JSON responses, and frontend communication to power your plugin's interactivity.

WordPressPHPAJAXJavaScriptAPIBackendplugin-development

Previously in this course, we explored unit testing foundations to ensure our code remains robust under pressure. Now that your plugin logic is verified, it's time to make it dynamic. In this lesson, we are moving beyond traditional page reloads by implementing AJAX (Asynchronous JavaScript and XML) to allow your Knowledge Base plugin to communicate with the server in the background.

Asynchronous Communication from First Principles

In a standard WordPress request, the browser sends a request, the server processes it, and the entire page reloads. AJAX changes this by allowing the frontend to send and receive data without a full refresh.

In WordPress, this is handled via a centralized endpoint: wp-admin/admin-ajax.php. When you send an asynchronous request to this file, WordPress spins up the environment and triggers a specific hook based on the action parameter you provide.

To handle these requests in your plugin, you need three things:

  1. The Backend Handler: A PHP function hooked into wp_ajax_{your_action}.
  2. The Security Layer: A nonce to prevent Cross-Site Request Forgery (CSRF).
  3. The Frontend Trigger: JavaScript using the fetch API to hit the endpoint.

Worked Example: Upvoting a Knowledge Base Article

Let’s add an "Upvote" feature to our Knowledge Base plugin. When a user clicks a button, we want to increment a count in the database without reloading the page.

1. Registering the AJAX Action

In your AdminController or a dedicated AjaxController, register your handler:

PHP
add_action('wp_ajax_kb_upvote_article', [$this, 'handle_upvote']);
add_action('wp_ajax_nopriv_kb_upvote_article', [$this, 'handle_upvote']);

public function handle_upvote() {
    #6A9955">// 1. Verify the nonce for security
    check_ajax_referer('kb_upvote_nonce', 'security');

    #6A9955">// 2. Sanitize and validate input
    $article_id = intval($_POST['id']);
    
    #6A9955">// 3. Perform the logic(e.g., updating post meta)
    $current = get_post_meta($article_id, '_kb_upvote_count', true);
    update_post_meta($article_id, '_kb_upvote_count', $current + 1);

    #6A9955">// 4. Send a JSON response and terminate
    wp_send_json_success(['new_count' => $current + 1]);
}

2. Preparing the Frontend

You must pass the AJAX URL and the nonce to your JavaScript file using wp_localize_script, as we covered in enqueuing scripts and styles.

PHP
wp_localize_script('kb-frontend-js', 'kb_ajax', [
    'url'   => admin_url('admin-ajax.php'),
    'nonce' => wp_create_nonce('kb_upvote_nonce')
]);

3. The JavaScript Request

Now, use fetch to send the request. If you are building modern interfaces, remember that handling form submissions or fetching data from an API follows similar asynchronous patterns.

JAVASCRIPT
const upvoteArticle = async (articleId) => {
    const formData = new FormData();
    formData.append(CE9178">'action', CE9178">'kb_upvote_article');
    formData.append(CE9178">'security', kb_ajax.nonce);
    formData.append(CE9178">'id', articleId);

    const response = await fetch(kb_ajax.url, {
        method: CE9178">'POST',
        body: formData
    });

    const data = await response.json();
    if (data.success) {
        console.log(CE9178">'New count:', data.data.new_count);
    }
};

Hands-on Exercise

  1. Create a new button in your Knowledge Base single-article template.
  2. Localize a script that passes the current post ID and a generated nonce to your JS.
  3. Implement the wp_ajax_ hook in your plugin core to handle the ID increment and return a JSON object with wp_send_json_success().
  4. Use fetch to send the request and update the button text with the new count returned from the server.

Common Pitfalls

  • Forgetting wp_die() or wp_send_json(): If you don't terminate the script, WordPress appends a 0 (or the whole page HTML) to your JSON response, causing a parsing error. wp_send_json_success handles this for you.
  • Missing wp_ajax_nopriv_: If you want logged-out users to use your AJAX features, you must hook into both wp_ajax_{action} and wp_ajax_nopriv_{action}.
  • Hardcoding URLs: Never hardcode admin-ajax.php. Always use admin_url('admin-ajax.php') to ensure compatibility with SSL and multisite environments.
  • Security Neglect: Always use check_ajax_referer to verify that the request originated from your own site's form.

Recap

We’ve learned that AJAX is the backbone of modern, interactive WordPress plugins. By using wp_ajax_ hooks, we can keep our PHP logic encapsulated while providing a fluid user experience. Always remember to sanitize your inputs, verify your nonces, and output valid JSON. These practices ensure your plugin remains secure and professional as it grows.

Up next: We will move from the legacy admin-ajax system to the modern, clean approach of REST API Integration.

Similar Posts