Компонент bitrix:catalog.top выводит на страницу первые N товаров инфоблока по заданной сортировке. Я использую catalog.top битрикс как основу для блоков «Хиты», «Новинки» и «Рекомендуем» на главной, а саму карусель делаю собственным шаблоном в /local на Swiper. Ниже схема, которую я повторяю из проекта в проект: вызов компонента, фильтр, шаблон, подключение скриптов и кэш.
Компонент catalog.top: какие товары попадают в подборку
Главное, что нужно знать про catalog.top: он ничего не считает. Он не смотрит на продажи, просмотры или рейтинг, а берёт элементы инфоблока, сортирует их по выбранному полю и отдаёт первые ELEMENT_COUNT штук. Поэтому «топ» на главной это ваше решение, а не магия компонента. Обычно оно выражается одним из трёх способов:
- свойство-флажок в карточке товара («Хит», «Новинка», «Рекомендуем»), по которому идёт фильтр;
- сортировка по полю
SORT, когда менеджер руками расставляет порядок; - сортировка по дате создания или активности для блока «Новинки».
Свойство-флажок самый предсказуемый вариант. Менеджер ставит галочку в карточке, товар появляется на главной, никто не трогает код. Для этого в инфоблоке каталога создаётся свойство типа «Список» с кодом, например, HIT и единственным значением «Да».
Компонент поставляется вместе с модулем «Торговый каталог»: его папка появляется при установке модуля каталога, а в линейке «Управление сайтом» торговый каталог доступен начиная с редакции «Малый бизнес». На «Старте» и «Стандарте», где есть только модуль «Информационные блоки», вызвать bitrix:catalog.top не получится, там такой блок я собираю на bitrix:news.list. Цены компонент берёт через модуль каталога, поэтому в вызове нужен параметр PRICE_CODE.
Подключение топа товаров на главную: параметры вызова
Компонент добавляется на главную либо через визуальный редактор, либо прямо в коде index.php. Я предпочитаю код: параметры видны сразу, их проще переносить между сайтами. Вызов выглядит так:
<?php
$GLOBALS['arrTopFilter'] = ['PROPERTY_HIT_VALUE' => 'Да'];
$APPLICATION->IncludeComponent(
'bitrix:catalog.top',
'hits_slider',
[
'IBLOCK_TYPE' => 'catalog',
'IBLOCK_ID' => '2',
'ELEMENT_SORT_FIELD' => 'sort',
'ELEMENT_SORT_ORDER' => 'asc',
'ELEMENT_SORT_FIELD2' => 'id',
'ELEMENT_SORT_ORDER2' => 'desc',
'ELEMENT_COUNT' => '12',
'LINE_ELEMENT_COUNT' => '4',
'FILTER_NAME' => 'arrTopFilter',
'PRICE_CODE' => ['BASE'],
'CACHE_TYPE' => 'A',
'CACHE_TIME' => '3600',
]
);
Значения IBLOCK_TYPE, IBLOCK_ID и код цены BASE здесь примерные, подставьте свои. Второй аргумент метода это имя шаблона компонента. Если оставить его пустым, подключится .default. Сигнатура метода такая: имя компонента, имя шаблона, массив параметров, дальше необязательные аргументы.
Что я проверяю после первого запуска:
- что
IBLOCK_IDуказывает на инфоблок товаров, а не на инфоблок предложений; - что у товаров заполнена картинка анонса, иначе в карусели будут пустые квадраты;
- что товары активны и попадают в нужный сайт.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Фильтр по свойству «Хит» и сортировка товаров
Параметр FILTER_NAME задаёт имя глобальной переменной, в которой лежит массив фильтра. Формат тот же, что у CIBlockElement::GetList. Для свойства типа «Список» по документации используется ключ PROPERTY_<КОД>_VALUE, и поиск идёт по строковому значению списка, а не по идентификатору. Поэтому в примере выше стоит PROPERTY_HIT_VALUE и значение «Да». Если значение в списке названо иначе, фильтр вернёт пустую выборку, и блок просто не отрисуется. Это самая частая причина фразы «компонент подключил, а на главной ничего нет».
Фильтр можно собирать и сложнее. Например, только товары в наличии или только из определённых разделов:
<?php
$GLOBALS['arrTopFilter'] = [
'PROPERTY_HIT_VALUE' => 'Да',
'SECTION_ID' => 15,
'INCLUDE_SUBSECTIONS' => 'Y',
];
Номер раздела здесь тоже примерный. Остаток на складе в фильтр инфоблока так просто не добавить, для этого нужна связка с модулем каталога, и я решаю это отдельно под конкретный проект.
Ловушка с одинаковой сортировкой
У меня на проектах регулярно повторяется одна и та же история. У большинства товаров стоит типовое значение SORT (обычно 500), и сортировка по нему не различает элементы. Вторая сортировка по id спасает порядок, но если вы хотите, чтобы свежий товар оказался в начале, ему нужно ставить SORT меньше общего. Аналогично с лимитом: компонент режет выборку по ELEMENT_COUNT уже после сортировки, и товар, который по порядку оказался тринадцатым, на главной не появится. Менеджер при этом уверен, что «поставил галочку, а ничего не работает». Перед тем как искать баг, посчитайте, сколько товаров с флажком стоит перед нужным.
Шаблон слайдера в /local и подключение Swiper
Стандартный шаблон компонента выводит товары сеткой. Чтобы получилась карусель, шаблон копируется и правится. Правило из документации: приоритет всегда у папки /local перед /bitrix, а скопированный шаблон лежит по пути /local/templates/шаблон_сайта/components/bitrix/catalog.top/hits_slider. Править файлы в /bitrix/components нельзя, при обновлении ядра правки пропадут.
Скопировать можно файловой системой (в путь выше переносится нужная папка шаблона из /bitrix/components/bitrix/catalog.top/templates/, а не сама папка templates) или через интерфейс командой «Копировать шаблон компонента» в режиме правки. Имя папки должно совпадать со вторым аргументом IncludeComponent, у нас это hits_slider.
В template.php оставляю только разметку слайдера:
<?php if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
if (empty($arResult['ITEMS'])) {
return;
}
?>
<div class="top-swiper swiper">
<div class="swiper-wrapper">
<?php foreach ($arResult['ITEMS'] as $arItem): ?>
<a class="swiper-slide top-card" href="<?= htmlspecialcharsbx($arItem['DETAIL_PAGE_URL']) ?>">
<?php if (!empty($arItem['PREVIEW_PICTURE']['SRC'])): ?>
<img src="<?= $arItem['PREVIEW_PICTURE']['SRC'] ?>" alt="<?= htmlspecialcharsbx($arItem['NAME']) ?>" loading="lazy">
<?php endif; ?>
<span class="top-card__name"><?= htmlspecialcharsbx($arItem['NAME']) ?></span>
<span class="top-card__price"><?= $arItem['PRICES']['BASE']['PRINT_DISCOUNT_VALUE'] ?? '' ?></span>
</a>
<?php endforeach; ?>
</div>
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
Цена выводится через ?? намеренно: в зависимости от версии модуля и настроек структура цен в $arResult может отличаться (в свежих версиях есть ещё блок ITEM_PRICES). Откройте свой шаблон и посмотрите, какие ключи реально приходят, например выведя print_r(array_keys($arResult['ITEMS'][0])) на тестовой странице. Выводить весь $arResult целиком я не советую: в объектах Битрикса бывают вложенные подключения к базе, и печатать их в браузер небезопасно.
Инициализация Swiper, которую я кладу в отдельный файл скрипта:
document.addEventListener('DOMContentLoaded', function () {
new Swiper('.top-swiper', {
slidesPerView: 1.4,
spaceBetween: 16,
navigation: {
nextEl: '.top-swiper .swiper-button-next',
prevEl: '.top-swiper .swiper-button-prev'
},
breakpoints: {
640: { slidesPerView: 2.5 },
1024: { slidesPerView: 4 }
}
});
});
Дробное значение slidesPerView на мобильных показывает край следующего слайда, и пользователь понимает, что карусель листается пальцем.
Кэш компонента и типичные ошибки карусели
С кэшем связана самая коварная проблема. У компонента с включённым кэшем на попадании в кэш template.php не выполняется. Если вы подключили Swiper из шаблона через Asset::getInstance()->addCss() или $APPLICATION->SetAdditionalCSS(), стили и скрипты подтянутся один раз, на первом запросе после сброса кэша, а дальше пропадут из <head>. Я попадал на это на боевом проекте со слайдером: после сброса кэша блок выглядит нормально, со второго открытия слайдер разваливается в колонку, и кажется, что файлы «откатились сами».
Два рабочих решения:
- подключать библиотеку из
header.phpшаблона сайта, ограничив условиемif ($APPLICATION->GetCurPage(false) === '/'), чтобы Swiper не грузился на всех страницах; - подключать из
component_epilog.phpв папке шаблона компонента: он выполняется и при попадании в кэш.
Для Swiper достаточно двух строк: стили https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css и скрипт https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js. Если не хотите зависеть от CDN, положите файлы в /local/templates/шаблон_сайта/ и подключайте оттуда.
Правка в админке не видна на сайте
Вторая проблема с кэшем: менеджер снял флажок «Хит» у товара, а на главной он висит. Если на сайте выключен управляемый (тегированный) кэш, сохранение элемента инфоблока кэш компонента не сбрасывает, и товар остаётся до конца CACHE_TIME. Для блока на главной я ставлю небольшое время жизни кэша, как в примере выше, а на сайтах с отключённым тегированным кэшем добавляю обработчики событий OnAfterIBlockElementUpdate и OnAfterIBlockElementAdd, которые чистят каталог кэша компонента catalog.top. Каталог кэша лежит по пути вида bitrix/cache/s1/bitrix/catalog.top/. Проверьте, какой режим у вас, прежде чем что-то городить.
Что смотреть, если блок пустой или сломан
- Фильтр: значение свойства в списке совпадает с тем, что в
PROPERTY_HIT_VALUE. - Переменная фильтра объявлена до вызова компонента и называется так же, как в
FILTER_NAME. - Шаблон лежит в
/local/templates/того шаблона сайта, который реально подключён на главной. - Кэш сброшен после смены параметров.
- В шаблоне есть проверка
B_PROLOG_INCLUDED, иначе файл можно открыть напрямую.
Когда вместо топа товаров лучше взять catalog.section
Catalog.top подходит для витрины из нескольких карточек. Как только нужны пагинация, сортировка пользователем или фильтр по нескольким свойствам, правильнее брать bitrix:catalog.section. Сравнение по сути:
| Компонент | Как формируется выборка | Пагинация | Для чего беру |
|---|---|---|---|
| catalog.top | первые N по сортировке, фильтр через FILTER_NAME |
нет, только лимит | карусель хитов и новинок на главной |
| catalog.section | товары раздела с фильтром и сортировкой | есть | листинг каталога, подборки с «показать ещё» |
catalog.section с FILTER_NAME |
товары по любому фильтру, в том числе без раздела | есть | рекомендации с постраничным выводом |
Стоимость моей работы от выбранного компонента не зависит, она определяется объёмом правок шаблона и логики подборки. Если каталог большой и нужна нестандартная выборка, например по остаткам или по реальным продажам из 1С, я подключаюсь как доработка и поддержка 1С-Битрикс, от 3 000 ₽/час, а маленькие задачи вроде настройки фильтра и шаблона обычно укладываются в пару часов.
Условия и возможности 1С-Битрикс и Swiper меняются, поэтому перед запуском я сверяюсь с актуальной документацией.
Частые вопросы
Чем catalog.top отличается от catalog.section?
Catalog.top выводит ограниченное число товаров по сортировке и не умеет листать страницы, поэтому он подходит для витрины на главной. Catalog.section выводит содержимое раздела или выборку по фильтру с пагинацией и подходит для каталога.
Как показать на главной только товары с флажком «Хит»?
Создайте в инфоблоке свойство типа «Список» с кодом HIT, объявите перед вызовом компонента фильтр ['PROPERTY_HIT_VALUE' => 'Да'] и передайте его имя в параметр FILTER_NAME. Значение в фильтре должно совпадать со значением в списке.
Почему после обновления страницы карусель теряет стили?
Скорее всего, Swiper подключён из template.php, а при попадании в кэш этот файл не выполняется. Перенесите подключение в header.php шаблона сайта или в component_epilog.php шаблона компонента.
Можно ли править стандартный шаблон прямо в /bitrix?
Нет, при обновлении правки пропадут. Скопируйте шаблон в /local/templates/шаблон_сайта/components/bitrix/catalog.top/ и меняйте его там: папка /local всегда имеет приоритет.