Если товар в корзине, поменять кнопку на "В корзине" в новом шаблоне 1С-Битрикс

Просмотров: 3757

Ранее я уже делал заметку на эту тему. Тогда, мы меняли значение input-а при добавлении товара в корзину в старых шаблонах детальной карточки.
В этой заметке рассмотрю этот же функционал для нового шаблона, при этом поправим и некоторый SEO момент данного функционала.

Логика работы будет заключаться в том что при клике на кнопку "В корзину" мы ее прячем и показываем, ранее спрятанную, ссылку "В корзине" которая будет отправлять пользователя на оформление заказа.

Рассматривать буду на примере детальной карточки, но заметка подойдет и для списка элементов раздела, с небольшой модификацией. При этом, если пользователь вышел из карточки (добавив товар в корзину) и снова в нее вернулся - у него останется ссылка "В корзине".

Заменям ссылку-кнопку "В корзину" на "В корзине", при клике

Блок с ссылкой кнопкой, в шаблоне, выглядит так:


<?if ($showAddBtn){?>
<div class="mb-3">
	<a
	class="btn <?=$showButtonClassName?> product-item-detail-buy-button"
	id="<?=$itemIds['ADD_BASKET_LINK']?>"
	href="javascript:void(0);">
		В корзину
	</a>
</div>
<?php}?>

Сначала, давайте сменим ссылку a на span, так как для SEO не очень хорошо наличие ссылки ведущей в никуда.

В карточке, может быть это не очень критично, но вот в списке таких ссылок получается много (да, эту инструкцию можно применить и для списка товаров). Меняем a на span и удаляем href, все будет работать - больше ничего не надо дорабатывать. Заодно избавимся от переизбытка class-ов, что бы проще версталось:


<?if ($showAddBtn){?>
<div class="mb-3">
	<span 
	class="add_to_cart" 
	id="<?=$itemIds['ADD_BASKET_LINK']?>">
		В корзину
	</span>
</div>
<?php}?>

У это spana-а есть уникальный для товара идентификатор , привязавшись к нему будем прятать span, при клике и показывать кнопку перехода в корзину.


<?if ($showAddBtn){?>
<div class="mb-3">
	<span 
	class="add_to_cart" 
	id="<?=$itemIds['ADD_BASKET_LINK']?>">
 		В корзину
 	</span>
 	<a 
	 class="link_to_card_dn" 
	 href="<?=$arParams['BASKET_URL']?>" 
	 id="to_cart_<?=$itemIds['ADD_BASKET_LINK']?>">
 		В корзине
 	</a>
 </div>

 <script>
 $('#<?= $itemIds['BASKET_ACTIONS_ID'] ?>').click(function () {
     $(this).addClass('add_to_cart_dn');
     $('#to_cart_<?=$itemIds['ADD_BASKET_LINK']?>').addClass('link_to_card_db');
 });
 </script>

<style type="text/css">
<!--
.link_to_card_dn, .add_to_cart_dn {
	 display: none;
}
.link_to_card_db {
	 display: block;
}
-->
</style>
<?php}?>

Суть заключается в следующем: изначально span c "В корзину" виден, а ссылка "В корзине" спрятана в display:none.

  • При клике по span-у к нему добавляется class add_to_cart_dn который его прячет (добавляет стиль с display:none)
  • К ссылке "В корзине" добавляется class link_to_card_db который переводит ее в display: block;
Само собой стили и скрипты данной логики можно разнести по файлам style.css и script.js, что бы не болтались прямо в шаблоне. Оставил так для упрощения.

Здесь все готово. Но, если пользователь обновит страницу, все стили вернутся в исходное состояние и хотя товар и будет в корзине, пользователь увидит кнопку "В корзину".

Проверка наличия товара в корзине

Что бы поправить этот момент нужно проверить наличие текущего товара в корзине пользователя и обработать вывод кнопок "В корзину" и "В корзине"

В result_modifer.php карточки товара добавляем:


$dbBasketItems = CSaleBasket::GetList(
    array(
        "NAME" => "ASC",
        "ID" => "ASC"
    ),
    array(
        "FUSER_ID" => CSaleBasket::GetBasketUserID(),
        "LID" => SITE_ID,
        "PRODUCT_ID" => $arResult['ID'],
        "ORDER_ID" => "NULL",
        "DELAY" => "N"
    ),
    false,
    false,
    array("PRODUCT_ID")
);
while ($arItemsBasket = $dbBasketItems->Fetch()) {
    $arResult['ITEM_HAS_IN_CART'] = $arItemsBasket['PRODUCT_ID'];
}

Методом CSaleBasket::GetList мы получили корзину текущего пользователя и отфильтровали текущий товар. Если этот товар есть в корзине-то $arResult['ITEM_HAS_IN_CART'] будет не пустой.

Далее дорабатываем наш кусочек кода:


<if ($showAddBtn){
if ($arResult['ITEM_HAS_IN_CART']) {
	$itemInCart = true;
}
?>
<div class="mb-3">
	<span
 	class="add_to_cart<?echo $itemInCart ? ' add_to_cart_dn' : ''?>"
 	id="<?=$itemIds['ADD_BASKET_LINK']?>">
 		В корзину
 	</span>
	<a
	 class="link_to_card_dn<?echo $itemInCart ? ' link_to_card_db' : ''?>"
	 href="<?=$arParams['BASKET_URL']?>"
	 id="to_cart_<?=$itemIds['ADD_BASKET_LINK']?>" >
	 	В корзине
	 </a>
 </div>

 <script>
 $('#<?= $itemIds['BASKET_ACTIONS_ID'] ?>').click(function () {
     $(this).addClass('add_to_cart_dn');
     $('#to_cart_<?=$itemIds['ADD_BASKET_LINK']?>').addClass('link_to_card_db');
 });
 </script>

<style type="text/css">
<!--
.link_to_card_dn, .add_to_cart_dn {
	 display: none;
}
.link_to_card_db {
	display: block;
}
-->
</style>
<?php}?>

Тут все просто: если $arResult['ITEM_HAS_IN_CART'] существует мы сразу прячем span и показываем ссылку "В корзине", теми же самыми стилями которые используем в js скрипте.

При желании, можно вообще попрятать все за условие, что бы в исходном коде и не было упоминания о spаn-е и скрипте. Тут уже, на ваше усмотрение:

Аналог CSaleBasket::GetList на D7

Для получения корзины пользователя на 1С-Битрикс с использованием D7, вы можете воспользоваться следующим кодом:


use Bitrix\Sale;

$basket = Sale\Basket::loadItemsForFUser(Sale\Fuser::getId(), Bitrix\Main\Context::getCurrent()->getSite());
$basketItems = $basket->getBasketItems();

$arResult['ITEM_HAS_IN_CART'] = false;

foreach ($basketItems as $basketItem) {
    if ($basketItem->getField('PRODUCT_ID') == $arResult['ID'] && $basketItem->getField('ORDER_ID') === null && $basketItem->getField('DELAY') == 'N') {
        $arResult['ITEM_HAS_IN_CART'] = true;
        break;
    }
}

В этом примере мы используем пространство имен Bitrix\Sale, чтобы работать с корзиной. Сначала мы загружаем корзину текущего пользователя, используя Sale\Basket::loadItemsForFUser(). Затем мы получаем список товаров в корзине с помощью $basket->getBasketItems().

Затем мы проходимся по каждому элементу корзины и проверяем, соответствует ли он вашему критерию (ID продукта, отсутствие заказа и отсутствие отложенного статуса). Если условие выполняется, мы устанавливаем $arResult['ITEM_HAS_IN_CART'] в true.

Михаил Базаров 28.05.2022
Что бы спрятатаь, точнее не показывать, всплывающее окно о добавлении товара в корзину.

В шаблоне catalog.item и catalog.element комментируем строчку с инициализацией этого окна.
Находим ее в файлах script.js

Код
this.initPopupWindow();

в секции
Код
basketResult: function(arResult)
Михаил Базаров 26.10.2023
Если вы хотите проверить, есть ли торговые предложения товара в корзине, используя метод CSaleBasket::GetList, то вам нужно сначала получить список торговых предложений текущего товара, а затем проверить их наличие в корзине.
Код
$offerList = CIBlockPriceTools::GetOffersArray(
    array(
        'IBLOCK_ID' => $arParams['IBLOCK_ID']
    ),
    array(
        $arResult['ID']
    ),
    false,
    array(
        'ID'
    ),
    false,
    false,
    false,
    false,
    false,
    false,
    false
);

$offerIds = array_column($offerList, "ID"); // Получаем ID торговых предложений

$dbBasketItems = CSaleBasket::GetList(
    array(
        "NAME" => "ASC",
        "ID" => "ASC"
    ),
    array(
        "FUSER_ID" => CSaleBasket::GetBasketUserID(),
        "LID" => SITE_ID,
        "PRODUCT_ID" => $offerIds, // Проверяем наличие торговых предложений в корзине
        "ORDER_ID" => "NULL",
        "DELAY" => "N"
    ),
    false,
    false,
    array("PRODUCT_ID")
);
$hasOffersInCart = false;
while ($arItemsBasket = $dbBasketItems->Fetch()) {
    if (in_array($arItemsBasket['PRODUCT_ID'], $offerIds)) {
        $hasOffersInCart = true;
        break;
    }
}

В этом примере мы сначала получаем список торговых предложений для текущего товара с помощью CIBlockPriceTools::GetOffersArray. Затем из этого списка извлекаем ID торговых предложений.

Затем мы используем CSaleBasket::GetList для проверки наличия этих торговых предложений в корзине. Если хотя бы одно из торговых предложений присутствует в корзине, то ITEM_HAS_OFFERS_IN_CART будет установлено в true.
Александр 12.12.2023
Эта информация будет кэшироваться в шаблоне  
Евгений 18.04.2024
Здравствуйте. А как для списка элементов раздела это сделать?
Возможно есть где-то но не нашел в блоге.
Михаил Базаров 19.04.2024
В целом, точно также, просто вместо $arResult['ID'] использовать $arResult['ITEM_ID']['ID']
Евгений 19.04.2024
Спасибо!!!
Оказывается я не в тот result_modifier.php код вставлял.
И на списке вот так сделал "PRODUCT_ID" => $arResult['ITEM']['ID'],
Гость 13.05.2024
Подскажите как вывести для торговых предложений на списке товаро?

это в шаблоне прописал верно?
if ($hasOffersInCart) {
$itemInCart = true;
}

возможно в result_modifier.php что то не так передаю.
Распечатывал в шаблоне, id торговых так выводятся $arResult["ITEM"]["OFFERS"][0]
Но не понимаю что поправить чтоб работало.

Подскажите :)
Михаил Базаров 14.05.2024
Это: так текстом понятно не объяснить. Пока не знаю когда, но постараюсь в течении пары недель сделать видеоинструкцию по этому вопросу
Появится в этой заметке
Гость 15.05.2024
Подскажите как вывести кнопку "Удалить из корзины" после того как мы добавили в нее товар?

Точнее как вывести кнопку в принципе понятно, вопрос где взять айдишник товара в корзине чтобы передать его в метод аякса.
Михаил Базаров 15.05.2024
Уберите из arSelect получение PRODUCT_ID и распечатайте весь массив, где то там будет ID записи в корзине, точно не помню какой у нее ключ, наверное так и есть "ID"
Код
$dbBasketItems = CSaleBasket::GetList(
    array(
        "NAME" => "ASC",
        "ID" => "ASC"
    ),
    array(
        "FUSER_ID" => CSaleBasket::GetBasketUserID(),
        "LID" => SITE_ID,
        "PRODUCT_ID" => $arResult['ID'],
        "ORDER_ID" => "NULL",
        "DELAY" => "N"
    ),
    false,
    false,
    array("*") // Выбираем все поля
);
while ($arItemsBasket = $dbBasketItems->Fetch()) {
     print_r($arItemsBasket) // распечатываем все поля
}