Ce guide s’adresse aux propriétaires et aux administrateurs qui veulent déplacer une boutique Magento vers WooCommerce sur un serveur cPanel, sans perdre de produits, de clients ni de trafic. Il couvre Magento 2, vendu sous le nom Adobe Commerce ou gratuit sous le nom Magento Open Source, et Magento 1, en fin de vie depuis juin 2020. Le déclencheur habituel est le coût. Magento exige des développeurs spécialisés, un hébergement lourd et des mises à niveau régulières que bien des boutiques moyennes ne peuvent pas justifier. La voie pratique consiste à restaurer une copie de la base Magento dans le compte cPanel, à l’importer dans WooCommerce, puis à bâtir les redirections à partir de la table d’URL de Magento. À la fin, WooCommerce sert la boutique, chaque ancienne adresse de produit et de catégorie répond par une redirection 301, et vous avez un plan pour les connexions des clients.
Ce que vous allez accomplir
- Décider si WooCommerce convient à votre boutique, ou si Magento ou Mage-OS reste le meilleur choix.
- Comprendre comment Magento stocke un produit et où chaque morceau arrive dans WooCommerce.
- Restaurer une copie de la base Magento dans cPanel, lisible par un utilisateur limité à
SELECT. - Importer les produits, les variations, les images, les clients et les anciennes commandes, en vérifiant chaque décompte.
- Transformer la table
url_rewritede Magento en redirections 301, basculer le DNS et garder un retour arrière prêt.
Prérequis
- Un accès shell au serveur Magento, ou un vidage de la base et une copie de
pub/media. - Un compte cPanel avec accès SSH sur le serveur de destination, et WP-CLI, l’outil en ligne de commande de WordPress. Vérifiez avec
wp --info. - Le client
mysqlet la commandeuapi, présents sur tout serveur cPanel. - PHP 8.2 ou 8.3 pour le site WordPress, réglé par domaine dans le MultiPHP Manager de cPanel.
- L’audit préalable d’une migration WooCommerce, fait en premier, qui cadre les passerelles de paiement, la livraison, les taxes et les courriels.
- Pour les boutiques Magento 1, la logique est la même, mais quelques noms de tables diffèrent. Chaque étape les signale.
Comment ça fonctionne
Magento stocke les produits selon un modèle EAV, pour entité-attribut-valeur. Chaque produit est une ligne de catalog_product_entity qui ne contient que son identifiant (entity_id), son UGS (unité de gestion des stocks, ou SKU) et son type. Tout le reste, comme le nom ou le prix, se trouve dans des tables de valeurs groupées par type de données, par exemple catalog_product_entity_varchar et catalog_product_entity_decimal. Chaque ligne de valeur porte aussi un store_id, si bien qu’un produit peut avoir un nom différent dans chaque vue de magasin. Une vue de magasin est le terme de Magento pour une langue ou une vitrine à l’intérieur d’un site.
WooCommerce est plus simple. Un produit est une publication dans wp_posts, et son UGS, son prix et son stock sont des lignes de wp_postmeta. Le schéma montre où arrive chaque notion de Magento.
Trois lignes demandent de l’attention. Un produit configurable est le produit parent de Magento, comme un chandail à capuchon, et chaque taille et couleur est un produit simple distinct qui lui est lié dans catalog_product_super_link. Dans WooCommerce, il devient un produit variable avec une variation par enfant. Les options qui servent à choisir un enfant, comme color et size, deviennent des attributs globaux, stockés comme des taxonomies nommées sur le modèle de pa_color.
Les mots de passe ne suivent pas. Magento 2 stocke le mot de passe de chaque client sous forme de hachage salé, une empreinte à sens unique du mot de passe, calculée avec SHA-256 ou Argon2id. WordPress ne peut vérifier ni l’un ni l’autre, alors prévoyez une réinitialisation pour chaque client. Les commandes arrivent comme historique, pas comme paiements actifs. Votre nouvelle passerelle n’a aucune trace des paiements encaissés par Magento, donc les remboursements des anciennes commandes se font dans le tableau de bord de l’ancienne passerelle. Avant de commencer, lisez la dernière section de ce guide pour confirmer que WooCommerce est la bonne destination.
Étapes
-
Lisez les paramètres de la base et comptez ce que vous avez. Sur le serveur Magento, depuis le dossier racine de Magento, affichez les paramètres de connexion de
app/etc/env.php:php -r '$c = include "app/etc/env.php"; print_r($c["db"]["connection"]["default"]); echo $c["db"]["table_prefix"], "\n";'Résultat attendu : un tableau qui montre
[host],[dbname],[username]et[password], puis le préfixe des tables, habituellement une ligne vide. Magento 1 garde ces valeurs dansapp/etc/local.xml. Faites ensuite l’inventaire :mysql -u magento -p magento -e "SELECT type_id, COUNT(DISTINCT entity_id) AS products FROM catalog_product_entity GROUP BY type_id; SELECT store_id, code, website_id FROM store; SELECT COUNT(*) AS customers FROM customer_entity; SELECT COUNT(*) AS orders FROM sales_order;"Résultat attendu, pour une boutique de taille moyenne :
+--------------+----------+ | type_id | products | +--------------+----------+ | configurable | 184 | | simple | 2317 | +--------------+----------+ +----------+---------+------------+ | store_id | code | website_id | +----------+---------+------------+ | 0 | admin | 0 | | 1 | default | 1 | +----------+---------+------------+Les décomptes de clients et de commandes suivent. Le
DISTINCTcompte sur Adobe Commerce, où les mises à jour planifiées peuvent créer plusieurs lignes par produit. Le magasin0contient les valeurs par défaut, donc cette boutique a une seule vraie vue de magasin. Sur Magento 1, la table des commandes s’appellesales_flat_order. Notez chaque nombre pour les vérifications finales. -
Copiez la base dans le compte cPanel. Sur le serveur Magento, prenez un vidage cohérent sans verrouiller la boutique en ligne :
mysqldump --single-transaction --no-tablespaces -u magento -p magento | gzip > ~/magento-copy.sql.gzCopiez le fichier dans votre dossier personnel cPanel avec
scp, puis créez une base et restaurez-la. Les noms de bases cPanel commencent par le nom du compte et un trait de soulignement, iciexmpl_:uapi Mysql create_database name=exmpl_mage gunzip < ~/magento-copy.sql.gz | mysql -u exmpl -p exmpl_mageRésultat attendu :
status: 1de la part deuapi, puis une demande de mot de passe et aucune autre sortie. Le vidage contient les adresses des clients et les hachages de mots de passe, alors gardez-le hors depublic_htmlet supprimez-le à la fin du projet. -
Créez un utilisateur de base en lecture seule. L’importateur n’a besoin que de lire les données Magento, et un utilisateur limité à
SELECTne peut rien modifier par erreur :uapi Mysql create_user name=exmpl_mageread password='REPLACE_ME' uapi Mysql set_privileges_on_database user=exmpl_mageread database=exmpl_mage privileges=SELECT mysql -u exmpl_mageread -p exmpl_mage -e "DELETE FROM sales_order LIMIT 1;"Résultat attendu :
status: 1deux fois, puisERROR 1142 (42000): DELETE command denied to user. Cette erreur prouve que la limite fonctionne. Si vous lisez un jour une base Magento en production plutôt qu’une copie, cet utilisateur devient indispensable. -
Vérifiez le format des hachages de mots de passe. Magento 2 écrit chaque hachage sous la forme
hash:salt:version. La dernière partie indique l’algorithme :mysql -u exmpl_mageread -p exmpl_mage -e "SELECT SUBSTRING_INDEX(password_hash, ':', -1) AS version, COUNT(*) AS customers FROM customer_entity GROUP BY version;"Résultat attendu : des lignes comme
1pour SHA-256, et2ou une valeur qui commence par3_pour Argon2id. WordPress ne peut vérifier aucun de ces formats, pas plus que les hachages MD5 ou SHA-256 salés de Magento 1. L’étape 8 couvre les réinitialisations. -
Installez WordPress et WooCommerce sur un sous-domaine de préproduction. Dans cPanel, créez
new.example.comavec la racine~/new.example.com, pointez son DNS vers ce serveur, et créez une base et un utilisateur vides pour WordPress. Installez ensuite :cd ~/new.example.com wp core download wp config create --dbname=exmpl_wp --dbuser=exmpl_wp --dbpass='REPLACE_ME' wp core install --url=https://new.example.com --title='Example Store' \ --admin_user=admin --admin_email=you@example.com --skip-email wp plugin install woocommerce --activate wp rewrite structure '/%postname%/' --hardRésultat attendu :
Success: WordPress installed successfully., puisSuccess: Installed 1 of 1 plugins.etSuccess: Rewrite structure set.Fixez dès maintenant les bases des produits et des catégories dans Réglages > Permaliens, car la carte de redirections en dépend. Ce guide garde les valeurs par défaut,/product/et/product-category/. -
Créez les attributs globaux. Listez les attributs qu’utilisent vos produits configurables :
mysql -u exmpl_mageread -p exmpl_mage -e "SELECT DISTINCT a.attribute_code, a.frontend_label FROM catalog_product_super_attribute s JOIN eav_attribute a ON a.attribute_id = s.attribute_id;"Résultat attendu : une ligne par attribut, comme
color | Coloretsize | Size. Créez un attribut global correspondant pour chacun :wp wc product_attribute create --name=Color --slug=color --user=1 wp wc product_attribute create --name=Size --slug=size --user=1Résultat attendu :
Success: Created product_attribute 1., puis la même ligne avec2. Notre guide sur les produits variables et les attributs explique comment WooCommerce s’en sert. -
Exportez et importez le catalogue. Deux voies s’offrent à vous.
La première est l’extension FG Magento to WooCommerce de Frédéric Gilles, qui lit directement la base Magento. Installez-la avec
wp plugin install fg-magento-to-woocommerce --activate, ouvrez Outils > Importer > Magento, puis entrezlocalhost, l’utilisateurexmpl_magereadet le préfixe des tables s’il y en a un. La version gratuite transfère les catégories, les produits simples, les images, les stocks et les pages CMS. La page de l’extension range les variations, les clients, les commandes et les redirections d’URL dans l’édition Premium payante, alors vérifiez-y la répartition actuelle.La deuxième voie est l’export de Magento. Dans l’administration, ouvrez Système > Transfert de données > Exporter, choisissez Produits et CSV, puis sélectionnez Continuer. Magento 2.4 met la tâche en file d’attente. Si aucun fichier n’apparaît après quelques minutes, démarrez le consommateur de la file depuis la racine de Magento :
bin/magento queue:consumers:start exportProcessor --max-messages=1 ls var/export/Résultat attendu : un fichier comme
catalog_product_20260915_140512.csv. Sur Magento 1, passez par Système > Import/Export > Export. Convertissez les colonnes avec un tableur ou un court script :Colonne Magento Colonne WooCommerce skuSKUproduct_type(configurable,simple)Type(variable,simple,variation)name,description,short_descriptionName,Description,Short descriptionprice,special_priceRegular price,Sale priceqty,is_in_stockStock,In stock?categories(Default Category/Men/Tops)Categories(Men > Tops)url_keyslug, réglé après l’import base_image,additional_imagesImages, en URL complètesGardez seulement les lignes où
store_view_codeest vide, car les autres sont des valeurs propres à une vue de magasin et créent des doublons. La colonneconfigurable_variationsdécrit chaque enfant sous la formesku=MH01-S-Black,size=S,color=Black, avec une barre verticale entre les enfants. Servez-vous-en pour régler leParentde chaque variation sur l’UGS du produit configurable. Importez d’abord les parents, puis les variations, avecAttribute 1 globalréglé à1. Notre guide de migration de Shopify vers WooCommerce détaille cet import en deux passes.Pour les images, copiez le dossier des médias sans le cache d’images redimensionnées de Magento :
rsync -a --exclude=cache magento-host:/var/www/magento/pub/media/catalog/product/ ~/new.example.com/wp-content/uploads/magento/ find ~/new.example.com/wp-content/uploads/magento -type f | wc -lRésultat attendu : un nombre proche de votre nombre d’images de produits. Dans la colonne
Images,/m/h/mh01-black_main_1.jpgdevienthttps://new.example.com/wp-content/uploads/magento/m/h/mh01-black_main_1.jpg, et l’importateur ajoute chaque image à la médiathèque. -
Importez les clients et planifiez les réinitialisations. Exportez le fichier principal des clients depuis le même écran d’export, puis ramenez-le aux colonnes
user_login,user_email,first_name,last_nameetrole, aveccustomercomme rôle :wp user import-csv magento-customers.csv --skip-update wp user list --role=customer --format=countRésultat attendu : une ligne par utilisateur créé, puis un nombre égal à celui de l’étape 1. L’édition FG Premium affirme accepter les mots de passe Magento à la connexion, alors testez un vrai compte si vous l’utilisez. Sinon, envoyez les réinitialisations après la bascule par lots de 200, car bien des serveurs cPanel plafonnent le nombre de courriels qu’un domaine peut envoyer par heure. La première ligne découpe les identifiants des clients en fichiers de 200, et la deuxième envoie le premier fichier :
wp user list --role=customer --field=ID | split -l 200 - ~/reset-batch- xargs wp user reset-password < ~/reset-batch-aaRésultat attendu : une ligne
Reset password forpar utilisateur du premier lot, puis une ligneSuccess:avec le total. Une heure plus tard, relancez la deuxième ligne avecreset-batch-ab, puisreset-batch-ac, et ainsi de suite jusqu’au dernier fichier listé parls ~/reset-batch-*. Prévenez vos clients la veille pour que le courriel ne passe pas pour de l’hameçonnage. -
Transférez l’historique des commandes comme archive. D’abord, désactivez Commande terminée dans WooCommerce > Réglages > E-mails, sinon chaque ancien client reçoit un courriel. Les commandes terminées réduisent aussi le stock, alors importez-les avant la synchronisation finale des stocks. Extrayez les commandes avec l’utilisateur en lecture seule :
mysql -u exmpl_mageread -p exmpl_mage -N -e "SELECT increment_id, created_at, customer_email, status, grand_total, order_currency_code FROM sales_order ORDER BY entity_id;" > ~/magento-orders.tsv wc -l ~/magento-orders.tsvRésultat attendu : un nombre de lignes égal à votre total de commandes. FG Premium peut les importer, ou un script peut créer chaque commande à partir de ces lignes et de
sales_order_item, en gardant le numéro de commande Magento dans une méta :wp wc shop_order create --user=1 --status=completed --customer_id=42 \ --billing='{"email":"jane@example.com"}' \ --line_items='[{"product_id":318,"quantity":1,"subtotal":"49.00","total":"49.00"}]' \ --meta_data='[{"key":"_magento_increment_id","value":"000000145"}]' --porcelainRésultat attendu : le seul identifiant de la nouvelle commande, par exemple
2051. Comptez ensuite les commandes terminées et comparez :wp eval 'echo count( wc_get_orders( array( "status" => "completed", "limit" => -1, "return" => "ids" ) ) ), "\n";'Résultat attendu : un seul nombre, égal au nombre de lignes de
~/magento-orders.tsv. -
Bâtissez la carte de redirections. La table
url_rewritede Magento liste chaque adresse publique dansrequest_path. Les lignes dontredirect_typevaut0sont les URL actives, etentity_typeindique vers quoi chacune pointe.Exportez les chemins des produits avec leur UGS, puis la liste UGS-slug de WooCommerce. Remplacez
1par lestore_idde votre vue de magasin, etwp_par le préfixe de vos tables WordPress s’il est différent :mysql -u exmpl_mageread -p exmpl_mage -N -e "SELECT DISTINCT u.request_path, p.sku FROM url_rewrite u JOIN catalog_product_entity p ON p.entity_id = u.entity_id WHERE u.entity_type = 'product' AND u.redirect_type = 0 AND u.store_id = 1;" > ~/product-paths.tsv wp db query "SELECT pm.meta_value, p.post_name FROM wp_postmeta pm JOIN wp_posts p ON p.ID = pm.post_id WHERE pm.meta_key = '_sku' AND p.post_type = 'product';" --skip-column-names > ~/woo-skus.tsv awk -F'\t' 'NR==FNR {slug[$1]=$2; next} ($2 in slug) {printf "Redirect 301 /%s https://example.com/product/%s/\n", $1, slug[$2]}' ~/woo-skus.tsv ~/product-paths.tsv > ~/magento-redirects.conf wc -l ~/product-paths.tsv ~/magento-redirects.confRésultat attendu : deux nombres de lignes identiques. Un produit a souvent plusieurs chemins, comme
mh01-hoodie.htmletmen/tops/mh01-hoodie.html, et chacun reçoit sa ligne. Un écart correspond à une UGS qui n’a pas été importée. Les slugs des catégories reprennent en général laurl_keyde Magento, donc ces chemins se transposent directement :mysql -u exmpl_mageread -p exmpl_mage -N -e "SELECT request_path FROM url_rewrite WHERE entity_type = 'category' AND redirect_type = 0 AND store_id = 1;" | awk '{p=$1; sub(/\.html$/, "", p); printf "Redirect 301 /%s https://example.com/product-category/%s/\n", $1, p}' >> ~/magento-redirects.conf head -3 ~/magento-redirects.confRésultat attendu :
Redirect 301 /mh01-hoodie.html https://example.com/product/mh01-hoodie/ Redirect 301 /men/tops/mh01-hoodie.html https://example.com/product/mh01-hoodie/ Redirect 301 /radiant-tee.html https://example.com/product/radiant-tee/Collez le fichier dans
~/new.example.com/.htaccessau-dessus de# BEGIN WordPress, pour garder le bloc hors de la section que WordPress réécrit quand on enregistre les permaliens. Si la boutique utilisait un autre suffixe que.html, ajustez le motif desub(). Sur Magento 1, la table s’appellecore_url_rewrite, et les produits y sont liés parproduct_id. Au-delà de quelques milliers de lignes, chargez plutôt la liste dans l’extension Redirection. -
Basculez, avec un retour arrière prêt. Abaissez le TTL du DNS (la durée pendant laquelle les résolveurs gardent l’enregistrement en cache) à 300 secondes deux jours à l’avance. Le jour venu, mettez Magento en maintenance avec
bin/magento maintenance:enable. Importez les commandes et les clients créés depuis votre vidage, synchronisez les stocks, puis déplacez WordPress vers le domaine principal :rsync -a ~/new.example.com/ ~/public_html/ cd ~/public_html wp search-replace 'https://new.example.com' 'https://example.com' --all-tables --skip-columns=guid wp option get siteurlRésultat attendu : un nombre de remplacements, puis
https://example.com. Pointez l’enregistrement A du domaine vers le serveur cPanel. Pour revenir en arrière, repointez-le vers le serveur Magento et lancezbin/magento maintenance:disable. Les commandes passées sur WooCommerce entre-temps devront être ressaisies à la main, alors fixez d’avance une date limite de retour arrière.
Vérifier que tout fonctionne
Testez un échantillon aléatoire d’anciennes adresses de produits :
shuf -n 25 ~/product-paths.tsv | cut -f1 | while read -r p; do
printf '%s /%s\n' "$(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' "https://example.com/$p")" "$p"
done
Résultat attendu : chaque ligne affiche 301 et une adresse en /product/. Un 404 signale un chemin sans règle. Confirmez ensuite qu’une redirection arrive en un seul saut :
curl -sIL -o /dev/null -w '%{http_code} %{num_redirects} %{url_effective}\n' https://example.com/mh01-hoodie.html
Résultat attendu : 200 1 https://example.com/product/mh01-hoodie/. Enfin, comparez les décomptes du catalogue avec l’étape 1 :
wp post list --post_type=product --format=count
wp post list --post_type=product_variation --format=count
Résultat attendu : le premier nombre égale les produits configurables plus les produits simples vendus seuls, et le second égale les produits simples liés à un parent. Passez ensuite une vraie commande test et confirmez qu’elle arrive dans le tableau de bord de la passerelle.
Dépannage
- La restauration s’arrête sur une erreur de privilège SUPER. Les déclencheurs de Magento 2 portent un
DEFINERqui nomme l’utilisateur de base d’origine, ce qu’un utilisateur cPanel ne peut pas définir. Supprimez et recréez la base, puis restaurez avecgunzip < ~/magento-copy.sql.gz | sed -E 's/DEFINER=[^*]*\*/\*/g' | mysql -u exmpl -p exmpl_mage. - Les produits variables n’affichent aucune option. L’attribut a été créé par produit plutôt que globalement. Vérifiez avec
wp term list pa_size --fields=name,count. Un résultat vide veut dire queAttribute 1 globalmanquait, alors supprimez ces produits et refaites les deux passes. - Les produits apparaissent deux ou trois fois. Des lignes de vues de magasin ont été importées. Supprimez les doublons et réimportez seulement les lignes où
store_view_codeest vide. WooCommerce gère un catalogue par site, alors servez les autres langues avec une extension multilingue, ou montez un site WordPress par site Magento. - Les redirections renvoient un 404. Le chemin n’a pas de ligne dans le fichier. Vérifiez avec
grep -c 'mh01-hoodie.html' ~/public_html/.htaccess, en utilisant le chemin en échec ;0veut dire qu’il manque. Les causes habituelles sont un chemin d’une autre vue de magasin, auquel cas relancez l’export avec cestore_id, ou une UGS modifiée à l’import, que vous pouvez chercher dans~/woo-skus.tsv. Si la ligne est là, vérifiez qu’elle n’a pas été collée dans le bloc# BEGIN WordPress, que l’enregistrement des permaliens efface.
Quand cette approche n’est pas la bonne
Restez sur Magento, ou passez à Mage-OS, la distribution communautaire de Magento Open Source, quand la boutique dépend de fonctions que WooCommerce n’offre pas d’emblée. Cela comprend les outils B2B comme les comptes d’entreprise, les catalogues partagés et les soumissions négociées. Cela comprend aussi plusieurs sites avec leurs propres prix gérés depuis une seule administration, et MSI, l’inventaire multisource de Magento, qui répartit le stock entre plusieurs entrepôts. Les modules sur mesure reliés à un ERP (progiciel de gestion intégré) deviennent chacun une extension à faire écrire de zéro. Un catalogue de dizaines de milliers d’UGS avec de nombreux filtres peut tourner sur WooCommerce, mais il demande un réglage soigné de la base de données et de la recherche.
Magento 1 ne reçoit plus de correctifs officiels depuis juin 2020, alors prévoyez bientôt cette migration ou un passage à Magento 2 ou à OpenMage. Adobe documente l’export de l’administration dans son guide d’export de données, et WooCommerce décrit chaque colonne d’import dans la documentation de l’importateur CSV de produits.
Un WordPress qui rapporte vraiment mérite un opérateur — Stack Harbor opère cette pile sous WordPress Entreprise ; réservez une consultation d’infrastructure.