Makina Blog

Le blog Makina-corpus

Migration d'un site Drupal 7 en Drupal 10


Trucs, astuces et "bouts" de code pour migrer votre site web de Drupal 7 à Drupal 10. Compte-rendu d'une conférence donnée au Drupalcamp Rennes 2024.

Cet article a été transformé suite à notre conférence à la Drupalcamp Rennes 2024, afin de le mettre à jour pour Drupal 10.

Nous avons récemment migré de nombreux sites clients de Drupal 7 à Drupal 9 ou Drupal 10. L'objet de cet article est de vous présenter les enseignements que nous en avons tiré.

Une migration, ça se prépare !

Un peu comme un déménagement, une migration se prépare : on commence par nettoyer le site existant, notamment en supprimant les contenus et fonctionnalités inutiles. On en profite également pour mettre à jour le site aux dernières versions Drupal 7 du core et des modules communautaires (pour s'assurer du bon fonctionnement des scripts automatiques de migration).

C'est également le bon moment pour identifier des contenus de tests : ce sont des contenus éditoriaux assez complets qui vous permettront de valider l'intégralité du bon fonctionnement de la migration.

Attention aux features !

La grande majorité des sites web Drupal 7 utilisent le module Features, qui permet d'externaliser la configuration dans du code. Le problème est qu'alors les scripts de migration ne tiendront pas compte de cette configuration. Nous vous recommandons d'utiliser un patch de Features (issue #663136) permettant d'"importer" l'intégralité de la configuration des Features en base de données, permettant une migration complète de cette configuration.

Déroulé de la migration

Il y a essentiellement 2 façons de migrer un site de Drupal 7 à Drupal 8+ :

  • Mettre le site à jour le site en utilisant les scripts de migration fournis par le cœur de Drupal (basé, depuis Drupal 8, sur le module Migrate issu de la communauté et désormais dans le cœur) ;
  • Créer entièrement un nouveau site Drupal 10, et tenter de récupérer les contenus de Drupal 7 (là encore en utilisant des outils basés sur Migrate).

En général, nous recommandons la deuxième solution, c'est celle qui souvent génère le moins de contraintes en promettant une transformation des contenus selon les besoins.

Dans le cas de ce projet, nous étions confiants sur l'implémentation "standard" (proche du cœur) du site, avec très peu de personnalisation, et nous avons, après une phase de prototypage, décidé de tester la première solution, basée sur une migration automatisée.

Une fois cette solution choisie, il reste deux possibilités techniques pour exécuter la migration :

  • Soit de façon totalement automatisée, générée puis lancée par Drupal ;
  • Soit de façon semi-automatisée, en utilisant Drupal pour générer la migration, puis en permettant une phase de modification manuelle de la migration, avant de la lancer finalement.

C'est naturellement cette deuxième option que nous retenons, pour permettre d'agir sur les (nombreux) points qui peuvent ne pas se comporter comme nous le souhaitons.

Migration automatisée

Ici, la procédure est simple :

  • Installer un Drupal 9 vierge avec le profil d'installation "Standard" (la migration va de toute façon écraser toute la configuration, donc inutile de perdre du temps avec une installation plus compliquée). Nous choisissons plutôt le standard que le profil minimal parce que ;
  • Activer l'intégralité des modules que vous souhaitez migrer (y compris des modules de la communauté), notamment les modules qui fournissent des champs ou de la configuration importante pour la migration ;
  • Attention, il est recommandé de récupérer également le module "Media Migration", qui réalisera la transformation de tout ce qui concerne les fichiers en Drupal 7 sous forme de Media en Drupal 10. Ce module est pas loin de faire de la magie, donc ne passez pas à côté !
  • Aller dans l'interface de migration ("Configuration" / "Development" / "Upgrade") et lancer la migration en indiquant les paramètres de la base de données source.

Vous obtenez alors un site avec le contenu migré.

Un outil communautaire

Vous pouvez également utiliser un outil fourni par la communauté, Acquia Migrate: Accelerate, complètement clé en main, qui réalise votre migration entièrement, grâce à une énorme base de connaissance sur les possibilités de migration :

Acquia: Migrate Accelerate

La principale limitation de cet outil est qu'il migre en Drupal 9, en utilisant Drupal 7. Cela demande donc un peu plus de travail d'obtenir une migration Drupal 10.

De notre côté, nous utilisons un outil interne qui effectue un certain nombre de requêtes SQL pour auditer la base de données source, et anticiper une partie des problèmes. C'est notre base de connaissance à nous, bien sûr moins complète que celle d'Acquia, mais qui nous assiste pour les migrations.

Migration semi-automatisée

Cette deuxième façon de réaliser une migration partiellement automatisée s'appuie sur la précédente : au lieu de faire la migration, on génère le code associé à la migration (des fichiers .yml pouvant être importés via la gestion de configuration de Drupal), ce qui nous permet d'agir dessus (et d'éventuellement corriger des points) avant de la lancer.

composer require drupal/migrate_upgrade:^4
drush en -y migrate_upgrade
drush migrate-upgrade --legacy-db-url=pgsql://user:password@host:port/postgres --legacy-root=https://domain/ --configure-only

L'option --configure-only est nécessaire pour uniquement générer les migrations au lieu de les lancer.

Une fois les migrations modifiées, on peut les importer par :

drush migrate:import --group=migrate_drupal_7 --tag='Configuration' --execute-dependencies --continue-on-failure

Cette migration va potentiellement générer des erreurs, il faut donc les corriger, puis exécuter à nouveau la migration. À ce stade, on va souvent exporter la configuration, puis ne plus jamais lancer ces migrations de configuration. En effet, il est désormais plus rapide pour votre développement de corriger la configuration directement au sein de Drupal plutôt que de travailler sur les fichiers yml générés…

drush migrate:import --group=migrate_drupal_7 --tag='Content' --execute-dependencies --continue-on-failure

Cette migration va également générer des erreurs à corriger. C'est également à cette étape que nous pouvons améliorer le site (transformer un type de contenu en entité, ou en média) en tirant partie des améliorations des versions récentes de Drupal.

C'est cette démarche que nous utilisons systématiquement, notamment pour la partie "amélioration du site", qui permet d'éliminer une bonne partie de la dette technique Drupal 7 et faire comme si c'était un nouveau projet Drupal 10.

The good

Conditionné par mon passé Drupaliste, j'appréhendais un peu la migration des contenus… Et bien c'est ce qui se passe le mieux : la configuration des contenus (au sens Drupal 8), et donc des objets "contenu", "taxonomie", "utilisateurs" se passe plutôt bien, migrant à la fois les contenus et les liens entre contenus (issus du module Entity Reference).

De ce point de vue là, si vous utilisez la migration automatique, vous ne serez pas déçus, la majorité du contenu peut être récupérée directement, avec éventuellement quelques ajustements basiques.

Le multilinguisme, en fait, c'est simple !

Mieux que ça, l'intégralité des traductions des contenus et taxonomies a également été correctement récupéré. C'était la vraie bonne surprise de cette migration. Un énorme travail a été réalisé dans la communauté Drupal sur ce sujet, et ce n'est désormais plus du tout un souci.

Les modules non compatibles Drupal 10

Il existe encore de nombreux modules communautaires qui ne sont pas compatibles avec Drupal 10. Cependant, la plupart de ces modules disposent d'une version Drupal 8 ou 9 ainsi que d'un patch de compatibilité. Pour les installer, il suffit alors d'utiliser Composer Lenient, fourni par la communauté :

composer require mglaman/composer-drupal-lenient
composer config --merge --json extra.drupal-lenient.allowed-list '["drupal/token"]'

The bad

Contenu + Configuration = ?!?!

Nous souhaitons utiliser le nouveau système de configuration issu de Drupal 8 (familièrement appelé CMI, pour "Configuration Management Initative").

Or, le lancement de la migration de façon entièrement automatisée génère pour l'ensemble des migrations de contenus des dépendances sur des migrations de configuration, que nous n'avons plus de raison de relancer puisqu'après les avoir lancés une fois, nous avons exporté la configuration afin de pouvoir la gérer en utilisant le workflow de développement de site basé sur les commandes "drush configuration:export" (cex) et "drush configuration:import" (cim).

Nous devons donc adapter une partie des migrations. Par exemple, la migration des utilisateurs ne pouvant plus se baser sur une migration automatisée des rôles, nous remplaçons simplement la dépendance (et la recherche basée sur une migration) par une correspondance statique des rôles (upgrade_d7_user.yml) :

 roles:
# -
#  plugin: migration_lookup
#  migration: upgrade_d7_user_role
#  source: roles
-
plugin: static_map
 source: roles
 map:
  2: authenticated
  3: administrator
  4: webmaster

Toute la configuration… ou pas !

Certaines configurations ne se migrent vraiment pas correctement.

Les vues (du module Views) ne sont pas migrées par la procédure automatique de Drupal. C'est une limitation documentée, et si le module "View Migration" est suggéré par cette page, en pratique nos tests n'ont pas été concluants : l'ensemble des affichages n'était pas exporté, et les exports générés étaient mal formattés et inexploitables.

Les blocs fonctionnant tout à fait différement entre Drupal 7 et Drupal 9 ne sont pas non plus correctement récupérés / traduits, et nous avons donc du les recréer (heureusement, leur nombre était limité dans le site source, ce qui ne nous a pas coûté trop de temps).

Les webforms ne se migrent également pas toujours très bien.

Cependant, compte-tenu des différences techniques importantes entre Drupal 7 et Drupal 10, il est parfois plus rapide de tout refaire, notamment quand le nombre des vues ou webforms est limité.

Le multilinguisme, c'est pas si simple

La migration des alias multilingues fait parfois à peu près n'importe quoi, et nous avons déjà du là adapter la migration (upgrade_d7_url_alias.yml) :

langcode:
# plugin: null_coalesce
# source:
# - '@node_translation/1'
#  - language
 plugin: get
 source: language

The ugly

Jusqu'à maintenant, avec quelques corrections faciles, on a pu améliorer rapidement l'état de la migration. On passe maintenant à ce qui nous a couté pas mal de temps sur ce projet.

Le thème

Sur certains sites Drupal 7, nous étions relativement fiers d'être partis sur Twig pour le site Drupal 7 et… et bien ça n'a pas servi à grand chose. En plus du renommage des templates (de .tpl.twig à .html.twig), opération mineure, il s'avère que de très nombreuses choses ont changées au niveau du thème :

  • D'abord, tout est block, en Drupal 8 : le titre de la page, le fil d'ariane, … et les anciennes variables utilisées dans les templates Drupal 7 n'ont donc plus cours ;
  • Ensuite, de très nombreuses fonctions d'API utilisées dans les templates ou les fonctions de _preprocess (t(), drupal_add_css(), drupal_is_logged_in(), drupal_get_path(), …) ont changées, et une bonne partie du code est donc à convertir ;
  • La gestion d'URLs, basée désormais sur les routes, oblige à revoir également la plupart des chemins utilisés directement dans les templates.
Par contre, nous avons pu ré-utiliser presque directement la feuille de style et le code javascript, une fois transformés en library, la nouvelle façon d'utiliser des JS & CSS depuis Drupal 8 (via le fichier theme.libraries.yml).
 
Il faut globalement refaire quand même pas mal de choses
 

Le code personnalisé

Là aussi, il existe des solutions techniques pour récupérer une partie du code personnalisé :

  • Si vous êtes pressés, la promesse de Retrofit est de vous permettre d'utiliser votre code Drupal 7 sous Drupal 10, le temps que vous le convertissiez petit à petit :
composer require retrofit-drupal/retrofit
composer require drupal/drupalmoduleupgrader
drush dmu-analyze mon_module

Mais de façon plus générale, beaucoup de choses ont changé dans Drupal, et il est courant de notre côté de supprimer tout ou partie du code Drupal 7 pour l'implémenter différemment, ne conservant que ce qui ne peut pas être transformé. Cela réduit de beaucoup la taille du code à réécrire.

Les médias

Comme toujours (en tout cas en Drupal), le point le plus critique des migrations concerne les médias. Même en utilisant "Media Migration", qui reste la meilleure solution, compatible avec l'ensemble des possibilités Drupal 7 de gestion des médias, il reste souvent des points à ajuster, notamment en ce qui concerne les liens entre les médias et l'éditeur de texte riche.

Attention, la migration des médias recherche les fichiers dans sites/default/files, et si vous êtes par exemple sur un multisite, vous devrez retravailler ce point de la migration.

De même, Media Migration utilise par défaut des drupal_entity dans l'éditeur de texte riche (compatibles avec le module entity_embed), et si vous souhaitez utiliser des "drupal_media", il vous faudra ajouter la ligne suivante dans votre settings.php :

$settings['media_migration_embed_token_transform_destination_filter_plugin'] = 'media_embed';

Enfin, le filtre "autop" (qui transforme balises <p> et <br>) doit se trouver en dernier dans votre éditeur de texte riche pour éviter de couper les liens sur les images dans les éditeurs de texte.

Snippets / Tips & Tricks

Ce paragraphe contient quelques bouts de codes ou astuces qui vous seront peut-être utiles.

Notre script complet de migration

// Disable auto-redirection because we will create lots of aliases
// and pathauto is enabled.
drush cset redirect.settings auto_redirect 0
// Migrate specific migrations
drush migrate:import --tag=File --continue-on-failure --execute-dependencies
drush migrate:import --tag=Content --continue-on-failure --execute-dependencies
// Remove auto-generated aliases before alias migration
drush pathauto:aliases-delete canonical_entities:node
// Migrate aliases
drush migrate:import --tag=Alias --continue-on-failure --execute-dependencies
// Re-enable auto-redirection from redirect module
drush cset redirect.settings auto_redirect 1
// Re-build caches
drush cr
// Generate new aliases with our updated pathauto rules
// (Redirects from old aliases will be automatically created)
drush pathauto:aliases-generate all canonical_entities:node
// Re-build caches
drush cr
// Disable migrate-related modules
drush pm-uninstall migrate migrate_drupal migrate_plus migrate_tools migrate_upgrade
// Re-build caches
drush cr

Le multiliguisme, c'est compliqué

D'abord, installer un site Drupal en synchronisant la configuration (merci CMI), dans un contexte multilingue, ça continue de poser des problèmes : les traductions ne seront pas forcément correctement récupérées à l'installation, et vous aurez parfois une grosse différence entre la configuration active et la configuration exportée.

Pour résoudre ce problème, nous avons simplement pris l'habitude de rajouter à la fin de nos scripts d'installation une tâche qui devrait être inutile mais qui ne l'est pas : une nouvelle synchronisation de configuration, avec un "drush configuration:import" additionnel.

De même, s'il est beaucoup plus facile aujourd'hui d'associer des traductions à des modules, via 2 lignes ajoutées dans un .info.yml de module :

'interface translation project': [module_name]
'interface translation server pattern': profiles/[profile_name]/modules/custom/[module_name]/%language.po

Ces traductions ne surchargent pas toujours les traductions du cœur de Drupal.

Nous avonc donc du ajouter à notre script de déploiement une commande drush pour recharger les traductions de façon forcée en surchargeant les autres :

drush locale:import fr profiles/[profile_name]/modules/custom/[module_name]/fr.po --type=customized --override=all

Le cas de PostgresSQL

Pour différentes raisons, chez Makina Corpus, nous aimons beaucoup PostgreSQL. Ce qui n'est pas forcément le cas de la communauté Drupal, et en choisissant cette base, il faut prendre conscience que vous vous exposez potentiellement à quelques problèmes spécifiques, par exemple au niveau de la casse.

Cependant, la communauté est de plus en plus concernée par ce problème, et a même des tickets [meta] permettant de lister l'ensemble des problèmes entre Drupal et PostgresSQL, facilitant ainsi le débogage et l'éventuelle correction.

Nos contributions à Drupal

Nous utilisons sur notre projet quelques patchs pas encore intégrés à leurs modules respectifs.

L'utilisation du multilinguisme provoque toujours quelques questions, notamment sur l'affichage des menus par langage, et nous avons été obligé de patcher le module "sitemap" pour afficher un plan du site par language : Filter Menu Tree By Language (un patch du cœur est nécessaire pour que celui-ci fonctionne également).

Enfin, nous avons réussi (d'après nous) à corriger à vieux problème de "Pathauto" concernant les mises à jour des alias en cas de modification de menu : Pathauto token for node menu hierarchy not working after updating parent node (pour "Pathauto") nécessitant également un patch du core (que nous avons réalisé) : Possible need to change the way MenuLinkManager update menu-item and menu-tree.

Conclusion

La flexibilité de l'éco-système Migrate reste un de nos outils favoris pour migrer des sites, et nous vous invitons à nous contacter pour vos projets de migration de sites Drupal !

Formations associées

Formations Drupal

Formation Drupal Administrateur

Toulouse Du 22 au 24 mai 2024

Voir la formation

Formations Drupal

Formation Drupal Développeur

À distance (FOAD) Du 2 au 4 avril 2024

Voir la formation

Actualités en lien

Image
Drupal 7 - 8 et 9
27/05/2020

Drupal 9 : préparez-vous !

Dans quelques jours, le 3 juin 2020, aura lieu la sortie de Drupal 9 en version stable. À quels changements s’attendre ? Quel sera l’impact sur les sites développés actuellement en Drupal 8 et Drupal 7 ? Voici quelques informations qui vous permettront de mieux appréhender cet événement et d'en mesurer les impacts.

Voir l'article
Image
Bruxelles_mobilité_drupal
18/09/2017

Retour d'expérience sur la réalisation d'un portail Drupal mêlant cartographie et Open Data

Utilisation de Drupal comme outil centralisateur de flux.

Voir l'article
Image
Drupal 8 logo
01/12/2016

Utiliser Migrate en Drupal 8

Trucs, astuces et points d'attention pour l'import de données avec Migrate en Drupal 8.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus