Authoritative Guide To Implementing Ajax In WordPress

Implement Ajax in WordPress

There are several guides available to implement ajax functionality in WordPress. When it comes to implementation in real-world, things get confusing pretty easily.

Ajax in WordPress is typically relied upon for communication between JavaScript & PHP (and vice versa). The data-type typically used for such communication is json. With that out of the way, how do you implement such communication to precise standards allowing data-validation and proper security authentication etc?

The official WordPress codex covers the basics of implementing ajax in admin area as well as front-end and also covers how to enqueue the script, pass it data by the way of localizing etc. For the basics please refer to the following articles:

Ajax in Plugins

Ajax in WordPress Developer Handbook

Where this gets tricky is when you want to use the proper functions on the server-side to respond to an ajax request. In all as of this date, there are 3 WordPress functions which allow you to send json data in response to an ajax request:

  1. wp_send_json_success
  2. wp_send_json_error
  3. wp_send_json

wp_send_json_success and wp_send_json_error are the ones that should typically be used in favour of data validation. They are basically wrappers around the third function (wp_send_json). wp_send_json_success and wp_send_json_error basically wrap the json data and include another Javascript property named success the value of which is true in case of wp_send_json_success and false in case of wp_send_json_failure.

The catch is that oftentimes the value of the success property is confused with an ajax response failure.

If you requested a json data-type and the data you received came along with the success property, here’s what it means in the various following cases:

Ajax Success Handler

1. success is true:

The server was able to fulfill the request successfully: The ajax request got a valid json response and completed successfully.

{
    "success": true,
    "data": {
        "property1": "value1"
    }
}

2. success is false:

The server was NOT able to fulfill the request successfully ; the ajax request however got a valid json response and completed successfully.

{
    "success": false,
    "data": {
        "property1": "value1"
    }
}

3. The success property doesn’t exist:

The ajax request-response completed successfully. Validate the data before handling it.

{
   "property1": "value1"
   
}

In this case the data could also be non-json and you should validate the data in either case.

All the above three cases trigger the JQuery success handler becasue regardless of server having executed your requested successfully or unsuccessfully, the server did successfully respond with a response.

Ajax Error Handler

The jQuery “error” handler comes in when a response from the server was not received; probably timedout for some reason or the other. That’s where you’d need the UI to reflect a failure.

Ajax Complete Handler

The JQuery “complete” handler triggers after the “success” and / or “error” handlers have finished executing. Thus it triggers at the very end regardless of whether the ajax call was successful or not.

Singleton PHP Class Demonstrating Ajax in WordPress Admin Area

The following singleton class in PHP can be used to experiment with various kinds of requests and responses inside the WordPress Admin area. You can deploy it as a drop-in, a must-use plugin or modify / add it to your plugin / theme. It’s well-commented (but untested).

<?php
// Singleton class
class Ajax_in_WP {
    static function get_instance() {
        static $instance = null;
        if ( is_null( $instance ) ) {
            $instance = new self();
            $instance->init();
        }
        return $instance;
    }

    // Hook relevant functions
    function init() {
        add_action( 'admin_footer', array( $this, 'footer_script' ) );
        add_action( 'wp_ajax_my_ajax_handler', array( $this, 'my_ajax_callback' ) ); // Respond to logged-in users.
        add_action( 'wp_ajax_nopriv_my_ajax_handler', '__return_false' ); // // Do not respond to logged-out users.
    }

    // Server-side ajax request handler / responder
    function my_ajax_callback() {
        check_ajax_referer( 'my_ajax', 'my_ajax_nonce' ); // don't respond if nonce is not valid
        // Uncomment either of the following lines. Only the first wp_send_json* call will be executed; subsequent lines will not be executed since wp_send_json* functions call wp_die / die
        wp_send_json_success( 'Uncommenting this line will return a json object with the success property set to true.' );
        wp_send_json_error( 'Uncommenting this line will return a json object with the success property set to false.' );
        wp_send_json( 'Uncommenting this line will return a json object without the success property.' );
        wp_send_json( $_REQUEST ); // Want to see what data was sent by the browser and received by the server?
    }

    // Browser-side script that triggers ajax request and handles response / error etc.
    function footer_script() {
        ?>
        <script type="text/javascript">

        // Trigger as soon as page is loaded
        jQuery(document).ready(function($){

            // Set up what data we are going to send to the server.
            let my_ajax_request = {
                my_ajax_nonce: '<?php echo wp_create_nonce( 'my_ajax' ); ?>',
                action: "my_ajax_handler",
                user: {
                    fn: $('#my_user_fname').val(),
                    ln: $('#my_user_lname').val(),
                    email: $('#my_user_email').val(),
                }
            };

            $.ajax({
                url: ajaxurl,
                method: 'POST',
                data: my_ajax_request,
                // Triggered when the ajax response is received (response data is not validated yet)
                success:function(response_data,textStatus,jqXHR){
                    console.log('==== SUCCESS HANDLER STARTS ====');
                    if ((typeof response_data) === 'object') { // Verify that the data is a json object
                        if (response_data.hasOwnProperty('success') ) { // ajax request has a success but we haven't tested if success is true or false
                            if( response_data.success ){ // If the value of success property is true. Triggered by wp_send_json_success
                                console.log('Server fulfilled your request successfully');
                            }
                            else { // // If the value of success property is false. Triggered by wp_send_json_error
                                console.log('Response received from server that it failed to fulfill your request');
                            }
                        } else { // Triggered by wp_send_json (success property does not exist)
                            console.log('Response received from server. Validate the response before handling it');
                        }
                    }
                    else { // Triggered when the data type is not json
                        console.log('Response received is not json but some other data type probably text.');
                    }
                    console.log('response_data');
                    console.dir(response_data);
                    console.log('textStatus');
                    console.dir(textStatus);
                    console.log('jqXHR');
                    console.dir(jqXHR);
                    console.log('==== SUCCESS HANDLER ENDS ====');
                },
                // Triggered when the ajax response failed
                error:function(jqXHR,textStatus,errorThrown){
                    console.log('==== ERROR HANDLER STARTS ====');
                    console.log('Ajax request could not be completed. Perhaps network issue or server did not respond etc.');
                    console.log('jqXHR');
                    console.dir(jqXHR);
                    console.log('textStatus');
                    console.dir(textStatus);
                    console.log('errorThrown');
                    console.dir(errorThrown);
                    console.log('==== ERROR HANDLER ENDS ====');
                },
                // Always runs regardless of success and failure
                complete:function(jqXHR,textStatus){
                    console.log('==== COMPLETE HANDLER STARTS ====');
                    console.log('Ajax complete always gets called regardless of success or error. Use it if you want to do something anyway.');
                    console.log('jqXHR');
                    console.dir(jqXHR);
                    console.log('textStatus');
                    console.dir(textStatus);
                    console.log('==== COMPLETE HANDLER ENDS ====');
                },
            }); // Ajax        
        }); // document-ready
        </script>
        <?php
    }
} // class Ajax_in_WP

function Ajax_in_WP() {
    return Ajax_in_WP::get_instance();
}

Ajax_in_WP();

Assuming that you are a developer implementing ajax in WordPress, you can tell that the above script responds inside the browser’s javascript console.

Feel free to drop a line if required.

Divi WordPress Theme