Une agence qui maintient une vingtaine de sites Drupal 10 a le même problème que ses clients, multiplié par vingt. Drupal 10 n'aura plus de correctifs de sécurité après le 9 décembre 2026, la semaine où Drupal 11.5 et Drupal 12 sont prévus. Chaque site doit passer en Drupal 11, et tous les prestataires Drupal regardent le même calendrier. Ce qui suit est une méthode pour traiter ce volume sans bloquer l'équipe, en cinq étapes : inventaire du parc, priorisation, industrialisation, estimation, puis choix de ce que l'on confie à un sous-traitant.

1. Inventorier le parc en une passe

Avant de chiffrer quoi que ce soit, il faut un tableau fiable : version de Drupal, version de PHP, nombre de modules contrib, présence de code sur mesure, alertes de sécurité en attente. Avec des alias Drush déclarés pour chaque site, un script suffit.

Les alias se déclarent dans drush/sites/*.site.yml, par exemple :

# drush/sites/client-a.site.yml
prod:
  host: web1.example.net
  user: deploy
  root: /var/www/client-a/web
  uri: https://www.client-a.fr

Puis un script parcourt la liste et produit un CSV :

#!/usr/bin/env bash
# inventaire.sh : une ligne par site
echo "site;drupal;php;modules_contrib;maj_securite"
for alias in @client-a.prod @client-b.prod @client-c.prod; do
  drupal=$(drush "$alias" status --field=drupal-version 2>/dev/null)
  php=$(drush "$alias" status --field=php-version 2>/dev/null)
  contrib=$(drush "$alias" pm:list --no-core --status=enabled --type=module --format=list 2>/dev/null | wc -l)
  secu=$(drush "$alias" pm:security --format=list 2>/dev/null | wc -l)
  echo "${alias};${drupal:-?};${php:-?};${contrib};${secu}"
done

Trois limites de ce script à connaître :

  • la version de PHP renvoyée par Drush est celle de la ligne de commande, pas forcément celle de PHP-FPM qui sert le site. Vérifiez sur le rapport d'état de Drupal si vous avez un doute ;
  • drush pm:security vérifie les paquets drupal/* du composer.lock au regard des avis de sécurité Drupal ; il ne voit pas les bibliothèques PHP tierces, que composer audit couvre ;
  • pour mesurer le code sur mesure, un simple comptage de lignes dans modules/custom et themes/custom donne un premier ordre de grandeur, à affiner avec Upgrade Status.

Pour les sites sans accès SSH ni Drush (mutualisés anciens), relevez ces informations à la main depuis Rapports > État du site et Rapports > Mises à jour disponibles. Ce sont souvent les sites les moins suivis, donc à regarder en priorité.

2. Prioriser par risque, pas par ordre alphabétique

Avec le tableau en main, classez les sites selon quelques critères simples :

Critère Risque élevé Risque faible
Version de Drupal 10.2 ou moins 10.5 ou 10.6
Version de PHP 8.1 ou 8.2 8.3 ou plus
Données sensibles Comptes, formulaires, paiement Site vitrine sans saisie
Code sur mesure Plusieurs modules métier Aucun ou presque
Modules retirés du cœur (Book, Forum, Activity Tracker…) Utilisés Absents

Deux rappels utiles pour ce classement. Un site doit être au minimum en Drupal 10.3 pour passer en 11, et Drupal 11 exige PHP 8.3. Un site en 10.1 sous PHP 8.1 cumule donc trois marches : rattrapage des versions mineures de Drupal 10, montée de PHP, puis changement de version majeure. Ceux-là se lancent en premier, car leur durée est la moins prévisible.

À l'inverse, un petit site en 10.6, PHP 8.3, sans code sur mesure, est le plus rapide à traiter une fois le processus rodé : c'est un bon candidat pour valider la procédure en début de campagne.

3. Industrialiser la mise à jour

Traiter vingt sites avec vingt façons de faire coûte cher en relecture et en recette. L'objectif est qu'une mise à jour ressemble à la précédente.

Une checklist commune

Rédigez-la une fois, affinez-la après les deux ou trois premiers sites :

  1. Sauvegarde base et fichiers, vérifiée (une sauvegarde jamais restaurée n'est pas une sauvegarde).
  2. Cœur en dernière 10.6.x, contrib à jour, drush updb et drush cex propres.
  3. Upgrade Status : liste des modules bloquants et décision pour chacun (mettre à jour, patch, remplacer, retirer). Le détail de cette étape est dans l'article sur les modules contrib qui bloquent la mise à jour.
  4. Modules retirés du cœur : version contrib ajoutée ou module désinstallé.
  5. Code sur mesure corrigé (Drupal Rector, puis à la main).
  6. Contraintes Composer en ^11, Drush 13, composer update, drush updb, drush cex.
  7. Recette sur préproduction avec la grille du client.
  8. Mise en production, puis surveillance des logs les jours suivants.

Une branche type et un nommage fixe

Une branche upgrade/drupal-11 par dépôt, des commits séparés par étape (mises à jour D10, retrait de modules, Rector, passage en 11) : la relecture et un éventuel retour arrière partiel deviennent simples. Les patchs appliqués via cweagans/composer-patches sont versionnés dans un dossier patches/, jamais pointés sur une URL de merge request qui peut changer.

Une CI minimale

Même sans tests fonctionnels complets, un pipeline qui exécute ces commandes à chaque push évite les régressions grossières :

composer validate --no-check-publish
composer install --no-interaction --prefer-dist
composer audit
vendor/bin/phpstan analyse web/modules/custom --level=1

Pour que PHPStan détecte les appels d'API dépréciées dans le code sur mesure, il lui faut les extensions mglaman/phpstan-drupal et phpstan/phpstan-deprecation-rules (installées en dépendances de développement, par exemple via drupal/core-dev). Sur un site donné, un smoke test (quelques URL clés attendues en 200 sur une préproduction alimentée par une base anonymisée) apporte beaucoup pour un coût faible.

4. Estimer sans se tromper de moitié

Chiffrer au nombre de pages mène à des écarts importants. La charge dépend surtout du nombre de modules contrib sans version compatible, du volume de code sur mesure et de l'écart de version de PHP. Une grille simple :

  • base : préparation, mise à jour, recette, mise en production ;
  • par module bloquant : très variable, d'une simple mise à jour quand un patch existe à un remplacement avec reprise de données ;
  • code sur mesure : proportionnel aux dépréciations relevées par Upgrade Status, pas au nombre de fichiers ;
  • montée de PHP : à part, surtout si l'hébergement est géré par le client.

Chiffrez les deux premiers sites au réel, puis servez-vous de l'écart constaté pour corriger les estimations suivantes. Gardez une marge pour les recettes clients, qui prennent souvent plus de temps calendaire que la technique.

5. Sous-traiter en marque blanche

Si le volume dépasse la capacité de l'équipe, une partie des sites peut être confiée à un développeur Drupal externe, en marque blanche : l'agence reste l'unique interlocuteur du client. Pour que cela fonctionne, quelques règles sont à poser dès le départ.

Le cadre

  • NDA signé avant tout accès, couvrant le code, les données et l'identité des clients.
  • Aucune prise de contact entre le sous-traitant et le client final, sauf demande explicite de l'agence.
  • Propriété : le code produit appartient à l'agence ou à son client, selon votre contrat.

Les accès

Donnez le minimum nécessaire : accès au dépôt Git (branche dédiée), à la préproduction, éventuellement une clé SSH nominative révocable. Pas d'accès à la production si ce n'est pas indispensable, et jamais de base de production non anonymisée sur un poste externe si le site contient des données personnelles. Ces règles relèvent aussi de vos obligations RGPD en tant que sous-traitant de votre client.

Les conventions

Transmettez votre checklist, vos conventions de commit et de branche, votre outillage de CI. Le sous-traitant livre une merge request relisible, pas un zip. C'est aussi ce qui permet à votre équipe de reprendre le site sans friction après la mise à jour.

La recette

Définissez qui recette quoi : le sous-traitant valide la technique (logs vides, drush updb sans erreur, configuration exportée, pages clés en 200), l'agence ou le client valide le fonctionnel. Un compte rendu court par site (modules remplacés, patchs appliqués, points d'attention) évite de redécouvrir ces choix à la prochaine mise à jour.

Le calendrier réaliste

Entre mi-septembre et le 9 décembre, il reste environ douze semaines, dont une partie sera consommée par les recettes et les délais de validation des clients. Si l'inventaire n'est pas fait, c'est la priorité de cette semaine ; il conditionne tout le reste, y compris la décision de sous-traiter.

Je travaille en renfort d'agences, en marque blanche, sur ce type de campagne : les conditions sont détaillées sur la page sous-traitance pour agences, et les forfaits de mise à jour Drupal 10 vers 11 servent de base de chiffrage par site.