Skip to content
ms3Variants
ms3Variants
Компонент вариантов товаров для MiniShop3
  • MODX 3
  • PHP 8.2
  • miniShop3
  • Vue 3
  1. Компоненты
  2. ms3Variants
  3. Интерфейс сайта
  4. Каталог товаров

Каталог товаров ​

Как вывести варианты в карточках каталога и добавлять в корзину выбранный вариант.

Подключение вариантов ​

fenom
{'msProducts' | snippet : [
    'parents' => 0,
    'usePackages' => 'ms3Variants',
    'tpl' => 'ms3_products_row_variants'
]}

С параметром usePackages каждый товар получает плейсхолдеры вариантов. В каталог попадают только активные варианты в порядке position.

Значение ms3Variants — с учётом регистра

При ms3variants или без usePackages плейсхолдеров нет: условие {if $has_variants} ложно, и карточка продаёт товар без варианта.

Второй вызов msProducts на той же странице получает плейсхолдеры вариантов от первого, даже без usePackages. У товаров из первого списка — их варианты, у остальных — пустые значения.

Модуль ProductCardUI ​

Для чанка с вариантами нужен модуль ProductCardUI.js из ms3Variants вместо стандартного модуля MiniShop3. Без замены у списка вариантов нет обработчика: виден и покупается только первый вариант, а состояние корзины пишется в формы первого варианта.

Замените в системной настройке ms3_frontend_assets (JSON-массив путей) элемент со стандартным модулем на путь к модулю ms3Variants:

БылоСтало
"[[+jsUrl]]web\/ui\/ProductCardUI.js""/assets/components/ms3variants/js/web/ProductCardUI.js"
  • В настройке слеши стандартного пути экранированы (web\/ui\/) — ищите строку в таком виде.
  • Путь к модулю ms3Variants указан от корня сайта. Если MODX установлен в подкаталог, поправьте его.

Чем модуль ms3Variants отличается от стандартного:

  • селекторы карточек прописаны в нём жёстко (.ms3-product-card, .qty-input), настройки ms3Config.selectors не учитываются;
  • кнопки «−/+» обрабатывает он сам во всех карточках, включая карточки без вариантов;
  • хуки MiniShop3 при «−/+» называются beforeChangeCart / afterChangeCart вместо beforeQuantityChange / afterQuantityChange. Обработчики подключаются через ms3.hooks.addHook('beforeChangeCart', fn); fn получает {productKey, count} (в afterChangeCart — ещё response), cancel = true в этом объекте отменяет изменение;
  • после «−/+» в карточке блоки корзины, выведенные сервером (например, мини-корзина в чанке), показывают прежнее содержимое до перезагрузки страницы;
  • в карточках, добавленных на страницу после загрузки (подгрузка, фильтры), выбор варианта не работает, и штатного способа подключить их нет.

Обновление MiniShop3 эту настройку не меняет: модуль ms3Variants остаётся, а исправления стандартного модуля до карточек не доходят.

Перед удалением ms3Variants верните стандартный модуль

При удалении пакета файл модуля удаляется, а настройка ms3_frontend_assets остаётся прежней. Корзина перестанет работать на всём сайте, в консоли браузера будет ReferenceError: ProductCardUI is not defined. Сначала верните в настройку "[[+jsUrl]]web/ui/ProductCardUI.js", затем удаляйте пакет.

Чанк ms3_products_row_variants ​

Стандартный чанк ms3_products_row_variants — готовая карточка. Свой чанк работает с модулем ProductCardUI, если в нём есть эта разметка:

ЭлементРазметкаЧто делает
Карточкаclass="ms3-product-card", data-product-id="{$id}"Без них модуль карточку не видит
Изображение<img class="product-image"> — первый такой элемент в карточкеМеняется при выборе варианта
Обёртка.ms3v-catalogВнутри — список и блоки вариантов
Список<select class="ms3v-select">, у пунктов value="{$variant.id}"Выбор варианта
Блок варианта.ms3v-variant-block, data-variant-id, data-variant-imageПоказывается блок выбранного варианта
Форма добавления.ms3_form.ms3v-add-form, data-cart-state="add", скрытое options = {"_variant_id": ID}Добавляет вариант в корзину
Форма изменения.ms3v-change-form, data-cart-state="change", поля product_key и count (.qty-input) — оставьте пустыми, модуль заполнит их данными позиции корзины, кнопки .qty-btn с data-action="decrease" / "increase"Показывается, когда вариант в корзине

Когда вариант в корзине, модуль показывает его форму изменения и добавляет « ✓» к пункту списка.

Если data-variant-image пустой, у карточки остаётся изображение предыдущего варианта. Пишите data-variant-image="{$variant.small ?: $variant.image_url}": эскиз small есть, только если его имя передано в параметре msProducts includeThumbs (например, 'includeThumbs' => 'small', имена — из настроек источника файлов товаров), иначе берётся оригинал.

Поле options с JSON имеет приоритет над полями options[...], поэтому стандартные опции MiniShop3 в форме варианта не передаются — см. Страница товара.

У товара без вариантов в стандартном чанке нет формы изменения: после добавления в корзину «−/+» в его карточке не появляются. В стандартном чанке MiniShop3 ms3_products_row они есть.

Минимальный чанк ​

Карточка без модуля ProductCardUI: список вариантов внутри формы меняет _variant_id в поле options.

fenom
<div>
    {$pagetitle}
    <form method="post" class="ms3_form">
        <input type="hidden" name="id" value="{$id}">
        <input type="hidden" name="ms3_action" value="cart/add">
        {if $has_variants}
            <input type="hidden" name="options" value='{["_variant_id" => $variants[0].id] | json_encode}'>
            <select onchange="this.form.elements.options.value = JSON.stringify({_variant_id: this.value})">
                {foreach $variants as $v}
                    <option value="{$v.id}">{$v.options_array | join : ', '} — {$v.price}</option>
                {/foreach}
            </select>
        {/if}
        <button type="submit">В корзину</button>
    </form>
</div>

У списка нет атрибута name, поэтому сам он в форму не отправляется. Закончившиеся варианты в этом чанке не блокируются, состояние «в корзине» не показывается.

Плейсхолдеры товара ​

ПлейсхолдерТипОписание
{$has_variants}boolЕсть ли у товара варианты для вывода
{$variants_count}intКоличество вариантов
{$variants}arrayВарианты — поля в разделе Поля варианта
{$variants_json}stringТе же данные JSON-массивом. Структура отличается от {$variants_json} сниппета msProductVariants

У товара без вариантов: {$has_variants} = false, {$variants_count} = 0, {$variants} — пустой массив, {$variants_json} — [].

Поля варианта ​

php
[
    'id' => 1,
    'product_id' => 42,
    'sku' => 'ABC-123-red',        // может быть пустым
    'price' => 1500.00,
    'old_price' => 2000.00,        // может быть пустым
    'count' => 10,
    'weight' => 0.5,
    'active' => true,
    'position' => 0,
    'in_stock' => true,
    'file_id' => 7,                // может быть пустым
    'image_url' => '/assets/images/42/product.jpg', // пусто без изображения
    'small' => '/assets/images/42/small/product.jpg', // только с includeThumbs
    'options' => [['key' => 'color', 'value' => 'Красный']],
    'options_array' => ['color' => 'Красный'],
    'created_at' => '2026-01-01 12:00:00',
    'updated_at' => '2026-01-01 12:00:00',
]

price — цена из записи варианта. Модификаторы цены MiniShop3 (событие msOnGetProductPrice, скидки групп покупателей) к ней не применяются.

Фильтрация по наличию ​

Зависит от настроек ms3variants_show_out_of_stock и ms3variants_check_stock:

  • Показ закончившихся = Да (по умолчанию) — показываются все активные варианты. В стандартном чанке кнопка закончившегося варианта заблокирована, только если включён контроль остатков. При ms3variants_check_stock = Нет вариант с остатком 0 считается «в наличии» и покупается.
  • Показ закончившихся = Нет — скрыты варианты с остатком 0. При ms3variants_check_stock = Нет такие варианты считаются «в наличии», и скрывать нечего.

Товар, у которого закончились все варианты, покупается по базовой цене

При показе закончившихся = Нет у такого товара {$has_variants} = false. Чанк рисует обычную форму без варианта, и товар уходит в корзину по базовой цене, без проверки остатков вариантов.

Производительность ​

Не указывайте usePackages там, где варианты не выводятся. Запросы на страницу:

  • один запрос — варианты всех товаров;
  • по запросу опций на каждый вариант;
  • по запросу файла на каждый вариант с изображением;
  • ещё один запрос эскизов при includeThumbs.