Перейти к содержимому

Фильтрация разделов по свойству элементов - список без пустых

Показываем в меню только те разделы, где действительно есть товары нужного бренда или в наличии, и убираем из списка пустые.

Решение

Собираем разделы по элементам:

$rows = CIBlockElement::GetList(
[], ['IBLOCK_ID' => 12, 'ACTIVE' => 'Y', 'PROPERTY_BRAND' => $brandId],
['IBLOCK_SECTION_ID'], // группировка: разделы с числом подходящих товаров
);
// прямого фильтра «разделы по свойству элемента» в платформе нет:
// значения свойств и разделы лежат в разных таблицах

Разделы собирают по элементам, а не запросом к самим разделам. Свойства принадлежат элементу, поэтому путь всегда один: сначала подходящие товары, потом их разделы.

Показываем найденные разделы:

$sectionIds = array_column($rows, 'IBLOCK_SECTION_ID');
$res = CIBlockSection::GetList(['SORT' => 'ASC'],
['IBLOCK_ID' => 12, 'ID' => $sectionIds, 'ACTIVE' => 'Y'], false, ['ID', 'NAME', 'SECTION_PAGE_URL']);
while ($section = $res->GetNext()) {
printf('<a href="%s">%s</a>', $section['SECTION_PAGE_URL'], $section['NAME']);
}

Отбор идёт по списку номеров, полученному на первом шаге. Сортировку и адреса при этом отдаёт уже запрос к разделам, и порядок в меню остаётся привычным.

Дотягиваем родительские разделы:

foreach ($sectionIds as $id) {
$nav = CIBlockSection::GetNavChain(12, $id, ['ID'], true);
$sectionIds = array_merge($sectionIds, array_column($nav, 'ID'));
}
$sectionIds = array_unique($sectionIds); // иначе верхний уровень меню опустеет

Товар лежит в подразделе, а показать обычно нужно и его родителя. Без этого шага меню верхнего уровня оказывается пустым при полном каталоге товаров ниже.

Считаем ответ заранее на большом каталоге:

// агент раз в час: складываем признак прямо в поле раздела
$brands = implode(',', $brandIdsInSection);
CIBlockSection::Update($sectionId, ['UF_BRANDS' => $brands]);
// дальше меню строится одним запросом к разделам, без обхода элементов

На каталоге в сотни тысяч позиций обход элементов при каждом показе слишком дорог. Признак кладут в поле раздела и пересчитывают по расписанию, а меню строится одним запросом.

Список разделов стоит кэшировать вместе с тегом инфоблока. Тогда обмен с учётной системой сбрасывает его сам, и меню не показывает вчерашний набор разделов после ночной выгрузки.

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

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

Задачу стоит начинать с вопроса, сколько разделов и товаров в каталоге на самом деле. На двух сотнях разделов подойдёт любой из способов, а на десяти тысячах разница между ними измеряется секундами ожидания покупателя.

Типичные проблемы

Раздел с товарами не попал в список.

Группировка идёт по основному разделу, а товар привязан к нему дополнительно. Множественную привязку читают отдельным запросом.

Верхний уровень меню оказался пустым.

Товары лежат в подразделах, а собраны только их прямые разделы. Родительские разделы дотягивают цепочкой вверх.

Список разделов строится по нескольку секунд.

При каждом показе обходятся все элементы каталога. На больших объёмах признак считают заранее и хранят в разделе.

После обмена меню показывает старые разделы.

Список закэширован без привязки к данным инфоблока. Кэш помечают тегом, и обмен сбрасывает его сам.

В выдаче есть разделы без товаров.

Пустые разделы скрыты стилями, а не убраны из списка и карты сайта. Прятать нужно на уровне данных.

Частые вопросы

Можно ли отфильтровать разделы одним запросом?

Нет: свойства принадлежат элементам, а не разделам. Путь всегда через выборку элементов.

Как учесть товары в подразделах?

Дотянуть цепочку родителей вверх или считать признак с учётом вложенности. Второе дороже, но точнее.

Подходит ли для этого умный фильтр?

Он решает задачу внутри раздела, а не отбор самих разделов. Для меню нужен свой расчёт.

Когда переходить на поле-агрегат?

Когда обход элементов перестаёт укладываться в доли секунды. Обычно это десятки тысяч товаров.

Смежное

Первоисточник