Prestashop 1.0 à 1.3 : Corriger le duplicate content

La plate-forme de commerce en ligne Prestashop™ propose nativement de très bonnes choses en matière de référencement, avec notamment une optimisation SEO de très bonne facture (URL Rewriting intégré, optimisation fine des balises META Description et des titres, structure technique, etc…)

Néanmoins, certains éléments manquaient à la version 1.0 et je vous propose une petite astuce pour corriger l’un d’eux : le risque de duplicate content en cas de changement de noms de produits ou de catégories par l’administrateur, et plus généralement (concernant les catégories) la gestion avancée de la pagination et des options de tri de produits, de manière à ce que ces pages secondaires soient suivies mais non indexées par les moteurs pour ne pas gêner le positionnement des pages principales…

IMPORTANT : les modifications exposées ci-après ne sont que les fondations de ce qu’il est possible de réaliser. Elles ne prennent pas en compte certains modules existants (comme « sendtoafriend » ou encore « contactproduct ») ni aucune modification mettant en œuvre des modifications de variables passées en GET (cas des modules utilisant les technologies AJAX notamment).

Par ailleurs, le code dépend en grande partie du paramétrage serveur (gestion des variables d’environnement et des variables serveur) et il n’est de ce fait pas possible de produire un code générique fonctionnant pour n’importe quelle boutique.

Réécriture des URL et problématique rencontrée

Le phénomène est très aisément décelable, en ce sens qu’une page produit reste accessible par son URL rewritée :

http://ma-boutique.com/10-nom-produit.html
Mais aussi sans contrôle aucun, par toute URL pseudo réécrite de même forme :
http://ma-boutique.com/10-ici-ce-que-vous-voulez.html

ou encore son URL non réécrite :

http://ma-boutique.com/product.php?id_product=10

Dans le cas des pages de catégories, on observe le même phénomène, en y ajoutant les options de pagination de listes de produits, ainsi que les options de tri :

http://ma-boutique.com/10-nom-categorie

Même page avec accès non réécrit :

http://ma-boutique.com/category.php?id_category=10

ou bien réécrite mais avec pagination (ici 3ème page) :

http://ma-boutique.com/10-nom-categorie?p=3

ou encore réécrite mais avec tri des produits sur le prix du moins cher au plus cher (nb : options cumulables avec la pagination !) :

http://ma-boutique.com/10-nom-categorie?orderway=ASC&orderby=price

Le principal soucis est que ces n formes d’URL peuvent potentiellement être détectées et indexées par les moteurs de recherche et notamment Google, et de ce fait se faire concurrence puisque leur contenu sera résolument identique (à quelques détails près si le phénomène est uniquement dû au changement du nom du produit par l’administrateur de la boutique !) ou en tout cas très proche, dans le cas des tris et paginations de catégories.

Qui dit contenu dupliqué, dit déclassement dans le positionnement, et donc indirectement, chute du chiffre d’affaire !

La solution

Le principe repose sur deux choses simples :

  • détecter si l’on se trouve sur une page produit ou catégorie
  • retrouver l’URL théoriquement correcte et le cas échéant, rediriger la page vers cette dernière si celle utilisée est différente !

Une limite technique de PHP fait que nous ne pouvons rediriger une page (en modifiant l’entête HTTP à la volée) que si aucune donnée n’a été balancée dans le flux HTML ; en d’autres termes, la détection doit impérativement se faire avant d’afficher quoi que ce soit ! La structure de Prestashop™ nous oblige donc à agir dans le premier fichier affichant des données dans le flux : header.php

Voici le code à insérer dans le fichier header.php (que vous trouverez à la racine de votre boutique Prestashop™) :

<?php require_once(dirname(__FILE__).'/init.php'); /* CODE A INSERER A PARTIR D'ICI */ /***** Test et correction des URL non valides *****/ if (isset($_GET['id_product']) AND Validate::isUnsignedId($_GET['id_product'])) { 	// Nous sommes sur une page produit 	$cookie = new Cookie('ps'); 	Tools::setCookieLanguage(); 	$product = new Product(intval($_GET['id_product']), true, intval($cookie->id_lang)); 	if (Validate::isLoadedObject($product) AND $product->active) 	{ 		$goodurl=$_GET['id_product']."-".$product->link_rewrite.".html";	// URL theorique 		$currenturl=basename($_ENV['REQUEST_URI']);				// URL courante 		$redir=strcmp($goodurl, $currenturl); 		if($redir!=0) 		{ 			// Pas la bonne URL donc redirection HTTP 301 vers l'URL correcte 			header('HTTP/1.1 301 Moved Permanently', false, 301); 			header("Location: http://" . $_SERVER["SERVER_NAME"] ."/". $goodurl); 			exit(); 		} 	}; } if (isset($_GET['id_category']) AND Validate::isUnsignedId($_GET['id_category'])) { 	// Nous sommes sur une page Categorie 	$cookie = new Cookie('ps'); 	Tools::setCookieLanguage(); 	$category = new Category(intval(Tools::getValue('id_category')), intval($cookie->id_lang)); 	if (Validate::isLoadedObject($category) AND $category->active) 	{ 		$paramurl=""; 		// Detection d'un eventuel numero de page 		if (isset($_GET['p'])) { 			$varpagenumber=$_GET['p']; 			if($varpagenumber>1) { 				$paramurl="?p=$varpagenumber"; 				$smarty->assign('nobots', 1);	// variable Smarty de Prestashop qui appose la valeur "noindex,follow" dans la balise META Robots 			}; 		}; 		// Detection des variables eventuelles de tri de produits 		if (isset($_GET['orderby'])) { 			$varorderby=$_GET['orderby']; 			$paramurl.=(empty($paramurl)?"?":"&")."orderby=$varorderby"; 			$smarty->assign('nobots', 1);		// variable Smarty de Prestashop qui appose la valeur "noindex,follow" dans la balise META Robots 		}; 		if (isset($_GET['orderway'])) { 			$varorderway=$_GET['orderway']; 			$paramurl.=(empty($paramurl)?"?":"&")."orderway=$varorderway"; 			$smarty->assign('nobots', 1);		// variable Smarty de Prestashop qui appose la valeur "noindex,follow" dans la balise META Robots 		}; 		$goodurl=$_GET['id_category']."-".$category->link_rewrite.$paramurl;	// URL theorique 		$currenturl=basename($_ENV['REQUEST_URI']);				// URL courante 		$redir=strcmp($goodurl, $currenturl); 		if($redir!=0) 		{ 			// Pas la bonne URL donc redirection HTTP 301 vers l'URL correcte 			header('HTTP/1.1 301 Moved Permanently', false, 301); 			header("Location: http://" . $_SERVER["SERVER_NAME"] ."/". $goodurl); 			exit(); 		} 	}; } // FIN DU CODE A INSERER Langage du code : PHP (php)

Et Prestashop 1.1 ?

La dernière version du script (au moment où j’écris cet article) a changé la réécriture d’URL pour les pages produit, qui intègrent désormais dans leur URL la catégorie et le cas échéant les sous-catégories de classification de l’article.

Cela a une incidence sur les produits potentiellement classables dans des catégories différentes (ce qui peut arriver) car les pages produit correspondantes seront inévitablement dupliquées, avec des URL différentes, ce qui engendrera du duplicate content à terme dans les moteurs de recherche.

La solution consiste donc à supprimer cette nouvelle réécriture d’URL ; pour cela, il suffit de se rendre dans le répertoire Classes à la racine de votre boutique, et d’éditer le fichier Link.php et plus particulièrement les lignes suivantes :

public function getProductLink($id_product, $alias = NULL, $category = NULL, $ean13 = NULL)     {          if (!isset($this->allow)) $this->allow = 0;         if (is_object($id_product))             return ($this->allow == 1)?(__PS_BASE_URI__.intval($id_product->id).'-'.$id_product->link_rewrite.($id_product->ean13 ? '-'.$id_product->ean13 : '').'.html') :             (_PS_USE_SSL_.__PS_BASE_URI__.'product.php?id_product='.intval($id_product->id));         elseif ($alias)             return ($this->allow == 1)?(__PS_BASE_URI__.intval($id_product).'-'.$alias.($ean13 ? '-'.$ean13 : '').'.html') :             (_PS_USE_SSL_.__PS_BASE_URI__.'product.php?id_product='.intval($id_product));         else             return _PS_USE_SSL_.__PS_BASE_URI__.'product.php?id_product='.intval($id_product);     } Langage du code : PHP (php)

Il s’agit en fait de modifier la fonction getProductLink, qui renvoie le lien « bien formé » de notre produit… en recopiant le code de cette fonction de la version 1.0 de la boutique 😉 

On se retrouve ainsi dans la configuration d’une version 1.0 et l’on peut donc appliquer de la même manière, les modifications ci-dessus pour corriger en temps réel les pages dupliquées !

Mise en œuvre sur votre boutique Prestashop™

On peut bien évidemment aller beaucoup plus loin au niveau technique, mais n’oubliez pas de réaliser une sauvegarde de votre boutique ET de votre base de données (même si ce type de modification n’est censé avoir aucun incidence sur les données) avant toute mise en place en production !

Voir tous les articles de la catégorie Prestashop

50 réflexions sur “Prestashop 1.0 à 1.3 : Corriger le duplicate content”

  1. Avatar de shams

    Bonjour,
    Et merci pour ces scripts bien utiles… Mais, comment faire lors d’une installation de Presta dans un sous-répertoire ?…

    Merci de votre attention.

    Répondre
  2. Avatar de Cédric G.

    Bonjour

    J’avoue ne pas m’être penché sur le problème… En théorie il devrait être suffisant de rajouter le répertoire juste dans les URL reconstruites dans le code.

    Mais bon je n’ai aucune expérience de boutique installée dans un sous-répertoire.

    Répondre
  3. Avatar de shams

    Merci Cédric, voulez-vous dire ligne 24 et 68 du script (je n’arrive pas à entrer le code dans le commentaire) après SERVER_NAME en changeant le slash par /repertoire/ par exemple ?…

    Répondre
  4. Avatar de Cédric G.

    Pour le débogage, incluez le code suivant :

    echo $currenturl. »< br / >« .$goodurl;

    juste avant les strcmp qui servent à comparer les valeurs (lignes 18 et 64)

    Ça vous aidera grandement à comprendre ce qui ne va pas et affichant la valeur lue et la valeur théorique reconstruite.

    Répondre
  5. Avatar de shams

    J’ai intégré votre code à la ligne après le commentaire // URL courante
    C’est bien ça ?… Avec ou sans, cela donne une erreur 404…

    Répondre
  6. Avatar de Cédric G.

    Commentez les lignes de code de header ou bien mettez un « exit; » juste après les echo ajoutés précédemment (cela arrêtera le script et vous verrez s’afficher la valeur des variables)

    Répondre
  7. Avatar de Grimaud

    Salut Cédric,
    Concernant le problème de la version 1.1 (ou 1.2.0.1) avec la nouvelle règle d’écriture (qui prends en compte la catégorie du produit) et qui génère du duplicate content que penses tu de cette méthode :
    1. Admettons qu’un produit appartienne à 2 catégories, categorie 1 et catégorie 2 (catégorie 2 étant définie par défaut dans le back office).
    2. Dans le fichier header.php, il suffirait de tester la catégorie renvoyée par getProductLink (), si celle-ci n’est pas la catégorie par défaut alors on redirige vers la page réécrite avec la catégorie par défaut.
    3. Je n’ai pas le code source de Presta sous les yeux, mais il me semble qu’il y a une méthode dans la classe Product.php qui permet de récupérer la valeur de la catégorie par défaut du produit et qui pourrait donc être bien utile ici.
    Dans l’attente de te lire.

    Répondre
  8. Avatar de Cédric G.

    Bonjour Grimaud

    C’est une méthode parfaitement valable tant que l’on s’assure qu’au final, tout produit a une unique URL 😉

    Je suis par contre plus réservé quant à l’intérêt d’une telle méthode d’un point de vue purement référencement… et au niveau pratique : si l’internaute est dans la catégorie 2 et qu’il clique sur le produit, il va donc arriver sur ce dernier « virtuellement » via la catégorie 1 (la catégorie principale).

    Le risque est de dérouter cet utilisateur vers une catégorie qui ne contient potentiellement pas exactement ce qu’il recherche…

    Mais d’un point de vue purement technique, c’est correct !

    Répondre
  9. Avatar de Jacques

    Bonjour
    est ce qu’il y a une évolution ou est compatible pour la Version 1.2.0.8 ?
    Cordialement
    Jacques

    Répondre
  10. Avatar de Cédric G.

    Bonjour

    Ce type de modification fonctionne toujours avec la version 1.2 même s’il y a effectivement eu quelques améliorations.

    Il faut néanmoins veiller à ce que tout colle bien (nb : je n’ai pas encore fait d’optimisation sur des boutiques en v1.2 à ce jour)

    Répondre
  11. Avatar de Jacques

    Bonjour
    Merci de ta réponse, mais apparemment il y a un problème , Google bloque sur le scan de mon sitemap , je me retrouve avec une croix rouge ..je regarderai cela de plus près après le WE
    bonne journée
    Jacques

    Répondre
  12. Avatar de besson

    Bonjour,
    Merci pour cette transformation du header qui évite pas mal de duplicitate mais pas tous… en effet je me suis aperçu que mes pages produits sont toujours accessibles par la catégorie; De plus, j’ai noté un petit problème à la suite de ce changement qui peut etre est spécifique à mon site: mon site est bilingue avec un sous domaine pour l’anglais et lorsque je change la devise du site, sur une autre page que la page d’accueil, la devise choisie n’est pas conservée!
    Auriez vous une solution à ce léger problème?
    Merci d’avance.

    Répondre
  13. Avatar de Cédric

    Bonjour

    Concernant les devises, sincèrement aucune idée !

    Une piste (puisque ça doit être un problème de cookie) : avez-vous « inscrit » le sous-domaine au niveau du backoffice dans les sous-domaines « autorisés » ?

    Répondre
  14. Avatar de Ludwig Wourms

    Bonjour,
    J’ai essayé votre code pour ma boutique. Mais au lieu de renvoyer vers la page actuellement rewritté, les anciens liens se dirigent vers l’accueil…
    J’ai cherché pendant des heures des erreurs dans le script, dans mes fichiers générant le php… Je ne trouve pas. Avez vous déjà détecté des problèmes similaires ?
    Ce pb de duplicate content est une vrai plaie pour le référencement…

    Répondre
  15. Avatar de SANSelle

    Bonjour,

    j’essaie de mettre en place la redirection sur mon site.

    La redirection marche en français. Toutefois, pour l’anglais ça coince. “lang-en” se rajoute à l’url, or ce dossier n’existe pas.

    Faut-il que je créer un nouveau répertoire “lang-en” ou y-a-t-il quelque chose à changer dans le code php?

    Merci beaucoup

    Répondre
  16. Avatar de Cédric Girard

    Bonjour

    Je ne saurais que vous conseiller soit de virer la langue anglaise, soit de la gérer différemment car la gestion par « sous-répertoire » virtuel dans Prestashop est une hérésie d’un point de vue SEO.

    Reportez-vous à l’article de Vemeo (recherchez « prestashop multilingue ») dans un premier temps. Ensuite, il est facile d’adapter ma modification…

    Dès que j’aurai trouvé le temps de finaliser le nouveau site effi10, je publierai un article complet sur les deux choses que sont la gestion du duplicate content dans Prestashop, et la gestion efficace d’une boutique bilingue (avec gestion en sous-domaines !)

    Répondre
  17. Avatar de SANSelle

    D’accord, je pense que je vais utiliser votre méthode car je suis plus à l’aise avec PHP et je suis encore débutant en référencement.

    Juste avec votre méthode, je dois bien activer l’url rewriting sur prestashop?

    Et dois-je modifier mon .htaccess ou cette méthode évite cela?

    Répondre
  18. Avatar de SANSelle

    Heu problèmes avec cette méthode.

    PREMIER PROBLEME :
    http://www.site.fr/perruque/891-perruque.html
    =
    http://www.site.fr/891-perruque.html

    DEUXIEME PROBLEME :
    www.site.fr/100-underwear
    –> 301 –>
    http://www.site.fr/100-lingerie
    Du coup, il n’y a plus de pages en anglais…

    Quelqu’un a-t-il une solution?

    Merci

    Répondre
  19. Avatar de Cédric G.

    Bonjour

    Sur les sites bilingues (ou plus) il faut IMPÉRATIVEMENT gérer les langues sur des sous-domaines (c’est de loin la solution la plus simple à mettre en oeuvre)

    Couplée à la gestion du DC en temps réel, les résultats sont excellents. CF l’un des sites sur lesquels j’ai appliqué cette méthode (anglais+français) => http://www.mastermateriel.com

    Aucun DC, un sous-domaine = une langue (ce qui permet la géolocalisation), un seul cookie pour les paiements (ce qui permet de n’utiliser qu’un seul module de paiement !…)

    Il faut donc détecter la langue avant la redirection (soit avec le cookie de langue si vous restez sur un seul sous-domaine, soit – comme je l’ai fait – forcer la langue selon le sous-domaine utilisé, les deux sous-domaines pointant au même endroit bien entendu)

    Répondre
  20. Avatar de david

    Bonjour à tous, pourriez vous m’indiquez comment puis je insérer la balise google sur prestashop1.3.5, pour pouvoir bénéficier des supers outils webmasters google ?

    merci

    Répondre
  21. Avatar de Cédric G.

    Bonjour

    Oui, dans une moindre mesure sur certains points, mais le DC n’est pas corrigé.

    La version 1.4 apporte quelques améliorations (notamment au niveau de la gestion multilingue) mais ce n’est pas encore la panacée.

    Répondre
  22. Avatar de triboulé

    quels sont les modifs seo por la 1.3.5 ou la 1.3.6
    pour le duplicate, plug seo fix?
    on remarque des problemes d indexation?
    merci!

    Répondre
  23. Avatar de mickagolberg

    bonjour
    devons nous inserer un code pour duplicate content
    ou pas la peine dans version 1.3.7?

    Répondre
  24. Avatar de jal

    Est ce que cette méthode permet de désindexer duplicate content que Google a déjà trouvé?

    Répondre
  25. Avatar de Loïc Besson

    Bonjour,
    Je reviens sur le problème que j’avais évoqué concernant le changement de devise.
    Sur les pages produits et catégorie, la modification de Cédric rendait le changement de devise non persistant (la dvise se change bien sur la page, mais lorsqu’on passe à une autre page la devise revenait à sa valeur initiale!).
    Pour remèdier à cela il suffit d’ajouter sous Tools::setCookieLanguage();
    Tools::setCurrency();

    Voila, si ça peut aider quelqu’un…

    Répondre
  26. Avatar de Max

    Bonjour,
    Et pour la version 1.4 ? Pour moi le problème y est toujours présent pourtant tout le monde à l’air de dire que le problème a été réglé. Dans les faits, je constate que une page reste accessible via les différentes URL listé en début d’article.

    Répondre
    1. Avatar de Cédric GIRARD
      Cédric GIRARD

      Bonjour Max

      Je n’ai (toujours) pas avancé sur la v1.4.x, faute de temps, mais des tests que j’ai réalisé sur les versions en démo, à priori une partie du DC est bien géré…

      Je ne suis pas allé au fond des choses, il est fort possible que tout ne soit pas correctement géré.

      Je n’ai toujours pas eu le temps de rédiger l’article COMPLET sur la gestion du DC, ne serait-ce que pour les plus vieilles versions, mais ça va venir. Patience !

      Répondre
      1. Avatar de Noraline

        Du coup, faut-il apporter la correction que vous donner ou la version 1.4 résous le problème automatiquement?

        Répondre
        1. Avatar de Cédric GIRARD
          Cédric GIRARD

          La version 1.4 résout en grand partie le problème 😉

          Je dois faire (depuis des mois…) un article complet sur la démarche dans sa totalité, il faut juste que je trouve le temps de le faire…

          Répondre
          1. Avatar de Noraline

            Je viens de vérifier mon référencement sur google et en fait, le problème est toujours d’actualité. En espérant voir un billet à ce sujet prochainement 🙂

          2. Avatar de Cédric G.

            Patience Noraline : Google ne corrige pas tout ça de manière instantanée 😉

            Cela peut mettre 2 à 3 semaines !

  27. Avatar de (noname)

    Bonjour Cédric, merci pour toutes ces informations relatives à la réécriture d’URL. Est-ce que vous avez connaissance d’autres éléments pouvant être à l’origine de contenu dupliqué sur Prestashop (idéalement les dernières versions de la bête) ?

    Répondre
    1. Avatar de Cédric GIRARD
      Cédric GIRARD

      Bonjour

      J’y travaille actuellement ! Mais bon pas avant mi juin comme c’est parti car j’ai beaucoup, beaucoup de choses sur le feu…

      (ps : j’ai modifié le pseudo, non conforme à mes règles…)

      Répondre
  28. Avatar de aldo Dell
    aldo Dell'utri

    bonjour

    est ce utilisable avec la version 1.4 qui apparemment génère encore pas mal de DC ????

    Répondre
  29. Avatar de aldo Dell
    aldo Dell'utri

    bonjour

    je viens d’integrer cette modif à mon header prestashop 1.4 et pas de soucis apparent

    comment savoir su ca marche correctement

    Répondre
  30. Avatar de REMBELPBERGT

    apparement 1.4.8 sembel avori probleme url n double
    je vois url rewiting /49-produits….
    puis ensuite la meme
    comme cela … /category.php?id_category=49
    comment faire pour corriger le 1.4.8.??

    Répondre
    1. Avatar de Cédric GIRARD
      Cédric GIRARD

      Bonjour

      Est-ce que la seconde ne redirige pas vers la première ? C’est étonnant car en principe c’est géré dans la 1.4.x…

      Si ce n’est pas le cas, ll faut effectivement travailler à remédier à cela !

      Répondre
  31. Avatar de aldo Dell
    aldo Dell'utri

    non ce n’est pas geré ,

    j’ai encore du duplicat avec 1.4.6

    Répondre
  32. Avatar de REMBELPBERGT

    cedric
    quel code a inserer dans 1.4.8.2 pour remedier au probeleme dc
    aussi le theme new (1.5) est t il compatible avec 14.8.2
    est ce ca tourne en mutualisé pro
    quand l appel sql pour theme fait 45 appels a la base,
    faut t il passer en dédié
    car memcached ni ZENDne marche pas sur les mutualisés
    ou faut til passer en mutualisé avec ce type de machine:
    2 processeurs Opteron 6128 (8 coeurs de 2.1GHz, soit 16 coeurs en tout),
    avec 4 disques et 2 SSD, 64 gigas de RAM pour le serveur web

    2 processeurs Opteron 2427 (6 coeurs de 2GHz, avec 2 disques et 2 SSD, et 16 gigas de RAM pour le serveur mysql

    1 processeur Opteron 4170 (6 coeurs de 2.1GHz),8 gigas de
    RAM pour le serveur de fichiers

    Répondre
    1. Avatar de Cédric GIRARD
      Cédric GIRARD

      Bonjour

      Je n’ai pas encore eu le temps de me consacrer pleinement aux nouvelles versions, je n’ai donc pas de réponse à apporter concernant la version 1.4.8 (la v1.5 sera à priori identique en matière d’optimisation)

      Concernant la machine nécessaire pour faire tourner ce genre de CMS, notamment en mutualisé, cela ne dépend pas du fait que ce soit mutualisé ou pas, mais surtout de l’hébergeur.

      Chez Phpnet un mutualisé Premium permet de faire tourner 5 boutiques en parallèle sans AUCUN soucis (avec un très bon trafic). Ce n’est pas (du tout) le cas chez d’autres hébergeurs 😉

      Quant aux configurations de dédiés, elles sont à mon humble avis… largement sur-dimensionnées pour faire tourner UNE boutique 🙂

      Répondre
  33. Avatar de REMBELPBERGT

    oui mais en mutualisé memcached ne marche pas,
    comment faire pour gerer le cache en mutualisé?
    et mccrypt php extension essentielle?
    je trouve le temps d appel a la base super lente chez ov.. pro mutualisé? faut t il ajouter sql privée 256Mo?, apprement je bouffe trop de RAM?
    pourtant modules éteind, pas de vente en ligne
    qq un reponse?
    enfin duplicate content corrigé en 14.8.2?
    ou devons adopter methode cedric? code etc
    comment faire pour seo, faire paser produits, catégories etc avant autre optimiser home page,
    code svp?
    merci
    je vois aleret rewirting mais rexwiting marche?

    Répondre
  34. Avatar de aldo Dell

    je marche sans memcached.. et sans phpmyscript avec l’option cache normal activé et pas de soucis
    sur un mutu perso sql de base ……

    Répondre

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Retour en haut