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