Create Proper WordPress Ajax Request in JavaScript, NOT jQuery

There are 4 filters to work with WordPress ajax.
According to your description, the following conditions are assumed

  • wp_ajax_{$action} is for running in frontend and the user is logged in
  • if echo something in the php file, it will not reflect in the frontend. Javascript alert will output ‘hello’
  • your javascript seems to be done in PHP and generate javascript, I suppose you have added proper header

According to WP Codex, the 4 filters for ajax are

Some facts about the code

  • There are missing echo to output nonce and admin_url
  • the script is actually not working (it is according to your shared code, there might be additional code. Anyway, if going to browser inspector, it gives 400 bad request error. It did not send ajax successfully.

There are a few issues in the code, here is the fixed script with missing pieces that I need for doing the test. I put the code into my theme functions.php and javascript code into test.php

In the testing, have put in the theme functions.php

// load the javascript
function q364077_enqueue_scripts()
{
    wp_enqueue_script('test-custom-scripts', get_theme_file_uri('/test.php'), array(), 't' . time(), true);
}
add_action('wp_enqueue_scripts', 'q364077_enqueue_scripts', 101);

// The ajax answer()
add_action( 'wp_ajax_my_action', 'answer' );
function answer() {
    // check_ajax_referer( 'nonce-name' );
    echo "hello";

    wp_die(); // terminate script after any required work, if not, the response text will output 'hello0' because the of function return after finish
}

The test.php is put in the theme folder, same level as functions.php

<?php
// inside the javascript test.php
/** Load WordPress Bootstrap */
// for test.php in theme folders
require_once( ( ( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) ) ) . '/wp-load.php' ); // to use admin_url(), if not, the script will be broken


// for output the javascript through php
header("Content-type: text/javascript");?>

function myFunction() {

    let dataContent = "hello";

    let myData = {
      _ajax_nonce: "<?php echo wp_create_nonce( 'nonce-name' );?>", // haven't added echo here, it is actually blank in output.
      // Action Hook name for Ajax Call
      action: 'my_action',
      // Currently typed username
      data: dataContent
    };
    // To send the JavaScript object to the server, convert it into a JSON string
    let myDataJSON = JSON.stringify(myData);

    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        alert(this.responseText);
      }
    };

    let link = "<?php echo admin_url( 'admin-ajax.php' );?>"; // require "echo" to output, otherwise, it will alert unexpected output
    xhttp.open("POST", link, true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");

    // It is explained in the following, I use static value for illustration purpose
    xhttp.send('_ajax_nonce=efc5e4029d&action=my_action&data=hello');

The data need to be serialized, not only string. Your data look likes

{"_ajax_nonce":"efc5e4029d","action":"my_action","data":"hello"}

Ajax looks for this which jQuery has done for user. For Vanilla JS, it need to be done manually or using any existing vanilla js tools.

_ajax_nonce=efc5e4029d&action=my_action&data=hello

You may test the above code by fixing the ‘echo’ and putting a static value of the data to experience and may also go to the inspector, Chrome as an example.

in the inspector -> Network Tab -> when you fire myFunction() in console log, it return the status to you with request/response header, in that way, it helps bug fixing.

The above code tested and proved working in a fresh WordPress 5.3.2, default twenty twenty theme.

Leave a Comment