Например, на одном из разрабатываемых сайтов было всего четыре товара, и покупатель не должен был иметь возможность добавить в корзину больше одного.
При этом важно сохранить возможность «передумать»:
- пользователь может добавить товар в корзину;
- затем выбрать другой товар, не оформляя заказ;
- в корзине в итоге должен остаться только последний добавленный товар.
Удалять товар вручную из корзины и добавлять новый — неудобно. Поэтому логика была реализована автоматически.
Логика решения: удаление и добавление товаров в корзине
Пользователь добавляет товары в каталогe без ограничений. Когда переходит на страницу корзины, мы проверяем её содержимое.
Если в корзине больше одного товара: все товары удаляются, обратно добавляется только последний добавленный товар.
После изменения корзины выполняется однократная перезагрузка страницы, чтобы интерфейс корректно обновился.
В шаблоне корзины (sale.basket.basket) добавляем файл result_modifier.php (если его нет — создаём).
if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) die();
/**
* Модификатор корзины - оставляет в корзине только последний добавленный товар
*
* Логика работы:
* 1. Если в корзине больше одного товара - удаляет все и оставляет только последний
* 2. После очистки делает перезагрузку страницы для обновления интерфейса
* 3. После перезагрузки скрипт не выполняется повторно благодаря GET-параметру
*/
// Проверяем, не пришли ли мы после редиректа
// Если параметр basket_updated=Y присутствует - значит корзина уже была обработана
$isAfterRedirect = isset($_GET['basket_updated']) && $_GET['basket_updated'] === 'Y';
// Выполняем операции только при первой загрузке страницы (не после редиректа)
if (!$isAfterRedirect) {
// Получаем все товары из текущей корзины пользователя
$arBasketItems = array();
$dbBasketItems = CSaleBasket::GetList(
array("ID" => "ASC"), // Сортировка по ID (первыми будут старые товары)
array(
"FUSER_ID" => CSaleBasket::GetBasketUserID(), // ID текущего пользователя корзины
"LID" => SITE_ID, // ID текущего сайта
"ORDER_ID" => "NULL" // Только товары не привязанные к заказу
),
false,
false,
array("PRODUCT_ID", 'ID') // Выбираем только ID продукта и ID записи корзины
);
// Подсчитываем количество товаров и запоминаем ID последнего товара
$basketCount = 0;
while ($arItems = $dbBasketItems->Fetch()) {
// Каждая итерация перезаписывает - в итоге останется последний
$lastAddedItem = $arItems['PRODUCT_ID'];
$basketCount++; // Счетчик товаров в корзине
}
// Выполняем операции только если в корзине больше одного товара
// Если товар один - ничего не делаем
if ($basketCount > 1) {
// Удаляем ВСЕ товары из корзины текущего пользователя
CSaleBasket::DeleteAll(CSaleBasket::GetBasketUserID());
// Формируем данные для добавления последнего товара обратно в корзину
$fields = [
'PRODUCT_ID' => $lastAddedItem, // ID последнего добавленного товара
'QUANTITY' => 1, // Количество = 1 шт
];
// Добавляем последний товар обратно в корзину
$r = Bitrix\Catalog\Product\Basket::addProduct($fields);
// Формируем URL с GET-параметром для предотвращения повторной обработки
// Этот параметр говорит скрипту, что корзина уже была обработана
$redirectUrl = $APPLICATION->GetCurPage() . '?basket_updated=Y';
// Делаем перезагрузку страницы для обновления интерфейса корзины
// После перезагрузки скрипт увидит параметр basket_updated=Y и не будет выполняться
LocalRedirect($redirectUrl);
}
}
Пояснения к реализации
- Мы получаем все товары корзины, отсортированные по ID записи корзины.
- ID записи корзины всегда уникален и увеличивается с каждым добавлением.
- Последний добавленный товар будет иметь максимальный ID.
- Мы сохраняем PRODUCT_ID последнего товара.
- Полностью очищаем корзину.
- Добавляем обратно только сохранённый товар.
После изменений выполняем редирект, так как: товары удаляются программно. Стандартный интерфейс корзины не успевает корректно перерисоваться.
GET-параметр basket_updated=Y предотвращает повторное выполнение кода после обновления страницы.
Таким образом, пользователь может свободно выбирать товары, но в корзине всегда будет находиться только один — последний выбранный.
Решение не требует кастомизации каталога или JS-ограничений и полностью реализуется на стороне шаблона корзины.