Migration Drupal vers WordPress – pipeline Python + WP-CLI


Migrer un site Drupal vers WordPress, c’est rarement une opération simple. Surtout quand on parle de 1 075 articles, ~4 438 images, des CPT custom, des champs ACF, des taxonomies, des newsletters et des auteurs à préserver. Ce retour d’expérience détaille le pipeline d’import que j’ai construit, avec une aide précieuse de Claude Code au passage.

Le contexte : pourquoi un pipeline en deux étapes

L’approche naïve de migration Drupal → WordPress, exporter la base de données et la réimporter, ne fonctionne pas dès que le site source a une structure de données complexe. Dans ce cas : des types de contenu Drupal qui ne correspondent pas 1:1 aux post types WordPress, des champs ACF relationnels, des formats détectés via des classes CSS spécifiques à Drupal, et un HTML à nettoyer à la volée.

La solution : séparer le scraping de l’import. Deux étapes indépendantes, deux responsabilités claires.

Étape 1 – Le scraper Python

Un script Python avec requests + BeautifulSoup qui parcourt le site source et produit des fichiers JSON structurés, un par type de contenu (articles, actions, newsletters). Ce n’est pas du scraping au sens « on arrache ce qu’on peut » : chaque type de contenu a sa logique de détection, son nettoyage HTML dédié, sa gestion des cas particuliers.

Quelques défis concrets résolus à cette étape :

  • Détection des formats – les podcasts sont identifiables via des classes CSS Drupal spécifiques. Les vidéos YouTube sont intégrées en iframe dans le contenu et ne sont pas détectables en liste : elles nécessitent une URL de recherche dédiée à part.
  • Nettoyage HTML à la volée – unwrap des balises inutiles, remapping des classes Drupal vers des équivalents WordPress, suppression des blocs vides qui se multiplient après nettoyage.
  • Image clé en double – sur certains articles, l’image mise en avant apparaît aussi en début de contenu. Détectée et retirée automatiquement.

Étape 2 – L’import PHP via WP-CLI

Un script PHP exécuté via wp eval-file qui consomme les JSON produits à l’étape 1 et crée les contenus dans WordPress dans le bon ordre : catégories → actions (CPT) → articles → newsletters. L’ordre est important : les articles peuvent être liés à des actions via un champ ACF relationnel, les actions doivent donc exister avant.

Deux principes ont guidé la conception :

  • Idempotence – chaque post, chaque image est vérifié par une meta _xxx_source_url avant création. On peut relancer le script autant de fois qu’on veut, il ne crée pas de doublons.
  • Mode DRY_RUN – une simulation complète sans aucune écriture en base. Indispensable pour valider les données avant d’importer 1 000+ articles.

La gestion des images mérite une mention : download_url() + wp_handle_sideload() + wp_insert_attachment() avec date forcée dans uploads/YYYY/MM/ pour respecter la structure attendue par WordPress. Les URLs Drupal relatives sont absolutisées avant traitement.

Ce que Claude Code a apporté sur ce projet

C’est la première fois que j’utilisais Claude Code de façon intensive sur un projet de migration. Le verdict : c’est particulièrement efficace sur ce type de tâche, pour plusieurs raisons.

D’abord, la génération de code répétitif. Un pipeline d’import, c’est beaucoup de patterns qui se ressemblent, vérification d’existence, création, gestion d’erreurs, logging. Claude Code génère ces patterns correctement du premier coup et maintient la cohérence sur l’ensemble du fichier.

Ensuite, le débogage de structure de données. Quand les données scrappées ne correspondent pas exactement à ce qu’on attendait, doublons de projets, champs manquants, formats non détectés, poser le problème à Claude Code avec le JSON en entrée produit rapidement des pistes concrètes.

Enfin, la rédaction du prompt de contexte lui-même. Pour qu’un outil comme Claude Code soit réellement utile sur un projet complexe, il faut lui fournir un contexte structuré, stack, types de contenu, champs ACF, points d’attention connus. Ce travail de formalisation est en lui-même utile : ça force à documenter ce qu’on fait.

Ce qui reste à traiter

Le pipeline est fonctionnel, mais quelques points sont encore ouverts :

  • La détection des articles au format vidéo – les iframes YouTube dans le contenu nécessitent un passage dédié via l’URL de recherche du site source
  • Le nettoyage final de la liste des projets – des doublons subsistent dans les données scrappées, les relations sont correctes mais la liste est à assainir
  • Les auteurs – 209 auteurs uniques à mapper vers des comptes WordPress ou à gérer comme métadonnées

Migration en cours. Suite au prochain épisode.


Stack : Python · BeautifulSoup · PHP · WP-CLI · ACF Pro · WordPress