Skip to content

Tout pour WordPress, le développement web — et plus encore

🔄 WordPress dans un sous-dossier : migrer l'installation depuis la racine et inversement

🔄 WordPress dans un sous-dossier : migrer l'installation depuis la racine et inversement

Situation connue: vous avez monté un site de développement, intégré le thème, transféré le contenu via WP Migrate DB Pro, et après le push vous découvrez des styles cassés, des images perdues et un wp-admin qui ne fonctionne pas. La cause est presque toujours la même: la production est à la racine, et le dev, dans un sous-dossier (ou l'inverse), et un simple search-replace d'URL dans la base ne corrige pas cette différence.

Le problème est plus profond qu'il n'y paraît: dans une installation à la racine, tous les liens WordPress (vers les pages comme vers les fichiers médias) utilisent le même domaine. Dans une installation en sous-dossier, les liens vers le contenu partent de l'adresse du site, et les liens vers les ressources (css, js, images), de l'adresse de WordPress. Un search-replace ordinaire sur la base remplace tout de la même façon et casse la moitié des chemins.

Dans ce guide, deux itinéraires de migration éprouvés (aller et retour) avec des réglages de search-replace concrets, la préparation de wp-config.php et le bon ordre de transfert des fichiers. Après lecture, vous amènerez soit le dev et la production à un schéma unique, soit vous mènerez sciemment une migration entre installations de types différents sans frontend cassé.

💡 Aperçu rapide:

  • Déterminez le type d'installation: «Adresse de WordPress» et «Adresse du site» coïncident-elles dans Réglages → Général
  • Pour migrer d'un sous-dossier vers la racine: codez en dur WP_SITEURL dans wp-config, effectuez le remplacement /subdir/ dans la base de données, transférez les fichiers d'un niveau au-dessus, mettez à jour l'index.php racine
  • Pour migrer de la racine vers un sous-dossier: remplacez dans la base seulement les chemins vers /wp-content, mettez à jour l'adresse de WordPress dans les réglages, créez le sous-dossier, copiez index.php et .htaccess de retour dans la racine
  • Après toute migration, allez dans Réglages → Permaliens et cliquez sur «Enregistrer»: cela reconstruira la structure des URL et videra le cache

Comment déterminer où WordPress est installé

Si vous avez installé WordPress manuellement, vous vous souvenez sûrement si c'était la racine du domaine ou un sous-dossier du type /wp ou /blog. Mais si le site est hérité d'un développeur précédent, déployé par l'hébergement en un clic, ou que plusieurs années ont passé, les détails s'effacent.

Le moyen le plus rapide: allez dans l'admin WordPress, ouvrez Réglages → Général et regardez les champs «Adresse web de WordPress (URL)» et «Adresse web du site (URL)». Si les valeurs coïncident, vous avez devant vous une installation à la racine:

Les champs adresse de WordPress et adresse du site coïncident

Si les champs diffèrent, WordPress est installé dans un sous-dossier (dans l'exemple ci-dessous, c'est /subdir):

L'adresse de WordPress diffère de l'adresse du site

Signe supplémentaire d'une installation en sous-dossier: à la connexion à l'admin, l'URL contient le sous-dossier, par exemple, example.com/wp/wp-admin/ au lieu de example.com/wp-admin/.

Pourquoi on ne peut pas simplement transférer

La racine du problème, c'est le double système d'URL que WordPress utilise lors d'une installation en sous-dossier. Décomposons sur des exemples concrets.

Supposons que vous ayez une installation à la racine sur example.com. Absolument tous les liens dans la base de données, vers l'article /2025/about-page comme vers l'image /wp-content/uploads/photo.jpg, commencent par //example.com. Un search-replace ordinaire //example.local//example.com fonctionne parfaitement.

Prenons maintenant une installation dans le sous-dossier /wp. Le lien vers le même article ressemble à //example.com/about-page (via l'adresse du site), et le lien vers la même image, à //example.com/wp/wp-content/uploads/photo.jpg (via l'adresse de WordPress avec le sous-dossier). Un simple remplacement //example.local//example.com cassera les fichiers médias: le système les cherchera sans /wp dans le chemin et recevra un 404.

Le tableau ci-dessous montre quels groupes d'URL il faut mettre à jour dans chaque direction de migration:

Direction

URL des pages et articles

URL des médias et ressources

Chemins vers les fichiers dans la BD

Sous-dossier → racine

Remplacer /subdir → `` (retirer le sous-dossier)

Remplacer /subdir/wp-content/wp-content

Remplacer /app/public/subdir/app/public

Racine → sous-dossier

Laisser tel quel

Remplacer /wp-content/subdir/wp-content

Remplacer /app/public/app/public/subdir

Outre la base de données, il faut physiquement déplacer les fichiers et mettre à jour index.php dans la racine, sinon WordPress ne trouvera pas wp-blog-header.php. Voyons ensuite les deux itinéraires étape par étape.

Méthode 1: transfert de WordPress d'un sous-dossier vers la racine

C'est la direction la plus simple: vous retirez le sous-dossier des chemins, et toutes les URL deviennent «plates», comme dans une installation standard.

Étape 0: diagnostic de ce qui va mal tourner

Avant d'intervenir, il est utile de voir l'ampleur du problème de ses propres yeux. Sur la capture ci-dessous, les réglages de migration de wp-in-a-subdirectory.local (WordPress dans /subdir) vers wp-standard-install.local (installation à la racine). Les réglages de WP Migrate DB Pro, standard, plus le remplacement du titre du site pour la démonstration:

Réglages de migration WP Migrate DB Pro depuis un sous-dossier

Le résultat est comme prévu déplorable: les pages s'ouvrent, mais sans styles et avec des images cassées:

Résultat de la migration sans styles et avec des images cassées

Dans le HTML, on voit des liens vers les ressources avec le chemin mort /subdir, qui n'existe déjà plus sur le serveur cible. La tentative d'accéder à wp-admin provoque une redirection vers wp-standard-install.local/subdir/wp-login.php, or un tel fichier n'existe pas. Réparons maintenant.

Étape 1: préparation

Tout d'abord, protégeons l'accès à l'admin pendant la migration. Ajoutez à wp-config.php des constantes qui redéfiniront les réglages de la base de données, ainsi WordPress continuera à vous laisser entrer dans l'admin par l'ancien chemin avec le sous-dossier, même après le nettoyage de la base:

1define( 'WP_SITEURL', 'http://wp-in-a-subdirectory.local/subdir' );
2define( 'WP_HOME', 'http://wp-in-a-subdirectory.local' );

Ensuite, mettez le site en maintenance: modifiez index.php dans la racine publique, commentez la ligne require( dirname( __FILE__ )... et, après la balise fermante ?>, insérez un bouchon html avec un message d'indisponibilité brève. Les visiteurs verront ceci:

Page de maintenance avec un message de travaux techniques

Vous continuez pendant ce temps à entrer dans l'admin à l'adresse http://wp-in-a-subdirectory.local/subdir/wp-admin/, la constante WP_SITEURL fonctionne.

Étape 2: recherche et remplacement dans la base de données

Nettoyons maintenant la base. Lancez un search-replace avec ces paires (montré dans l'interface de WP Migrate DB Pro, mais le même principe fonctionne avec WP-CLI search-replace ou des requêtes SQL via phpMyAdmin):

  • //wp-in-a-subdirectory.local/subdir//wp-in-a-subdirectory.local
  • /app/public/subdir/app/public (chemin vers les fichiers sur le serveur)
Fenêtre de recherche et remplacement WP Migrate DB Pro pour retirer le sous-dossier

Juste après la migration, l'apparence ne changera pas, la page de maintenance reste affichée, l'admin fonctionne via la constante codée en dur. Mais si l'on regarde le contenu des articles, les images ne se chargent pas encore, et les liens internes ont «perdu» le sous-dossier, c'est précisément ce que nous visions à cette étape:

Contenu d'un article après le nettoyage de la base du sous-dossier

Étape 3: transfert physique des fichiers

Supprimez (ou commentez) les lignes avec WP_SITEURL et WP_HOME de wp-config.php. Maintenant l'admin va tomber, et transférez aussitôt les fichiers du sous-dossier d'un niveau au-dessus.

Via SSH ou la ligne de commande sur le serveur, cela se fait en trois commandes:

1rm index.php && mv subdir/* . && rm -rf subdir

Via FTP ou le gestionnaire de fichiers de l'hébergement, glissez tout le contenu du sous-dossier dans la racine publique en remplaçant index.php:

Transfert des fichiers WordPress vers le dossier racine via FTP

Voilà. Le site s'ouvre par l'URL racine, images et styles sont en place:

Le site fonctionne correctement après le transfert vers la racine

Dernière touche: allez dans l'admin (c'est maintenant http://wp-in-a-subdirectory.local/wp-admin sans sous-dossier), ouvrez Réglages → Permaliens et cliquez sur «Enregistrer les modifications», même si vous n'avez rien changé. WordPress reconstruira la structure des URL et videra le cache.

Méthode 2: transfert de WordPress de la racine vers un sous-dossier

Beaucoup de développeurs considèrent l'installation de WordPress dans un sous-dossier comme une bonne pratique: les fichiers du cœur n'encombrent pas la racine, la gestion via Git/Composer est simplifiée, et le domaine lui-même peut servir à d'autres applications. Mais la migration d'un site existant vers un sous-dossier est objectivement plus complexe que l'inverse, car désormais une partie des liens DOIT conserver le sous-dossier, et une autre, non.

Étape 0: diagnostic

Le même point de départ: on tente une migration standard de l'installation racine wp-standard-install.local vers celle en sous-dossier wp-in-a-subdirectory.local (WordPress dans /subdir):

Réglages de migration WP Migrate DB Pro de la racine vers un sous-dossier

Le résultat est tout à fait attendu: les pages s'ouvrent, mais les styles et les images sont cassés, /subdir n'a pas été ajouté à leur chemin:

Styles et images cassés après la migration vers un sous-dossier

Contrairement au premier scénario, les liens vers les articles et les pages fonctionnent correctement, ils ne doivent justement pas contenir le sous-dossier. Ce sont précisément les ressources (css, js, médias) qui cassent, dont les chemins doivent désormais inclure /subdir.

Étape 1: préparation

Les constantes WP_SITEURL et WP_HOME à cette étape, on ne les inscrit PAS, notre search-replace ne touchera pas à ces valeurs, et nous mettrons à jour l'adresse de WordPress manuellement un peu plus tard.

La page de maintenance, on la met de la même façon: on commente require(...) dans index.php et on ajoute un bouchon html. Les visiteurs voient un message de maintenance, et vous continuez à entrer dans l'admin par http://wp-standard-install.local/wp-admin/.

Étape 2: search-replace sélectif dans la base

La différence clé avec la première méthode: nous remplaçons SEULEMENT les chemins vers les fichiers et les ressources, sans TOUCHER aux URL des pages. Pour cela, on cible le remplacement par le masque /wp-content:

  • //wp-standard-install.local/wp-content//wp-standard-install.local/subdir/wp-content
  • /app/public/app/public/subdir (chemin sur le serveur)
Réglage du remplacement sélectif pour ajouter le sous-dossier

Après la migration, on vérifie le contenu des articles: les liens vers d'autres pages du site ne contiennent PAS le sous-dossier (correct), tandis que les images intégrées, si (correct aussi):

Article après le remplacement sélectif : les images avec le sous-dossier

Étape 3: mise à jour de l'adresse de WordPress et transfert des fichiers

Allez maintenant dans Réglages → Général et ajoutez le sous-dossier à la fin de «Adresse web de WordPress (URL)», par exemple, http://wp-standard-install.local/subdir. Juste après l'enregistrement, l'admin va tomber, car WordPress tentera de trouver les fichiers par le nouveau chemin, or ils n'y sont pas encore:

Mise à jour de l'adresse de WordPress avec l'ajout du sous-dossier

Créez le sous-dossier subdir dans la racine publique et déplacez-y TOUS les fichiers de WordPress. Ensuite, copiez index.php et .htaccess de RETOUR dans la racine, pour que la page de maintenance reste affichée pendant que nous terminons:

Les fichiers WordPress transférés dans le sous-dossier subdir

Restaurez index.php À L'INTÉRIEUR du sous-dossier à son état d'origine, retirez le bouchon html et décommentez la ligne avec require:

1<?php
2define( 'WP_USE_THEMES', true );
3require( dirname( __FILE__ ) . '/wp-blog-header.php' );

Maintenant l'admin est de nouveau accessible à l'adresse http://wp-standard-install.local/subdir/wp-admin/:

L'admin WordPress fonctionne après le transfert dans le sous-dossier

Vérifiez le contenu, les images sont en place, les styles se chargent:

Contenu de l'article vérifié : toutes les images sont en place

Touche finale: l'index.php racine

Il reste à mettre à jour index.php dans la racine publique. Retirez la page de maintenance et inscrivez le chemin actuel vers wp-blog-header.php en tenant compte du sous-dossier:

1<?php
2define( 'WP_USE_THEMES', true );
3require( dirname( __FILE__ ) . '/subdir/wp-blog-header.php' );

Le site s'ouvre par l'URL racine, toutes les ressources sont récupérées depuis le sous-dossier:

Le site fonctionne correctement après le transfert dans le sous-dossier

Allez de nouveau dans Réglages → Permaliens et enregistrez sans modification, pour que WordPress rafraîchisse la structure des URL.

Outils alternatifs et méthode officielle

L'approche décrite ci-dessus avec WP Migrate DB Pro est pratique, mais pas la seule. Voici avec quoi vous pouvez travailler aussi:

  • WP-CLI search-replace. La commande wp search-replace '//oldsite.local/subdir' '//newsite.com' avec le drapeau --dry-run montrera d'abord combien d'occurrences seront remplacées. Pour un remplacement sélectif (racine → sous-dossier), affinez le masque: wp search-replace '//newsite.com/wp-content' '//newsite.com/subdir/wp-content'.

  • Méthode officielle de WordPress. La documentation developer.wordpress.org décrit la procédure «Giving WordPress Its Own Directory», avec des configurations détaillées pour Apache (.htaccess), nginx (server block) et IIS (web.config). La méthode ne requiert pas d'extensions et fonctionne sur n'importe quel hébergement.

  • SQL manuel. Si le volume de modifications est faible, on peut exécuter UPDATE wp_posts SET post_content = REPLACE(post_content, '/subdir/', '/') directement dans phpMyAdmin, mais impérativement avec une sauvegarde préalable, une telle substitution détruira les données sérialisées dans wp_options et wp_postmeta.

Quel que soit l'outil que vous choisissez, la règle est une: lors d'une migration RACINE → SOUS-DOSSIER, remplacez seulement /wp-content et les chemins de fichiers; lors d'une migration SOUS-DOSSIER → RACINE, remplacez tout ce qui renvoie au sous-dossier.

⁉️🤔 Questions fréquentes

Est-il obligatoire d'utiliser WP Migrate DB Pro pour une telle migration?

Non. WP Migrate DB Pro donne simplement une interface pratique pour le search-replace avec la compréhension des données sérialisées de PHP. Techniquement, vous pouvez effectuer les mêmes remplacements via WP-CLI (la commande wp search-replace traite aussi correctement les serialized strings) ou utiliser la méthode officielle de WordPress avec transfert manuel des fichiers et modification d'index.php. L'extension économise du temps sur les projets grands et moyens, où il y a beaucoup d'occurrences.

Que faire si, après la migration, une partie des images ne se charge toujours pas?

La cause la plus fréquente: il reste dans la base des URL codées en dur avec les chemins absolus de l'ancien serveur, qui ne sont pas tombés sous le masque de remplacement. Vérifiez le contenu des articles via phpMyAdmin: SELECT ID, post_content FROM wp_posts WHERE post_content LIKE '%/subdir/%' (ou l'ancien domaine). Deuxième candidat, le cache du navigateur et le CDN: videz-les et vérifiez en navigation privée.

Faut-il mettre à jour le.htaccess après le transfert?

Si vous utilisez des permaliens jolis, oui, mais WordPress le fait lui-même quand vous cliquez sur «Enregistrer» sur la page Réglages → Permaliens. Si le serveur n'a pas les droits d'écriture, WordPress affichera le contenu du.htaccess prêt à l'emploi, copiez-le manuellement. Lors d'une migration vers un sous-dossier, assurez-vous que le.htaccess racine (et non celui à l'intérieur du sous-dossier) ne contient pas de règles en conflit avec la nouvelle structure.

Peut-on effectuer la migration sans aucun temps d'arrêt?

Techniquement oui, en utilisant la méthode avec redirections.htaccess (Method I de la documentation officielle de WordPress, «Sans changer les URL»). Dans cette approche, les fichiers sont transférés dans le sous-dossier, et le.htaccess racine dirige de façon transparente toutes les requêtes vers le nouvel emplacement. Les visiteurs ne remarquent pas le déménagement. Inconvénient: vous restez sur le même domaine, et l'URL du site ne change pas formellement (le sous-dossier n'est pas visible dans la barre d'adresse).

Pourquoi WP Migrate DB Pro ne prend-il pas en charge la migration entre installations de types différents d'origine?

Les développeurs de Delicious Brains en ont discuté sur GitHub pendant presque trois ans. La racine du problème: l'extension applique UNE paire search-replace à TOUTE la base, alors que pour une migration entre root et subdirectory il faut des remplacements DIFFÉRENTS pour différents groupes d'URL (pages vs ressources). La détermination automatique de quel URL appartient à quel groupe exigerait de parser la structure du contenu, ce qui dépasse le cadre d'un simple search-replace. C'est pourquoi la recommandation actuelle: amenez les sites à un schéma d'installation unique AVANT la migration.

Discussion sur la prise en charge de la migration sur le GitHub de Delicious Brains

Au final: racine ou sous-dossier?

Le choix entre une installation de WordPress à la racine et en sous-dossier se ramène, au fond, à un seul compromis. L'installation à la racine est plus simple: moins de pièces mobiles, compatibilité directe entre dev et production, aucune surprise avec les doubles URL. Celle en sous-dossier, plus propre sur le plan architectural: les fichiers du cœur sont isolés, dans la racine ne se trouve que index.php, il est plus facile de mettre à jour WordPress via Git/Composer et plus sûr d'héberger plusieurs applications sur un même domaine.

Si vous avez un site de production et un site de dev, amenez les deux à un schéma unique (n'importe lequel) et oubliez le problème. Si vous travaillez en équipe, où une partie des projets est historiquement à la racine et une autre, en sous-dossier, vous connaissez maintenant les masques exacts de search-replace pour chaque direction.

La règle d'or à mettre en favori: lors d'une migration RACINE → SOUS-DOSSIER, ne touchez qu'à /wp-content et aux chemins de fichiers; lors d'une migration SOUS-DOSSIER → RACINE, remplacez tout ce qui contient le sous-dossier. Et toujours, toujours, cliquez sur «Enregistrer» dans les Permaliens après le déménagement.