Deux façons de ranger une extension WordPress s’opposent depuis toujours : par couche technique, avec un dossier controllers, un dossier models, un dossier views ; ou par fonctionnalité, avec un dossier par capacité métier, chacun contenant son propre contrôleur, son propre modèle et sa propre vue. Les deux fonctionnent au démarrage d’un projet. Elles ne vieillissent pas de la même manière.
Prenons une extension de gestion de formations professionnelles, avec trois fonctionnalités distinctes : inscriptions, émargements et attestations. L’architecture en couches classique regroupe tout le code d’inscription, d’émargement et d’attestation dans les mêmes dossiers techniques, mélangés fonctionnellement. L’architecture par fonctionnalité regroupe au contraire tout ce qui concerne les inscriptions au même endroit, indépendamment de son rôle technique.
À quoi ressemble l’organisation en couches techniques
Voici la structure typique d’une extension organisée par couche, telle qu’on la retrouve encore fréquemment :
extension-formations/
├── controllers/
│ ├── class-inscription-controller.php
│ ├── class-emargement-controller.php
│ └── class-attestation-controller.php
├── models/
│ ├── class-inscription-model.php
│ ├── class-emargement-model.php
│ └── class-attestation-model.php
├── views/
│ ├── inscription-formulaire.php
│ ├── emargement-tableau.php
│ └── attestation-pdf.php
└── hooks/
├── inscription-hooks.php
├── emargement-hooks.php
└── attestation-hooks.php
Chaque fonctionnalité existe, mais son code est réparti sur quatre dossiers distincts. Pour retirer entièrement la fonctionnalité « émargement », il faut identifier et supprimer un fichier dans chacun des quatre dossiers, en espérant n’en avoir oublié aucun.
À quoi ressemble l’organisation par fonctionnalité

La même extension, réorganisée par fonctionnalité, ressemble à ceci :
extension-formations/
├── inscriptions/
│ ├── class-inscription-controller.php
│ ├── class-inscription-model.php
│ ├── vue-formulaire.php
│ └── hooks.php
├── emargements/
│ ├── class-emargement-controller.php
│ ├── class-emargement-model.php
│ ├── vue-tableau.php
│ └── hooks.php
└── attestations/
├── class-attestation-controller.php
├── class-attestation-model.php
├── vue-pdf.php
└── hooks.php
Chaque dossier de fonctionnalité est autonome : il contient tout ce qui la concerne, quel que soit son rôle technique. Retirer la fonctionnalité « émargements » revient alors à supprimer un seul dossier et sa ligne de chargement dans le fichier principal de l’extension, sans avoir à parcourir mentalement quatre arborescences différentes.
Ce que cette organisation facilite concrètement
Au-delà de la suppression, plusieurs situations deviennent plus simples avec un découpage par fonctionnalité :
- Confier une fonctionnalité entière à un développeur sans qu’il ait besoin de comprendre l’ensemble de l’extension.
- Désactiver une fonctionnalité par condition, par exemple selon une licence ou un réglage, en chargeant ou non son dossier.
- Retrouver rapidement tout le code lié à un bug signalé sur une fonctionnalité précise, sans naviguer entre plusieurs dossiers techniques.
Ce que cette organisation complique en contrepartie
Le découpage par fonctionnalité a un coût : le code partagé entre plusieurs fonctionnalités, comme une classe utilitaire de formatage de date ou un service d’envoi d’e-mail commun, ne trouve pas naturellement sa place dans un dossier de fonctionnalité unique. Il faut alors prévoir, dès le départ, un dossier commun ou partage clairement identifié, réservé au code réellement transverse, pour éviter qu’il ne finisse dupliqué dans chaque fonctionnalité par facilité.
Un repère simple pour trancher
La question à se poser pour chaque classe ou fonction : sert-elle une seule fonctionnalité, ou plusieurs ? Dans le premier cas, elle rejoint le dossier de la fonctionnalité concernée. Dans le second, elle rejoint le dossier commun, à condition que ce dossier reste volontairement restreint : s’il grossit au point de contenir la moitié du code de l’extension, le découpage par fonctionnalité perd son intérêt.
Comparaison directe
| Critère | Par couche technique | Par fonctionnalité |
|---|---|---|
| Suppression d’une fonctionnalité | Plusieurs dossiers à parcourir | Un seul dossier à retirer |
| Onboarding sur une fonctionnalité | Vue d’ensemble nécessaire | Un seul dossier à lire |
| Code réellement transverse | Naturellement centralisé | Nécessite une convention explicite |
| Petites extensions (moins de 5 fichiers) | Suffisant | Complexité inutile |
Pour une extension de moins d’une dizaine de fichiers, l’organisation par couche reste parfaitement raisonnable ; le découpage par fonctionnalité prouve sa valeur surtout au-delà, quand une fonctionnalité doit pouvoir vivre ou mourir indépendamment des autres.
En résumé
Le choix entre ces deux organisations n’est ni universel ni définitif. Il dépend surtout d’une question concrète : combien de fois, dans la vie de l’extension, faudra-t-il ajouter ou retirer une fonctionnalité entière ? Plus cette fréquence est élevée, plus le découpage par fonctionnalité rembourse rapidement l’effort de conception initial qu’il demande.