Оставить заявку
WEB CENTER

Принципы построения канонических ссылок на сайте

Как грамотно настроить тег canonical?

Страницы пагинации

Правило: Все страницы пагинации ссылаются на корневой раздел.

site.ru/d/page2 (canonical) => site.ru/d/
***
site.ru/d/page** (canonical) => site.ru/d/
site.ru/d/ (canonical) => site.ru/d/

URL с параметрами

Правило: Все параметры должны ссылаться на страницу без параметров, если содержимое не изменяется.

site.ru/d/?page=2 (canonical) => site.ru/d/
site.ru/d/ (canonical) => site.ru/d/

При наличие заданных параметров страница должна ссылаться канонически на страницу без параметров. Исключением является сортировка, фильтрация, другие технические параметры - все они должны ссылаться на страницу без параметров.

Разные версии сайта

Правило: Канонические ссылки с других версий сайта должны ссылаться на страницы с доменом и протоколом, указанным в директиве host файла robots.txt

К примеру, задана директива host в файле robots.txt:

Host: https://site.ru, тогда:

http://site.ru/* (canonical) => https://site.ru/*
http://www.site.ru/* (canonical) => https://site.ru/*
https://www.site.ru/* (canonical) => https://site.ru/*
https://site.ru/* (canonical) => https://site.ru/*

Страницы со слешем и без слеша

Правило: Желательно делать 301-редиректы на URL со слешем на конце, тогда проблема будет исчерпана. Если же такое невозможно и присутствуют страницы со слешем и без слеша, то ссылаемся канонически на страницы со слешем:

site.ru/d/ (canonical) => site.ru/d/
site.ru/d (canonical) => site.ru/d/

Один товар в разных категориях

Правило: В первую очередь каноническим должен быть тот товар, на который ссылается больше всего внутренних ссылок. Такая проблема возникает, если один и тот же товар находится в разных категориях и имеет 2 и более URL:

site.ru/category1/ - как корень товара, остальные разделы дополнительные.
site.ru/category1/tovar1/ (canonical) => site.ru/category1/tovar1/ 
site.ru/category1/category2/tovar1/ (canonical) => site.ru/category1/tovar1/
site.ru/category2/tovar1/ (canonical) => site.ru/category1/tovar1/
site.ru/category3/tovar1/ (canonical) => site.ru/category1/tovar1/

Оригинал ссылается сам на себя

Правило: В любых других исключениях, если URL страницы канонический, то эта страница должна ссылаться на саму себя.

Canonical - инструкции

Canonical для Webasyst

Добавляем в хедер:

<!-- начало canonical {$wa->domainUrl()} -->
{if $smarty.server.REQUEST_URI == "`$wa->shop->productUrl($product, 'reviews')`"}
   {$canonical_reviews = $wa->shop->productUrl($product)}
   <link rel="canonical" href="https://site.ru{$canonical_reviews}"/>
{else}
   {if $smarty.get != null} <!-- есть параметры --> 
      {$trimmed_absolute_url = $wa->currentUrl(true, true)}
      <link rel="canonical" href="{$trimmed_absolute_url}"/>
   {else}
      <link rel="canonical" href="https://site.ru{$wa->currentUrl()}"/>
   {/if}
{/if}
<!-- конец canonical -->

Canonical для Bitrix

1 вариант для Битрикса

К примеру, в файле: /bitrix/templates/*/header.php

<?
   if (defined('ERROR_404') && ERROR_404 == 'Y') {
      getCanonicalSEO('Y');
   } else {
      getCanonicalSEO();
   }
?>

К примеру, в файле: /bitrix/php_interface/init.php

function getCanonicalSEO($er404 = "") {
   $address = "";

   if ($er404 != "Y") {

      if ($_SERVER["REDIRECT_STATUS"] != 404) {
         $cutfrom =strpos($_SERVER["REQUEST_URI"], "filter/");

         if ($cutfrom) {
            $address = substr($_SERVER["REQUEST_URI"], 0, $cutfrom);
         } elseif ($_SERVER["QUERY_STRING"]) {
            $address = str_replace("?".$_SERVER["QUERY_STRING"], '', $_SERVER["REQUEST_URI"]);
         } else {
            $address = $_SERVER["REQUEST_URI"];
         }
      }
   }

   $url  = ($_SERVER["HTTPS"] != 'on')?'http://'.$_SERVER["SERVER_NAME"]:'https://'.$_SERVER["SERVER_NAME"];
   $url .= ($_SERVER["SERVER_PORT"] != 80)?":".$_SERVER["SERVER_PORT"]:"";
   $url .= $address;
   echo '<link rel="canonical" href="'.$url.'" />';
   return false;
}

AddEventHandler('main', 'OnEpilog', '_Check404Error', 1);

function _Check404Error() {

   if (defined('ERROR_404') && ERROR_404 == 'Y') {
      global $APPLICATION;
      $APPLICATION->RestartBuffer();
      include $_SERVER['DOCUMENT_ROOT'] . SITE_TEMPLATE_PATH . '/header.php';
      include $_SERVER['DOCUMENT_ROOT'] . '/404.php';
      include $_SERVER['DOCUMENT_ROOT'] . SITE_TEMPLATE_PATH . '/footer.php';
   }
}

function getCanonicalSEO($er404 = "") {
   $address = "";

   if ($er404 != "Y") {

      if ($_SERVER["REDIRECT_STATUS"] != 404) {
         $cutfrom =strpos($_SERVER["REQUEST_URI"], "filter/");

         if ($cutfrom) {
            $address = substr($_SERVER["REQUEST_URI"], 0, $cutfrom);
         } elseif(strpos($_SERVER["REQUEST_URI"], 'detail.php') !== false) {
            $address = $_SERVER["REQUEST_URI"];
         } elseif($_SERVER["QUERY_STRING"]) {
            $address = str_replace("?".$_SERVER["QUERY_STRING"], '', $_SERVER["REQUEST_URI"]);
         } else {
            $address = $_SERVER["REQUEST_URI"];
         }
      }
   }

   $url  = ($_SERVER["HTTPS"] != 'on')?'http://'.$_SERVER["SERVER_NAME"]:'https://'.$_SERVER["SERVER_NAME"];
   $url .= ($_SERVER["SERVER_PORT"] != 80)?":".$_SERVER["SERVER_PORT"]:"";
   $url .= $address;
   echo '<link rel="canonical" href="'.$url.'" />';
   return false;
}

2 вариант для Битрикса

К примеру, в файле: /bitrix/php_interface/init.php

function getCanonicalUrl($elementId = null, $iblockId = null) {

   if (empty($elementId)) {

      if (defined("ERROR_404") && ERROR_404 == "Y") {
         return "https://" . SITE_SERVER_NAME;
      }

      $uri = new Bitrix\Main\Web\Uri(Bitrix\Main\Context::getCurrent()->getRequest()->getRequestUri());
      $uri->deleteParams(array_keys($_REQUEST));
      $GLOBALS['CANONICAL_URL_SET'] = true;
      return "https://" . SITE_SERVER_NAME . $uri->getUri();
   }

   $cacheId = "canonical$elementId";
   $cacheTime = 30 * 24 * 3600;
   $cacheDir = "canonical";
   $cache = new CPhpCache();

   if ($cache->InitCache($cacheTime, $cacheId, $cacheDir)) {
      $vars = $cache->GetVars();
      $canonicalUrl = $vars['CANONICAL_URL'];
   } elseif ($cache->StartDataCache($cacheTime, $cacheId, $cacheDir)) {
      $dbIblock = CIBlock::GetList(array(), array("ID" => $iblockId));

      if ($arIblock = $dbIblock->Fetch()) {
         $dbElements = CIBlockElement::GetList(array(), array("IBLOCK_ID" => $iblockId, "ID" => $elementId), false, false, array("ID", "DETAIL_PAGE_URL"));
         $dbElements->SetUrlTemplates($arIblock['DETAIL_PAGE_URL']);

         if ($arElement = $dbElements->GetNext()) {
            $canonicalUrl = "https://" . SITE_SERVER_NAME . $arElement['DETAIL_PAGE_URL'];
            $cache->EndDataCache(array("CANONICAL_URL" => $canonicalUrl));
         }
      }
   }

   $GLOBALS['CANONICAL_URL_SET'] = true;
   return $canonicalUrl;
}

function isCanonicalUrlSet() {
   return !empty($GLOBALS['CANONICAL_URL_SET']);
}

К примеру, в файле: /bitrix/templates/*/footer.php

<?
   if (!isCanonicalUrlSet()) {
      $canonicalUrl = getCanonicalUrl();
      $APPLICATION->AddHeadString("<link rel=\"canonical\" href=\"$canonicalUrl\" />");
   }
?>

К примеру, в файле: /bitrix/templates/youstore_/components/bitrix/catalog/.default/bitrix/catalog.element/.default/result_modifier.php

$canonicalUrl = getCanonicalUrl($arResult['ID'], $arResult['IBLOCK_ID']);
$APPLICATION->AddHeadString("<link rel=\"canonical\" href=\"$canonicalUrl\" />");