Par défaut avec Magento ( c’était déjà le cas pour magento 1 et ça l’est toujours pour Magento 2 ), les pages CMS sont accessibles via plusieurs urls

Ex : http://www.magento2.dev/privacy-policy-cookie-restriction-mode/ et http://www.magento2.dev/privacy-policy-cookie-restriction-mode

La seule différence étant la présence du “/” en fin de ligne.

Pour les moteurs de recherche le contenu est donc présent sur 2 pages différentes ce qui créé du duplicate content.
La solution pour corriger cette problématique est d’ajouter une balise “canonical” qui permettra de dire laquelle des urls on souhaite indexer.
De mon côté je part du postulat que c’est l’url avec un “/” à la fin.

Pour cela nous allons faire un module Hhennes_CMS avec l’arborescence suivante :

Magento Cms module structure

Voici les contenus des fichiers de déclaration du module

etc/module.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Hhennes_Cms" setup_version="0.1.1">
        <sequence>
            <module name="Mage_Cms"/>
        </sequence>
    </module>
</config>

registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Hhennes_Cms',
    __DIR__
);

La logique du module est ensuite d’ajouter un nouveau bloc qui va ajouter cette balise sur l’ensemble des pages cms.
Pour cela nous allons créer le fichier view/frontend/layout/cms_page_view.xml avec le contenu suivant :

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="head.additional">
            <block class="Hhennes\Cms\Block\Page\Canonical" name="cms_page.canonical"/>
        </referenceContainer>
    </body>
</page>

Ne reste plus qu’a configurer le code du bloc dans Block/Page/Canonical.php

<?php
 
namespace Hhennes\Cms\Block\Page;
 
use \Magento\Framework\View\Element\AbstractBlock;
 
class Canonical extends AbstractBlock {
 
    /** @var \Magento\Cms\Model\Page  */
    protected $_page;
 
    /**
     * Canonical constructor.
     * @param Context $context
     * @param array $data
     * @param \Magento\Cms\Model\Page $page
     */
    public function __construct(
        \Magento\Framework\View\Element\Context $context,
        array $data = [],
        \Magento\Cms\Model\Page $page
    )
    {
        $this->_page = $page;
        parent::__construct($context, $data);
    }
 
    /**
     * @return \Magento\Cms\Model\Page
     */
    public function getPage()
    {
        return $this->_page;
    }
 
    /**
     * Get Canonical Page Url ( with trailing / )
     */
    public function getCanonicalPageUrl()
    {
        if ($this->getPage()) {
            return $this->getUrl($this->getPage()->getIdentifier());
        } else {
            return false;
        }
    }
 
    /**
     * Display block
     * @return string
     */
    public function _toHtml()
    {
        if ( $this->getCanonicalPageUrl() ) {
            return "\n".'<link rel="canonical" href="'.$this->getCanonicalPageUrl().'"/>'."\n";
        }
 
        return '';
    }
 
}

Si vous souhaitez indexer l’url sans le slash, il vous suffit de remplacer la ligne

return $this->getUrl($this->getPage()->getIdentifier());

par

return $this->getUrl('').$this->getPage()->getIdentifier();

Une fois le module installé, la balise canonical est bien présente 🙂

Magento 2 cms canonical