vendredi 25 septembre 2026

À propos

Contact

Extensions

AJAX dans l’admin WordPress : admin-ajax.php proprement, étape par étape

Un tableau de bord qui se rafraîchit sans recharger la page, ça passe encore par admin-ajax.php. Voici comment le brancher sans se tromper de hook.

Par Clément Hadrot • 29 janvier 2020 • 6 min de lecture • Aucun commentaire
AJAX dans l'admin WordPress : admin-ajax.php proprement, étape par étape

Un client qui gère un catalogue de pièces détachées m’a demandé un tableau de bord d’administration capable de filtrer une liste de plusieurs milliers de références sans recharger la page à chaque clic. Pas question d’installer un framework JavaScript pour ça : admin-ajax.php suffit largement, à condition de comprendre les deux ou trois pièges qui font perdre une soirée entière quand on ne les a jamais rencontrés.

Ce fichier existe depuis les origines de WordPress et reste, en 2020, le point d’entrée le plus simple pour exécuter du PHP depuis du JavaScript dans l’admin. Il n’a rien d’obsolète : REST API est plus adaptée aux échanges front-end publics ou aux applications complexes, mais pour une action ponctuelle dans un écran d’administration, admin-ajax.php reste souvent la solution la plus rapide à mettre en œuvre.

Déclarer les deux hooks wp_ajax_

Le principe tient en une ligne : WordPress route toute requête POST ou GET envoyée à admin-ajax.php avec un paramètre action vers un hook nommé wp_ajax_{action} pour un utilisateur connecté, et wp_ajax_nopriv_{action} pour un visiteur anonyme.

add_action( 'wp_ajax_filtrer_pieces', 'kaolin_filtrer_pieces_callback' );

function kaolin_filtrer_pieces_callback() {
    check_ajax_referer( 'kaolin_pieces_nonce', 'nonce' );

    if ( ! current_user_can( 'edit_posts' ) ) {
        wp_send_json_error( array( 'message' => 'Permission refusée.' ), 403 );
    }

    $reference = isset( $_POST['reference'] ) ? sanitize_text_field( wp_unslash( $_POST['reference'] ) ) : '';

    $resultats = kaolin_rechercher_pieces( $reference );

    wp_send_json_success( array( 'items' => $resultats ) );
}

Dans un écran strictement réservé aux administrateurs, il est tentant d’omettre wp_ajax_nopriv_. C’est justement la bonne pratique : si l’action ne concerne que des utilisateurs connectés, n’enregistrez que le premier hook. Ajouter le second par réflexe ouvre une porte inutile.

Transmettre l’URL et le nonce au bon moment

Le script JavaScript ne connaît ni l’URL d’admin-ajax.php ni le nonce attendu par check_ajax_referer. C’est le rôle de wp_localize_script, appelé juste après wp_enqueue_script, qui injecte un objet global exploitable côté client.

L'essentiel à retenir : Deux hooks à connaître : wp_ajax_ et wp_ajax_nopriv_ ; wp_localize_script pour transmettre l'URL et le nonce ; wp_send_json_success et wp_send_json_error pour répondre proprement
wp_enqueue_script( 'kaolin-admin-pieces', plugins_url( 'js/pieces.js', __FILE__ ), array( 'jquery' ), '1.0', true );

wp_localize_script( 'kaolin-admin-pieces', 'kaolinPieces', array(
    'ajaxUrl' => admin_url( 'admin-ajax.php' ),
    'nonce'   => wp_create_nonce( 'kaolin_pieces_nonce' ),
) );

Côté JavaScript, l’appel ressemble à ceci :

jQuery.post( kaolinPieces.ajaxUrl, {
    action: 'filtrer_pieces',
    nonce: kaolinPieces.nonce,
    reference: valeurSaisie
} ).done( function( reponse ) {
    if ( reponse.success ) {
        afficherResultats( reponse.data.items );
    }
} );

Une erreur fréquente : oublier que action doit correspondre exactement au suffixe du hook PHP, sans le préfixe wp_ajax_. Une faute de frappe ici renvoie une erreur 400 silencieuse, sans message explicite dans la console.

Répondre avec wp_send_json_success et wp_send_json_error

Avant l’introduction de ces deux fonctions, il fallait construire soi-même un tableau avec une clé success et appeler wp_send_json. Elles font exactement cela, mais avec une convention stable que jQuery et fetch savent exploiter côté client sans code supplémentaire.

  • wp_send_json_success( $data ) envoie un objet { success: true, data: ... } et termine l’exécution avec wp_die()
  • wp_send_json_error( $data, $status_code ) fait de même avec success: false et permet de préciser un code HTTP
  • Les deux appellent wp_die() en interne : tout code placé après ne s’exécute jamais

C’est justement cette dernière ligne qui piège le plus de développeurs débutants : ils ajoutent un return après wp_send_json_success() en pensant arrêter la fonction, alors que l’exécution s’est déjà arrêtée à l’appel précédent. Le code n’est pas faux, simplement inutile.

Vérifier les permissions avant de traiter la requête

check_ajax_referer vérifie que la requête vient bien du navigateur qui a chargé la page admin, pas qu’elle vient d’un utilisateur autorisé. Ce sont deux vérifications distinctes, et j’ai vu plusieurs extensions confondre les deux.

La règle que je retiens de ce projet : toujours enchaîner check_ajax_referer puis current_user_can, dans cet ordre. Le nonce protège contre le rejeu et la falsification de requête intersite, la capacité protège contre un utilisateur connecté mais non autorisé à effectuer l’action demandée.

Un nonce valide ne prouve jamais qu’un utilisateur a le droit de faire une action : il prouve seulement que la requête vient du bon formulaire. Les deux contrôles sont complémentaires, jamais interchangeables.

admin-ajax.php ou REST API : lequel choisir

Pour ce projet, la question s’est posée : fallait-il migrer directement vers un endpoint REST personnalisé ? La réponse a été non, pour une raison simple : l’action ne concernait qu’un unique écran d’administration, sans besoin d’authentification par clé d’API ni de réutilisation externe.

  • Restez sur admin-ajax.php pour une action ponctuelle, interne à un écran d’admin, sans consommateur externe
  • Passez à REST API dès qu’une application mobile, un site tiers ou un bloc Gutenberg autonome doit consommer les mêmes données
  • REST API expose automatiquement une documentation de schéma et gère nativement les méthodes HTTP, ce qu’admin-ajax.php ne fait pas

Dans les faits, une bonne partie des extensions professionnelles continuent d’utiliser admin-ajax.php pour leurs écrans internes, tout en exposant une API REST pour les fonctionnalités destinées à être consommées ailleurs. Les deux mécanismes cohabitent très bien dans un même projet.

Pour aller plus loin

Le couple wp_ajax_ / wp_ajax_nopriv_ reste, dix-sept ans après sa création, l’un des mécanismes les plus utilisés du cœur de WordPress. Sa simplicité est sa force : pas de schéma à déclarer, pas de route à enregistrer, juste une action et un callback.

Le prix de cette simplicité, c’est la rigueur qu’il faut s’imposer soi-même : nonce systématique, vérification de capacité, et sortie propre via wp_send_json_*. Sur ce projet, ces trois réflexes ont suffi à livrer un tableau de bord fluide, sans jamais toucher à la couche REST.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi