Déployer une extension WordPress par FTP : pourquoi l’ordre des fichiers peut compter autant que le code
Un problème de déploiement souvent sous-estimé
Dans un déploiement WordPress par FTP, on pense d’abord au contenu des fichiers envoyés. Mon retour d’expérience sur une mise à jour d’une extension maison de 0.3.1 vers 0.4.0, réalisée sans SSH ni WP-CLI, m’a montré autre chose : l’ordre d’envoi peut être tout aussi déterminant que le code lui-même.
Le point important est que l’extension est restée active pendant le transfert. Dans ce contexte, le serveur peut se retrouver, pendant quelques instants, avec un mélange d’anciens et de nouveaux fichiers. Ce n’est pas seulement une question théorique : si certaines parties du code basculent avant les autres, l’application peut traverser un état intermédiaire incohérent.
Dans mon cas, l’extension utilisait un autoloader PSR-4. J’en tire une analyse pratique : une requête qui arrive au milieu du transfert peut potentiellement rencontrer une classe déjà mise à jour qui appelle une méthode encore absente d’un fichier non envoyé. Je ne présente pas ici cela comme un comportement mesuré requête par requête, mais comme le risque structurel qui m’a conduit à organiser le transfert avec beaucoup plus de soin.
Le vrai point de bascule n’était pas partout dans le code
La version 0.4.0 contenait une migration de réglages. Cette migration réécrivait deux clés et supprimait les anciennes dans la même écriture. Selon mon constat, cette opération était irréversible sans sauvegarde. Autrement dit, si elle se déclenchait au mauvais moment, il n’y avait pas de retour simple à l’état précédent.
Le premier travail utile n’a donc pas été d’envoyer des fichiers, mais d’identifier le point exact à partir duquel la nouvelle logique devenait atteignable. En relisant l’ancien Plugin.php avant de l’écraser, j’ai constaté qu’il ne référençait pas du tout la classe de migration. Tant que ce fichier n’était pas remplacé, la migration restait physiquement injoignable.
Ce détail change complètement la stratégie de déploiement. Tous les nouveaux fichiers ne présentent pas le même niveau de risque. Certains peuvent être présents sur le disque sans effet immédiat. D’autres servent de câblage et rendent soudain le nouveau comportement accessible. Dans ce cas précis, la question n’était donc pas seulement de savoir quels fichiers étaient nouveaux, mais quels fichiers ouvraient réellement le chemin d’exécution vers la migration.
La séquence d’envoi qui a limité l’exposition
J’ai commencé par envoyer les 102 fichiers feuilles. Ensuite, j’ai envoyé la dépendance de la migration, puis la migration elle-même. Après cela seulement sont venus les fichiers de câblage, notamment Container et Plugin. Le fichier principal a été envoyé en dernier.
Avec cet ordre, la base de données est restée intacte pendant les 100 premiers fichiers. En pratique, cela signifie que la plus grande partie du transfert ne pouvait pas encore déclencher la migration de réglages. Le seul moment de bascule se situait à l’avant-dernier fichier.
La raison est précise : le fichier principal définissait la constante de version de schéma comparée par le migrateur. Tant que ce fichier principal n’était pas en place, aucune migration ne pouvait se déclencher, même si tous les migrateurs étaient déjà présents sur le disque.
Cette approche revient à repousser le plus loin possible le moment où le nouveau graphe d’exécution devient réellement actif. On peut voir cela comme une forme de déploiement par activation différée : les briques sont copiées d’abord, puis seulement les points d’entrée qui les rendent utilisables.
Ce que ce cas dit d’un déploiement FTP sur une extension active
Le point clé n’est pas que tous les déploiements FTP doivent suivre exactement cette séquence. Le point clé est qu’un transfert sur une extension active doit être pensé comme une succession d’états observables par des requêtes réelles. Dans ce cadre, l’ordre d’envoi devient une propriété du déploiement, pas un simple détail opérationnel.
Pour une extension structurée avec autoloading, il est utile de distinguer au moins trois catégories de fichiers :
- les fichiers inertes au sens où leur présence seule n’active rien immédiatement ;
- les dépendances nécessaires à une nouvelle fonctionnalité ou à une migration ;
- les fichiers de câblage ou d’entrée qui rendent cette fonctionnalité atteignable.
Dans mon cas, la migration de réglages était le risque principal, parce qu’elle modifiait des données et supprimait les anciennes clés dans la même opération. Cela imposait de retarder au maximum tout ce qui pouvait la déclencher. Le fait que l’ancien Plugin.php n’expose pas la classe de migration a fourni un point d’appui concret pour construire l’ordre d’envoi.
Il reste une question ouverte que je ne présente pas comme un fait vérifié ici : avec un autoloader PSR-4, le chargement des classes expose-t-il, à chaque requête, un état intermédiaire pendant un transfert FTP ? Mon analyse de risque m’a conduit à agir comme si cette exposition était possible, mais cette formulation doit rester au niveau de l’hypothèse de travail dans cet article.
Le contre-exemple du thème : un bon ordre pour une extension peut être mauvais ailleurs
Le même jour, j’avais prévu sur le thème d’envoyer functions.php en dernier à cause d’un require_once. J’ai finalement conclu que c’était une erreur.
La raison était simple : un autre fichier appelait une fonction définie dans le fichier chargé par functions.php. Si ce fichier avait été envoyé avant functions.php, cela aurait provoqué une erreur fatale sur toutes les pages avec fil d’Ariane.
L’ordre correct observé dans ce cas a donc été l’inverse de l’intuition initiale : d’abord les fichiers inertes, puis functions.php, puis les fichiers qui en dépendent.
Ce contre-exemple est utile parce qu’il évite une règle trop générale du type envoyer le fichier principal en dernier. Ce n’est pas une méthode universelle. Sur une extension, retarder le point d’entrée peut empêcher une migration de partir trop tôt. Sur un thème, retarder un fichier qui fournit des fonctions déjà appelées ailleurs peut au contraire casser immédiatement l’exécution.
Méthode pratique : raisonner en accessibilité du code, pas seulement en arborescence
La leçon la plus utile pour des développeurs n’est pas liée à FTP en tant qu’outil, mais à la manière de préparer un déploiement quand on ne dispose ni de SSH ni de WP-CLI et qu’on laisse le code actif pendant le transfert.
La bonne question n’est pas seulement quels fichiers changent, mais à partir de quel fichier le nouveau comportement devient accessible. Il faut repérer :
- ce qui peut être copié sans effet immédiat ;
- ce qui introduit une dépendance nécessaire mais encore inactive ;
- ce qui sert de déclencheur, de point d’entrée ou de câblage final.
Dans l’extension décrite ici, cette lecture a permis de concentrer le risque sur une fenêtre très courte, au lieu de l’étaler sur tout le transfert. Dans le thème, la même logique a conduit à une conclusion différente, parce que la dépendance fonctionnelle passait par functions.php.
Autrement dit, l’ordre d’envoi ne se déduit pas de la place d’un fichier dans l’arborescence ni de son statut symbolique de fichier principal. Il se déduit du graphe réel des dépendances et du moment où WordPress peut atteindre le nouveau code.
À retenir
- Lors d’un déploiement WordPress par FTP sur une extension active, l’ordre d’envoi des fichiers peut être aussi important que leur contenu.
- Dans le cas décrit, la migration de réglages réécrivait deux clés et supprimait les anciennes dans la même écriture, ce qui en faisait un point de risque majeur.
- L’ancien fichier Plugin.php ne référençait pas la migration, ce qui a permis de retarder son accessibilité réelle pendant le transfert.
- La séquence choisie a été : 102 fichiers feuilles, dépendance de migration, migration, câblage dont Container et Plugin, puis fichier principal en dernier.
- Pour le thème, la bonne séquence était différente : fichiers inertes, puis functions.php, puis les fichiers qui en dépendent.