Create Proper WordPress Ajax Request in JavaScript, NOT jQuery

The question:

Okay, so I programmed the following ajax code for my plugin, and I’m wondering why it’s not working:

JavaScript:

function myFunction() {

  let dataContent = "hello";

  let myData = {
    // Nonce
    _ajax_nonce: "<?php wp_create_nonce( 'nonce-name' );?>",
    // 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 admin_url( 'admin-ajax.php' );?>";
  xhttp.open("POST", link, true);
  xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xhttp.send("data=" + myDataJSON);
}

PHP (Callback):

function answer() {
  check_ajax_referer( 'nonce-name' );
  echo "hello";
}

PHP (Hook):

add_action( 'wp_ajax_my_action', 'answer' );

When launching the call, I get “undefined” displayed in the alert window. What’s wrong?

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

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.

Method 2

You’re focusing on the script – side, but the addition of slashes to the json object only happens once the data is sent and received by the server, before being sent back to javascript. Guess I need to find out how to define the datatype in pure javascript in wordpress, with jquery its simply by using dataType:json (tried to serialize in pure js, didn’t work, lmk if u get the answer, and thx!)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment