- Проверено Modstore
- Бесплатные будущие обновления
- Работа на тестовом и публичном домене
- 12 месяцев тех. поддержки
Требует установки SendIt
Есть встроенная работа с промокодами.
НЕ РАБОТАЕТ С MODX 3
msProductDiscounts предназначен для управления скидками на товары интернет-магазина на базе miniShop2.
Основные возможности:
- Скидка в виде подарка;
- Скидки на каждый N-ый товар;
- Скидки на каждую N-ую позицию в корзине
- Скидки по дням недели
- Скидки по группам пользователей
- Скидки по определённым датам, на определенный период или бессрочно
- Скидки по категориям, с возможностью исключить дочерние
- Скидки на определённый товар, с возможностью задать исключения по отдельным модификациям (требуется дополнение msOprionPrice2) или по опциями и основным свойствам
- Скидки на товары с определенными опциями и свойствами
- Скидки на отдельные модификации
- Возможность ограничить применение скидок общей суммой товаров в корзине
- Автоматическая актуализация корзины
- Возможность определить приоритетность скидок
- Вывод информации о скидках на странице товара
- Возможность привязать ресурс с подробным описанием скидки
- Возможность вывести информацию о скидке на странице товара
- Возможность задать размер скидки как в относительных единицах измерения (%) так и в абсолютных
ВИДЕО ПРЕЗЕНТАЦИЯ
Для начала работы требуется просто установить компонент и задать параметры скидки. Если в параметрах скидки есть зависимость от опций, свойств или модификаций, эта информация должна передаваться на сервер стандартными средствами miniShop2, т.е. через массив options.
Для того, чтобы работала актуализация корзины, нужно в системных настройках указать ID страницы с корзиной (mspd_cart_page).
В чанке корзины должны присутствовать следующие элементы
<span data-ms-price>{$product.price}</span>
<span data-ms-old-price>{$product.old_price}</span>
<span data-ms-cost>{$product.cost}</span>Ключевой момент здесь это data-атрибуты любого из них может не быть, но в этом случае, информация обновляться не будет, пока не перезагрузят страницу.С версии 1.4.1 сниппет вывода информации о скидках на конкретный товар удалён. Вместо него добавлен процессор.
Таким образом показ цены со скидкой происходит автоматически, если в чанк товара добавлены соответствующие атрибуты.
Так вся информация о товаре должна быть внутри блока с атрибутом data-mspd-product="{$id}" где $id — идентификатор товара в админке.
Блок вывода цены должен содержать атрибут data-mspd-price в качестве значения нужно указать цену товара, для старой цены data-mspd-old-price — значение старая цена.
Свойства и опции влияющие на цену нужно обозначать соответственно data-mspd-data (свойство, например артикул или цвет или вес)
и data-mspd-option (любая кастомная опция). При этом если html элемент, которому вы добавляете эти атрибуты НЕ содержит атрибута name, необходимо в качестве значения указать ключ опции или свойства,
например так: data-mspd-data=«color» или data-mspd-option=«length».
Такие свойства как
- Производитель,
- Страна изготовитель,
- Новый,
- Особый,
- Популярный
Чтобы нулевая старая цена скрывалась необходимо обернуть весь блок вывода старой цены в элемент с атрибутом data-mspd-old-price-wrap и убедиться, что в стилях описан класс d-none, либо, если за визуальное скрытие элементов у вас отвечает другой класс, указать свой класс в системных настройках компонента.
Там же, в системных настройках, можно изменить время принудительной перезагрузки страницы с корзиной. Принудительная перезагрузка происходит 1 раз в сутки. Это нужно на случай если пользователь оставил вкладку браузера на длительное время, а срок действия акции закончился. Тогда принудительная перезагрузка обновит стоимость корзины. Если оставить системную настройку mspd_reload_interval пустой принудительной перезагрузки не случится.
Стандартный скрипт показывает цену со скидкой и старую цену. Однако может возникнуть необходимость показывать ещё какую-то информацию о скидках на данный товар.
Для этого есть событие в JavaScript (с версии 1.4.1) mspd-get-discounts
document.addEventListener('mspd-get-discounts', e => {
console.log(e.detail);
// e.detail.response - ответ сервера с реальной ценой, ценой со скидкой/скидками и списком всех применённых скидок
// e.detail.wrapper - блок-обёртка товара обозначенная атрибутом data-mspd-product
// e.detail.price - цена от которой рассчитывалась скидка
// e.detail.target - элемент вызвавший событие
// e.detail.object - объект JS класса mspdGetDiscounts можно использовать его метод форматирования цены
//e.detail.object.formatPrice(e.detail.response.discount_price, e.detail.object.config.price_format, e.detail.object.config.price_format_no_zeros)
});Для работы с msOprionsPrice2 необходимо внутри блока с data-mspd-product добавить
<input type="hidden" name="options[modification]">Пример страницы товара
{'!msOptionsPrice.initialize' | snippet:[]}
<div class="text-center text-md-left mb-2 mb-md-0">
{if $_modx->resource.new?}
<span class="badge badge-secondary badge-pill col-auto">{'ms2_frontend_new' | lexicon}</span>
{/if}
{if $_modx->resource.popular?}
<span class="badge badge-secondary badge-pill col-auto">{'ms2_frontend_popular' | lexicon}</span>
{/if}
{if $_modx->resource.favorite?}
<span class="badge badge-secondary badge-pill col-auto">{'ms2_frontend_favorite' | lexicon}</span>
{/if}
</div>
<div id="msProduct" class="row align-items-center" itemtype="http://schema.org/Product" itemscope>
<meta itemprop="name" content="{$_modx->resource.pagetitle}">
<meta itemprop="description" content="{$_modx->resource.description ?: $_modx->resource.pagetitle}">
<div class="col-12 col-md-6">
{'!msGallery' | snippet : []}
</div>
<div class="col-12 col-md-6" itemtype="http://schema.org/AggregateOffer" itemprop="offers" itemscope data-mspd-observe>
<meta itemprop="category" content="{$_modx->resource.parent | resource: "pagetitle"}">
<meta itemprop="offerCount" content="1">
<meta itemprop="price" content="{$price | replace:" ":""}">
<meta itemprop="lowPrice" content="{$price | replace:" ":""}">
<meta itemprop="priceCurrency" content="RUR">
<form class="form-horizontal ms2_form msoptionsprice-product" method="post" data-mspd-product="{$_modx->resource.id}">
<input type="text" name="options[modification]" value="0" data-mspd-option>
<h1 class="text-center text-md-left msoptionsprice-name msoptionsprice-[[*id]]">{$_modx->resource.pagetitle}</h1>
<input type="hidden" name="id" value="{$_modx->resource.id}"/>
<div class="form-group row align-items-center">
<label class="col-6 col-md-3 text-right text-md-left col-form-label">{'ms2_product_article' | lexicon}:</label>
<div class="col-6 col-md-9 msoptionsprice-article msoptionsprice-[[*id]]">
{$article ?: '-'}
</div>
</div>
<div class="form-group row align-items-center">
<label class="col-6 col-md-3 text-right text-md-left col-form-label">{'ms2_product_price' | lexicon}:</label>
<div class="col-6 col-md-9">
<span class="msoptionsprice-cost msoptionsprice-[[*id]]" data-mspd-price="{$_modx->resource.price}">{$_modx->resource.price}</span> {'ms2_frontend_currency' | lexicon}
<span data-mspd-old-price-wrap class="old_price {$old_price == 0 ? 'd-none' : ''}">
<span class=" ml-2 msoptionsprice-old-cost msoptionsprice-[[*id]]" data-mspd-old-price="{$_modx->resource.old_price}">{$_modx->resource.old_price}</span>
{'ms2_frontend_currency' | lexicon}
</span>
</div>
</div>
<div class="form-group row align-items-center">
<label class="col-6 col-md-3 text-right text-md-left col-form-label" for="product_price">{'ms2_cart_count' | lexicon}:</label>
<div class="col-6 col-md-9">
<div class="input-group">
<input type="number" name="count" id="product_price" class="form-control col-md-6" value="1"/>
<div class="input-group-append">
<span class="input-group-text">{'ms2_frontend_count_unit' | lexicon}</span>
</div>
</div>
</div>
</div>
<div class="form-group row align-items-center">
<label class="col-6 col-md-3 text-right text-md-left col-form-label">{'ms2_product_weight' | lexicon}:</label>
<div class="col-6 col-md-9">
<span class="msoptionsprice-mass msoptionsprice-[[*id]]" data-mspd-data="weight">{$weight}</span> {'ms2_frontend_weight_unit' | lexicon}
</div>
</div>
<div class="form-group row align-items-center">
<label class="col-6 col-md-3 text-right text-md-left col-form-label">{'ms2_product_made_in' | lexicon}:</label>
<div class="col-6 col-md-9">
{$made_in ?: '-'}
</div>
</div>
{'msOptions' | snippet : [
'options' => 'color,size,test_5,test_6'
]}
{'msProductOptions' | snippet : []}
<div class="form-group row align-items-center">
<div class="col-12 offset-md-3 col-md-9 text-center text-md-left">
<button type="submit" class="btn btn-primary" name="ms2_action" value="cart/add">
{'ms2_frontend_add_to_cart' | lexicon}
</button>
</div>
</div>
</form>
</div>
</div>
<div class="mt-3">
{$_modx->resource.content}
</div>!!! ВАЖНО При использовании msOptionsPrice2 атрибут data-mspd-product и класс msoptionsprice-product должны принадлежать одному HTML элементу. Атрибут data-mspd-old-price-wrap должен быть непосредственным родителем для элемента с атрибутом data-mspd-old-price.[УСТАРЕЛО с версии 1.4.1]
Пример вызова сниппет для показа скидок на текущий товар (данный вызов следует размещать на странице товара). Вызов написан для Fenom
{set $discounts = '!getProductDiscounts' | snippet:[
'id' => $_modx->resource.id,
'tpl' => '',
'tplEmpty' => '@INLINE Скидки для данного товара не найдены.',
'price' => $_modx->resource.price,
'weight' => $_modx->resource.weight,
'options' => ['color'=>'','size'=>'','test_5'=>'','test_6' => '', 'modification' => 1],
'data' => ['article' => ''],
'total_cost' => 999999
]}
{$discounts | print} 2.9.2-rc — 30.09.2026 Fixed
- Исправление 2.9.1-rc было неполным: запрос активных скидок по-прежнему падал с ошибкой «Column 'createdby' in field list is ambiguous» — поля присоединённого ресурса тоже выбирались без имени таблицы. Скидки в корзине и каталоге снова работают.
2.9.1-rc — 30.09.2026 Fixed
- Скидки перестали применяться в корзине и показываться в каталоге после обновления до 2.9.0-rc: запрос активных скидок падал с ошибкой «Column 'createdby' in field list is ambiguous» — новые поля скидки совпали по имени с полями присоединённого ресурса.
- Отключение проверки общих условий из обработчика
mspdOnBeforeCheckDiscountдействует только на ту скидку, для которой его включили, а не на все следующие скидки и товары. - Расчёт скидок падал с ошибкой «Class 'MsProductDiscounts\msProductDiscountsManagerAccess' not found», как только у какой-нибудь скидки истекал период (с 2.7.9-rc).
- Добавлено описание системной настройки
mspd_check_common_conditions_on_show.
2.9.0-rc — 29.09.2026 Added
- Форма скидки: основные поля на виду, настройки и условия — во вкладках. Видимые вкладки
и их порядок задают новые системные настройки
mspd_discount_tabs(страница скидки) иmspd_discount_modal_tabs(скидка в модалке на странице промокода). - Условия новой скидки задаются до первого сохранения и сохраняются вместе с ней.
- Выбор товара-подарка через модалки товара и модификации; поиск товаров, модификаций и подарка срабатывает при вводе; списки в модалках с пагинацией; автосохранение в модалках категорий, товаров и модификаций.
- Промокод: создание, редактирование, удаление и закрепление скидок прямо из формы промокода; новый промокод создаётся вводом кода, сохранённый сохраняется автоматически; по умолчанию безлимитный и бессрочный.
- Поиск скидок промокода: фильтры-плашки, отдельный поиск по исключениям, фильтр по создателю. У скидок и промокодов хранятся создатель и дата создания.
- Списки скидок и промокодов: поиск и фильтры по контексту, создателю, дате создания, у промокодов — по коду, скидкам и состоянию.
- Промокод без скидок остаётся черновиком (отметка и фильтр «Без скидок»), а не удаляется вместе с последней скидкой.
- Меню: пункты собраны в группы «Скидки» и «Промокоды», добавлены «Создать скидку» и «Создать промокод». При обновлении группа встаёт туда, где на сайте лежал прежний пункт.
- Создание из меню без
mspd_base_ctxпри нескольких контекстах открывает окно выбора контекста. - Модалка «Подробнее» о скидке переоформлена.
- Системная настройка
mspd_gift_price(цена товара-подарка, по умолчанию 0) видна в админке.
Changed
mspd_debugпри новой установке выключен.
Fixed
- Период скидки и промокода не меньше часа, даты формы без сдвига на час.
- Промокод и его скидки — в одном контексте; пустой контекст не сохраняется.
- Занятое название скидки показывается ошибкой у поля.
- Версии скриптов менеджера в URL: браузер не берёт старый JS из кэша.
2.8.0-rc — 21.09.2026 Added
- Поиск скидок при редактировании промокода по названию, категориям, товарам, опциям и модификациям. Результаты показывают совпавшие условия и исключения.
- Просмотр параметров и условий скидки кнопкой «Подробнее» без ухода из промокода.
- Выбранные скидки отображаются отдельно и сохраняются при смене запроса и страницы.
2.7.10-rc — 17.09.2026 Fixed
- ИСПРАВЛЕНО: скидка считалась не для выбранного варианта товара.
getProductOptionsсобирал все поляoptions[...]подряд и перезаписывал значение по имени, поэтому из группы переключателей в запрос уходил последний в разметке, а не отмеченный покупателем. Невыбранныеradio/checkboxи отключённые поля теперь в опции не попадают.
Added
msProductDiscounts.refreshDiscounts()— публичный вызов принудительного пересчёта скидок всех товаров страницы, и атрибут формыdata-mspd-manual, при котором пакет не шлёт запрос скидок сам поchangeопций и ждёт этого вызова. Нужно сайтам, где цена зависит от модификации, получаемой отдельным ajax-запросом: запрос поchangeуходил бы с прежнимoptions[modification], и цена отставала бы на один выбор. Поля формы, кромеoptions[...](количество и прочее), обрабатываются как раньше.
2.7.9-rc — 06.09.2026 Security
- ИСПРАВЛЕНО: точка входа
assets/components/msproductdiscounts/action.phpпускала к процессорам менеджера кого угодно, без входа в админку. Списки скидок и промокодов (включая сами коды) отдавались анонимному посетителю по прямой ссылке. Проверка прав стояла только вconnector.php, аaction.phpподнимал MODX в режиме API и звал процессор как есть. Теперь оба входа спрашивают одно и то же право:mgr/promocode/*—mspd_promocodes, прочиеmgr/*—mspd_discounts; действия витрины (неmgr/) прав по-прежнему не требуют. - ИСПРАВЛЕНО: право теперь проверяет сам процессор, а не только точка входа. У каждого
процессора каталога
processors/mgr/объявлено требуемое право, поэтому новая точка входа или прямой вызов процессора больше не обходят разграничение «скидки отдельно от промокодов». Внутренний вызов пакета (уборка истёкших периодов при расчёте скидок на витрине) идёт черезmsProductDiscountsManagerAccess::runProcessor()и прав не требует. Fixed - ИСПРАВЛЕНО: установка и обновление пакета больше не разрегистрируют права
mspd_discountsиmspd_promocodesв общем шаблонеAdministratorTemplateи не вычищают их из политикиAdministrator. Разовый перенос прав из версий 2.1.9-2.6.0 выполнялся при каждом апгрейде, и на проектах, где эти права заведены в общем шаблоне сознательно, доступ тихо ломался: право пропадало из шаблона, а первое же сохранение политики через админку стирало ключ из её данных — процессор ядра пишет политику полным снимком формы. Свежая установка прав в общем шаблоне не создаёт, переносить нечего.
2.7.8-rc — 18.08.2026 Fixed
- ИСПРАВЛЕНО: подарок появлялся и пропадал в корзине только после перезагрузки страницы. Признак «состав корзины изменился» сбрасывался в начале каждого расчёта скидок, а читает его ответ фронту — то есть уже следующий запрос. Изменение количества товара подарок добавляло или снимало на сервере, но список строк на странице оставался прошлым до F5; итоги при этом были верными. Теперь признак живёт до ближайшего ответа корзины и сбрасывается только после того, как отдан фронту.
2.7.7-rc — 18.08.2026 Fixed
- ИСПРАВЛЕНО: строка корзины в ответе сервера показывала прошлое состояние цен. Разметка строки собирается один раз, при чтении корзины, — то есть до применения скидок и до добавления подарка. Дальше пересчёт менял цены и суммы, а разметка оставалась прежней: только что добавленный подарок печатался каталожной ценой вместо нулевой, и это держалось до перезагрузки страницы. Тот же дефект был у обычного товара, впервые получившего скидку.
Changed
- ТРЕБУЕТСЯ msAltCart 1.2.4-pl и выше (метод
renderProductRow()). Со старой корзиной пакет работает по-прежнему, разметка строк просто не обновляется. Порядок выкладки: сначала msAltCart, потом msProductDiscounts.
2.7.6-rc — 18.08.2026 Fixed
- ИСПРАВЛЕНО: сумма позиций корзины расходилась с итогом, когда товаров больше одного. Точная сумма позиции сверялась с состоянием строки только по количеству, а пересчёт скидок меняет разбивку внутри позиции: «две единицы со скидкой из трёх» становятся тремя, когда рядом появляется второй товар. Количество прежнее, цена и сумма другие — строка печатала новую сумму, а итог считался по снимку прошлого расчёта.
- ИСПРАВЛЕНО: снимок точной суммы не доживал до серверного рендера. Пара полей
снималась, когда сумма сходилась с ценой × количеством, а хранилище
dbпри этом оставляло вpropertiesстроки прежние значения — в базе не было ни одногоexact_cost, и до ответаgetcartстраница печатала цену × количество с потерянной копейкой (636.99 вместо 637.00).
Changed
- ИЗМЕНЕНО: контракт точной суммы с корзиной расширен ценой. Строка метится тройкой
exact_cost+exact_count+exact_price, потребитель принимает снимок только при совпадении и количества, и цены единицы. Снимок безexact_price(формат до 2.7.6-rc) игнорируется. - ИЗМЕНЕНО: отпечаток пишется всегда — и при сбросе цен к исходным, и для подарка. «Пары нет» перестало быть состоянием, в котором строка остаётся с чужим снимком.
- ТРЕБУЕТСЯ msAltCart 1.2.2-pl и выше. Порядок выкладки: сначала msAltCart, потом msProductDiscounts.
2.7.5-rc — 14.08.2026 Changed
- ИЗМЕНЕНО: русское предупреждение для принятого промокода без эффекта сокращено до «Промокод принят, но не суммируется с другими скидками.» — без предположения, что причина обязательно в товарах, уже имеющих скидку.
2.7.4-rc — 14.08.2026 Fixed
- ИСПРАВЛЕНО: очистка поля не отменяла действующий промокод — фронт прекращал запрос при пустом значении. Теперь очистка сразу отправляет отмену и возвращает корзину к состоянию без промокода.
- ИСПРАВЛЕНО: если поверх действующего промокода ввести другой, форма пыталась отменить новый код, оставляя неверные лимиты, и не применяла его. Теперь новый код сначала полностью проверяется, затем за один запрос возвращается лимит старого и списывается лимит нового. Неверный новый код не снимает уже действующий.
- ИСПРАВЛЕНО: отмена больше не доверяет значению поля формы — активный промокод берётся из сессии. Повторная отправка уже применённого кода не списывает его лимит второй раз.
2.7.3-rc — 14.08.2026 Fixed
- ИСПРАВЛЕНО: промокод, не давший скидки, сообщал «Промокод применён» и оставлял корзину без изменений — клиент видел успех и прежнюю сумму. Так бывает, когда на товары уже действует другая скидка, а промокодная «Все кроме этой» с ней не суммируется. Теперь пакет проверяет, сработала ли хоть одна привязанная к промокоду скидка, и отвечает честно: «Промокод принят, но на товары в корзине уже действует скидка — промокод с ней не суммируется». Промокод при этом остаётся применённым: доложите в корзину товар без скидки — он сработает.
Added
- НОВОЕ:
Discounts::$appliedDiscountIds— id скидок, реально изменивших корзину в этом пересчёте (скидка начислена хотя бы одному товару либо подарок оказался в корзине), и методDiscounts::hasAppliedPromocodeDiscounts()поверх него. Отбор скидки ещё не означает, что она сработала, — теперь это различимо. - НОВОЕ: ответ действия
applypromocodeсодержит полеdata.effect— дал ли промокод эффект. Фронт пакета по нему показывает уведомление жёлтым (предупреждение) вместо зелёного, подменяя тип в штатном событии SendItsi:notify:before.
Changed
- ИЗМЕНЕНО: текст ответа на применение промокода без эффекта берётся из нового ключа
лексикона
mspd_promocode_applied_no_effect.
2.7.2-rc — 14.08.2026 Fixed
- ИСПРАВЛЕНО: точная сумма позиции терялась после пересчёта, и корзина снова показывала
копейку меньше. Корзина перечитывается после операций с подарками, а обработчик корзины
собирает
costзаново как цена × количество — восстановленная сумма затиралась ещё до сохранения. Теперь пакет помнит сумму вместе с количеством, для которого она посчитана, и возвращает её в перечитанную корзину. - ИСПРАВЛЕНО: итог корзины брал сумму позиции, не проверяя, тому ли количеству она соответствует. Теперь сначала берётся помеченная пара «сумма + количество», и только при несовпадении — обычный расчёт.
Added
- НОВОЕ: точная сумма позиции передаётся корзине парой полей
exact_costиexact_count(сумма и количество, для которого она посчитана). Поля выставляются только там, где цена × количество даёт другую сумму. Их понимает msAltCart с 1.2.1-pl —msAltCartHandler::getItemCost(); порядок выкладки: сначала msAltCart, потом этот пакет.
2.7.1-rc — 14.08.2026 Fixed
- ИСПРАВЛЕНО: сумма позиции со скидкой теряла копейки, когда не делилась нацело на
количество. Скидка на часть единиц размазывается в среднюю цену за штуку, а та
округляется до
mspd_round_precision: три товара по 245 со скидкой 20 % на две единицы давали цену 212.33 и сумму 636.99 вместо 637.00. Теперь пакет вычитает скидку из суммы позиции, а цена за штуку остаётся производной для показа. - ИСПРАВЛЕНО: выгода по позиции (
discount_cost) считалась как усреднённая разница цен, умноженная на число единиц со скидкой, — величина не сходилась ни с суммой позиции, ни с ценой до скидки. Теперь это разность сумм:old_cost − cost.
Added
- НОВОЕ: пакет подписан на событие
msOnGetStatusCartи пересчитывает итог корзины по суммам позиций. miniShop2 складывает итог как «цена за штуку × количество», из-за чего та же копейка терялась и в итоге корзины, и в сумме заказа. Обработчик продолжает с уже накопленного статуса, поэтому не зависит от порядка плагинов на событии.
2.7.0-rc — 13.08.2026 Added
- НОВОЕ: установщик создаёт две отдельные политики доступа:
msproductdiscountsFullдля управления скидками и промокодами иmsproductdiscountsPromocodesдля управления только промокодами. Политики назначаются группе пользователей в дополнение к обычной manager-политике.
Security
- БЕЗОПАСНОСТЬ: права
mspd_discountsиmspd_promocodesтеперь проверяются не только у пунктов меню и страниц списков, но также у прямых URL страниц редактирования и у всех запросов manager-коннектора. Пользователь без права больше не может обойти меню прямой ссылкой или вызовом процессора. - БЕЗОПАСНОСТЬ: права пакета перенесены из общей политики
Administratorв собственный шаблон политик. РаньшеAdministratorвыдавал оба права всем своим получателям, поэтому политика «только промокоды» не могла ограничить доступ: MODX объединяет разрешения.
2.6.0-rc — 12.08.2026 Fixed
- ИСПРАВЛЕНО: строковые значения в итогах корзины превращались в
0. Коннектор округлял всё подряд, кроме ключей с_str, а сайт через событиеmsOnGetStatusCartкладёт в статус и текст — подпись единиц измерения, готовую разметку блока о доставке.round()от такой строки даёт ноль, и корзина после любого AJAX-обновления показывала0вместо текста. Теперь округляются только числовые значения.
Changed
- ИЗМЕНЕНО: пакет больше не рисует корзину. Раньше при добавлении или снятии товара-подарка он
сам обновлял разметку чужой корзины и знал про конкретный компонент корзины. Теперь он бросает
отменяемое событие
mspd:cart:changedс составом и итогами, а рисует себя сама корзина и отменяет событие. Событие никто не отменил — пакет, как и прежде, перезагружает страницу. Имя события настраивается параметромcartChangedEventмодуля Cart. - ИЗМЕНЕНО: событие
mspd:gift:manageстало отменяемым — теперьpreventDefault()в подписчике действительно отключает штатную реакцию пакета на изменение состава корзины. - ИЗМЕНЕНО: запрос скидок после действий с корзиной откладывается на 50 мс (
getCartDelay). Несколько колбэков miniShop2 подряд схлопываются в один запрос, а корзина успевает отрисовать изменённую строку до того, как пакет проставит в неё свои значения. - ВНИМАНИЕ: для работы подарков без перезагрузки страницы msAltCart нужен версии 1.2.0 и выше; обновлять его следует до обновления этого пакета.
2.5.0-rc — 12.08.2026 Added
- НОВОЕ: значение
*системной настройкиmspd_tpls_with_cartвключает пересчёт скидок корзины при загрузке ресурса с любым шаблоном. Прежний список ID шаблонов через запятую работает без изменений. Это позволяет корректно актуализировать боковую корзину на сайтах, где она входит в общий wrapper всех страниц.
2.4.1-rc — 31.07.2026
- ИСПРАВЛЕНО: в фоновом режиме (cron сайта, консольные скрипты) скидки не видели
родительские категории товара, а в лог ошибок на каждый товар падало «PHP warning:
Invalid argument supplied for foreach()». Пакет брал предков ядровым
modX::getParentIds(), который обходит карту дерева контекста, а она в API-режиме не построена: список родителей возвращался пустым, и скидка, назначенная на родительскую категорию, молча не применялась. Теперь предки считаются по собственной карте «ресурс → родитель»: один запрос на контекст, дальше подъём в памяти — в вебе это ещё и быстрее ядрового обхода (поиск по ключу вместо перебора всей карты).
2.4.0-rc — 23.07.2026
- НОВОЕ: журнал действий менеджера со скидками и промокодами. Пакет записывает в mxLogger,
кто и когда создал, изменил, удалил или продублировал скидку, а также кто создал, изменил
или удалил промокод. В записи попадают пользователь (id и логин), действие, объект с его id
и названием (кодом) и то, что именно изменилось: при создании и дублировании — все значения
объекта, при изменении — только изменённые поля парами «было / стало», при удалении — полное
состояние удалённого объекта. Для промокода так же фиксируются привязанные к нему скидки,
в том числе их изменение. Значения полей сохраняются целиком, без сокращений, поэтому по
журналу можно восстановить прежние настройки скидки. Время проставляет сам mxLogger.
Найти записи можно по тэгам
msproductdiscountsиaudit, а историю конкретного объекта — по процессуmspd_discount_IDилиmspd_promocode_ID. Журнал ведётся всегда и не требует включённой отладки (mspd_debug). Если mxLogger на сайте не установлен, скидки и промокоды сохраняются как обычно — записи просто не ведутся. - ИСПРАВЛЕНО: при отборе скидок учитывались только первая категория товара и его первая модификация. Товар, лежащий в нескольких категориях каталога, мог не получить скидку, назначенную на «неглавную» категорию; то же касалось товаров с несколькими модификациями. Теперь берутся все категории товара вместе с их родительскими и все модификации.
2.3.0-rc — 23.07.2026
- НОВОЕ: системное событие
mspdOnGetShowPrices— точка расширения, через которую сайт может подать пакету собственную цену показа и старую цену конкретного товара. Событие возникает при подготовке ответа для каталога и карточки товара: после того как пакет применил свои скидки, но до того как посчитал строковые значения цены, поэтому перечёркнутая цена и цена со скидкой остаются единым механизмом пакета, а не рисуются сайтом отдельно. Параметры события:productData— данные товара,discounts— скидки, попавшие в показ (может быть пустым),scope— область показа (catalogилиproduct),prices— текущая пара цен,object— экземпляр класса Discounts. Подписчик подменяет цены через$object->showPrices['price']и$object->showPrices['old_price']; цену, которую он не тронул, пакет считает как раньше. Кейс: товар-комплект, выгода которого не выражается ни одной записью скидки — сайт считает пару цен сам и отдаёт её пакету, а показ остаётся единым. - НОВОЕ: свойство
$object->externalPrices. Сайт, который подаёт свои цены показа, выставляет его в подписчике событияmspdOnFilterIdsByDiscount. Флаг снимает ранний выход по корзине — без него товар, у которого скидок нет вовсе, до расчёта цены показа не доходит. Внимание: со снятым ранним выходом в ответ попадают и товары, о которых сервер раньше молчал, поэтому старая цена таких товаров берётся из карточки товара — если она там заполнена, а показывать её не нужно, подписчику следует обнулить её самому. Пока подписчика нет, флаг остаётся выключенным и ответ сервера не меняется. - ИЗМЕНЕНО: пункт меню компонента больше не возвращается в свою категорию при обновлении. Раньше обновление пакета перезаписывало пункт меню целиком, и он «уезжал» обратно из той категории, куда его перенёс администратор сайта. Теперь существующий пункт меню при обновлении не трогается совсем — сохраняются и его расположение, и порядок в списке.
2.2.0-rc — 21.07.2026
- НОВОЕ: у каждой скидки появились настройки показа — «Показ в каталоге», «Показ в карточке»
и «Описание акции». Каждая принимает три значения: «По умолчанию» (как раньше — по системным
настройкам), «Показывать» и «Не показывать». Раньше показом скидок в списках товаров управляли
только глобальные
mspd_show_for_allиmspd_check_common_conditions_on_show: включив показ ради одной акции, приходилось включать его для всех скидок сразу. «Показывать» означает, что скидка участвует в расчёте цены для показа независимо от корзины: цена со скидкой и зачёркнутая старая цена видны даже при пустой корзине и невыполненных общих условиях (сумма, количество). «Не показывать» убирает скидку из показа совсем, в том числе приmspd_show_for_all=1. Настройки влияют только на показ — корзина продолжает считать фактические скидки по прежним правилам, поэтому у скрытой в каталоге скидки цена в корзине может отличаться от показанной. Кейс: «Товары недели» показывают старую и новую цену в каталоге, а «−20% на вторую единицу» в списке товаров не показывается. - НОВОЕ: каталог и карточка товара различаются атрибутом
data-mspd-scopeна обёртке товара или любом его предке: значениеproduct— карточка товара, всё остальное (и отсутствие атрибута) — каталог. Шаблоны без атрибута работают как раньше. - НОВОЕ: системная настройка
mspd_show_discount_info(по умолчанию «Да») — дефолт показа описания акции для скидок, у которых эта настройка оставлена в значении «По умолчанию». Раньше инфоблок поmspd_info_tplвыводился всегда и отключить его было нечем. - Обновление БД: у скидок появились поля
show_in_catalog,show_in_product,show_description(по умолчанию 0 — «По умолчанию»), поэтому на уже работающих сайтах поведение не меняется. Затрагивает: модель mspdDiscount, Discounts::filterIdsByDiscount, Discounts::getProductDiscounts, Base::initialize, шаблон управления скидкой, js-модуль Discounts.
2.1.22-rc — 21.07.2026
- НОВОЕ: тип применения «Суммируется с другими» (
apply_type=3). Такая скидка не участвует в эксклюзивном отсечении: если у товара есть скидка «Только эту скидку», суммируемая всё равно применяется поверх неё. Работает только приmspd_many_behaviour=3— при других значениях пакет применяет одну скидку-победителя, и суммируемая в расчёт не попадает. Порядок применения в корзине: обычные скидки → «Все кроме этой» → «Суммируется с другими». Благодаря такому порядку суммируемая скидка не отбирает у «Все кроме этой» её товары: для отбора товар по-прежнему считается «без скидки», если получил только суммируемую. Математика — каскад от текущей цены, как и у остальных скидок: 1000 ₽ при основной 10% и суммируемой 5% даёт 855 ₽, а не 850 ₽. Превью карточек товара показывает ту же цену, что даст корзина: суммируемая скидка добавляется в стек последней и не влияет на показ «Все кроме этой». Кейс: «coming_soon 5%» поверх основной скидки и поверх эксклюзивных «Товаров недели». Затрагивает: Discounts::filterDiscountsByApplyType, Discounts::applyDiscounts, Discounts::filterIdsByDiscount, шаблон управления скидкой.
2.1.21-rc — 17.07.2026
- FIX: промокод больше не «слетает» при применении/отмене через браузер. Причина —
гонка сессии: фронт после applypromocode параллельно слал getDiscounts + getCart,
и их запись в незалоченную сессию MODX затирала только что записанный промокод
(
$_SESSION['mspd']). Теперь applypromocode/cancelpromocode сами возвращают пересчитанную корзину (products/totals/giftsChanged) в своём ответе, а фронт рендерит из него без отдельных follow-up-запросов — гоняющегося запроса больше нет. Затрагивает: сниппет mspdConnector, JS-модуль promocodes.js (successHandler).
2.1.20-rc — 16.07.2026
- ИЗМЕНЕНИЕ ПОВЕДЕНИЯ: тип применения «Все кроме этой» (
apply_type=2) теперь учитывает ФАКТИЧЕСКИ применённые скидки, а не применимые по условиям. Такая скидка применяется после остальных и только к товарам, не получившим скидку в текущем пересчёте корзины. Раньше она отбрасывалась, если у товара были другие подходящие по условиям скидки — даже когда те не дали товару никакой выгоды (например, из-за отступа). Кейс: промокод со скидкой «Все кроме этой» теперь даёт выгоду товарам, оставшимся без основной акции. В превью карточек такая скидка не стекуется с другими. Работает приmspd_many_behaviour=3.
2.1.19-rc — 16.07.2026
- Включающие «Произвольные условия» скидки (
Discounts::checkProductOptions) теперь проверяются все, а не только первое: условия группируются по ключу, внутри одного ключа — ИЛИ, между ключами — И. Раньше цикл завершалсяreturnна первой строке, и несколько include-условий не работали (в т.ч. нельзя было ограничить скидку несколькими контекстами черезcontext_key). Exclude-условия — без изменений. Тест:dev/tests/check-product-options.php(13 кейсов).
2.1.18-rc — 16.06.2026
- Исправлена ошибка mixed content в админке: из URL подключаемых mgr-скриптов в контроллерах
(
getdiscounts,getpromocodes,discount/manage,promocode/manage) убран лишний слеш после{$assetsUrl}. Переменная уже оканчивается наjs/, поэтому вimport ... from "{$assetsUrl}/mgr/..."получался двойной слешjs//mgr/.... Теперь путь корректный —js/mgr/....
2.1.17-rc — 16.06.2026
- Логирование переведено на mxLogger. Отладочная трассировка скидок (
$this->modx->logподmspd_debug) теперь делегируется сервису mxLogger через новый классMsProductDiscounts\Loggerи фасадBase::log(). Если mxLogger не установлен — записи молча пропускаются. - Новая настройка
mspd_log_level(минимальный уровень debug|info|warning|error, по умолчанию error; единый приёмник mxLogger, включено из коробки), консистентно сmxlogger.min_level. Переключательmspd_debugсохранён. - Тэги: базовые
msproductdiscounts+cart, этапdiscount. process_uid воронки — по сессии. Ранее негейтнутые вызовы$this->modx->log(например дамп SQL) теперь тоже под гейтомmspd_debug. - ВНИМАНИЕ: перед сборкой настройку
mspd_log_levelсоздать в менеджере (namespace msproductdiscounts) — сборка тянет настройки из БД стенда.
2.1.16-rc — 23.04.2026
- Улучшил совместимость с msAltCart: корзина теперь обновляется по событиям msac:row:add/replace/remove:after, когда msAltCart активен, стандартный ms2-колбэк пропускается во избежание двойного запроса и гонок.
- Сделал свойство $apply в Discounts nullable (?bool), чтобы плагины на событиях mspdOnBeforeCheckDiscount/mspdOnCheckDiscount могли безопасно сбрасывать флаг применения скидки.
2.1.15-rc — 14.04.2026
- Исправлена потеря скидок по промокодам: дисконтированные цены теперь сохраняются в сессию перед обработкой подарков, что предотвращает перезатирание цен при перечитывании корзины.
2.1.14-rc — 16.03.2026
- Исправление ошибок
2.1.13-rc — 14.03.2026
- Добавил поддержку мультиконтекстных подарков: товар-подарок автоматически резолвится в текущий контекст по связующему полю (настройка mspd_gift_link_field).
- Добавил поддержку резолва модификаций подарков в другой контекст по набору опций.
- Добавил проверку соответствия товара-подарка текущему контексту перед добавлением в корзину.
2.1.12-rc — 14.03.2026
- Перевёл добавление и удаление подарков на стандартные методы miniShop2 (cart->add/cart->remove) с защитой от рекурсии через статический флаг.
- Добавил флаг giftsChanged в ответ коннектора getcart для отслеживания операций с подарками.
- Добавил вызов window.msAltCart.updateCarts() при изменении подарков в корзине.
- Добавил событие mspd:gift:manage для кастомной обработки изменений подарков на фронтенде.
- Добавил версионирование подключаемых JS-модулей (?v=) на основе времени последнего изменения файлов.
2.1.11-rc — 14.03.2026
- Убрал округление строк при получении статуса корзины в коннекторе.
2.1.10-rc — 13.03.2026
- Добавил автоматическое удаление промокодов при удалении скидки, если она была единственной привязанной к ним.
- Добавил предупреждение в окне подтверждения удаления скидки о промокодах, которые будут удалены вместе с ней.
2.1.9-rc — 12.03.2026
- Добавил раздельные permissions для скидок (mspd_discounts) и промокодов (mspd_promocodes).
- Добавил проверку permissions в контроллерах скидок и промокодов.
- Добавил резольвер для регистрации permissions в AdministratorTemplate и политике Administrator.
- Добавил установку permissions на пунктах меню.
2.1.8-rc — 10.03.2026
- Добавил приведение к float в Discounts::applyDiscount()
2.1.7-rc — 2025-12-26 - 06.03.2026
- Уменьшил размер ключа для промокода.
- Добавил новый тип скидки "Подарок" (unit "g") — автоматическое добавление товара-подарка в корзину.
- Добавил поддержку модификаций msOptionPrice в качестве подарка (чекбокс gift_class_key).
- Добавил системную настройку mspd_gift_price для указания цены подарка в корзине.
- Добавил учёт manyBehaviour и apply_type для подарочных скидок.
- Добавил исключение подарков из подсчёта позиций, количества и стоимости корзины.
- Добавил автоматическое удаление подарка из корзины при несоответствии условиям скидки.
- Добавил панель "Произвольные условия" (ключ-значение) в настройках скидки.
- Добавил поддержку кастомных значений для чекбоксов в админке (data-checked-value, data-unchecked-value).
2.1.6-rc — 2025-12-06 - 2025-12-24
- Исправил чанк информации о скидке.
- Исправил применение скидок при указании отношения к количеству "кратно"
- Добавил округление.
2.1.5-rc — 2025-10-20 - 2025-12-06
- Добавил задержку после применения или отмены промокода перед получением данных корзины.
- Перенёс переопределение корзины в метод applyDiscounts.
- Добавил прерывание проверки соответствия условий скидки конкретному товару при нахождении первого несоответствия
- Исправил ошибку связанную с удалением неподходящих скидок.
- Изменил значение defaultEngine в файле msproductdiscounts.mysql.schema.xml на InnoDB
2.1.4-rc — 2025-10-14
- Исправил ошибку в методах cancelPromocode и applyPromocode
2.1.3-rc — 2025-09-30 - 2025-10-01
- Разделил загрузку вебконфига и файла js для возможности раздельного подключения.
- Добавил явное преобразование типов при передачи значений метод formatPrice
2.1.2-rc — 2025-09-23
- Добавил возможность отключения проверки общих условий при показе скидок без применения при помощи системной настройки mspd_check_common_conditions_on_show.
2.1.1-rc — 2025-09-19
- Добавил проверку общих условий при показе скидок без применения.
2.1.0-rc12 — 2025-08-17
- Добавил явное приведение типов для статусов.
2.1.0-rc11 — 2025-08-03
- Мелкие правки.
2.1.0-rc10 — 2025-08-02
- Добавил в системное событие mspdOnBeforeApplyDiscount.
2.1.0-rc9 — 2025-08-02
- Добавил в JS событие mspd:on:get:productdata.
2.1.0-rc8 — 2025-08-02
- Установил глобальную переменную msProductDiscounts в JS.
2.1.0-rc7 — 2025-08-02
- Добавил удаление активных скидок для которых нет товаров.
- Сделал наличие JS miniShop2 необязательным.
2.1.0-rc6 — 2025-05-13 - 2025-05-17
- Добавил проверку на наличие старой цены перед расчётом скидки.
- Добавил приведение типов в методе checkCommonConditions.
- Поменял discount_total на discount_cost.
- Добавил возможность делать скидки с учётом наличия акционных товаров в корзине.
2.1.0-rc5 — 2025-05-05
- Добавил проверку $order_id при удалении привязки промокода к заказу.
- Добавил обработку колбэков минишопа для получения скидок в каталоге.
2.1.0-rc4 — 2025-05-02 - 2025-05-04
- Добавил фильтр скидок на странице редактирования промокода.
- Добавил возможность переходить к редактированию скидки со страницы редактирования промокода.
- Добавил системное событие mspdOnBeforeGetPromocode.
- Добавил системное событие mspdOnGetWebConfig.
- Сделал рефакторинг JavaScript.
- Добавил зависимость от компонента SendIt.
- Вынес шаблон информации о скидках в чанк.
- Добавил сниппет mspdConnector.
- Переписал сниппет msCart так чтобы он корректно отображал данные товара со скидкой в корзине.
2.1.0-rc3 — 2025-05-02
- Добавил фильтр промокодов по названию скидки
2.1.0-rc2 — 2025-05-02
- Доработал совместную работу обычных скидок и скидок по промокодам.
2.1.0-rc1 — 2025-04-29
- Добавил возможность создавать промокоды.
2.0.0-rc5 — 2025-04-11
- Добавил подключение пакета в процессор поиска совпадений.
- Улучшил совместимость с msAltCart.
- Добавил системные события mspdOnGetProductDiscounts и mspdOnBeforeCheckDiscount
- Добавил куку mspd_context для сохранения текущего контекста
- Добавил событие mspdOnBeforeGetDiscounts
2.0.0-rc4 — 2025-04-08
- Исправил метод сброса корзины при отсутствии скидок
2.0.0-rc3 — 2025-02-15
- Исправил условие в методе checkCommonConditions()
2.0.0-rc2 — 2025-02-08
- Добавил проверку общих параметров скидок таких как отношение к количеству и минимальная сумма
2.0.0-rc1 — 2024-09-15
- Added parameter
showHiddenin category tree. - Fix some bugs in JS
- Add check in get conditions method.
- Fixed the error of passing parameters from the mspdOnCheckDiscount plugin.
- Fixed error on check allowed resources.
- Fixed an error where the processor returns an empty result if no discounts are found
- Add for product in cart information about value and unit of discount
- Change way to get original price
- Exclude class mspdPeriod from the list of checked classes
2.0.0-rc — 2024-09-14
- Added limit, offset and context parameters to discounts.
- Added composer autoloader.
- Rewrite base class for discounts.
- Exclude using Session for keeping discounts.
- No compatibility with previous versions.
- No compatibility with other discount components
1.4.7 — 2023-12-25
- Added the data-mspd-cart-row="${key}" attribute to indicate a separate item in the cart
- Аdded support for multiple shopping carts
- The mspd_cart_page system setting has been replaced with mspd_tpls_with_cart
1.4.6 — 2023-03-25
- Fixed bug with rename manager path
- Fixed bug with week day check
1.4.5 — 2023-03-17
- Fixed bug on remove additional objects
1.4.4 — 2023-02-25
- Аdded output of information about the discount
- Fixed bug with clearing the resource field
- Fixed the error of multiple application of discounts
- Added automatic activation and deactivation of discounts
- Changed the minimum validity period to 1 hour
- Fixed bug Clean button
Added
- session cleanup
1.4.3 — 2022-12-26
Fixed some bugs
1.4.2 — 2022-12-25
Fixed some bugs
Added
- Support for ajax pagination in pdoPage
1.4.1 — 2022-12-24
Added
- JS Event mspd-get-discounts
- Processor GetProductDiscountsProcessor
- Reload cart interval
Removed
- Snippet getProductDiscounts
1.3.1 — 2022-12-04
Added
- Mass deletion of conditions
Changed
- Fixed a bug with updating the cart
1.2.3 — 2022-12-04
Added
- "discount_price" parameter to the getProductDiscounts snippet
- Bread crumbs for categories
Changed
- Product search
- Build package
1.2.0 — 2022-12-03
Added
- Search for products with msearch2 if it is installed
- Category tree
- Processors: /mgr/products/, /mgr/exproducts/, /mgr/categories/ and /mgr/excategories/
Changed
- Selecting a resource with a description of the discount
Removed
- Some modal windows on discount manage page
- Processors: /mgr/product/, /mgr/exproduct/, /mgr/category/ and /mgr/excategory/
1.0.1 — 2022-12-01
- Initial release.




Последние обсуждения в сообществе MODX.pro