Alexander
Alexander

Reputation: 111

Proper way to send JSON in XMLHttpRequest in WordPress without jQuery.ajax

I am trying to send JSON data using XMLHttpRequest in WordPress:

document.getElementById("user_vote").addEventListener("click", function(event) {
    event.preventDefault();

    //action to handle in WP add_action("wp_ajax_my_user_vote", "my_user_vote");
    let action = "my_user_vote";
    let url = myAjax.ajaxurl;

    let data = {
        action: action,
        post_id : this.dataset.post_id,
        nonce: this.dataset.nonce
    };

    let json = JSON.stringify(data);

    let xhr = new XMLHttpRequest();

    xhr.open("POST", url, true);
    xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');

    xhr.onreadystatechange = function() {
        if (this.readyState != 4) return;

        document.getElementById('response').innerHTML = this.responseText;
    }

    xhr.send(json);
});

When I am setting headers to JSON xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); I am getting empty $_REQUEST variable. It seems that WP do not understanding this headers or I am doing something wrong.

I saw this post. When I am checking $input = file_get_contents('php://input'); in admin-ajax.php it returning string of my data: {"action":"my_user_vote","post_id":"1","nonce":"2b2eaea6d3"} but $_REQUEST variable is empty.

All working good with this headers xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); but I want to send JSON.

Why using jQuery.ajax I can simple send JSON data to admin-ajax.php and cant do it with javascript?

Add 1

Here are the right way to send AJAX in WP:

jQuery.ajax({
    type : "post",
    dataType : "json",
    url : myAjax.ajaxurl,
    data : {action: "my_user_vote", post_id : post_id, nonce: nonce},
    success: function(response) {
        //do stuff
    }
})

You mean that in this case jQuery will not set headers to application/json but will set them to application/x-www-form-urlencoded and all this request will be produced to simple XMLHttpRequest with standard headers and xhr.send(data) converted to string, something like this "action=my_user_vote&post_id=1&nonce=2b2eaea6d3"?

And I do not need to set headers to application/json and use simple POST request with standard headers?

Upvotes: 1

Views: 2131

Answers (1)

Quentin
Quentin

Reputation: 943635

PHP will not automatically decode JSON and put it in $_POST or $_REQUEST.

As you have already discovered, you need to read the raw HTTP request body from STDIN and parse it explicitly to read a JSON formatted request in PHP.


Your problem appears to be a misunderstanding of what jQuery does. Probably when you are using jQuery you are doing something like this:

var data = { some: "object" };
jQuery.ajax({
    url: "foo",
    data: data,
    method: "POST"
});

When you do that, jQuery will URL Encode the data object. It will not JSON encode it.

Remember, while JSON syntax is inspired by JavaScript literal syntax, the results of having an object literal in JavaScript source code will give you an object and not a string of JSON.

If you were using jQuery to make a JSON formatted request you would need something like this:

jQuery.ajax({
    url: "foo",
    data: JSON.stringify(data),
    contentType: "application/json; charset=utf-8",
    method: "POST"
});

To encode your object as form data with XHR, you would want something along the lines of:

var data = { some: "object" };
var array = [];
Object.keys(data).forEach(element => 
    array.push( 
        encodeURIComponent(element) + "=" + encodeURIComponent(data[element])
    )
);
var body = array.join("&");
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(body);

Upvotes: 4

Related Questions