Сортировка каталога по числу добавлений в корзину в Битрикс
Идея
Чтобы витрина показывала «любимые» позиции первыми, удобно заранее накапливать метрику: сколько раз товар попадал в корзину. Хранить это как числовое свойство элемента каталога и сортировать по нему в параметрах компонента проще и быстрее, чем на лету считать строки таблицы b_sale_basket для каждой выборки.
Свойство в инфоблоке
Создайте свойство типа «Число» с символьным кодом, например BASKET_HIT_NUM, и включите участие в сортировке в настройках инфоблока. Идентификатор торгового каталога в примерах замените на свой — переменная $storeCatalogIblockId.
Инкремент при добавлении позиции
Подключите обработчик к событию после добавления записи корзины. Внутри загружаются модули iblock и sale, читается текущее значение свойства и увеличивается на единицу для PRODUCT_ID из полей события.
use Bitrix\Main\Entity\Event;
use Bitrix\Main\EventManager;
$dispatcher = EventManager::getInstance();
$dispatcher->addEventHandler(
'sale',
'\\Bitrix\\Sale\\Internals\\Basket::OnAfterAdd',
['BasketAddCounter', 'incrementHitProperty']
);
class BasketAddCounter
{
public static function incrementHitProperty(Event $event)
{
\Bitrix\Main\Loader::includeModule('iblock');
$row = $event->getParameter('fields');
if (empty($row['PRODUCT_ID'])) {
return;
}
$storeCatalogIblockId = 1; // ID инфоблока каталога
$propertyCode = 'BASKET_HIT_NUM';
$prior = \CIBlockElement::GetProperty(
$storeCatalogIblockId,
(int)$row['PRODUCT_ID'],
[],
['CODE' => $propertyCode]
)->fetch();
$baseline = isset($prior['VALUE']) && $prior['VALUE'] !== ''
? (int)$prior['VALUE']
: 0;
\CIBlockElement::SetPropertyValuesEx(
(int)$row['PRODUCT_ID'],
$storeCatalogIblockId,
[$propertyCode => $baseline + 1]
);
}
}Разовая инициализация из открытых корзин
Если нужно выставить стартовые значения по уже накопленным «висящим» корзинам без заказа, можно пройти агрегат по таблице корзины и записать свойство пакетом. Отфильтруйте сайт через SITE_ID или конкретный LID; для строк без оформленного заказа обычно используют фильтр '=ORDER_ID' => false (в отдельных версиях встречается сравнение с null — сверьтесь со схемой своей установки).
\Bitrix\Main\Loader::includeModule('iblock');
\Bitrix\Main\Loader::includeModule('sale');
use Bitrix\Main\Entity\ExpressionField;
use Bitrix\Sale\Internals\BasketTable;
$storeCatalogIblockId = 1;
$propertyCode = 'BASKET_HIT_NUM';
$rollup = BasketTable::getList([
'filter' => [
'=ORDER_ID' => false,
'=LID' => 's1',
],
'select' => ['PRODUCT_ID', 'ROW_QTY'],
'runtime' => [
new ExpressionField('ROW_QTY', 'COUNT(*)'),
],
'group' => ['PRODUCT_ID'],
]);
while ($bucket = $rollup->fetch()) {
\CIBlockElement::SetPropertyValuesEx(
(int)$bucket['PRODUCT_ID'],
$storeCatalogIblockId,
[$propertyCode => (int)$bucket['ROW_QTY']]
);
}Сортировка в компоненте списка
После того как свойство участвует в индексах свойств инфоблока, передайте его в параметры catalog.section (или родительского комплексного компонента): основное поле сортировки — псевдоним свойства через префикс PROPERTY_, порядок — по убыванию для популярных записей первыми.
'ELEMENT_SORT_FIELD' => 'PROPERTY_BASKET_HIT_NUM',
'ELEMENT_SORT_ORDER' => 'DESC',На что обратить внимание
- Если SKU лежит в отдельном инфоблоке, свойство нужно вести на том уровне, по которому реально фильтрует каталог на витрине.
- При активном обмене с 1С убедитесь, что обновление реквизитов не обнуляет пользовательские свойства без вашего участия.
- В проектах с очень высоким трафиком десятки обновлений свойства в секунду можно вынести в очередь или агента; для большинства витрин прямой
SetPropertyValuesExдостаточен.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии