# Filtrer le contenu traduit d’un site headless avec un paramètre ?lang= maison

> Exposer un contenu multilingue via l'API REST sans dépendre d'une extension : un paramètre de requête, un filtre et une réponse propre.

- Auteur : WordPress Développement
- Publié le : 2023-11-24
- Mis à jour le : 2023-11-24
- Catégorie : Multilingue
- URL : https://www.wpmoderne.fr/multilingue/filtrer-contenu-traduit-api-rest-parametre-lang-maison/

## L’essentiel

- Un paramètre de requête custom filtre les réponses par langue
- Le filtre rest_<type>_query relie la requête à WP_Query
- Aucune dépendance à une extension de traduction

`GET /wp-json/wp/v2/posts?lang=de` : voilà la requête qu'on veut voir fonctionner, alors qu'aucune extension de traduction n'est installée sur ce projet. Le client a construit sa propre table de correspondance entre objets et langues (souvent via une taxonomie personnalisée ou une colonne de métadonnées), et il attend que l'API REST native de WordPress sache en tenir compte sans qu'on ait à réécrire les points de terminaison.

C'est un cas fréquent sur les projets headless : le contenu multilingue existe déjà côté base de données, mais l'API expose tout, toutes langues confondues, dans le même flux. La bonne nouvelle, c'est que WordPress prévoit exactement ce genre d'extension via ses filtres de requête REST, sans qu'il soit nécessaire de dupliquer les routes ou d'écrire un contrôleur maison.

## Le point d'entrée : rest_<post_type>_query

Chaque type de contenu interrogeable via l'API REST déclenche un filtre nommé `rest_{$post_type}_query` juste avant que la requête WP_Query ne soit exécutée. Il reçoit deux arguments : le tableau d'arguments de requête déjà préparé par le contrôleur, et l'objet `WP_REST_Request` qui contient les paramètres bruts de l'URL, y compris ceux qu'on ajoute soi-même.

```
add_filter( 'rest_post_query', function ( $args, $request ) {
    $lang = $request->get_param( 'lang' );

    if ( $lang ) {
        $args['meta_query'][] = [
            'key'   => '_site_lang',
            'value' => sanitize_key( $lang ),
        ];
    }

    return $args;
}, 10, 2 );
```

Ce filtre suppose qu'une métadonnée `_site_lang` est déjà renseignée sur chaque article — c'est la partie « architecture maison » qui précède ce tutoriel. Si la langue est plutôt stockée via une taxonomie, on remplace le `meta_query` par un `tax_query` classique, la mécanique du filtre reste identique.

> L'essentiel à retenir : Un paramètre de requête custom filtre les réponses par langue ; Le filtre rest_<type>_query relie la requête à WP_Query ; Aucune dépendance à une extension de traduction

## Déclarer le paramètre pour qu'il soit accepté

Sans déclaration explicite, `WP_REST_Request::get_param()` renverra bien la valeur si elle est présente dans l'URL — l'API REST ne rejette pas les paramètres inconnus par défaut. Mais pour profiter de la validation automatique (et éviter qu'un visiteur envoie `?lang=%3Cscript%3E` sans contrôle), il vaut mieux enregistrer le paramètre via `rest_{$post_type}_collection_params`.

```
add_filter( 'rest_post_collection_params', function ( $params ) {
    $params['lang'] = [
        'description' => 'Filtrer par code de langue interne',
        'type'        => 'string',
        'validate_callback' => function ( $value ) {
            return is_string( $value ) && preg_match( '/^[a-z]{2}(-[a-z]{2})?$/i', $value );
        },
    ];

    return $params;
} );
```

Cette validation rejette proprement toute valeur qui ne ressemble pas à un code de langue (`fr`, `en-us`...), avec une réponse 400 explicite plutôt qu'un filtrage silencieux qui renverrait une liste vide sans prévenir personne.

## Exposer la langue dans la réponse

Un client headless a aussi besoin de savoir, pour chaque objet reçu, dans quelle langue il est rédigé — sinon il doit deviner. On ajoute un champ personnalisé via `register_rest_field()` :

```
add_action( 'rest_api_init', function () {
    register_rest_field( 'post', 'site_lang', [
        'get_callback' => function ( $post ) {
            return get_post_meta( $post['id'], '_site_lang', true ) ?: 'fr';
        },
    ] );
} );
```

Ce champ apparaît alors dans chaque objet de la réponse JSON, à côté de `title` et `content`. Côté frontend (Next.js, Nuxt, ou un simple fetch), il devient trivial de vérifier la cohérence entre la langue demandée et la langue réellement servie.

## Gérer les types de contenu personnalisés

Si le projet expose des types personnalisés (une bibliothèque de recettes, un catalogue d'événements), il faut répéter l'enregistrement du filtre pour chaque `post_type` concerné, ou généraliser avec une boucle sur `get_post_types( [ 'show_in_rest' => true ] )` plutôt que de multiplier les `add_filter` à la main :

- Lister les types exposés à l'API avec `get_post_types()` et le paramètre `show_in_rest`
- Enregistrer dynamiquement `rest_{$post_type}_query` pour chacun
- Centraliser la logique de résolution de langue dans une fonction unique, appelée par tous les filtres

## Un piège fréquent : le cache d'objet

Si le projet utilise un cache de requêtes REST (une passerelle, un CDN, ou simplement `rest_pre_serve_request` détourné), il faut s'assurer que la clé de cache intègre le paramètre `lang`. Sinon, la première requête en français fige la réponse pour toutes les langues suivantes, jusqu'à expiration du cache — un bug particulièrement difficile à reproduire en local, où le cache est souvent désactivé.

> Sur un projet headless, toute variable qui change la réponse doit systématiquement changer la clé de cache associée : la langue n'échappe pas à cette règle, même quand on l'ajoute après coup.

## En résumé

Filtrer du contenu multilingue via l'API REST sans extension tierce tient en trois briques : un filtre `rest_{$post_type}_query` pour restreindre la requête, une déclaration de paramètre pour la valider, et un champ exposé pour que le client sache ce qu'il reçoit. Cette approche reste entièrement portable : elle survivrait même à un changement ultérieur de stratégie de traduction, puisqu'elle ne dépend que des mécanismes natifs de WordPress.
