# Un WordPress, plusieurs fronts : site web et application mobile

> Concevoir une seule API WordPress capable de nourrir à la fois un site web et une application mobile, sans dupliquer le back-office.

- Auteur : WordPress Développement
- Publié le : 2024-08-08
- Mis à jour le : 2026-09-30
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/un-wordpress-plusieurs-fronts-web-mobile/

## L’essentiel

- Une API versionnée, plusieurs consommateurs différents
- Chaque client demande exactement les champs dont il a besoin
- Les besoins spécifiques au mobile passent par des champs dédiés

Une fédération sportive nous a confié un projet à deux visages : un site web éditorial classique pour le grand public, et une application mobile pour les licenciés, avec des notifications, un calendrier de compétitions et des résultats en direct. Deux équipes différentes, deux calendriers de livraison différents, mais un seul back-office de contenu : hors de question de dupliquer la saisie des articles et des résultats à deux endroits.

L'architecture retenue repose sur un principe simple : une seule instance WordPress, une API versionnée, et des contrats de champs différents selon le client qui interroge.

## Un espace de noms d'API par génération de contrat

Les routes personnalisées de la fédération vivent sous un espace de noms propre, `federation/v1`, distinct du cœur `wp/v2`. Quand un changement de structure incompatible devient nécessaire (un champ renommé, un format de date modifié), on introduit `federation/v2` plutôt que de casser silencieusement l'application mobile déjà publiée sur les stores, dont la mise à jour prend plusieurs semaines à se propager chez tous les utilisateurs.

> L'essentiel à retenir : Une API versionnée, plusieurs consommateurs différents ; Chaque client demande exactement les champs dont il a besoin ; Les besoins spécifiques au mobile passent par des champs dédiés

Cette discipline de versionnement protège le client le plus lent à évoluer. Le site web se redéploie en quelques minutes ; une application mobile, elle, reste installée dans des versions anciennes pendant des mois. Tant qu'il existe des utilisateurs de la première version de l'application, `federation/v1` doit continuer à répondre exactement comme avant.

On prépare la fin de vie d'un espace de noms en la signalant dans les réponses. Le filtre `rest_post_dispatch` permet d'ajouter un en-tête `Sunset`, défini par la RFC 8594, que l'équipe mobile peut surveiller :

```
add_filter( 'rest_post_dispatch', 'federation_signaler_fin_de_vie', 10, 3 );

function federation_signaler_fin_de_vie( $reponse, $serveur, $requete ) {
    if ( 0 === strpos( $requete->get_route(), '/federation/v1/' ) ) {
        $reponse->header( 'Sunset', 'Wed, 31 Dec 2025 23:59:59 GMT' );
        $reponse->header( 'Link', '</wp-json/federation/v2/>; rel="successor-version"', false );
    }
    return $reponse;
}
```

Le troisième argument `false` de la méthode `header()` ajoute l'en-tête sans remplacer un éventuel en-tête `Link` déjà présent, celui de la pagination par exemple.

## Laisser chaque client demander ce dont il a besoin

La REST API de WordPress propose nativement le paramètre `_fields`, qui limite la réponse aux champs demandés. Le site web, qui affiche une liste d'articles, n'a besoin que de quelques champs ; l'application, qui affiche un écran de calendrier, en demande d'autres :

```
# Le site web : liste d'articles
curl "https://federation.example/wp-json/wp/v2/posts?per_page=10&_fields=id,date,link,title.rendered,excerpt.rendered"

# L'application : calendrier des compétitions
curl "https://federation.example/wp-json/wp/v2/competition?per_page=50&_fields=id,title.rendered,mobile"
```

Chaque consommateur télécharge donc l'essentiel, et rien de plus : sur un réseau mobile, la taille de la réponse se traduit directement en temps d'affichage. Les en-têtes `X-WP-Total` et `X-WP-TotalPages` de la réponse permettent à l'application de paginer sans jamais demander la liste complète.

## Des champs dédiés aux besoins du mobile

Certaines données n'ont de sens que pour l'application : l'état « en direct » d'une épreuve, l'heure de début au format attendu par l'agenda du téléphone, ou l'identifiant à transmettre au service de notifications. Plutôt que de surcharger les champs communs, on les regroupe dans un champ dédié, déclaré avec `register_rest_field()` :

```
add_action( 'rest_api_init', 'federation_champ_mobile' );

function federation_champ_mobile() {
    register_rest_field( 'competition', 'mobile', array(
        'get_callback' => function ( $objet ) {
            return array(
                'debut_iso' => gmdate( 'c', (int) get_post_meta( $objet['id'], 'debut_timestamp', true ) ),
                'lieu'      => (string) get_post_meta( $objet['id'], 'lieu', true ),
                'en_direct' => (bool) get_post_meta( $objet['id'], 'en_direct', true ),
            );
        },
        'schema'       => array(
            'description' => 'Données spécifiques à l\'application mobile.',
            'type'        => 'object',
            'context'     => array( 'view' ),
            'readonly'    => true,
        ),
    ) );
}
```

Ce champ s'ajoute à la réponse standard du type de contenu `competition`, à condition que celui-ci soit enregistré avec `show_in_rest` à vrai. Le site web l'ignore en n'utilisant pas `_fields` pour le réclamer ; l'application le demande explicitement. Le back-office reste unique : les rédacteurs saisissent une épreuve une fois, et les deux fronts la consomment.

> Une API partagée n'est pas une API identique pour tous : c'est un contrat stable, dont chaque client lit seulement la partie qui le concerne.

## Les décisions qui coûtent cher si on les repousse

- **L'authentification.** Ne glissez jamais d'identifiants d'administrateur dans l'application : le paquet se décompile. Pour les lectures publiques, aucun jeton n'est nécessaire ; pour les données d'un licencié, utilisez une authentification propre à l'utilisateur, avec des droits limités.
- **La mise en cache.** Les résultats en direct changent toutes les minutes, le calendrier toutes les semaines : distinguez-les par des durées de cache différentes, configurées au niveau du serveur ou de la couche de diffusion.
- **Les notifications.** WordPress n'envoie pas de notifications poussées : c'est l'événement de publication (le crochet `transition_post_status`, par exemple) qui déclenche l'appel au service de diffusion choisi.
- **La suppression de champs.** Retirer ou renommer un champ d'un espace de noms publié casse les applications déjà installées : ajoutez, ne retirez pas, ou passez à une nouvelle version.

## Un protocole de recette pour deux fronts

Avant chaque livraison du back-office, exécutez une suite de requêtes de contrôle, une par route utilisée par chaque front, et comparez les réponses à des instantanés de référence. Un test automatique qui vérifie la présence et le type des champs attendus par l'application suffit à détecter la plupart des régressions avant qu'elles n'atteignent les stores. C'est peu de travail pour protéger une version mobile que l'on ne peut pas corriger en quelques minutes.

## Conclusion

Nourrir un site et une application avec un seul WordPress repose sur trois principes : des espaces de noms versionnés pour ne jamais casser les clients installés, des requêtes qui ciblent exactement les champs nécessaires, et des champs dédiés pour les besoins propres au mobile. Le back-office reste unique, la saisie n'est jamais dupliquée, et chaque équipe avance à son rythme sur un contrat qu'elle comprend.
