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

Headless & API

Arguments et schéma des routes REST : validate_callback et sanitize_callback

Déclarer proprement les arguments d'une route REST évite la moitié des bugs de validation. Tour d'horizon du schéma JSON et de ses callbacks.

Par WordPress Développement • 30 septembre 2026 • 7 min de lecture • Aucun commentaire
Arguments et schéma des routes REST : validate_callback et sanitize_callback

La première route REST personnalisée que j’ai écrite validait ses arguments « à la main », avec une série de if au début du callback. Ça fonctionnait, mais chaque erreur retournait un message différent, parfois un code HTTP incohérent, et le code devenait vite illisible dès que la route acceptait plus de deux paramètres. Le tableau args de register_rest_route() existe justement pour éviter ça : il externalise la validation et le nettoyage, avant même que le callback principal ne soit appelé.

Cet article détaille comment déclarer des arguments avec un schéma JSON, la différence entre validate_callback et sanitize_callback, et les pièges que j’ai rencontrés en les combinant sur des routes réelles.

Déclarer un argument avec son schéma

Chaque entrée du tableau args décrit un paramètre attendu par la route, sous forme d’un sous-ensemble de JSON Schema : type, required, default, enum, minimum/maximum pour les nombres, et les deux callbacks qui nous intéressent ici.

L'essentiel à retenir : Chaque argument déclare son type, sa validation et son nettoyage ; validate_callback rejette, sanitize_callback transforme ; Erreurs 400 automatiques et cohérentes

Voici une route complète qui liste des événements d’un agenda. Elle déclare quatre arguments de natures différentes, ce qui permet de voir chaque mécanisme à l’œuvre :

add_action( 'rest_api_init', 'agenda_declarer_routes' );

function agenda_declarer_routes() {
	register_rest_route( 'agenda/v1', '/evenements', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'agenda_lister_evenements',
		'permission_callback' => '__return_true',
		'args'                => array(
			'par_page'  => array(
				'description'       => "Nombre d'événements par page.",
				'type'              => 'integer',
				'default'           => 10,
				'minimum'           => 1,
				'maximum'           => 50,
				'validate_callback' => 'rest_validate_request_arg',
				'sanitize_callback' => 'rest_sanitize_request_arg',
			),
			'statut'    => array(
				'type'    => 'string',
				'default' => 'a_venir',
				'enum'    => array( 'a_venir', 'passe', 'tous' ),
			),
			'depuis'    => array(
				'type'              => 'string',
				'validate_callback' => 'agenda_valider_date',
			),
			'recherche' => array(
				'type'              => 'string',
				'sanitize_callback' => 'agenda_nettoyer_texte',
			),
		),
	) );
}

function agenda_valider_date( $valeur, $requete, $cle ) {
	if ( ! is_string( $valeur ) ) {
		return false;
	}
	$date = DateTime::createFromFormat( '!Y-m-d', $valeur );
	if ( false === $date || $date->format( 'Y-m-d' ) !== $valeur ) {
		return new WP_Error(
			'agenda_date_invalide',
			sprintf( '%s doit être une date au format AAAA-MM-JJ.', $cle )
		);
	}
	return true;
}

function agenda_nettoyer_texte( $valeur ) {
	return sanitize_text_field( $valeur );
}

Les quatre arguments illustrent quatre manières de procéder. par_page nomme explicitement les deux fonctions fournies par le cœur, rest_validate_request_arg() et rest_sanitize_request_arg(), qui lisent le schéma (type, minimum, maximum) dans la déclaration de la route. statut ne déclare aucun callback : comme l’argument possède un type, WordPress applique de lui-même rest_parse_request_arg(), qui valide puis nettoie d’après le schéma. depuis remplace la validation par une fonction maison, et recherche remplace le nettoyage.

validate_callback et sanitize_callback : deux rôles distincts

La distinction est simple, mais elle se brouille à l’usage. Le validate_callback répond à la question « cette valeur est-elle acceptable ? » : il ne modifie rien, il accepte ou il refuse. Le sanitize_callback répond à la question « sous quelle forme voulez-vous la manipuler ? » : il retourne la valeur transformée (entier, chaîne débarrassée de ses balises, tableau normalisé) et n’a pas à juger.

L’ordre d’exécution, dans le cœur, est le suivant : contrôle des paramètres obligatoires (required), puis tous les validate_callback, puis tous les sanitize_callback, puis le permission_callback, et enfin le callback principal. Celui-ci ne reçoit donc que des valeurs déjà contrôlées et nettoyées, à condition que la déclaration soit complète.

Le contrat d’un validate_callback mérite d’être cité précisément : seuls false et un objet WP_Error sont considérés comme un refus. Retourner false produit le message générique « Invalid parameter. » (traduit selon la langue du site) ; retourner un WP_Error permet de fournir un message lisible, comme dans agenda_valider_date() ci-dessus. Les trois arguments transmis au callback sont la valeur, l’objet WP_REST_Request et le nom du paramètre.

Le format de l’erreur renvoyée au client

Lorsqu’au moins un argument est refusé, le callback principal n’est jamais appelé. Le client reçoit un code HTTP 400 et un corps JSON dont la clé data.params détaille chaque paramètre fautif. Pour un appel à /wp-json/agenda/v1/evenements?depuis=demain, la réponse ressemble à ceci :

{
  "code": "rest_invalid_param",
  "message": "Invalid parameter(s): depuis",
  "data": {
    "status": 400,
    "params": {
      "depuis": "depuis doit être une date au format AAAA-MM-JJ."
    }
  }
}

Cette cohérence est le principal bénéfice pour le front : un seul format d’erreur à traiter, quel que soit l’argument fautif, avec le nom du champ à surligner dans un formulaire. Le paramètre obligatoire manquant produit, lui, le code rest_missing_callback_param, également en 400.

Les pièges rencontrés en combinant les deux

  • Un sanitize_callback maison remplace la validation par défaut. Si vous déclarez 'type' => 'integer', 'minimum' => 1 et 'sanitize_callback' => 'absint' sans validate_callback, la valeur abc devient silencieusement 0 et la borne minimale n’est jamais contrôlée. Ajoutez 'validate_callback' => 'rest_validate_request_arg' dès que vous personnalisez le nettoyage.
  • Un callback qui ne retourne rien valide tout. Une fonction de validation qui oublie son return retourne null, et null n’est pas false : la valeur passe. Terminez toujours par un return true explicite.
  • Une valeur de type inattendu atteint votre callback. Dès que vous remplacez la validation du cœur, un paramètre envoyé sous forme de tableau (?depuis[]=1) arrive tel quel : d’où le contrôle is_string() en tête de agenda_valider_date().
  • Les fonctions natives de PHP reçoivent trois arguments. WordPress appelle le callback avec la valeur, la requête et le nom du paramètre. Une fonction interne de PHP à un seul paramètre, comme is_numeric, peut produire un avertissement ; enveloppez-la dans une fonction à vous.
  • La validation ne remplace pas le permission_callback. Une valeur bien formée n’est pas une valeur autorisée : les deux contrôles répondent à des questions différentes.

Cas concret : un agenda consommé par un front JavaScript

Sur la route ci-dessus, un appel avec par_page=-5 ou par_page=1000 transmettrait la valeur telle quelle à WP_Query si la route n’avait aucun schéma, avec des résultats difficiles à prévoir. Avec le schéma, ces appels sont refusés avant d’atteindre la requête, et la documentation de la route (visible en envoyant une requête OPTIONS sur son adresse) décrit chaque argument avec son type, ses bornes et sa valeur par défaut. Le développeur du front n’a plus à lire le code PHP pour savoir ce que la route accepte.

Un argument sans schéma est une promesse non tenue : la route prétend accepter n’importe quoi, puis laisse le hasard décider de la suite.

Conclusion

Déclarer ses arguments dans args déplace la validation là où elle appartient : hors du callback, à un endroit unique, avec des erreurs 400 uniformes. Retenez la règle de répartition (validate_callback refuse, sanitize_callback transforme), le contrat exact de retour (false ou WP_Error) et le piège du nettoyage personnalisé qui écarte la validation du schéma. Avec ces trois points, la plupart des bugs de paramètres disparaissent avant d’atteindre votre logique métier.

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