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

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);
    }

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 😉 (ndlr : astuce donnée par Cameleon sur le forum Prestashop)

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 !

50 commentaires sur Prestashop 1.0 à 1.3 : Corriger le duplicate content
  1. shams Répondre

    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.

  2. Cédric G. Répondre

    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.

  3. shams Répondre

    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 ?…

  4. Cédric G. Répondre

    Je pense que cela devrait effectivement suffire.

  5. shams Répondre

    Heu… et bien non justement, cela ne fonctionne pas…

  6. Cédric G. Répondre

    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.

  7. shams Répondre

    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…

  8. Cédric G. Répondre

    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)

  9. shams Répondre

    Désolé, page blanche et, aucune valeur ne s’affiche !…

  10. Grimaud Répondre

    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.

  11. Cédric G. Répondre

    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 !

  12. Jacques Répondre

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

  13. Cédric G. Répondre

    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)

  14. Jacques Répondre

    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

  15. besson Répondre

    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.

  16. Cédric Répondre

    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 » ?

  17. Ludwig Wourms Répondre

    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…

  18. SANSelle Répondre

    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

  19. Cédric Girard Répondre

    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 !)

  20. SANSelle Répondre

    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?

  21. SANSelle Répondre

    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 :
    http://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

  22. Cédric G. Répondre

    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)

  23. david Répondre

    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

  24. triboulé Répondre

    y a t il toujous un meme probleme ave presta 1.3.5?

  25. Cédric G. Répondre

    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.

  26. triboulé Répondre

    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!

  27. mickagolberg Répondre

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

  28. mickagolberg Répondre

    quel module pour le duplicate seo crol fix?

  29. jal Répondre

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

  30. Loïc Besson Répondre

    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…

  31. mickagolberg Répondre

    passer sur wordpress?

  32. Cédric G. Répondre

    MMMmm… moui : un WordPress mal rempli aura lui aussi du DC 😉

  33. Max Répondre

    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.

    • Cédric GIRARD Répondre

      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 !

      • Noraline Répondre

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

        • Cédric GIRARD Répondre

          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…

          • 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 🙂

          • Cédric G.

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

            Cela peut mettre 2 à 3 semaines !

  34. (noname) Répondre

    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) ?

    • Cédric GIRARD Répondre

      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…)

  35. aldo Dell'utri Répondre

    bonjour

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

  36. aldo Dell'utri Répondre

    bonjour

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

    comment savoir su ca marche correctement

  37. REMBELPBERGT Répondre

    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.??

    • Cédric GIRARD Répondre

      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 !

  38. aldo Dell'utri Répondre

    non ce n’est pas geré ,

    j’ai encore du duplicat avec 1.4.6

  39. REMBELPBERGT Répondre

    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

    • Cédric GIRARD Répondre

      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 🙂

  40. aldo Dell'utri Répondre

    en effet je tourne en mutu chez ovh sans probleme

  41. REMBELPBERGT Répondre

    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?

  42. aldo Dell'utri Répondre

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

Laisser un commentaire

Votre adresse email ne sera pas publiée. Merci de saisir votre nom ou pseudo (pas de pseudo SEO merci !), votre email et votre commentaire.


Warning: call_user_func_array() expects parameter 1 to be a valid callback, function 'subscribe_reloaded_show' not found or invalid function name in /home/users3/c/cedricg/www/_SITES/effi10.com/static/lib/plugin.php on line 525