web-dev-qa-db-fra.com

Autoriser admin-ajax.php à recevoir "application/json" au lieu de "x-www-form-urlencoded"

J'utilise la fonction $http d'AngularJS pour envoyer ma charge utile au sous-système admin-ajax.php de WordPress, mais il semble que ce dernier accepte uniquement les données x-www-form-urlencoded, au lieu du application/json fourni par Angular.

Je sais il y a moyen de rendre la fonction $ http plus semblable à $.post(), mais cela n'a aucun sens - pourquoi transformer un tas de données JSON en un formulaire alors que c'est déjà JSON?

À cette fin - est-il possible d'indiquer à admin-ajax de saisir le type en tant que application/JSON au lieu de x-www-form-urlencoded?

3
aendrew

il semble que ce dernier accepte uniquement x-www-form-urlencoded

Ce n'est pas complètement vrai.

WordPress admin-ajax.php prend l'action à partir de $_REQUEST['action'] et $_REQUEST est égal à:

array_merge($_POST, $_GET);

Mais ce que beaucoup de gens ne réalisent pas, c’est que $_GET dans PHP est not les données ont été envoyées à la page à l’aide de la méthode HTTP GET. En fait, vous pouvez utiliser n’importe quelle méthode HTTP (POST, PUT, DELETE ...) et quel que soit le type de contenu, et $_GET contiendra toujours les données que vous transmettez à la chaîne de requête url.

Cela signifie que si vous envoyez une demande à wp-admin/admin-ajax.php?action=awesome_action "awesome_action" est toujours atteinte, quelle que soit la méthode HTTP utilisée et le type de contenu HTTP utilisé.

En bref, si vous pouvez envoyer l'argument action avec l'URL, vous pouvez utiliser admin-ajax.php pour envoyer toutes les données JSON et toute méthode HTTP, alors votre problème les traite.

Cependant, c'est assez facile d'utiliser php://input stream.

Exemple

Tout d'abord, je vais écrire une fonction qui utilise curl pour envoyer une requête HTTP avec un type de contenu JSON (car je ne veux pas écrire du code Angular ici):

/**
 * @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);
}

Plutôt facile.

Maintenant, juste à des fins de test, je vais mettre une fonction dans le pied de page frontal qui envoie une requête HTTP avec un type de contenu JSON en utilisant la fonction ci-dessus, et attend un retour de JSON:

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>';
});

Désormais, lorsque admin-ajax.php sera demandé, il recherchera tout rappel associé à 'wp_ajax_json-test' hook (ou 'wp_ajax_nopriv_json-test') pour les utilisateurs non connectés.

Ajoutons une fonction personnalisée à ces points:

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

La fonction myWpAjaxTest() sera appelée par WordPress lorsque la requête HTTP avec le type de contenu JSON sera envoyée à admin-ajax.php.

Ecrivons le:

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
    ));
}

Merci à php://input ( docs ) dernière fonction

Comme résultat final, si vous regardez le pied de page du thème, vous trouverez quelque chose comme:

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

)
6
gmazzap

admin-ajax.php a été conçu pour fonctionner avec jQuery. Si vous ne convertissez pas le site JS, vous devrez le faire côté serveur pour que cela fonctionne. Au lieu de cela, vous pouvez ajouter votre propre "point final" pouvant traiter json. Le plus gros problème de cette approche est la requête selon laquelle WP s'exécute sur des URL "front-end".

0
Mark Kaplun