Un thème WordPress classique mélange presque toujours trois choses au même endroit : la requête à la base de données, la mise en forme HTML et la logique d’affichage conditionnelle. C’est ce mélange qui rend une migration headless brutale, parce qu’il faut tout réécrire d’un coup pour obtenir un front propre. L’équipe produit d’un éditeur de logiciels de gestion des stocks nous a demandé l’inverse : garder le thème existant qui tournait bien, mais préparer le terrain pour qu’une partie du site bascule progressivement vers une application React sans tout casser.
La réponse a été Timber, la librairie qui sépare la logique PHP des templates via le moteur Twig. Non pas parce que Timber est un framework headless — il ne l’est pas — mais parce que sa structure impose déjà une discipline utile : les données transitent par des objets PHP propres avant d’arriver au template, ce qui les rend tout aussi faciles à sérialiser en JSON qu’à afficher en HTML.
L’arborescence retenue
Voici comment le thème a été réorganisé, avec un dossier models qui n’existe pas dans un thème Timber standard mais que nous avons ajouté pour centraliser la préparation des données :
theme-timber/
├── models/
│ ├── class-produit.php (étend Timber\Post)
│ ├── class-categorie.php (étend Timber\Term)
│ └── class-fiche-technique.php
├── views/
│ ├── produit.twig
│ ├── categorie.twig
│ └── partials/
│ ├── fiche-technique.twig
│ └── badge-stock.twig
├── rest/
│ └── class-produit-rest-field.php
├── functions.php
└── style.css
Chaque classe du dossier models hérite d’une classe Timber (Timber\Post le plus souvent) et ajoute des méthodes métier : get_niveau_stock(), get_fiches_liees(), get_badge_couleur(). Le template Twig appelle ces méthodes directement, sans jamais toucher à $wpdb ou à une fonction WordPress brute. C’est ce niveau d’abstraction qui rend la donnée réutilisable ailleurs.
Le miroir REST, vue par vue
Plutôt que de construire un schéma d’API complet dès le départ, nous avons choisi de convertir une vue à la fois. La fiche produit a été la première, parce que c’était celle que l’équipe voulait tester dans un prototype React avant de s’engager plus loin.

Le principe : la classe Produit expose déjà une méthode to_array_public() qui retourne exactement les champs jugés sûrs à publier. Le template Twig et le champ REST appellent tous les deux cette même méthode, ce qui élimine tout risque de divergence entre ce que voit un visiteur du site classique et ce que reçoit le futur front React.
class Produit extends Timber\Post {
public function to_array_public() {
return array(
'nom' => $this->title(),
'reference' => $this->meta( 'reference_interne' ),
'stock' => $this->get_niveau_stock(),
'categories' => wp_list_pluck( $this->terms( 'categorie_produit' ), 'name' ),
);
}
}
add_action( 'rest_api_init', function () {
register_rest_field( 'produit', 'donnees_timber', array(
'get_callback' => function ( $post ) {
$produit = Timber::get_post( $post['id'] );
return $produit->to_array_public();
},
) );
} );
Ce que cette transition ne couvre pas
Il faut être précis sur les limites de cette approche : elle ne traite pas le rendu côté serveur d’un framework JavaScript. Le prototype React de l’équipe produit consomme l’API en client-side rendering pur, sans Next.js ni aucune couche de rendu serveur. C’est un choix assumé pour ce projet, mais une équipe visant le SEO sur ces pages devrait étudier une solution avec rendu serveur ou statique, ce qui sort du périmètre de cette architecture intermédiaire.
Les points de friction rencontrés
- Les méthodes Twig utilisant des filtres personnalisés (
|prix_formate) ont dû être dupliquées en PHP pur côté modèle pour rester utilisables par l’API - Certaines fiches techniques référençaient des fichiers PDF liés en dur dans le contenu Twig, invisibles pour l’API tant qu’ils n’étaient pas remontés en custom field
- Le cache Twig (compilation des templates) devait être vidé séparément du cache de l’API lors des déploiements
Un thème Timber bien construit n’est pas un thème « prêt pour le headless », c’est un thème dont les données sont déjà rangées assez proprement pour qu’un headless devienne une option plutôt qu’une réécriture.
Après quatre semaines
La fiche produit a été le seul type de contenu converti dans ce sprint, volontairement. L’équipe a préféré valider la méthode sur un cas concret avant de généraliser aux catégories et aux fiches techniques, prévues pour les mois suivants. Le thème classique n’a subi aucune régression visible pendant toute l’opération, ce qui était la condition posée dès le départ par la direction produit.
Pour la suite
Cette bascule progressive montre qu’un headless ne s’oppose pas forcément à un thème existant : il peut en être le prolongement naturel si la donnée a déjà été correctement isolée de sa présentation. Timber et Twig ne sont pas des outils headless, mais ils imposent une hygiène de code qui rend la transition beaucoup moins coûteuse le jour où elle devient nécessaire.