Разработка модуля сравнения товаров 1С-Битрикс
В стандартной поставке Битрикс есть компонент bitrix:catalog.compare и встроенная сессионная корзина сравнения. На несложных проектах этого хватает. Но как только появляются требования — хранить список между сессиями, сравнивать товары из разных категорий, выделять отличающиеся характеристики, экспортировать таблицу — стандартный компонент упирается в потолок. Собственный модуль решает эти задачи без костылей.
Как работает встроенное сравнение и где оно ломается
Встроенный механизм хранит список в $_SESSION['CATALOG_COMPARE'] и в куке catalog_compare_items. При добавлении товара вызывается AJAX-метод компонента, который пишет в сессию. Проблемы:
- Сессия живёт до закрытия браузера или таймаута — пользователь вернулся через день и список пуст.
- Нет разделения по категориям — можно добавить в сравнение телевизор и сапоги, и компонент попытается их сравнить.
- Характеристики выводятся все подряд без выделения различий.
- Нет поддержки авторизованных пользователей: один человек на двух устройствах — два разных списка.
Архитектура модуля
Модуль регистрируется в системе через local/modules/vendor.compare/ со стандартным include.php и install/index.php. Хранение списков:
Таблица b_compare_list:
| Поле | Тип | Назначение |
|---|---|---|
| ID | int auto_increment | Первичный ключ |
| USER_ID | int | ID авторизованного пользователя, NULL для гостей |
| SESSION_ID | varchar(64) | Хэш сессии для гостей |
| CREATED_AT | datetime | Дата создания |
| UPDATED_AT | datetime | Дата последнего изменения |
Таблица b_compare_item:
| Поле | Тип | Назначение |
|---|---|---|
| ID | int auto_increment | — |
| LIST_ID | int | FK на b_compare_list |
| PRODUCT_ID | int | ID товарного предложения |
| SECTION_ID | int | ID раздела каталога |
| ADDED_AT | datetime | Когда добавлен |
ORM-классы наследуются от \Bitrix\Main\ORM\Data\DataManager. Ограничение на количество товаров в одном списке задаётся через настройки модуля (таблица b_option, пространство имён модуля).
Логика слияния при авторизации
Когда гость авторизуется, его анонимный список нужно смерджить с постоянным:
public static function mergeOnLogin(int $userId, string $sessionId): void
{
$guestList = CompareListTable::getRow([
'filter' => ['=SESSION_ID' => $sessionId, '=USER_ID' => false],
]);
if (!$guestList) {
return;
}
$userList = CompareListTable::getOrCreate($userId);
$guestItems = CompareItemTable::getList([
'filter' => ['=LIST_ID' => $guestList['ID']],
]);
foreach ($guestItems as $item) {
CompareItemTable::addIfNotExists($userList['ID'], $item['PRODUCT_ID']);
}
CompareListTable::delete($guestList['ID']);
}
Событие OnAfterUserLogin из модуля main — место для вызова этого метода.
Выделение отличающихся характеристик
Это то, что покупатель ждёт от сравнения: строки, в которых товары отличаются, должны быть визуально выделены. Алгоритм:
- Получаем свойства всех товаров в сравнении через
CIBlockElement::GetList()сSELECT = ['PROPERTY_*']. - Строим матрицу: ключ — символьный код свойства, значение — массив значений по каждому товару.
- Для каждой строки матрицы проверяем
count(array_unique($values)) > 1— если больше одного уникального значения, строка помечается как «различающаяся». - На фронте к строкам с отличиями добавляется CSS-класс
compare-row--diff.
Дополнительно фильтруем строки, где все значения пустые — их незачем показывать.
Фронтенд: AJAX и состояние
Кнопка «Добавить к сравнению» на карточке товара отправляет POST на компонент через bitrix:main.ajax. Состояние иконки (добавлен / не добавлен) синхронизируется через localStorage при загрузке страницы и обновляется после каждого AJAX-ответа.
Счётчик количества товаров в сравнении выводится в шапке через отдельный компонент, который читает количество из сессии или API модуля без полной загрузки данных.
Экспорт таблицы сравнения
На крупных проектах просят экспорт в PDF или Excel. Для PDF используется mPDF или TCPDF (подключается как зависимость через composer в local/). Для Excel — PhpSpreadsheet. Таблица сравнения формируется из той же матрицы свойств и рендерится в файл по запросу пользователя.
Сроки разработки
| Масштаб | Состав | Срок |
|---|---|---|
| Базовый | Хранение в БД, AJAX-добавление/удаление, таблица сравнения | 4–6 дней |
| Стандартный | + Слияние при авторизации, выделение отличий, счётчик в шапке | 8–10 дней |
| Расширенный | + Экспорт PDF/Excel, сравнение между категориями, настройки модуля в админке | 12–16 дней |







