vendredi 25 septembre 2026

À propos

Contact

Multilingue

Migrer de Polylang vers WPML sur un site en production : notre retour d’expérience

Un client nous a demandé de basculer son site de Polylang vers WPML sans perdre ni ses traductions ni son référencement. Voici comment nous avons procédé.

Par Clément Hadrot • 19 février 2026 • 6 min de lecture • Aucun commentaire
Migrer de Polylang vers WPML sur un site en production : notre retour d'expérience

Un client gérant un site institutionnel en trois langues nous a sollicités avec une demande précise : basculer de Polylang, utilisé depuis la création du site, vers WPML, devenu nécessaire pour bénéficier de son gestionnaire de traduction plus riche à mesure que l’équipe de contenu s’étoffait avec plusieurs rédacteurs et traducteurs externes. Le site comptait environ mille deux cents contenus traduits (articles, pages, produits) répartis sur trois langues, un volume suffisant pour rendre toute erreur de migration coûteuse à corriger a posteriori.

Ce retour d’expérience détaille la méthode suivie, les difficultés rencontrées, et ce que nous ferions différemment sur une prochaine migration de ce type.

Pourquoi cette migration n’est jamais une simple désactivation-réactivation

Polylang et WPML stockent les relations de traduction dans des structures totalement différentes. Polylang s’appuie sur un système de taxonomies cachées (chaque groupe de traduction et chaque langue sont en réalité des termes de taxonomie internes, invisibles dans l’interface standard), tandis que WPML utilise sa propre table icl_translations, organisée autour d’un identifiant de groupe de traduction (trid) complètement étranger au système de Polylang.

Désactiver Polylang et activer WPML sans étape intermédiaire aurait simplement fait disparaître toute connaissance des relations de traduction existantes : chaque contenu serait redevenu une page isolée, sans lien connu vers ses équivalents dans les autres langues, obligeant à reconstituer ces liens manuellement un par un.

Étape 1 : cartographier les relations existantes

La première étape a consisté à extraire, depuis les tables internes de Polylang, la correspondance complète entre chaque post et ses traductions dans les autres langues, sous forme d’un export structuré (identifiant de post, langue, identifiant du groupe de traduction Polylang). Un script WP-CLI personnalisé a permis de générer cet export exhaustif avant toute modification :

wp eval '
$posts = get_posts( array( "post_type" => "any", "numberposts" => -1 ) );
$export = array();
foreach ( $posts as $post ) {
    $langue = pll_get_post_language( $post->ID );
    $groupe = pll_get_post_translations( $post->ID );
    $export[] = array(
        "id"     => $post->ID,
        "langue" => $langue,
        "groupe" => $groupe,
    );
}
file_put_contents( "export-traductions-polylang.json", wp_json_encode( $export ) );
'
L'essentiel à retenir : Les deux plugins utilisent des structures de tables incompatibles entre elles ; Un script de correspondance a permis de préserver les liens de traduction existants ; La bascule s'est faite sur un environnement de préproduction testé pendant deux semaines

Étape 2 : reconstituer les relations dans WPML

Une fois WPML installé (sans encore désactiver Polylang, les deux ayant coexisté temporairement le temps de la migration), un script de correspondance a parcouru l’export généré à l’étape précédente pour recréer, via les fonctions internes de l’API WPML, les mêmes groupes de traduction. La fonction clé utilisée ici est l’action wpml_set_element_language_details, qui permet d’associer explicitement un post à une langue et à un groupe de traduction (trid) sans passer par l’interface graphique :

<?php
foreach ( $export_polylang as $groupe_traductions ) {
    $trid = null;
    foreach ( $groupe_traductions as $entree ) {
        $trid = apply_filters( 'wpml_element_trid', $trid, $entree['id'], 'post_post' );
        do_action( 'wpml_set_element_language_details', array(
            'element_id'    => $entree['id'],
            'element_type'  => 'post_post',
            'trid'          => $trid,
            'language_code' => $entree['langue'],
        ) );
    }
}

Cette approche a permis de reconstituer la totalité des mille deux cents liaisons sans intervention manuelle, en s’appuyant strictement sur les API publiques documentées de WPML plutôt que sur une écriture directe dans ses tables, plus fragile face aux évolutions futures du plugin.

Étape 3 : deux semaines de test en préproduction

Avant toute bascule en production, la migration complète a été rejouée sur un environnement de préproduction, avec un jeu de données identique à la production. Pendant deux semaines, l’équipe éditoriale du client a été invitée à naviguer sur cet environnement comme si c’était le site réel, avec pour consigne explicite de signaler toute traduction manquante ou tout lien de traduction incohérent constaté.

Cette période a permis de détecter un problème que le script de migration n’avait pas anticipé : les chaînes de traduction gérées par Polylang (Chaînes de traduction, pour les textes hors contenu comme les libellés de thème) n’étaient pas couvertes par notre script initial, centré sur les contenus de type post. Un second script, dédié cette fois à la migration des chaînes via icl_register_string et son équivalent de récupération côté Polylang, a dû être développé spécifiquement pour combler ce manque.

Étape 4 : la bascule finale

La bascule en production s’est faite un mardi matin, hors période de forte affluence pour ce site institutionnel, avec Polylang désactivé juste après confirmation que l’ensemble des relations avait été correctement reconstitué dans WPML sur l’environnement final. Les URL n’ont pas changé (les deux plugins partageant la même structure de préfixe de langue en sous-dossier déjà en place), ce qui a évité tout besoin de plan de redirection supplémentaire pour cette migration précise.

Ce que nous ferions différemment

  • Inclure dès le premier script la migration des chaînes de traduction, plutôt que de la découvrir comme un manque en cours de test.
  • Prévoir une période de test en préproduction encore plus longue pour un site de volume supérieur à celui-ci, le temps de détection des incohérences ayant été le facteur limitant, pas le temps d’exécution technique du script lui-même.
  • Documenter systématiquement, pour le client, la liste des réglages spécifiques à reconfigurer manuellement dans la nouvelle extension (les réglages de synchronisation de champs personnalisés notamment), qui ne se migrent jamais automatiquement quel que soit le soin apporté au script de migration des contenus.

Ce projet nous a confirmé une règle que nous appliquons depuis à toute demande de changement de plugin multilingue : ne jamais migrer sans avoir d’abord écrit noir sur blanc, avant tout script, la liste exhaustive de tout ce qui vit dans l’ancien système et qui devra exister dans le nouveau.

En résumé

Migrer d’un plugin multilingue à un autre sur un site en production est un chantier qui dépasse largement la simple désactivation-réactivation : cartographie complète des relations existantes, reconstitution via les API publiques du plugin cible, période de test en préproduction suffisamment longue, et documentation des réglages annexes à reconfigurer manuellement. Sur ce projet, cette méthode a permis de migrer mille deux cents contenus traduits sans perte de liaison ni impact sur le référencement existant, au prix d’une préparation nettement plus longue que ce qu’un client imagine généralement au moment de formuler la demande.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi