WordPress
9 septembre 2026

Quand des redirections SEO écrasent les pages natives de PrestaShop et cassent le checkout

Le signalement était limpide : impossible d’accéder au tunnel de commande. Pas d’erreur 500, pas de page blanche, aucune trace dans les logs PHP. La page ne s’affichait simplement pas.

La cause n’était ni dans le checkout, ni dans le JavaScript, ni dans un module de paiement. Elle était dans une table de redirections importée plusieurs mois plus tôt par un prestataire externe, dans le cadre d’un chantier SEO.

Ce cas mérite d’être raconté parce que le mécanisme est transverse : il ne casse pas une page, il peut neutraliser n’importe quel contrôleur natif de PrestaShop, et le symptôme n’a jamais l’air de venir de là.

Le diagnostic en une commande

Devant une page qui ne s’affiche pas sans produire d’erreur, la première chose à faire n’est pas d’ouvrir le code. C’est de regarder ce que le serveur répond réellement :

curl -sI https://exemple.tld/commande | head -5

Réponse : un 301 vers une autre page de la boutique.

Cette seule ligne fait gagner des heures. Elle déplace instantanément la question de « pourquoi le contrôleur ne fait rien » vers « pourquoi le contrôleur n’est jamais atteint ». Ce sont deux enquêtes complètement différentes, et la seconde est bien plus rapide.

Le réflexe à prendre : avant de chercher pourquoi une page s’affiche mal, vérifiez qu’elle s’affiche. Un curl -I coûte deux secondes et élimine d’emblée toute une famille de causes.

Pourquoi une redirection peut neutraliser un contrôleur natif

Les modules de redirection s’accrochent typiquement à un hook exécuté très tôt dans le cycle de vie de la requête, avant que PrestaShop n’ait déterminé quel contrôleur doit répondre.

C’est parfaitement logique de leur point de vue : une redirection doit partir le plus tôt possible, avant qu’on ne dépense des ressources à construire une page qu’on ne servira pas.

Mais la conséquence est que ce mécanisme est prioritaire sur tout le reste. Si une règle correspond à l’URL demandée, la redirection part et le contrôleur natif n’est jamais instancié. Ni le tunnel de commande, ni l’espace client, ni la page de connexion.

Le module ne fait aucune différence entre une URL de produit supprimé, qu’il est légitime de rediriger, et l’URL du tunnel de commande, qu’il ne faut jamais toucher. Pour lui, ce sont deux chaînes de caractères.

L’audit qui révèle l’ampleur réelle

Une fois la cause identifiée, la tentation est de supprimer la règle fautive et de refermer le ticket. C’est une erreur, parce que si une règle a pu être créée sur une page native, d’autres l’ont probablement été aussi.

Les URLs des pages natives sont stockées dans ps_meta, dans la colonne url_rewrite, une ligne par contrôleur et par langue. Il suffit donc de croiser la table de redirections avec elle :

Le découpage mérite d’être connu, parce qu’il explique la jointure. La table ps_meta ne contient que l’identifiant du contrôleur, et c’est ps_meta_lang qui porte l’URL, une ligne par langue et par boutique :

CREATE TABLE `ps_meta` (
  `id_meta`      int(10) unsigned NOT NULL auto_increment,
  `page`         varchar(64) NOT NULL,   -- 'order', 'my-account', 'authentication'...
  `configurable` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
  UNIQUE KEY `page` (`page`)
);

CREATE TABLE `ps_meta_lang` (
  `id_meta`     int(10) unsigned NOT NULL,
  `id_shop`     INT(11) UNSIGNED NOT NULL DEFAULT '1',
  `id_lang`     int(10) unsigned NOT NULL,
  `url_rewrite` varchar(255) NOT NULL,   -- 'commande', 'mon-compte', 'connexion'...
  PRIMARY KEY (`id_meta`, `id_shop`, `id_lang`)
);

Conséquence pratique souvent ratée : sur une boutique multilingue ou multiboutique, le même contrôleur a autant d’URL que de couples langue et boutique. Un audit qui ne teste que la version française d’une boutique principale déclarera le site sain alors que la version anglaise reste neutralisée. La jointure ci-dessous les couvre toutes, à condition de ne pas la filtrer sur une langue.

SELECT r.*
FROM ps_redirect_rules r
JOIN ps_meta_lang m ON r.source LIKE CONCAT('%', m.url_rewrite, '%')
WHERE m.url_rewrite != '';

Le nom exact de la table de règles dépend du module utilisé, mais le principe reste le même : toute règle dont la source correspond à une url_rewrite native est suspecte par construction.

Dans notre cas, l’audit a révélé que le tunnel de commande n’était pas seul concerné. Plusieurs pages de l’espace client étaient également redirigées. Le checkout était simplement la plus visible, parce que c’est celle qui génère du chiffre d’affaires et donc des signalements.

Le risque qu’on ne voit pas venir : la boucle

Un détail aggrave sérieusement l’affaire pour les clients connectés.

PrestaShop utilise abondamment un paramètre de retour qui renvoie l’utilisateur vers la page d’où il vient après une action. Si la page de destination de ce retour est elle-même redirigée vers une page qui redirige à son tour vers la première, l’utilisateur se retrouve dans une boucle dont il ne sort qu’en changeant d’URL manuellement.

Un client bloqué dans une boucle de redirection ne remplit pas de formulaire de contact, et votre conversion en pâtit sans que rien ne l’explique. Il quitte le site, et vous n’aurez jamais de signalement.

Le piège de la validation : le 301 est mis en cache

Point crucial pour le support et pour votre propre vérification après correction.

Un code 301 signifie « déplacé de façon permanente », et les navigateurs le prennent au mot : ils mettent la redirection en cache, parfois durablement, sans revenir interroger le serveur.

Conséquence directe : après avoir supprimé la règle, votre navigateur continuera de rediriger. Vous conclurez que le correctif n’a pas fonctionné, alors que le serveur répond correctement.

La vérification doit donc se faire hors navigateur, avec curl comme au diagnostic, ou dans une fenêtre de navigation privée jamais utilisée sur ce site. Et il faut prévenir le support que les clients ayant rencontré le problème pourront le rencontrer encore un moment, avec pour seule solution un vidage de cache de leur côté.

# Après suppression de la règle : on interroge le serveur, pas le navigateur
curl -sI https://exemple.tld/commande | head -1

# Et sur toutes les langues et boutiques, pas seulement la principale
for u in /commande /order /mon-compte /my-account /connexion /login; do
  printf '%-16s %s\n' "$u" "$(curl -s -o /dev/null -w '%{http_code}' "https://exemple.tld$u")"
done

Tout ce qui ne répond pas 200 sur une URL native mérite une explication. Un 301 encore présent sur /commande après correction signifie qu’une seconde règle existe, pas que la première n’a pas été supprimée.

C’est aussi un argument sérieux pour utiliser des 302 plutôt que des 301 tant qu’un plan de redirections n’est pas stabilisé. Un 302 mal placé se corrige immédiatement, un 301 mal placé vous poursuit pendant des semaines.

L’autre moitié de l’audit consiste à établir la liste de ce qu’il ne faut jamais toucher, pour la transmettre à qui produira le prochain plan de redirections :

-- La liste blanche : toutes les URL natives, toutes langues et boutiques
SELECT m.page, ml.id_shop, ml.id_lang, ml.url_rewrite
FROM ps_meta m
JOIN ps_meta_lang ml ON ml.id_meta = m.id_meta
WHERE ml.url_rewrite != ''
ORDER BY m.page, ml.id_shop, ml.id_lang;

Sur une boutique bilingue, cette requête sort deux fois plus de lignes qu’il n’y a de contrôleurs. C’est précisément le genre de chiffre qu’un prestataire SEO externe n’a aucune raison de connaître avant qu’on le lui donne.

Le garde-fou durable

Supprimer les règles fautives résout l’incident, pas le problème. Rien n’empêche le prochain import d’en recréer.

La protection tient en une règle : refuser toute redirection dont la source correspond à une URL native. Le contrôle se fait au moment de l’import, ou dans le module lui-même s’il est maintenu en interne.

/**
 * Une règle dont la source correspond à une url_rewrite native ne doit
 * jamais être créée : elle rendrait le contrôleur PrestaShop inatteignable.
 */
private function isNativeUrl(string $source): bool
{
    foreach ($this->getNativeRewrites() as $rewrite) {
        if ($rewrite !== '' && str_contains($source, $rewrite)) {
            return true;
        }
    }

    return false;
}

Ce contrôle est peu coûteux et rejette une catégorie entière d’incidents. Il a aussi l’avantage d’être explicite : quand un import refuse une ligne en expliquant pourquoi, la personne qui l’a produite comprend son erreur, ce qui vaut mieux qu’un import silencieux dont personne ne mesure les conséquences.

Trois enseignements

Un fichier de redirections est du code, pas de la donnée. Il mérite la même rigueur qu’un plan de redirections de refonte. Il a autant d’impact qu’une refonte mal préparée sur le référencement. Il modifie le comportement de l’application pour tous les visiteurs. Il mérite le même niveau de revue qu’un déploiement : qui l’a produit, sur quelles règles, et qu’est-ce qui garantit qu’il ne touche pas à des URLs système.

Les mécanismes qui s’exécutent tôt dans le cycle de requête méritent une méfiance particulière. Ils sont prioritaires par conception, donc ils peuvent tout neutraliser. Un module de redirection, une règle de pare-feu applicatif ou un middleware de maintenance ont tous ce pouvoir.

Vérifiez toujours qu’une page répond avant d’enquêter sur ce qu’elle affiche. Ce réflexe a sa place dans toute recette de mise en ligne. C’est deux secondes, et ça oriente toute la suite du diagnostic.

Nous vous recommandons aussi