Добавление и удаление товара из корзины со страницы категории и товара
Периодически клиенты просят функционал, чтобы можно было изменять количество товара не только находясь в корзине, но и со страниц категорий и самого товара.
Поэтому поделюсь своим решением. Сразу отмечу, что оно не претендует на позицию идеального, так что если есть замечания и предложения, то с радостью их выслушаю.
ВАЖНО! У меня версия miniShop2 4.2.0. Код будет отличаться для версий ниже. Так например до 4.1.4 отличается метод генерации ключа товара, а до версии 4.1.0 методы add и change корзины возвращают только ключ товара, когда в более новых версиях также есть измененное кол-во товара и прочая информация о нем.
1) Итак, для начала создадим сниппет inCart, который будет отвечать за вывод HTML-разметки, в зависимости от того, есть товар в корзине или нет. И соответственно два чанка tpl.inCart.btn и tpl.inCart.btn.not
Код сниппета inCart
Код чанка tpl.inCart.btn
Замените ID ресурса в ссылке на корзину.
Код чанка tpl.inCart.btn.not
2) Теперь нужно немного расширить методы add и remove класса msCartHandler.
Зачем это нужно? Метод add будет возвращать HTML-разметку после успешного добавления товара в корзину, а remove соответственно — HTML-разметку после успешного удаления товара из корзины.
Как расширять класс я описывать не буду, информация по этому есть в документации, поэтому просто напишу, что и куда добавить.
3) Допишем нужные скрипты. Для этого копируем default.js от minishop2 и создаем условный custom.js (не забудьте потом указать его в системных настройках по ключу ms2_frontend_js).
В чанке карточки товара на странице категории, вместо сабмит-кнопки вставляете следующий код:
Осталось добавить нужные стили и на выходе должно получится что-то наподобие этого (кликабельная gif-ка)
Поэтому поделюсь своим решением. Сразу отмечу, что оно не претендует на позицию идеального, так что если есть замечания и предложения, то с радостью их выслушаю.
ВАЖНО! У меня версия miniShop2 4.2.0. Код будет отличаться для версий ниже. Так например до 4.1.4 отличается метод генерации ключа товара, а до версии 4.1.0 методы add и change корзины возвращают только ключ товара, когда в более новых версиях также есть измененное кол-во товара и прочая информация о нем.
1) Итак, для начала создадим сниппет inCart, который будет отвечать за вывод HTML-разметки, в зависимости от того, есть товар в корзине или нет. И соответственно два чанка tpl.inCart.btn и tpl.inCart.btn.not
Код сниппета inCart
<?php
$output = '';
$product = (int) $modx->getOption('product', $scriptProperties, $modx->resource->id);
if (!$productItem = $modx->getObject('msProduct', $product)) {
return;
}
$miniShop2 = $modx->getService('miniShop2');
$miniShop2->initialize($modx->context->key);
$cart = $miniShop2->cart->get();
$options = array();
//$key = md5($product . $productItem->getPrice() . $productItem->getWeight() . (json_encode($options))); - используйте этот код, если у вас версия miniShop2 ниже 4.1.4
if (!function_exists('getProductKey')){
function getProductKey(array $product, array $options = [])
{
$key_fields = ['id','options'];
$product['options'] = $options;
$key = '';
foreach ($key_fields as $key_field) {
if (isset($product[$key_field])) {
if (is_array($product[$key_field])) {
$key .= json_encode($product[$key_field]);
} else {
$key .= $product[$key_field];
}
}
}
return 'ms' . md5($key);
}
}
$key = getProductKey($productItem->toArray(), $options);
if (array_key_exists($key, $cart)) {
$count = $cart[$key]['count'];
$output = $modx->getChunk('tpl.inCart.btn', ['count' => $count, 'key' => $key]);
} else {
$output = $modx->getChunk('tpl.inCart.btn.not');
}
return $output;
Код чанка tpl.inCart.btn
Замените ID ресурса в ссылке на корзину.
<div class="incart-wrap d-flex">
<button type="button" class="incart-btn btn-minus btn" data-count="[[+count:decr=`1`]]">-</button>
<a href="[[~27]]"><span>В корзине <span class="incart-count" data-key="[[+key]]">[[+count]]</span> шт</span><span>Перейти</span></a>
<button type="submit" class="incart-btn btn-plus btn" name="ms2_action" value="cart/add">+</button>
</div>
Код чанка tpl.inCart.btn.not
<button type="submit" class="btn" name="ms2_action" value="cart/add">
<span>В корзину</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" fill="#fff">
<path d="M16,18C17.1,18 18,18.9 18,20C18,21.1 17.1,22 16,22C14.9,22 14,21.1 14,20C14,18.9 14.9,18 16,18M16,19C15.45,19 15,19.45 15,20C15,20.55 15.45,21 16,21C16.55,21 17,20.55 17,20C17,19.45 16.55,19 16,19M7,18C8.1,18 9,18.9 9,20C9,21.1 8.1,22 7,22C5.9,22 5,21.1 5,20C5,18.9 5.9,18 7,18M7,19C6.45,19 6,19.45 6,20C6,20.55 6.45,21 7,21C7.55,21 8,20.55 8,20C8,19.45 7.55,19 7,19M18,6H4.27L6.82,12H15C15.33,12 15.62,11.84 15.8,11.6L18.8,7.6V7.6C18.93,7.43 19,7.22 19,7C19,6.45 18.55,6 18,6M15,13H6.87L6.1,14.56L6,15C6,15.55 6.45,16 7,16H18V17H7C5.9,17 5,16.1 5,15C5,14.65 5.09,14.32 5.25,14.03L5.97,12.56L2.34,4H1V3H3L3.85,5H18C19.1,5 20,5.9 20,7C20,7.5 19.83,7.92 19.55,8.26L16.64,12.15C16.28,12.66 15.68,13 15,13Z" />
</svg>
</button>
2) Теперь нужно немного расширить методы add и remove класса msCartHandler.
Зачем это нужно? Метод add будет возвращать HTML-разметку после успешного добавления товара в корзину, а remove соответственно — HTML-разметку после успешного удаления товара из корзины.
Как расширять класс я описывать не буду, информация по этому есть в документации, поэтому просто напишу, что и куда добавить.
//Переопределяем метод add и в return добавляем incart_html
return $this->success(
'ms2_cart_add_success',
$this->status([
'key' => $key,
'cart' => $this->cart,
'row' => $this->cart[$key],
'incart_html' => $this->modx->getChunk('tpl.inCart.btn', ['count' => $count, 'key' => $key])
]),
['count' => $count]
);
//Переопределяем метод remove и в return добавляем incart_html и ключ deleted со значением true
return $this->success(
'ms2_cart_remove_success',
$this->status([
'cart' => $this->cart,
'row' => $row,
'deleted' => true,
'incart_html' => $this->modx->getChunk('tpl.inCart.btn.not')
])
);
3) Допишем нужные скрипты. Для этого копируем default.js от minishop2 и создаем условный custom.js (не забудьте потом указать его в системных настройках по ключу ms2_frontend_js).
//Находите строку (в 4.2.0 197) var xhr = function (callbacks, userCallbacks) и дописываем строчки сразу после if
var xhr = function (callbacks, userCallbacks) {
return $[method](url, data, function (response) {
if (response.success) {
//Добавляем код ниже
if (data[3] && data[3].name == 'ms2_action' && data[3].value == 'cart/add') {
var thisForm = miniShop2.sendData.$form;
if (thisForm.find('.incart-container').length) {
thisForm.find('.incart-container').html(response.data.incart_html); //после успешного добавления товара в корзину меняем вид кнопки на ту, что возвращаем метод add из предыдущего пункта
}
}
...
//Почти в самом низу этого скрипта вставляем следующий код внутри $(document).ready(function ($)
miniShop2.Callbacks.Cart.add.response.success = function(response) {
let key = response.data.key;
if ($('.incart-count[data-key="'+key+'"]').length) {
$('.incart-count[data-key="'+key+'"]').text(response.data.row.count); //меняем кол-во товара в кнопке
}
};
$(document).on('click', '.incart-btn.btn-minus', function() {
let btn = $(this),
count = $(this).attr('data-count'),
key = $(this).next().find('.incart-count').attr('data-key');
$.post(document.location, {ms2_action: 'cart/change', key:key, count:count, ctx:'web'}, function(data) {
let response = JSON.parse(data);
if (response.success == true) {
if (response.data.deleted == true) {
let container = btn.closest('.incart-container');
container.html(response.data.incart_html); //меняем кнопку после удаления товара из корзины
miniShop2.Message.success(response.message);
} else {
btn.attr('data-count', parseInt(response.data.row.count) - 1);
btn.next().find('.incart-count').text(response.data.row.count);
miniShop2.Message.success(response.message);
}
}
});
});
Вот и все. В чанке карточки товара на странице категории, вместо сабмит-кнопки вставляете следующий код:
<div class="incart-container">
{'!inCart' | snippet : ['product' => $id]}
</div>
На странице товара делаете то же самое, просто можно не указывать параметр product у сниппета.Осталось добавить нужные стили и на выходе должно получится что-то наподобие этого (кликабельная gif-ка)
Комментарии: 13
Делал вот такое. Если что, там критика ниже, поправить статью пока руки не дошли.
modx.pro/howto/23874
modx.pro/howto/23874
Интересное решение с использованием ZoomX!
Ну, как я и писал, мое решение не претендует на топ. Если будет критика и правки, я только за — поправлю на сайтах своих)
Ну, как я и писал, мое решение не претендует на топ. Если будет критика и правки, я только за — поправлю на сайтах своих)
Пытаюсь реализовать метод, описанный в статье, но еще с кодом не слишком знаком, чтобы самостоятельно разобраться.) Как понял по докам нужно:
1. Создать свой php-файл. У меня это — mscarthandlerbtn.class.php;
2. Зарегистрировать новый метод вызовом в консоли:
4. А вот какой код должен быть в моем новом, расширяющем классе msCartHandlerBtn? Пока я просто скопировал в него «переопределенные методы add и return с добавленным incart_html» — описанные в статье. При этом в родительском классе они также присутствуют, т.к. на их удаление IDE реагирует ошибкой. В итоге у меня появились кнопки "+" и "-" на карточке товара (на странице категории пока еще не разобрался) и ими можно добавлять товар в корзину. Работает правда немного косячно. Думаю, что из-за неправильного наследования класса.
1. Создать свой php-файл. У меня это — mscarthandlerbtn.class.php;
2. Зарегистрировать новый метод вызовом в консоли:
if ($miniShop2 = $modx->getService('miniShop2')) {
$miniShop2->addService('cart', 'msCartHandlerBtn',
'{core_path}components/minishop2/custom/cart/mscarthandlerbtn.class.php');
}
3. Указать свой класс в системной настройке ms2_cart_handler_class.4. А вот какой код должен быть в моем новом, расширяющем классе msCartHandlerBtn? Пока я просто скопировал в него «переопределенные методы add и return с добавленным incart_html» — описанные в статье. При этом в родительском классе они также присутствуют, т.к. на их удаление IDE реагирует ошибкой. В итоге у меня появились кнопки "+" и "-" на карточке товара (на странице категории пока еще не разобрался) и ими можно добавлять товар в корзину. Работает правда немного косячно. Думаю, что из-за неправильного наследования класса.
Все верно. Копируете полностью методы add и remove (полный код функций function add и function remove). И добавляете им в return $this->success ключ incart_html с нужным чанком.
на странице категории пока еще не разобралсяВ чанке tpl товара, вместо кнопки сабмит вставляете код, который указан в статье (сниппет inCart с параметром product обернутый в incart-container)
Работает правда немного косячноЧто не так работает?
Спасибо за информацию! У меня странно эти плюсы-минусы работают на странице товара. Плюсуешь — все работает. А вот минусовка не работает — т.е. в корзине число меняется, а на странице при минусации не уменьшается. Тут с нашим фронтом разбираться нужно. У нас не bootstrap, а свой UI-фреймворк стоит.
Класс может не добавили или в скрипте ошибка какая. А тут нет разницы какой CSS-фреимворк, я ими вообще не пользуюсь например) если что можете написать доступы мне телеграмм (аккаунт в профиле) гляну сегодня и поправлю, заодно напишу в чем была проблема
Спасибо за помощь! Пока нет неоходимости. У меня это не рабочий проект, я просто хотел попрактивоваться в коде.)) Но жена, которая в нашем семейном подряде отвечате за фронтенд, предложила более простое (для нашего случая) решение, которое не требует изменений в php- и js-файлах Minishop2. Поскольку, как упоминал, у нас свой фреймворк, она просто взяла из корзины (где у нее также свои стили) свои стилизованные инпуты и добавила их на страницу категории.
Единственное отличие — в вашем решении больше динамики. Т.е. у вас при каждом нажатии изменяется количество в корзине. У нас сначала нужно «наплюсовать» нужное количество, а потом оно отправляется в корзину.
Единственное отличие — в вашем решении больше динамики. Т.е. у вас при каждом нажатии изменяется количество в корзине. У нас сначала нужно «наплюсовать» нужное количество, а потом оно отправляется в корзину.
То, про что вы говорите, не требует PHP вообще. Это чистый js в 3 строчки. Мое решение позволяет видеть какой товар есть в корзине и в каком количестве на любой странице сайта, и в то же время позволяет удалять товар из корзины, не находясь на ее странице.
Да, у вас это уже почти мини-корзина. После праздников я еще внимательно поразбираюсь. Если будут вопросы — напишу. Спасибо!
Осмелюсь предложить msAltCart я уже за вас покодил.
Спасибо! Одно другому не мешает) Я видел уже msAltCart на демосайте. Полезный компонент. После праздников, думаю, поставим на один из клиентских магазинов и посмотрим.
Для начинающих кодеров, типа меня, стоит упомянуть, чтобы в чанке tpl.inCart.btn в ссылке
<a href="[[~27]]">
поставили ID своей корозины. Не сразу доходит, почему ссылка не работает.))
точно, забыл, добавил
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.