Передо мной стояла следующая задача: сделать фильтрацию всех товаров в инфоблоке по одному свойству, сохранив штатный функционал и рабочий «Умный фильтр». Вы скажете, что в битриксе есть замечательный «умный» фильтр с его фасетными индексами, а я скажу, что да, он есть. Но давайте взглянем на исходные данные задачи:
1. У нас есть инфоблок, в корне которого лежат основные разделы
2. Фильтрация должна происходить по ссылкам с главной страницы
И так, у нас есть сразу 2 проблемы:
1. В битриксе нельзя вывести все товары из инфоблока, не указав определенный раздел инфоблока (как бы можно, но в настройках штатного компонента этого нет)
2. Как сделать ссылку на фильтр, если в запросе на фильтрацию подставляются какие-то левые значения (arrFilter_55_4161729085=Y&set_filter=Показать)?
Для более полного понимая способа решения данной задачи проделаю все шаги с самого начала на демо-сайте битрикса (https://bitrixlabs.ru/#create-demo).
Первым делом нужно создать отдельную страницу, на которой будет выводиться наш каталог с умным фильтром:
Специально выбрал фильтр по цвету, потому что цвет есть у нас во всех разделах сайта, как раз то, что нам нужно.
При переходе на созданную страницу мы видим список всех разделов инфоблока (а нам нужен список всех товаров из всех разделов данного инфоблока).
Копируем стандартный шаблон компонента «каталог», чтобы не портить стандартный + чтобы избежать возможных перезаписей шаблона после обновлений:
Теперь переходим к редактированию самого шаблона, а именно нам нужен файл «sections.php», удаляем в нем весь код и заменяем его на:
<?if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();
include "section_vertical.php";
?>
Здесь мы просто подключаем вертикальную секцию шаблона, чтобы у нас сразу выводился фильтр и список товаров без каких либо списков раздела. Вам может понадобиться подключить горизонтальную секцию, а может и вовсе оставить вывод списка разделов и сравнение товаров (в таком случае вам нужно будет скопировать из файла section_vertical.php код для вызова компонента умного фильтра и код для вызова компонента секции).
Смотрим что получилось:
Переходим к редактированию параметров компонента и выбираем нужный инфоблок:
Смотрим что получилось и ловим фиаско:
Переходим в редактирование параметров компонента и включаем умный фильтр (попутно выбираем нужные свойства для фильтрации и отключаем сайдбар и вывод дерева каталога):
Переходим к редактированию файла «section_vertical.php», ищем вызов компонента «bitrix::catalog.section» и добавляем ему к параметрам:
"SHOW_ALL_WO_SECTION" => "Y",
А вот пояснение к параметру из официальной документации:
Теперь переходим на нашу страницу с товарами и видим уже примерно следующее:
Список товаров выводится из всех разделов + фильтр на месте
Чуть не забыл, у фильтра в параметрах нужно отключить SEF_MODE (чпу), иначе работать наш фильтр не будет.
Остается теперь только понять алгоритм генерации ссылок для фильтра, как нам с главной страницы перейти по ссылке и чтобы фильтр автоматом подхватил ее и отфильтровал данные.
Смотрим что у нас передает фильтр после отправки формы:
Пробуем оставить только свойство цвета и переходим по полученной ссылке:
Все прекрасно работает
Остается понять алгоритм генерации данного параметра в запросе:
arrFilter_33_744714710
33 — это у нас ID свойства с цветом
А вот откуда тут берется 744714710 — не понято. Сначала я думал, что это может быть айдишкой самого значения свойства, но тут циферки для ID большие слишком + я все таки решил убедиться и проверил все это дело примерно таким способом:
$res = CIBlockElement::GetList($arSort, $arFilter, false, false, $arSelect);
while($ob = $res->GetNextElement()){
$arFields = $ob->GetFields();
print_r($arFields);
}
Но там и рядом не было ничего с нужным нам значением. Тогда я решил заглянуть в исходники компонента умного фильтра и там нашел вот такой кусочек кода:
Собственно тут видно, что ключ фильтрации у нас генерируется за счет метода «fillItemValues»:
$this->fillItemValues($arResult["ITEMS"][$PID], $value)
Находим его в файле «class.php» с исходниками компонента умного фильтра (кто бы сомневался, хотя… битрикс же):
На 642 строке данного файла находим код, который и генерирует ключ фильтра:
$keyCrc = abs(crc32($htmlKey));
Получается, что тут просто высчитывается сумма из некого «htmlKey» и берется значение суммы по модулю
Находим происхождение «htmlKey» на строке 518:
$htmlKey = htmlspecialcharsbx($key);
Смотрим из чего у нас выходит «key»:
И видим, что при обычных раскладах это просто значение свойства.
Получается, что значение свойства хешируют и берут его значение по модулю + перед хеш суммой добавляется ID свойства.
Возвращаемся к моей изначальной задаче и делаем следующее:
$propValues = CIBlockElement::GetPropertyValues(8, array(), false, array("ID" => 55));//Получаем все значения свойства "производитель"
$pvalues = array();
while ($val = $propValues->Fetch()) {
$pvalues[$val[55]] = abs(crc32($val[55]));
}
Перебираем все значения нужного нам свойства и записываем все это дело в ассоциативный массив.
А уже при выводе списка производителей просто ищем значение по уже готовому массиву:
<?if(!empty($pvalues[$arItem['NAME']])):?>
<a href="/manufacturer/?arrFilter_55_<?=$pvalues[$arItem['NAME']]?>=Y&set_filter=Показать">
<?endif;?>
Тут html код вывода картинки производителя
<?if(!empty($pvalues[$arItem['NAME']])):?>
</a>
<?endif;?>
Вауля и наш костыль готов к работе =)
При использовании данного метода есть свои нюансы, на странице с фильтром при выборе свойства фильтрации у нас всегда показывает 0 значений, хотя по факту там больше 0:
Но думаю, что если покопаться, то можно разобраться и с этим. В любом случае, данное решение лучше, чем просто выборка всех элементов через «GetList» и создание своего кастомного фильтра с нуля.
Надеюсь, что данная статья хоть кому-то облегчит жизнь и сэкономит пару часов,.
Автор: диванный аналитик