Table des matières

Le 20 août, WordPress 7.1 est sorti, et quelques heures plus tard, certains sites utilisant WP Rocket ont commencé à rencontrer une erreur fatale. Pour certains d’entre vous, c’est le front-end qui était touché. Pour d’autres, c’était aussi le tableau de bord. Et sans moyen d’y accéder pour résoudre le problème par vous-mêmes.

Nous en assumons la responsabilité : nous n’avons pas réagi à temps. Nous voulons vous expliquer en détail ce qui s’est passé et ce que nous mettons en place pour que ça ne se reproduise pas.

L’origine technique du problème

WP Rocket embarque un petit module de communication avec Cloudflare, actif que vous utilisiez ce service ou non. Dans l’une de ces routines de nettoyage, ce module fait appel à une fonction PHP, substr(), sur l’identifiant que WordPress génère pour les callbacks de deux hooks bien précis. Avant WordPress 7.1, cet identifiant était toujours une chaîne de caractères. Or PHP 8 impose un typage strict : lui passer autre chose qu’une chaîne de caractères déclenche une erreur fatale, là où avant cela fonctionnait sans problème.

WordPress 7.1 a changé la manière dont ces identifiants de callback sont construits, et dans certains cas, l’identifiant peut désormais être un entier plutôt qu’une chaîne. Weston Ruter, mainteneur du Core WordPress, a confirmé le 21 août qu’il s’agissait bien d’une rupture de compatibilité introduite côté WordPress. Un contributeur du Core a depuis ouvert un ticket avec un correctif, qui devrait être intégré dans WordPress 7.1.1.

Ce cas précis ne se déclenche que si une autre extension active enregistre elle-même un callback d’une certaine façon. Nous avons passé en revue les 200 extensions les plus utilisées sur WordPress.org, ainsi que les retours de nos utilisateurs et l’activité publique sur GitHub, pour identifier lesquelles étaient concernées. Voici les exemples que nous avons identifiés, et nous tenons à le préciser clairement : ces extensions ne font rien de mal. Elles correspondent simplement, par un jeu de circonstances, aux conditions qui exposent notre bug.

  • Elementor Pro, dès qu’une licence valide est active et l’extension activée
  • Elementor Free, si le réglage expérimental e_atomic_elements est activé
  • Redirection for Contact Form 7, dès que l’extension est activée

Autrement dit, le problème apparaît dans une configuration bien précise : WordPress 7.1, PHP 8.x, WP Rocket, et au moins une autre extension qui enregistre des callbacks sur ces hooks d’une manière particulière. Une configuration spécifique, donc, mais qui s’est révélée très répandue, ce qui explique l’ampleur de l’impact. À partir des extensions identifiées et des habitudes de mise à jour de notre base d’utilisateurs, nous estimons qu’environ 27 % des sites utilisant WP Rocket étaient exposés au risque, et que 10 % environ ont été réellement touchés.

La chronologie des événements

6 juillet. C’est la première fois que le problème nous est signalé : un utilisateur de WP Rocket ouvre un ticket GitHub en testant la version alpha de WordPress 7.1. Le ticket identifie correctement le bug, et suggère le correctif que nous déploierons. Notre équipe QA s’y penche le jour même, lance nos tests automatisés sur la version nightly de WordPress : tout passe. Elle essaie de reproduire le problème, sans succès. Le ticket reste ensuite sans suite. Dans les semaines qui suivent, deux clients rencontrent à leur tour la même erreur fatale et ouvrent chacun un ticket de support. Les deux cas sont résolus en revenant simplement à la version stable de WordPress, sans que personne ne fasse le lien avec le ticket GitHub resté sans réponse.

15 juillet. La première bêta de WordPress 7.1 sort. Le bug y est déjà présent. Nos tests automatisés et manuels sur cette bêta passent tous. Nous marquons WP Rocket comme testé et compatible jusqu’à la version 7.1.

19 août, 23h39 CEST. La release candidate de WordPress 7.1 sort lors d’une release party, et des tickets de support à propos d’une erreur fatale commencent à arriver ce même soir. C’est en dehors des horaires habituels de notre équipe plugin, mais un développeur d’une autre équipe repère l’escalade, se penche sur le sujet, et identifie la cause du problème.

20 août, 00h35 CEST. Nous disposons d’un correctif manuel. À ce stade, il n’est pas encore passé par notre validation QA habituelle : plutôt que de le déployer plus largement sans l’avoir vérifié, nous l’envoyons directement à toutes les personnes ayant déjà un ticket de support ouvert, avec une note précisant qu’une mise à jour officielle est en cours.

20 août, 02h18 CEST. WordPress 7.1 sort officiellement. Tous les sites avec les mises à jour automatiques activées commencent à se mettre à jour, et peuvent dès lors rencontrer le bug.

20 août, 04h08 CEST. Notre équipe support publie un article de documentation expliquant le problème et la solution de contournement disponible en attendant.

20 août, 07h30 CEST. L’équipe plugin de WP Rocket démarre sa journée et prend le sujet en main. La communication publique suit dans le quart d’heure : notifications in-app, réseaux sociaux, mise à jour de la page de statut, et réponse sur tous les tickets GitHub concernés, en renvoyant vers l’article de support et en annonçant qu’un correctif est en préparation.

20 août, 10h11 CEST. WP Rocket 3.23.2.2 sort, validé par nos tests automatisés et des tests manuels ciblés. Nous surveillons tous nos canaux pour confirmer que le correctif fonctionne bien, et c’est le cas.

21 août. Nous envoyons un e-mail à tous nos clients actifs pour leur expliquer ce qui s’est passé, et leur recommander de mettre à jour WP Rocket avant de passer à WordPress 7.1.

Pourquoi nos tests n’ont pas détecté le problème

C’est la question qui compte le plus, et elle est tout à fait légitime au vu de l’ampleur de l’impact. Voici comment fonctionne notre processus de test, et où il a montré ses limites.

Tout commence au stade de la pull request : chaque modification est relue par un autre développeur, avec un test manuel du changement et la confirmation que les tests automatisés passent sur plusieurs versions de WordPress et PHP. Ces tests sont accessibles publiquement sur notre dépôt GitHub. Un ingénieur QA valide ensuite le changement sur la dernière version nightly de WordPress, pour repérer d’éventuelles régressions avant que le code soit accepté.

Une fois le code accepté, la version de développement tourne en continu sur une centaine de tests automatisés de bout en bout, sur NGINX et Apache, avec la dernière version de WordPress, bêtas et release candidates comprises. Cette suite est elle aussi publique. Elle vérifie la compatibilité avec un ensemble défini de solutions tierces : Query Monitor, Imagify, Cloudflare, WPML, Divi, Avada, Astra, Flatsome, Storefront, Hello Elementor, Neve, Kadence, GeneratePress, Genesis Sample et OceanWP.

Cette liste n’a pas été construite en se demandant quelles extensions nos utilisateurs utilisent le plus. Elle s’est plutôt formée au fil des années, de manière opportuniste : chaque fois que nous améliorions la compatibilité avec une extension ou un thème, nous ajoutions les tests automatisés correspondants pour éviter toute régression future. C’est une approche cohérente pour constituer une suite de tests au fil du temps, mais elle a ses limites, et l’absence d’Elementor Pro dans cette liste en est une.

Avant la sortie d’une nouvelle version, nous la publions aussi en interne comme release candidate, pour que toute l’équipe puisse mener des tests exploratoires supplémentaires. Nous la déployons ensuite progressivement auprès de nos clients, sur plusieurs jours plutôt que d’un coup, justement pour repérer ce qu’un déploiement massif pourrait révéler, et sortir un correctif avant que cela n’affecte tout le monde. Rien de tout cela n’a permis de détecter ce problème, tout simplement parce qu’il n’apparaissait qu’avec des extensions tierces absentes de nos vérifications automatisées, et qu’aucun plan de test manuel des dernières versions ne les incluait non plus.

Ce que nous mettons en place

Le tri des tickets GitHub est désormais confié à une personne dédiée. Le ticket du 6 juillet avait bien été examiné, mais personne n’en était réellement responsable, et il a été laissé de côté après l’échec de la première tentative de reproduction. Nous avons maintenant clarifié cette responsabilité : chaque ticket est trié, catégorisé, transmis à l’équipe produit si besoin, et suivi à mesure que de nouveaux commentaires arrivent.

Nous reconstruisons notre liste de compatibilité, cette fois de façon délibérée. Notre suite de tests de compatibilité reflète des années d’ajouts au fil de l’eau, pas une cartographie réfléchie de ce que nos utilisateurs utilisent réellement. Nous rebâtissons cette liste en partant des extensions et thèmes les plus utilisés avec WP Rocket, et nous continuerons à l’enrichir selon leur popularité et notre travail de compatibilité au fil du temps. WordPress est un écosystème trop ouvert pour que nous puissions promettre une couverture à 100 % de toutes les configurations existantes, mais nous nous engageons à construire cette liste avec intention, plutôt que par accumulation.

Nous déployons aussi, dès maintenant, un correctif plus ciblé. Le module Cloudflare s’exécutait sur tous les sites, que Cloudflare soit utilisé ou non. Nous le conditionnons désormais à la présence active de l’extension Cloudflare, pour que cette portion de code ne s’exécute plus du tout sur les sites qui n’en ont pas besoin.

D’autres chantiers suivront une fois ceux-ci en place : réduire le délai entre l’escalade interne et la communication publique, supprimer le code inutile qui n’a pas lieu de se charger, et raccourcir le temps nécessaire pour valider et publier un correctif d’urgence une fois le problème identifié.

Regagner votre confiance

Cet incident nous a coûté du temps, à nous comme à vous. Il nous a aussi coûté quelque chose de plus précieux : votre confiance. Nous sommes sincèrement désolés pour l’interruption de service, et pour le stress que cela a pu causer. Cela n’aurait jamais dû se passer ainsi.

À toutes les personnes qui ont signalé le problème, trouvé une solution de contournement, ou aidé d’autres à faire de même : merci. Grâce à vous, cet épisode a été plus court et moins pénible pour les autres qu’il ne l’aurait été sans vous.

Nous savons qu’un mea culpa ne suffit pas à reconstruire la confiance : seuls le temps et les actes le peuvent. Les changements décrits plus haut sont notre façon de progresser sur la durée, et de regagner cette confiance par ce que nous faisons, concrètement, à partir de maintenant.


Autres articles sur Les coulisses de WP Rocket
S’abonner à notre newsletter

Stay in the loop with the latest WordPress and web performance updates.
Straight to your inbox every two weeks.

Obtenez un site Web plus rapide
en quelques clics

Installation en 3 minutes chrono
Obtenir WP Rocket