1

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?

2 Answers 2

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.

12
  • Worked! Thank you so much! Now, you wrote that callbacks hooked to wp_ajax_{hook-name} are for logged-in frontend users. The request above shall be used for users logged into the wp backend admin area, and it works when I hook the php callback of the request to wp_ajax_{hook-name} (wp_ajax_nopriv_{} not necessary), so the wp_ajax_{hook-name} is also used for backend requests? Also, I did not enqueue any script or set any header, because I wrote the javascript code onto the corresponding page via simple script tags. Even if everything works now, I wondered about your opinion on that?
    – Joe
    Apr 15, 2020 at 10:15
  • About the admin area, it is different hooks, let me add them all for you and other benefits. Apr 15, 2020 at 10:16
  • Using hooks and page checking mechanism is more WP way to my understanding. And hooks can help you to control in one place. If you do it on the corresponding page with many pages, it is not a very maintenance friendly option. While making it work, it is also needed to consider the ease of maintenance, the structure and so on. It is more on a design basis if speaking about a software development. I have updated the answer with admin hook for reference. You may learn more by reading different source codes. Thank for trusting and testing, your positive involvement encourage us, the volunteer. Apr 15, 2020 at 10:31
  • Dude thanks a lot for your explanations. As you replied to my question and my current problem is similar: When I send one single string (or several, serialized) via the improved code according to your recommendations, it all works. But, if I want to send one JSON object, I get the following: JavaScript output sent to server: {"name":"Frank","gender":male"}, JavaScript request received on server: {\"name\":\"Frank\",\"gender\":\"male\"}. It seems that the server does not recognize that the data type is json, and escapes the strings. How can I avoid this??
    – Joe
    Apr 19, 2020 at 21:51
  • I think the easiest way is by comparing vanilla script and jQuery sending to the server once and inspect the object sent. So that you could learn how jQuery handle this. Because jQuery is a framework of many people involved. So I think they might have some clever operations to handle and that we could learn from. Apr 20, 2020 at 1:34
0

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!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.