vendredi 25 septembre 2026

À propos

Contact

Headless & API

register_rest_field : ajouter vos champs aux réponses de l’API REST

Besoin d'un champ calculé ou d'une méta dans vos réponses REST sans créer de route entière ? register_rest_field fait exactement ça, proprement.

Par Clément Hadrot • 1 avril 2020 • 5 min de lecture • Aucun commentaire
register_rest_field : ajouter vos champs aux réponses de l'API REST

Sur un projet e-commerce headless, il fallait afficher le prix affiché sur la fiche produit du front, une valeur calculée à partir d’une méta _prix_ht et d’un taux de TVA stocké ailleurs. Créer une route REST entière pour ça aurait été disproportionné : la fonction register_rest_field() existe précisément pour ce cas, ajouter un champ à une réponse existante sans réécrire le contrôleur.

Elle s’utilise sur n’importe quel type d’objet déjà exposé par l’API : articles, pages, types personnalisés, taxonomies, utilisateurs, commentaires. Le champ ajouté apparaît alors dans toutes les routes concernées, y compris les listes, ce qui la rend bien plus économique qu’une route sur mesure quand il s’agit simplement d’enrichir une réponse.

La structure de base

register_rest_field() prend trois arguments : le type d’objet concerné, le nom du champ à ajouter, et un tableau de configuration contenant get_callback, update_callback et schema. On l’appelle généralement au hook rest_api_init, après l’enregistrement des types de contenu.

add_action( 'rest_api_init', function () {
    register_rest_field( 'product', 'prix_ttc', array(
        'get_callback'    => 'monsite_get_prix_ttc',
        'update_callback' => null,
        'schema'          => array(
            'description' => 'Prix TTC calculé à partir du prix HT et du taux de TVA.',
            'type'        => 'number',
            'context'     => array( 'view', 'edit' ),
        ),
    ) );
} );

function monsite_get_prix_ttc( $object ) {
    $prix_ht = get_post_meta( $object['id'], '_prix_ht', true );
    $taux    = 1.20;
    return round( (float) $prix_ht * $taux, 2 );
}

Le premier paramètre de la fonction de lecture reçoit le tableau représentant l’objet déjà préparé par le contrôleur REST (avec la clé id, entre autres), pas l’objet WP_Post complet. C’est une source d’erreur fréquente chez les débutants qui tentent d’appeler $object->ID et obtiennent une notice PHP.

Rendre le champ modifiable avec update_callback

Si le champ doit pouvoir être écrit depuis le front (par exemple une préférence utilisateur stockée en méta), on renseigne update_callback. Elle reçoit la valeur envoyée dans la requête, puis l’objet WP_Post complet cette fois.

L'essentiel à retenir : Ajouter un champ sans dupliquer une route ; get_callback et update_callback séparés ; Schéma déclaré pour la documentation
function monsite_update_note_interne( $value, $post ) {
    if ( ! current_user_can( 'edit_post', $post->ID ) ) {
        return new WP_Error( 'rest_forbidden', 'Permission refusée.', array( 'status' => 403 ) );
    }
    update_post_meta( $post->ID, '_note_interne', sanitize_text_field( $value ) );
}

register_rest_field( 'post', 'note_interne', array(
    'get_callback'    => function ( $object ) {
        return get_post_meta( $object['id'], '_note_interne', true );
    },
    'update_callback' => 'monsite_update_note_interne',
    'schema'          => array(
        'type'    => 'string',
        'context' => array( 'edit' ),
    ),
) );

Notez le contrôle de permission explicite à l’intérieur du callback : register_rest_field ne gère pas les permissions pour vous, contrairement à une route déclarée avec permission_callback. Oublier cette vérification revient à laisser n’importe quel utilisateur authentifié modifier la méta, même sans droit d’édition sur l’article.

Documenter le champ avec le schéma

Le tableau schema n’est pas obligatoire pour que le champ fonctionne, mais il conditionne son apparition dans la documentation générée par /wp-json et dans les outils qui s’appuient dessus (comme la découvrabilité OPTIONS d’une route). Je le renseigne systématiquement : type, description et context suffisent dans la majorité des cas.

Le rôle du context

  • view : le champ apparaît dans les réponses publiques standard.
  • edit : le champ n’apparaît que lorsque la requête précise context=edit, généralement réservée aux utilisateurs autorisés (l’éditeur de blocs, par exemple).
  • embed : le champ apparaît dans les réponses allégées utilisées par _embed.

Restreindre un champ sensible au contexte edit évite de l’exposer publiquement par erreur, sans avoir à écrire de logique de permission dans get_callback.

Un cas concret : exposer le temps de lecture estimé

Sur un blog headless, j’ai ajouté un champ temps_lecture calculé à la volée à partir du nombre de mots du contenu, pour l’afficher sur les vignettes d’articles sans recalcul côté front.

register_rest_field( 'post', 'temps_lecture', array(
    'get_callback' => function ( $object ) {
        $post = get_post( $object['id'] );
        $mots = str_word_count( wp_strip_all_tags( $post->post_content ) );
        return (int) ceil( $mots / 200 );
    },
    'schema' => array(
        'type'        => 'integer',
        'description' => 'Temps de lecture estimé en minutes.',
        'context'     => array( 'view' ),
    ),
) );

Le calcul reste simple volontairement : 200 mots par minute est une moyenne suffisante pour un affichage indicatif, et le coût de calcul reste négligeable sur une réponse de liste paginée à dix éléments.

Limites à connaître

Le champ ajouté n’est pas filtrable ni triable via les paramètres de requête standard de l’API REST : on ne peut pas demander ?orderby=prix_ttc sans ajouter en plus un filtre sur rest_product_query. Pour un besoin de tri ou de filtre sur un champ calculé, il faut donc combiner register_rest_field avec un filtre de requête, ou stocker la valeur en méta indexable en amont plutôt que de la calculer à la volée.

Notre verdict

register_rest_field est l’outil à utiliser par défaut dès qu’il s’agit d’enrichir une réponse existante avec une donnée calculée ou une méta cachée. Réserver register_rest_route aux cas où la donnée n’a pas de rattachement naturel à un objet REST déjà exposé évite de multiplier des routes qui dupliquent en réalité de simples champs.

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