Le WordPress d'aujourd'hui, décodé pour les développeurs

Extensions

Un register_rest_route mal structuré qui efface silencieusement une méthode

Déclarer GET et POST sur la même route avec un tableau d'arguments réutilisé fait disparaître l'un des deux gestionnaires, sans message d'erreur explicite.

Par WordPress Développement • 5 décembre 2024 • 5 min de lecture • Aucun commentaire
Un register_rest_route mal structuré qui efface silencieusement une méthode

« Method not allowed » ou, pire, un simple 404 silencieux : c’est souvent ainsi que se manifeste ce bug, plusieurs jours après la mise en production d’un point de terminaison REST censé répondre aussi bien en lecture qu’en écriture. Le symptôme est déroutant, car la route existe bel et bien, les journaux ne montrent rien d’anormal, et pourtant une des deux méthodes déclarées ne répond simplement plus.

Ce cas concret est tiré d’une extension de gestion de contenus qui expose une route personnalisée acceptant à la fois GET pour la consultation et POST pour la mise à jour d’un enregistrement. Le correctif tient en quelques lignes, mais comprendre pourquoi WordPress se comporte ainsi demande de revenir sur la façon dont register_rest_route() traite ses arguments.

Symptôme : une des deux méthodes répond, l’autre non

Le développeur constate que les requêtes POST vers /wp-json/gestion/v1/dossier/(?P<id>\d+) aboutissent bien, mais que les requêtes GET vers la même route renvoient une erreur rest_no_route avec un code HTTP 404. Aucune trace dans les journaux PHP, aucune exception : la route semble simplement ne jamais avoir été enregistrée pour cette méthode.

Diagnostic : un tableau d’arguments réutilisé par référence

L'essentiel à retenir : Réutiliser le même tableau d'arguments pour deux méthodes écrase le premier enregistrement ; WordPress ne signale aucune erreur dans ce cas précis ; La correction tient dans la structure du tableau passé à register_rest_route

Le code fautif ressemble à ceci : un tableau $args est construit une première fois pour la méthode de lecture, puis réutilisé et modifié pour la méthode d’écriture, avant d’être passé une seconde fois à register_rest_route() sur la même route.

$args = array(
    'methods'  => WP_REST_Server::READABLE,
    'callback' => 'gestion_lire_dossier',
);

register_rest_route( 'gestion/v1', '/dossier/(?P<id>\d+)', $args );

$args['methods']  = WP_REST_Server::CREATABLE;
$args['callback'] = 'gestion_ecrire_dossier';

register_rest_route( 'gestion/v1', '/dossier/(?P<id>\d+)', $args );

À première vue, ce code semble correct : deux appels distincts à register_rest_route(), chacun avec ses propres methods et callback. Le piège vient d’ailleurs : dans une version antérieure du fichier, un développeur avait factorisé les deux appels dans une boucle, en passant chaque fois la même variable $args par référence à un tableau collecteur, avant de tout enregistrer d’un coup à la fin de la fonction. Le tableau final ne contenait alors qu’une seule entrée par route, la dernière écrasant systématiquement la précédente au moment de la fusion.

$routes = array();

foreach ( array( 'GET', 'POST' ) as $methode ) {
    $args['methods']  = $methode;
    $args['callback'] = ( 'GET' === $methode ) ? 'gestion_lire_dossier' : 'gestion_ecrire_dossier';
    $routes['/dossier/(?P<id>\d+)'] = $args; // écrase l'entrée précédente à chaque tour
}

foreach ( $routes as $route => $config ) {
    register_rest_route( 'gestion/v1', $route, $config );
}

La clé du tableau $routes est la route elle-même, identique pour les deux méthodes. Chaque itération de la boucle remplace donc l’entrée précédente au lieu de l’ajouter, et seule la configuration de la dernière méthode survit jusqu’à l’appel final de register_rest_route().

Correctif : un seul enregistrement avec un tableau de méthodes

La bonne pratique consiste à ne pas dupliquer l’appel du tout quand les deux méthodes partagent une même logique de permission, et à passer un tableau à la clé methods plutôt que d’enregistrer la route deux fois.

register_rest_route(
    'gestion/v1',
    '/dossier/(?P<id>\d+)',
    array(
        array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => 'gestion_lire_dossier',
            'permission_callback' => 'gestion_verifier_lecture',
        ),
        array(
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => 'gestion_ecrire_dossier',
            'permission_callback' => 'gestion_verifier_ecriture',
        ),
    )
);

Cette forme, un tableau numérique d’endpoints, est la structure que register_rest_route() attend réellement quand une même route doit répondre à plusieurs méthodes avec des rappels différents. Chaque endpoint conserve sa propre configuration, sans risque d’écrasement puisqu’il n’y a plus de clé partagée entre les deux définitions.

Pourquoi WordPress ne signale rien

Le cœur de WordPress ne peut pas deviner qu’un développeur avait l’intention d’enregistrer deux méthodes distinctes : du point de vue de register_rest_route(), un seul endpoint a été fourni, et il l’enregistre fidèlement. Il n’y a donc aucune erreur à remonter, puisque la fonction fait exactement ce qu’on lui demande avec les données reçues.

  • Toujours passer un tableau numérique d’endpoints à register_rest_route() dès qu’une route doit répondre à plusieurs méthodes avec des callbacks différents.
  • Éviter de construire les arguments dans une structure intermédiaire clé par route quand deux méthodes partagent la même route.
  • Tester chaque méthode HTTP individuellement avec curl -X GET puis curl -X POST sur la même URL avant la mise en production.

Un test systématique par méthode HTTP sur chaque route, même quand tout « semble » fonctionner en lecture, aurait révélé ce bug en quelques secondes.

Prévention

Ce type de régression échappe facilement à une revue de code rapide, car le diff paraît anodin. La meilleure protection reste un test d’intégration minimal qui interroge chaque route avec chacune de ses méthodes déclarées, et qui échoue explicitement si l’une d’elles retourne un rest_no_route inattendu.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

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

Voir tous ses articles

Dans la même veine

À lire aussi