
msAltCart 
На этой странице представлены примеры чанков, описание атрибутов и вызов сниппета. Навигация в правом сайдбаре поможет перейти к описанию нужного шага.
Осторожно
Компонент некорректно работает с другими компонентами, меняющими ключи товаров в корзине, например, с msPromoCode2.
Внимание
Перед установкой компонента убедитесь, что у вас уже установлены pdoTools, SendIt, miniShop2.
Подсказка
Данный компонент может заменить и основную корзину. В нём есть поддержка стандартных JS событий из miniShop2. Однако совместимость с другими дополнениями не тестировалась, поэтому применение этого кейса может привести к поломке какой-либо функциональности, предоставляемой другими компонентами, в том числе связанным с оформлением заказов.
Системные требования 
- miniShop2 >= 3.0.7
 - SendIt >= 2.0.2
 - PHP >= 7.4 (работа на PHP 8 не тестировалась, но IDE ошибок не нашла).
 
Возможности 
- Вывод любого количества корзин на одной страницы.
 - Динамическое обновление всех корзин.
 - Каждая корзина может иметь собственный шаблон.
 - Изменение опций в корзине.
 - JS API для программного управления корзиной.
 - Получение статуса и состава корзины на фронте.
 - Изменение логики работы посредством JS событий.
 - Есть поддержка модификаций msOptionsPrice2.
 - Кастомизация поля ввода количества.
 
Особенности 
- Компонент заменяет стандартный класс-обработчик корзины на свой.
 - Компонент делает метод getProductKey() публичным.
 - Компонент добавляет плагин на событие msOnCreateOrder, меняющий имя товара на имя модификации, если таковая была выбрана.
 
Базовое использование 
Добавим динамическую корзину, которая будет появляться из-за экрана слева в элементе offcanvas.
Внимание
В примере ниже будет рассмотрен пример созданный с помощью Bootstrap 5, если хотите чтобы на вашем сайте всё заработало подключите скрипты и стили Bootstrap 5 по инструкции из документации
Осторожно
Одновременное использование стандартных для miniShop2 атрибутов и атрибутов данного компонента недопустимо. Исключение можно сделать только для класса ms2_form
Порядок действий 
- Создаём чанк-обёртку(wrapper).
 - Создаём чанк товара(row) (опционально).
 - В шаблоне вызываем сниппет getCarts.
 - Вставляем плейсхолдер там, где должна быть динамическая корзина.
 - Пользуемся.
 
Чанк-обертка (wrapper) 
<div data-msac-rows class="{!$rows ? 'd-none':''}">
  {$rows}
</div>
<div class="col-12 {!$rows ? 'd-none':''}" data-msac-totals>
  <div class="row">
    <p class="col-5 mb-3 h6">Сумма: <br><span  data-msac-prop="total_cost">{$total.cost}</span> {'ms2_frontend_currency' | lexicon}</p>
    <p class="col-3 mb-3 h6">Вес: <br><span data-msac-prop="total_weight">{$total.weight}</span> {'ms2_frontend_weight_unit' | lexicon}</p>
    <p class="col-4 mb-3 h6">Кол-во: <br><span data-msac-prop="total_count">{$total.count}</span> {'ms2_frontend_count_unit' | lexicon}</p>
    <div class="col-6">
      <button class="btn btn-danger" type="button" data-si-form data-si-preset="cart_clean" data-si-event="click">
        {'ms2_cart_clean' | lexicon}
      </button>
    </div>
    <div class="col-6">
      <a href="{179 | url}" class="btn btn-primary">Оформить заказа</a>
    </div>
  </div>
</div>
<div class="alert alert-warning {$rows ? 'd-none':''}" data-msac-empty>
    {'ms2_cart_is_empty' | lexicon}
</div>Этот чанк содержит три отдельных блока обозначенных соответствующими атрибутами.
Список товаров 
data-msac-rows - блок вывода списка товаров, если не указан - товары выведены не будут.
<div data-msac-rows class="{!$rows ? 'd-none':''}">
  {$rows}
</div>Суммарные значения 
data-msac-totals - блок вывода суммарных значений цены, веса и количества.
<div class="col-12 {!$rows ? 'd-none':''}" data-msac-totals>
  <div class="row">
    <p class="col-5 mb-3 h6">Сумма: <br><span  data-msac-prop="total_cost">{$total.cost}</span> {'ms2_frontend_currency' | lexicon}</p>
    <p class="col-3 mb-3 h6">Вес: <br><span data-msac-prop="total_weight">{$total.weight}</span> {'ms2_frontend_weight_unit' | lexicon}</p>
    <p class="col-4 mb-3 h6">Кол-во: <br><span data-msac-prop="total_count">{$total.count}</span> {'ms2_frontend_count_unit' | lexicon}</p>
    <div class="col-6">
      <button class="btn btn-danger" type="button" data-si-form data-si-preset="cart_clean" data-si-event="click">
        {'ms2_cart_clean' | lexicon}
      </button>
    </div>
    <div class="col-6">
      <a href="{179 | url}" class="btn btn-primary">Оформить заказа</a>
    </div>
  </div>
</div>Пустая корзина 
data-msac-empty - блок, который будет показан, если корзина пуста.
<div class="alert alert-warning {$rows ? 'd-none':''}" data-msac-empty>
  {'ms2_cart_is_empty' | lexicon}
</div>Осторожно
Ни один из блоков не должен быть вложен в другой.
Очистка корзины 
Поскольку для отправки данных на сервер используется SendIt, то для кнопки очистки корзины необходимо добавить следующие атрибуты:
- data-si-form - без значения.
 - data-si-preset - со значением cart_clean.
 - data-si-event - со значением click, для очистки корзины по клику.
 
<button class="btn btn-danger" type="button" data-si-form data-si-preset="cart_clean" data-si-event="click">
  {'ms2_cart_clean' | lexicon}
</button>Вывод данных 
Также обратите внимание на атрибуты data-msac-prop, которые позволяют выводить любые данные из корзины по ключу, его нужно указать в качестве значения данного атрибута.
<span data-msac-prop="total_cost">{$total.cost}</span>Чанк товара(row) 
Осторожно
Это опциональный чанк, если вам нужно вывести только общие значения, например в шапке, то не нужно указывать параметр row в сниппите getCarts
<div class="col-12 py-2" data-msac-product="{$key}">
  <div class="row align-items-center justify-content-between">
    <div class="col-12 mb-3 d-flex" style="gap:15px;">
      {if $thumb?}
        <img src="{$thumb}" alt="{$pagetitle}" title="{$pagetitle}"/>
      {else}
        <img src="{'assets_url' | option}components/minishop2/img/web/ms2_small.png"
          srcset="{'assets_url' | option}components/minishop2/img/web/ms2_small@2x.png 2x"
          alt="{$pagetitle}" title="{$pagetitle}"/>
      {/if}
      <form data-si-form data-si-preset="cart_change" data-si-event="change" data-si-nosave>
        <input type="hidden" name="key" value="{$key}"/>
        {if $id?}
          <a href="{$id | url}">{$pagetitle}</a>
        {else}
          {$name}
        {/if}
        {'!msOptions' | snippet: [
          'options' => 'color',
          'product' => $id,
          'currentOptions' => $options,
          'tpl' => '@FILE chunks/selectoption.tpl'
        ]}
        <div class="small">
          Размеры: {$options['size']}
        </div>
        <form class="col-10 mb-3" data-si-form data-si-preset="cart_change" data-si-event="change" data-si-nosave>
            <input type="hidden" name="key" value="{$key}"/>
            <div class="ms-input-number-wrap">
                <button class="ms-input-number-btn ms-input-number-minus btn btn-sm btn-secondary" type="button">−</button>
                <input class="ms-input-number-emulator" value="{$count}" name="count" data-msac-prop="count" type="text">
                <button class="ms-input-number-btn ms-input-number-plus btn btn-sm btn-secondary" type="button">+</button>
            </div>
        </form>
        <form class="col-2 mb-3" data-si-form>
            <input type="hidden" name="key" value="{$key}">
            <button class="btn btn-sm btn-danger" type="button" data-si-preset="cart_remove" data-si-event="click">×</button>
        </form>
        <div class="col-3 mb-3">
            <span class="text-nowrap">{$weight} {'ms2_frontend_weight_unit' | lexicon}</span>
        </div>
        <div class="col-6 mb-3">
            <span class="mr-2 text-nowrap">{$price | replace: ' ': '' | number: 0: '.': ' '} {'ms2_frontend_currency' | lexicon}</span>
            {if $old_price?}
                <s class="old_price text-nowrap">{$old_price | replace: ' ': '' | number: 0: '.': ' '} {'ms2_frontend_currency' | lexicon}</s>
            {/if}
        </div>
        <div class="col-3 mb-3">
            <span class="mr-2 text-nowrap"><span data-msac-prop="cost">{$cost | replace: ' ': '' | number: 0: '.': ' '}</span> {'ms2_frontend_currency' | lexicon}</span>
        </div>
      </form>
    </div>
    <form class="col-10 mb-3" data-si-form data-si-preset="cart_change" data-si-event="change" data-si-nosave>
      <input type="hidden" name="key" value="{$key}"/>
      <div class="ms-input-number-wrap">
        <button class="ms-input-number-btn ms-input-number-minus btn btn-sm btn-secondary" type="button">−</button>
        <input class="ms-input-number-emulator" value="{$count}" name="count" data-msac-prop="count" type="text">
        <button class="ms-input-number-btn ms-input-number-plus btn btn-sm btn-secondary" type="button">+</button>
      </div>
    </form>
    <form class="col-2 mb-3" data-si-form data-si-preset="cart_remove">
      <input type="hidden" name="key" value="{$key}">
      <button class="btn btn-sm btn-danger" type="button" data-si-event="click">×</button>
    </form>
    <div class="col-3 mb-3">
      <span class="text-nowrap">{$weight} {'ms2_frontend_weight_unit' | lexicon}</span>
    </div>
    <div class="col-6 mb-3">
      <span class="mr-2 text-nowrap">{$price | replace: ' ': '' | number: 0: '.': ' '} {'ms2_frontend_currency' | lexicon}</span>
      {if $old_price?}
        <s class="old_price text-nowrap">{$old_price | replace: ' ': '' | number: 0: '.': ' '} {'ms2_frontend_currency' | lexicon}</s>
      {/if}
    </div>
    <div class="col-3 mb-3">
      <span class="mr-2 text-nowrap"><span data-msac-prop="cost">{$cost | replace: ' ': '' | number: 0: '.': ' '}</span> {'ms2_frontend_currency' | lexicon}</span>
    </div>
  </div>
</div>Внимание
Все данные отдельного товара должны располагаться внутри блока с атрибутом data-msac-product, которому в качестве значения нужно передать ключ товара в корзине.
Изменение опций 
Если хотите, чтобы можно было менять какую-то опцию товара в динамической корзине, то следует обернуть select с нужной опцией в форму. Если нужно менять несколько опций, то можно каждую из них обернуть в отдельную форму или все в одну. При этом каждая форма обязательно должна иметь следующие атрибуты:
- data-si-form - без значения.
 - data-si-preset - со значением cart_change
 - data-si-event - со значением change, чтобы обновление корзины происходило при изменении в форме.
 - data-si-nosave - без значения, чтобы выбранные значения не сохранялись. И скрытый input с именем key и значением равным ключу товара.
 
<form data-si-form data-si-preset="cart_change" data-si-event="change" data-si-nosave>
  <input type="hidden" name="key" value="{$key}"/>
  {if $id?}
    <a href="{$id | url}">{$pagetitle}</a>
  {else}
    {$name}
  {/if}
  {'!msOptions' | snippet: [
    'options' => 'color',
    'product' => $id,
    'currentOptions' => $options,
    'tpl' => '@FILE chunks/selectoption.tpl'
  ]}
  <div class="small">
    Размеры: {$options['size']}
  </div>
  <div class="small">
    Вес: {$options['weight']}
  </div>
</form>Изменение количества 
Изменение количества происходит аналогичным образом, с той лишь разницей, что для кастомизации поля количества используется самописный плагин
<form class="col-10 mb-3" data-si-form data-si-preset="cart_change" data-si-event="change" data-si-nosave>
  <input type="hidden" name="key" value="{$key}"/>
  <div class="ms-input-number-wrap">
    <button class="ms-input-number-btn ms-input-number-minus btn btn-sm btn-secondary" type="button">−</button>
    <input class="ms-input-number-emulator" value="{$count}" name="count" data-msac-prop="count" type="text">
    <button class="ms-input-number-btn ms-input-number-plus btn btn-sm btn-secondary" type="button">+</button>
  </div>
</form>Удаление товара 
Чтобы была возможность удалить отдельный товар из корзины, нужно добавить в чанк товара форму со следующими атрибутами:
- data-si-form - без значения.
 - data-si-preset - со значением cart_remove
 
Внутри формы следует разместить скрытый input с именем key и значением равным ключу товара. А так же кнопку с типом button и атрибутом data-si-event="click".
<form class="col-2 mb-3" data-si-form>
    <input type="hidden" name="key" value="{$key}">
    <button class="btn btn-sm btn-danger" type="button" data-si-preset="cart_remove" data-si-event="click">×</button>
</form>Вывод свойств 
Для динамического обновления свойств товара, каждый блок содержащий конкретное свойство должен иметь атрибут data-msac-prop со значением равным ключу свойства, для стоимости отдельного товара ключом будет cost.
<span data-msac-prop="cost">{$cost | replace : ' ' : '' | number : 0 : '.' : ' '}</span>Вызов сниппета 
Сниппет getCarts имеет только один параметр tpls, который принимает в качестве значения строку в формате JSON.
{'!getCarts' | snippet: [
  'tpls' => '{ "maincart": { "wrapper":"@FILE msac/cart.tpl","row":"@FILE msac/cartrow.tpl" } }'
]}Внимание
Сниппет следует вызывать некешированным
Вставка плейсхолдера 
Поскольку по задумке наша динамическая корзина должна присутствовать на всех страницах, мы разместим плейсхолдер перед закрывающим тегом body.
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasExampleLabel">Корзина</h5>
    <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Закрыть"></button>
  </div>
  <div class="offcanvas-body" data-msac-cart="maincart" data-mspd-cart-wrap>
    {'maincart' | placeholder}
  </div>
</div>Внимание
Обратите внимание, что имя плейсхолдера равно ключу в JSON в вызове сниппета, а сам плейсхолдер расположен внутри блока с атрибутами data-mspd-cart-wrap и data-msac-cart. При этом data-msac-cart обязательно должен иметь значение равное имени плейсхолдера.
Системные настройки 
| Ключ | Описание | Значение | 
|---|---|---|
| msac_frontend_js | Путь к основным JS скриптам | assets/components/msaltcart/js/web/default.js |