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
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.
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.
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 ?…
Je pense que cela devrait effectivement suffire.
Heu… et bien non justement, cela ne fonctionne pas…
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.
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…
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)
Désolé, page blanche et, aucune valeur ne s’affiche !…
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.
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 !
Bonjour
est ce qu’il y a une évolution ou est compatible pour la Version 1.2.0.8 ?
Cordialement
Jacques
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)
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
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.
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 » ?
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…
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
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 !)
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?
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
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)
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
y a t il toujous un meme probleme ave presta 1.3.5?
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.
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!
bonjour
devons nous inserer un code pour duplicate content
ou pas la peine dans version 1.3.7?
quel module pour le duplicate seo crol fix?
Est ce que cette méthode permet de désindexer duplicate content que Google a déjà trouvé?
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…
passer sur wordpress?
MMMmm… moui : un WordPress mal rempli aura lui aussi du DC 😉
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.
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 !
Du coup, faut-il apporter la correction que vous donner ou la version 1.4 résous le problème automatiquement?
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…
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 🙂
Patience Noraline : Google ne corrige pas tout ça de manière instantanée 😉
Cela peut mettre 2 à 3 semaines !
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) ?
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…)
bonjour
est ce utilisable avec la version 1.4 qui apparemment génère encore pas mal de DC ????
bonjour
je viens d’integrer cette modif à mon header prestashop 1.4 et pas de soucis apparent
comment savoir su ca marche correctement
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.??
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 !
non ce n’est pas geré ,
j’ai encore du duplicat avec 1.4.6
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
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 🙂
en effet je tourne en mutu chez ovh sans probleme
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?
je marche sans memcached.. et sans phpmyscript avec l’option cache normal activé et pas de soucis
sur un mutu perso sql de base ……