Хлебные крошки — тот случай, когда компонент выглядит примитивно, а вопросы к нему приходят годами: «почему на главной висит одинокая „Главная“», «почему в цепочке появился раздел, которого нет в меню», «почему Google не видит разметку». Все три вопроса решаются на уровне шаблона и правильного понимания того, откуда компонент вообще берёт данные.
Ключевой момент: bitrix:breadcrumb ничего не строит сам. Он лишь выводит цепочку, которую до него наполнили — компоненты (catalog.element добавляет товар), файлы .section.php и прямые вызовы AddChainItem. Отсюда следует главное правило отладки: если в крошках не то, чинить нужно не шаблон компонента, а того, кто добавил лишний пункт.
Базовое подключение
В файле header.php шаблона сайта:
<?php $APPLICATION->IncludeComponent(
"bitrix:breadcrumb",
"", // Имя шаблона (пусто = default)
[
"START_FROM" => "0",
"PATH" => "",
"SITE_ID" => SITE_ID,
]
); ?>Параметры компонента
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
START_FROM | Номер пункта, с которого строить цепочку | 0 (с корня) |
PATH | Путь для построения цепочки | Текущий путь |
SITE_ID | ID сайта | Текущий сайт |
Скрытие на главной странице
<?php if ($APPLICATION->GetCurPage(false) !== '/'): ?>
<?php $APPLICATION->IncludeComponent(
"bitrix:breadcrumb",
"custom",
[
"START_FROM" => "0",
"PATH" => "",
"SITE_ID" => SITE_ID,
]
); ?>
<?php endif; ?>Альтернативный способ:
<?php
$curPage = $APPLICATION->GetCurPage(false);
$isHomePage = ($curPage === '/' || $curPage === '/index.php');
if (!$isHomePage) {
$APPLICATION->IncludeComponent("bitrix:breadcrumb", "custom", [
"START_FROM" => "0",
]);
}
?>Почему скрывать крошки на главной — правильно. Навигационная цепочка из одного элемента не несёт информации, а в разметке BreadcrumbList с единственным пунктом Google не видит смысла и в выдаче её не покажет. Кроме того, ссылка «Главная», ведущая на текущую страницу, — лишний самореферентный линк.
Кастомный шаблон
Создайте шаблон в /local/templates/ШАБЛОН_САЙТА/components/bitrix/breadcrumb/custom/:
template.php
<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
// $arResult содержит цепочку навигации
if (empty($arResult)) {
return;
}
?>
<nav class="breadcrumb" aria-label="Навигация">
<ol class="breadcrumb__list" itemscope itemtype="https://schema.org/BreadcrumbList">
<?php foreach ($arResult as $index => $item): ?>
<?php $isLast = ($index === count($arResult) - 1); ?>
<li class="breadcrumb__item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<?php if (!$isLast && !empty($item['LINK'])): ?>
<a href="<?= $item['LINK'] ?>" class="breadcrumb__link" itemprop="item">
<span itemprop="name"><?= htmlspecialchars($item['TITLE']) ?></span>
</a>
<?php else: ?>
<span class="breadcrumb__current" itemprop="item">
<span itemprop="name"><?= htmlspecialchars($item['TITLE']) ?></span>
</span>
<?php endif; ?>
<meta itemprop="position" content="<?= $index + 1 ?>">
</li>
<?php if (!$isLast): ?>
<li class="breadcrumb__separator" aria-hidden="true">/</li>
<?php endif; ?>
<?php endforeach; ?>
</ol>
</nav>Три решения в этом шаблоне, которые стоят пояснения.
return при пустом $arResult — без него на страницах без цепочки в вёрстку попадёт пустой <nav> с отступами, и появится «необъяснимая дырка» над заголовком.
Последний элемент — не ссылка. Ссылка на страницу, на которой пользователь уже находится, бесполезна для него и вредна для внутренней перелинковки.
htmlspecialchars на TITLE. Заголовок приходит из названия элемента инфоблока — то есть из данных, которые вводит контент-менеджер. Кавычка в названии товара без экранирования ломает вёрстку, а в худшем случае даёт XSS через админку.
style.css
.breadcrumb {
margin-bottom: 1.5rem;
font-size: 0.875rem;
}
.breadcrumb__list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
list-style: none;
padding: 0;
margin: 0;
}
.breadcrumb__item {
display: inline-flex;
align-items: center;
}
.breadcrumb__link {
color: var(--muted);
text-decoration: none;
transition: color 0.2s;
}
.breadcrumb__link:hover {
color: var(--accent);
}
.breadcrumb__current {
color: var(--fg);
font-weight: 500;
}
.breadcrumb__separator {
color: var(--border);
user-select: none;
}
/* Мобильная версия — скрываем промежуточные элементы */
@media (max-width: 640px) {
.breadcrumb__item:not(:first-child):not(:last-child) {
display: none;
}
.breadcrumb__separator:not(:first-of-type):not(:last-of-type) {
display: none;
}
}Скрытие промежуточных пунктов на мобильных через display: none — компромисс, о котором стоит знать. Элементы остаются в DOM и в микроразметке, поэтому поисковики цепочку видят целиком, но пользователь мобильной версии теряет контекст. Если уровней вложенности больше трёх, лучше сделать горизонтальную прокрутку цепочки, чем прятать её середину.
Добавление пунктов в цепочку
Из компонента (автоматически)
Большинство компонентов Битрикса автоматически добавляют пункты:
news.detail— название новостиcatalog.element— название товараcatalog.section— название раздела
Вручную на странице
<?php
// В начале страницы
$APPLICATION->AddChainItem("Название пункта", "/url/страницы/");
// Несколько пунктов
$APPLICATION->AddChainItem("Каталог", "/catalog/");
$APPLICATION->AddChainItem("Смартфоны", "/catalog/smartphones/");
$APPLICATION->AddChainItem("iPhone 15 Pro"); // Без ссылки — текущая страница
?>Через свойства страницы
В файле раздела .section.php:
<?php
$APPLICATION->SetPageProperty("nav_chain", [
["TITLE" => "Каталог", "LINK" => "/catalog/"],
["TITLE" => "Смартфоны", "LINK" => "/catalog/smartphones/"],
]);
?>Микроразметка Schema.org
Шаблон выше уже включает разметку BreadcrumbList. Результат в HTML:
<ol itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/">
<span itemprop="name">Главная</span>
</a>
<meta itemprop="position" content="1">
</li>
...
</ol>Проверка разметки: Google Rich Results Test
JSON-LD разметка (альтернатива)
Микроразметка атрибутами привязана к вёрстке: поменяли шаблон — потеряли разметку, и узнаете вы об этом из отчёта в Search Console через пару недель. JSON-LD от вёрстки не зависит, поэтому Google сам рекомендует именно его. Держать оба варианта одновременно не нужно — это дублирование одной сущности.
<?php
// result_modifier.php
$jsonLd = [
'@context' => 'https://schema.org',
'@type' => 'BreadcrumbList',
'itemListElement' => [],
];
foreach ($arResult as $index => $item) {
$jsonLd['itemListElement'][] = [
'@type' => 'ListItem',
'position' => $index + 1,
'name' => $item['TITLE'],
'item' => !empty($item['LINK'])
? (strpos($item['LINK'], 'http') === 0 ? $item['LINK'] : 'https://' . $_SERVER['HTTP_HOST'] . $item['LINK'])
: null,
];
}
$arResult['JSON_LD'] = json_encode($jsonLd, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?><!-- template.php -->
<script type="application/ld+json">
<?= $arResult['JSON_LD'] ?>
</script>Хлебные крошки внутри компонента
Для отображения цепочки внутри компонента (не в header.php):
<?php
// В шаблоне компонента
$APPLICATION->IncludeComponent(
"bitrix:breadcrumb",
"inline",
[
"START_FROM" => "1", // Пропустить "Главная"
"PATH" => $arResult['SECTION']['SECTION_PAGE_URL'],
]
);
?>В JSON-LD нужны абсолютные URL. В примере выше хост берётся из $_SERVER['HTTP_HOST'] — это заголовок запроса, которым управляет клиент. На сайте без строгой проверки Host в конфиге веб-сервера туда попадёт что угодно, и в разметке окажутся ссылки на чужой домен. Берите хост из настроек сайта Битрикса (SITE_SERVER_NAME или поле сайта), а не из запроса.
Итоги
Что я проверяю на приёмке шаблона крошек:
- На главной цепочки нет — ни в вёрстке, ни в разметке.
- Последний пункт не является ссылкой и совпадает с
H1страницы по смыслу (не обязательно дословно — в крошках уместнее короткое название). - Разметка одна, микроданные или JSON-LD, и она проходит Rich Results Test.
- Абсолютные URL в JSON-LD собираются из настроек сайта, а не из заголовка
Host. - Названия экранируются — данные приходят от контент-менеджера.
- Глубина цепочки — до 4–5 уровней. Дело не в мифическом «SEO-вреде», а в том, что более длинная цепочка не помещается на экран и перестаёт выполнять свою единственную задачу: показывать, где пользователь находится.
Комментарии
Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.