# rest_prepare_post ajoute un champ calculé à chaque réponse d’article

> Ajoutez un champ calculé à la réponse REST d'un article sans créer d'endpoint dédié, grâce au filtre rest_prepare_post et à quelques précautions.

- Auteur : Clément Hadrot
- Publié le : 2024-08-23
- Mis à jour le : 2024-08-23
- Catégorie : Headless &amp; API
- URL : https://wpmoderne.dev.wordpress-developpement.fr/headless/rest-prepare-post-champ-calcule-reponse-article/

## L’essentiel

- Un filtre plutôt qu'un endpoint
- Calcul fait à la volée, pas stocké
- Attention à la charge sur les listes

`add_filter( 'rest_prepare_post', 'ajouter_temps_lecture', 10, 3 );` — voilà, à lui seul, ce bout de code règle un problème que beaucoup de développeurs headless résolvent par un endpoint personnalisé alors qu'un simple filtre suffit. Le filtre `rest_prepare_post` s'exécute juste avant l'envoi de la réponse REST pour chaque article, et permet d'y ajouter, retirer ou modifier des champs sans toucher au schéma de la route existante.

Cette approche évite de multiplier les appels réseau côté front découplé : au lieu d'interroger un endpoint supplémentaire pour récupérer une donnée dérivée (temps de lecture, nombre de mots, résumé automatique), le front reçoit tout dans la réponse standard de `/wp/v2/posts`. Voyons comment l'implémenter proprement, et où elle montre ses limites.

## Le filtre rest_prepare_post en détail

La fonction `rest_prepare_post` reçoit trois arguments : l'objet `WP_REST_Response` déjà construit, l'objet `WP_Post` source, et la requête REST courante sous forme de `WP_REST_Request`. C'est en manipulant le premier argument que l'on ajoute un champ :

```
add_filter( 'rest_prepare_post', function( $response, $post, $request ) {
    $contenu = get_post_field( 'post_content', $post );
    $nb_mots = str_word_count( wp_strip_all_tags( $contenu ) );
    $temps_lecture = (int) ceil( $nb_mots / 200 );

    $response->data['temps_lecture_minutes'] = $temps_lecture;

    return $response;
}, 10, 3 );
```

Le calcul se fait à chaque requête, ce qui signifie que la donnée est toujours fraîche : si l'article est modifié, le temps de lecture recalculé reflète immédiatement la nouvelle longueur du texte. Aucun champ personnalisé n'est stocké en base, aucune migration n'est nécessaire.

### Restreindre le filtre au bon type de contenu

Ce filtre s'applique par type de contenu grâce à un suffixe dynamique. Pour ne cibler que les articles standards, `rest_prepare_post` convient ; pour un type personnalisé nommé `guide`, il faudrait accrocher le filtre sur `rest_prepare_guide`. Cette granularité évite d'alourdir toutes les réponses REST du site alors que seul un type de contenu a besoin du champ calculé.

> L'essentiel à retenir : Un filtre plutôt qu'un endpoint ; Calcul fait à la volée, pas stocké ; Attention à la charge sur les listes

## Où cette technique montre ses limites

Sur une route de collection comme `/wp/v2/posts?per_page=100`, le filtre s'exécute une fois par article renvoyé. Un calcul léger comme un comptage de mots reste négligeable, mais un calcul qui interroge la base de données (par exemple compter les commentaires approuvés via une requête `$wpdb`) peut ralentir sensiblement une liste de cent éléments, chacun déclenchant sa propre requête.

Dans ce cas, deux solutions s'offrent au développeur :

- Précalculer la donnée à la publication, via le hook `save_post`, et la stocker en meta pour une lecture rapide dans le filtre.
- Limiter le champ calculé aux routes de détail (un seul article), en testant `$request->get_param( 'id' )` ou en vérifiant le contexte de la requête.

## Un champ qui respecte le schéma REST

Ajouter directement une clé dans `$response->data` fonctionne, mais elle n'apparaît pas dans le schéma OpenAPI généré automatiquement par WordPress, ce qui peut dérouter une équipe front qui consulte la documentation de l'API via `/wp-json`. Pour un champ destiné à durer, `register_rest_field()` reste préférable, car il déclare explicitly le type et la description du champ dans le schéma. Le filtre `rest_prepare_post` garde toute sa valeur pour des ajustements ponctuels, des expérimentations, ou des champs qui dépendent fortement du contexte de la requête (rôle de l'utilisateur, paramètre de langue, etc.), là où `register_rest_field()` serait plus rigide.

> Un champ calculé bien placé dans `rest_prepare_post` évite un aller-retour réseau ; mal placé sur une collection de cent éléments, il en crée cent en coulisses. Le bon réflexe consiste à toujours tester la route de liste avant de valider en production.

## Vérifier l'impact avec l'outil Query Monitor

Avant de déployer ce type de filtre, il est utile de mesurer son coût réel. L'extension Query Monitor affiche le nombre de requêtes SQL déclenchées par une page, y compris pour les réponses REST consultées depuis le navigateur. Comparer le nombre de requêtes avec et sans le filtre actif permet de chiffrer précisément le surcoût, plutôt que de le supposer.

Un tableau de suivi simple, tenu sur un projet réel, aide à documenter la décision :

| Route | Requêtes sans filtre | Requêtes avec filtre |
| --- | --- | --- |
| /wp/v2/posts/42 (détail) | 6 | 7 |
| /wp/v2/posts?per_page=50 (liste) | 9 | 58 |

L'écart sur la route de liste illustre bien pourquoi un calcul qui interroge la base ne devrait jamais être branché sans réflexion sur une collection paginée.

## En résumé

Le filtre `rest_prepare_post` est l'outil le plus direct pour enrichir une réponse REST existante sans créer de route supplémentaire. Il convient parfaitement à un calcul léger et sans requête, comme un temps de lecture ou un indicateur dérivé du contenu déjà chargé en mémoire. Dès que le calcul devient coûteux ou qu'il doit apparaître dans le schéma documenté de l'API, il vaut mieux basculer vers `register_rest_field()` ou précalculer la valeur au moment de la sauvegarde de l'article. Le choix entre ces trois approches dépend moins du champ à ajouter que du nombre d'articles renvoyés par la route qui le portera.
