Разработка модуля избранного 1С-Битрикс
Стандартный Битрикс не имеет готового модуля избранного для каталога. Есть модуль sale с «отложенными товарами» — они попадают в корзину со статусом Y в поле DELAY. Это не избранное: товары смешиваются с корзиной логически и технически, нет возможности создавать несколько списков, нет поддержки гостей с синхронизацией при входе. Полноценное избранное реализуется отдельным модулем.
Хранение данных
Модуль размещается в local/modules/vendor.wishlist/. Две основные таблицы:
Таблица b_wishlist — списки избранного (пользователь может иметь несколько: «Хочу купить», «Подарки», «Отложено»):
| Поле | Тип | Назначение |
|---|---|---|
| ID | int auto_increment | Первичный ключ |
| USER_ID | int | ID пользователя (NULL для гостей) |
| SESSION_ID | varchar(64) | Хэш сессии гостя |
| TITLE | varchar(255) | Название списка |
| IS_PUBLIC | tinyint(1) | Можно ли делиться по ссылке |
| PUBLIC_HASH | varchar(32) | Уникальный хэш для публичного URL |
| CREATED_AT | datetime | — |
Таблица b_wishlist_item:
| Поле | Тип | Назначение |
|---|---|---|
| ID | int auto_increment | — |
| LIST_ID | int | FK на b_wishlist |
| PRODUCT_ID | int | ID товарного предложения |
| ELEMENT_ID | int | ID элемента инфоблока (родительский товар) |
| ADDED_AT | datetime | — |
| NOTE | text | Личная заметка пользователя к товару |
Синхронизация гость → авторизованный пользователь
При входе пользователя в систему запускается обработчик события OnAfterUserLogin:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'main',
'OnAfterUserLogin',
[WishlistMerger::class, 'merge']
);
Метод merge находит анонимный список по SESSION_ID, переносит из него товары в основной список пользователя (с проверкой дублей через SELECT перед INSERT), после чего удаляет анонимный список. Если у пользователя ещё нет ни одного списка, анонимный список просто переназначается через UPDATE b_wishlist SET USER_ID = ?, SESSION_ID = NULL WHERE SESSION_ID = ?.
Кнопка «В избранное» на карточке товара
Кнопка отправляет AJAX-запрос на компонент vendor:wishlist.button. Компонент принимает PRODUCT_ID и ACTION (add/remove/toggle), выполняет операцию и возвращает JSON с новым состоянием.
На странице каталога состояние кнопок инициализируется один раз: при загрузке страницы делается единственный запрос, возвращающий массив PRODUCT_ID текущего пользователя, которые уже в избранном. JavaScript помечает соответствующие кнопки без повторных запросов к серверу.
// Получение всех ID товаров в избранном для текущего пользователя
$items = WishlistItemTable::getList([
'filter' => ['=LIST_ID' => $listId],
'select' => ['PRODUCT_ID'],
])->fetchAll();
$productIds = array_column($items, 'PRODUCT_ID');
Публичные списки и шаринг
Каждый список может быть сделан публичным. В этом случае генерируется PUBLIC_HASH через \Bitrix\Main\Security\Random::getString(32). URL вида /wishlist/share/abc123/ открывает список для любого посетителя в режиме просмотра. Просматривающий может добавить отдельные товары в свою корзину, но не может редактировать чужой список.
Функция полезна для подарочных списков: пользователь составляет список желаемых подарков и отправляет ссылку родственникам.
Уведомления о снижении цены
Опциональная, но популярная функция: если товар из избранного подешевел, пользователь получает email-уведомление. Реализуется агентом (\Bitrix\Main\Agent) или cron-задачей:
- Агент раз в сутки перебирает уникальные
PRODUCT_IDизb_wishlist_item. - Для каждого получает текущую цену через
\CCatalogProduct::GetByID()илиPrice::getList(). - Сравнивает с ценой, сохранённой в поле
LAST_PRICE(добавляется в таблицуb_wishlist_item). - При снижении отправляет почтовое событие
WISHLIST_PRICE_DROP.
Счётчик в шапке
Количество товаров в избранном выводится в шапке. Чтобы не делать тяжёлый запрос при каждой загрузке страницы, счётчик кешируется в $_SESSION['WISHLIST_COUNT'] и инвалидируется при каждом изменении списка. Компонент шапки читает значение из сессии — один PHP-вызов без обращения к БД.
Сроки разработки
| Масштаб | Состав | Срок |
|---|---|---|
| Базовый | Один список, хранение в БД, AJAX-кнопка, счётчик в шапке | 4–5 дней |
| Стандартный | + Слияние гость/пользователь, страница избранного в ЛК, несколько списков | 7–10 дней |
| Расширенный | + Публичные списки, уведомления о снижении цены, экспорт списка | 12–15 дней |







