5

I'm using AngularJS's $http function to send my payload to WordPress's admin-ajax.php subsystem, but it seems the latter only accepts x-www-form-urlencoded data, instead of the application/json supplied by Angular.

I know there are ways of making $http function more like $.post(), but this is nonsensical — why transform a bunch of JSON data into a form when it's already JSON?

To that end — is there any way of instructing admin-ajax to consume type as application/JSON instead of x-www-form-urlencoded?

10

it seems the latter only accepts x-www-form-urlencoded

That's not completely true.

WordPress admin-ajax.php takes the action from $_REQUEST['action'] and $_REQUEST is equal to:

array_merge($_POST, $_GET);

But what many people don't realize is that $_GET in PHP is not the data was sent to page using HTTP GET method, in fact, you can use whatever HTTP method (POST, PUT, DELETE...) and whatever content type, and $_GET will always contain data you pass to url query string.

It means that if you send a request to wp-admin/admin-ajax.php?action=awesome_action "awesome_action" is always reached, no matter the HTTP method you use and no matter the HTTP content type.

In short, if you are able to send the action argument with the url, you can use admin-ajax.php to send whatever JSON data and whatever HTTP method, then is your problem handle them.

However that's quite easy using php://input stream.

Example

First of all I'll write a function that uses curl to send an HTTP request with JSON content type (because I don't want to write Angular code here):

/**
 * @param string $url  Url for for the request
 * @param string $data JSON-encoded data to send
 */
function mySendJson($url, $data)
{
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); // PUT HTTP method
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',           // JSON content type
        'Content-Length: ' . strlen($data))
    );
    return curl_exec($ch);
}

Pretty easy.

Now, just for testing purpose, I'll put a function in frontend footer that sends a HTTP request with JSON content type using the function above, and expects some JSON back:

add_action('wp_footer', function() {

    $ajax_url = admin_url('admin-ajax.php?action=json-test');

    // some dummy json data
    $data = array("name" => "Giuseppe", "country" => "Italy");
    $json = json_encode($data);

    // Using curl we simulate send HTTP request with json content type
    // in your case is Angular that perform the request
    $json_response = mySendJson($ajax_url, $json);

    echo '<pre>';
    print_r(json_decode($json_response, true));
    echo '</pre>';
});

Now, when admin-ajax.php is requested it will look for any callback attached to 'wp_ajax_json-test' hook (or 'wp_ajax_nopriv_json-test') for non-logged users.

Let's add a custom function to those hooks:

add_action('wp_ajax_json-test', 'myWpAjaxTest');
add_action('wp_ajax_nopriv_json-test', 'myWpAjaxTest');

The function myWpAjaxTest() will be called by WordPress when the HTTP request with JSON content type is sent to admin-ajax.php.

Let's write it:

function myWpAjaxTest() {
    // Retrieve HTTP method
    $method = filter_input(INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_STRING);
    // Retrieve JSON payload
    $data = json_decode(file_get_contents('php://input'));

    // do something intersting with data,
    // maybe something different depending on HTTP method

    wp_send_json(array(  // send JSON back
      'method'        => $method,
      'data_received' => $data
    ));
}

Thanks to php://input (docs) last function

  • parses the JSON data that was sent to admin-ajax.php
  • manipulates it
  • sends back a JSON response (because wp_send_json uses json content type)

As final result, if you look at theme footer, you'll find something like:

Array
(
    [method] => PUT
    [data_received] => Array
        (
            [name] => Giuseppe
            [country] => Italy
        )

)
| improve this answer | |
  • 2
    Epic. Win. Possibly one of the best answers I've received on WP.SE. Nice work! – aendrew Feb 11 '15 at 16:15
0

admin-ajax.php was designed to work against jQuery, most likely if you do not make the conversion on the JS site you will have to do it on the server side to make it work. Instead you can add your own "end point" that can process json. The biggest problem with this approach is the query that WP runs on "front end" urls.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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