MiniShop3 1.11.0
Вышел MiniShop3 1.11.0-beta1 — крупный релиз: 26 смерженных PR с прошлого релиза, три breaking change, новая модель группировки опций, явный пересчёт стоимости заказа в админке, новое JS событие для интеграции с компонентами и заметные правки в работе сниппетов.
Раньше для группировки опций товара использовалась системная категория MODX (modCategory). В выпадающем списке группы при создании опции висели категории всех компонентов, плюс группы TV-полей, плюс ваши собственные — каша. Управлять сортировкой через дерево категорий MODX тоже неудобно.
Теперь это собственная модель msOptionGroup. В админке появилась отдельная вкладка «Группы опций» рядом с «Опциями»: создание, редактирование, удаление, перетаскивание для сортировки, счётчик опций в каждой группе. Список групп в форме редактирования опции сразу подтягивается из новой модели — никаких посторонних категорий.

Если вы раньше уже создавали опции с категориями, предусмотрена автоматическая миграция данных.
Для каждой уникальной modcategory_id, на которую ссылались опции, миграция создаёт запись в ms3_option_groups с именем из самой modCategory. Старая колонка modcategory_id удаляется.
Параллельно переписано дерево категорий в форме привязки опции (#237): раньше оно показывало пустоту, если ваши msCategory лежали не сразу под корнем сайта, а под каким-нибудь контейнером каталога. Теперь дерево возвращает msCategory как выбираемые узлы плюс контейнеры с isfolder=1 — как навигационные (italic, без чекбокса). Работает для вложенных структур и мульти-магазинных конфигураций из коробки, без системных настроек.

Это правка, которая давно просилась. Раньше плейсхолдеры цен и веса в сниппетах возвращали готовую строку с локалью и валютой — например, 5 300 ₽. Использовать такой плейсхолдер в условии типа {if $order.cost > 1000} было нельзя, выражение всегда было ложным.
Теперь плейсхолдер без суффикса — это всегда число (float) для арифметики и Fenom-фильтра |number. Готовая строка с локалью / валютой / единицей живёт в полях *_formatted. Перечень:
Что нужно проверить в кастомных шаблонах: если вы выводили один из этих плейсхолдеров рассчитывая на готовую строку — замените на одноимённый с суффиксом _formatted. Если использовали для арифметики или условий — оставьте как есть, теперь работает правильно. Параметры сниппета formatPrices (в msProducts и msOrderTotal) больше ничего не делают — оставлены для совместимости.
Менеджер открывает заказ, меняет способ доставки или оплаты — а цена остаётся прежней. Приходилось править руками или сохранять и надеяться, что не сломается интеграция с CDEK / Яндекс.Доставкой (которые делают API-запрос и могут упасть).
Появилась кнопка «Пересчитать стоимость» на вкладке «Информация» заказа. Endpoint POST /api/mgr/orders/{id}/recalculate-cost работает в трёх режимах. В режиме auto пересчёт идёт по полям только для стандартных DefaultDelivery / DefaultPayment — внешние провайдеры не дёргаются, при кастомном handler-классе возвращается предупреждение «нужно вручную». Режим manual принимает оператор-указанную стоимость доставки. Режим force_provider явно вызывает провайдера в try/catch — если упал, прежняя стоимость не затирается.
Учитывает скидки/наценки доставки и оплаты (отрицательные значения, см. ниже) и финальную защиту от ухода итога в минус.

Поле «Доп. стоимость» способа доставки и оплаты теперь принимает отрицательные значения и проценты: -100, -5%. Это удобно для скидок за самовывоз, бонусов за безналичную оплату, акций. В админке у поля появляется реактивный бейдж — «Скидка» (зелёный) для отрицательных или «Наценка» (серый) для положительных, чтобы менеджер на знаке не ошибся.
Параллельно ввели защиту: OrderService::clampComputedTotal() при сборке итога обнуляет cost, если сумма ушла в минус, и пишет в журнал MODX предупреждение с разбивкой по слагаемым. Применяется во всех точках расчёта — оформление, черновик, финализация, менеджерский пересчёт.
Знакомая ситуация: на странице каталога стоит mFilter (или другой компонент, который перерисовывает товары через AJAX). После применения фильтра в карточках перестают работать кнопка «В корзину» и ±. Приходится перезагружать страницу.
В новой версии достаточно одной строки в шаблоне каталога, чтобы это починилось:
Раньше для этого приходилось руками вызывать внутренние методы MS3 (которые могли меняться от версии к версии). Теперь это публичный API — стабильный контракт, на который можно опираться.
Огромная благодарность @Иван Бочкарев — большая часть PR этого цикла прошла через его руки, а также @Алексей Шумаев, который активно включился в тестирование и публикацию проблем
Полный список изменений — в CHANGELOG. Релиз с собранным транспортным пакетом — v1.11.0-beta1.
Я наконец более-менее доволен полученным продуктом и решился опубликовать его в официальном репозитории MODX.com — через несколько дней компонент будет доступен еще и там.
Багрепорты и предложения — в issues, обсуждения — здесь.
Группы опций — собственная модель вместо modCategory (#10)
Раньше для группировки опций товара использовалась системная категория MODX (modCategory). В выпадающем списке группы при создании опции висели категории всех компонентов, плюс группы TV-полей, плюс ваши собственные — каша. Управлять сортировкой через дерево категорий MODX тоже неудобно.
Теперь это собственная модель msOptionGroup. В админке появилась отдельная вкладка «Группы опций» рядом с «Опциями»: создание, редактирование, удаление, перетаскивание для сортировки, счётчик опций в каждой группе. Список групп в форме редактирования опции сразу подтягивается из новой модели — никаких посторонних категорий.

Если вы раньше уже создавали опции с категориями, предусмотрена автоматическая миграция данных.
Для каждой уникальной modcategory_id, на которую ссылались опции, миграция создаёт запись в ms3_option_groups с именем из самой modCategory. Старая колонка modcategory_id удаляется.
Параллельно переписано дерево категорий в форме привязки опции (#237): раньше оно показывало пустоту, если ваши msCategory лежали не сразу под корнем сайта, а под каким-нибудь контейнером каталога. Теперь дерево возвращает msCategory как выбираемые узлы плюс контейнеры с isfolder=1 — как навигационные (italic, без чекбокса). Работает для вложенных структур и мульти-магазинных конфигураций из коробки, без системных настроек.

Числовой контракт сниппетов витрины (#242, breaking)
Это правка, которая давно просилась. Раньше плейсхолдеры цен и веса в сниппетах возвращали готовую строку с локалью и валютой — например, 5 300 ₽. Использовать такой плейсхолдер в условии типа {if $order.cost > 1000} было нельзя, выражение всегда было ложным.
Теперь плейсхолдер без суффикса — это всегда число (float) для арифметики и Fenom-фильтра |number. Готовая строка с локалью / валютой / единицей живёт в полях *_formatted. Перечень:
- msProducts (на каждый товар): price, old_price, weight
- msCart (на позицию корзины): price, old_price, cost, old_cost, discount_price, discount_cost, weight
- msCart (total): cost, count, weight, discount, positions
- msOrder: cost, cart_cost, delivery_cost, discount_cost
- msOrderTotal: cost, cart_cost, delivery_cost, payment_cost, total_cost, total_discount, total_weight
- msGetOrder (на позицию): price, old_price, cost, discount_price, discount_cost, weight
- msGetOrder (total): cost, cart_cost, delivery_cost, weight, cart_weight, cart_discount
Что нужно проверить в кастомных шаблонах: если вы выводили один из этих плейсхолдеров рассчитывая на готовую строку — замените на одноимённый с суффиксом _formatted. Если использовали для арифметики или условий — оставьте как есть, теперь работает правильно. Параметры сниппета formatPrices (в msProducts и msOrderTotal) больше ничего не делают — оставлены для совместимости.
Пересчёт стоимости заказа в админке (#212)
Менеджер открывает заказ, меняет способ доставки или оплаты — а цена остаётся прежней. Приходилось править руками или сохранять и надеяться, что не сломается интеграция с CDEK / Яндекс.Доставкой (которые делают API-запрос и могут упасть).
Появилась кнопка «Пересчитать стоимость» на вкладке «Информация» заказа. Endpoint POST /api/mgr/orders/{id}/recalculate-cost работает в трёх режимах. В режиме auto пересчёт идёт по полям только для стандартных DefaultDelivery / DefaultPayment — внешние провайдеры не дёргаются, при кастомном handler-классе возвращается предупреждение «нужно вручную». Режим manual принимает оператор-указанную стоимость доставки. Режим force_provider явно вызывает провайдера в try/catch — если упал, прежняя стоимость не затирается.
Учитывает скидки/наценки доставки и оплаты (отрицательные значения, см. ниже) и финальную защиту от ухода итога в минус.

Отрицательные стоимости доставки и оплаты (#211, #265)
Поле «Доп. стоимость» способа доставки и оплаты теперь принимает отрицательные значения и проценты: -100, -5%. Это удобно для скидок за самовывоз, бонусов за безналичную оплату, акций. В админке у поля появляется реактивный бейдж — «Скидка» (зелёный) для отрицательных или «Наценка» (серый) для положительных, чтобы менеджер на знаке не ошибся.
Параллельно ввели защиту: OrderService::clampComputedTotal() при сборке итога обнуляет cost, если сумма ушла в минус, и пишет в журнал MODX предупреждение с разбивкой по слагаемым. Применяется во всех точках расчёта — оформление, черновик, финализация, менеджерский пересчёт.
Поддержка интеграций с фильтрами и AJAX-пагинацией (#274)
Знакомая ситуация: на странице каталога стоит mFilter (или другой компонент, который перерисовывает товары через AJAX). После применения фильтра в карточках перестают работать кнопка «В корзину» и ±. Приходится перезагружать страницу.
В новой версии достаточно одной строки в шаблоне каталога, чтобы это починилось:
document.addEventListener('mfilter:contentLoaded', () => window.ms3?.refresh?.())Для любого другого компонента (mFilter, ваш собственный AJAX, бесконечный скролл) — подпишитесь на то событие, которое он диспатчит после замены HTML каталога, и вызовите внутри window.ms3.refresh(). Логика везде одна: «вы заменили карточки → скажите MiniShop3 пересобрать к ним обработчики». Метод делает всё остальное сам.Раньше для этого приходилось руками вызывать внутренние методы MS3 (которые могли меняться от версии к версии). Теперь это публичный API — стабильный контракт, на который можно опираться.
Прочие фиксы релиза
- Дублирование товаров в выдаче msProducts/msCart/msGetOrder при includeThumbs — фиксированный JOIN превью одного главного фото вместо размножения по галерее (#281).
- Очистка числового поля в форме доставки или оплаты теперь сохраняется — раньше isset-проверка пропускала null от PrimeVue InputNumber.
- Опции товара при дублировании ресурса через контекстное меню MODX корректно копируются в новый товар (#257).
- Опции товара не обнуляются при сохранении формы без вкладки «Опции» (#199 follow-up).
- События с мутацией данных через returnedValues теперь работают для msOnBeforeSendNotification, msOnBeforeImport, msOnImportRow, msOnProductsLoad, msOnProductPrepare и ряда других (#219, #221).
- Сниппет msCart на странице «спасибо» больше не возвращает пустую строку по умолчанию — мини-корзина в общем layout продолжает работать. Поведение возвращается через параметр hideOnThanks=1 (#249).
- Подтверждение email на витрине — ссылка из письма ведёт на Web API, повторная отправка из ЛК работает (#226).
- Web API покупателя получил недостающие маршруты customer/add и customer/changeAddress (#241), быстрый профиль поддерживает кастомные поля через msExtraField (#261).
- Phinx defensive checks из 1.10.x-эры наконец-то реально работают — была регрессия с двойным префиксом таблицы, из-за которой seed-миграции на свежих установках уходили в no-op везде (#276).
- Импорт товаров поддерживает поле «Остаток на складе» в маппинге (#283), с автоподстановкой типичных названий CSV-колонок (stock / remains / quantity / qty).
- Редактор правил валидации доставки подтягивает поля msOrder и msOrderAddress из «Полей админки» и Object Extension — раньше был захардкоженный список (#215).
Спасибо контрибьюторам
Огромная благодарность @Иван Бочкарев — большая часть PR этого цикла прошла через его руки, а также @Алексей Шумаев, который активно включился в тестирование и публикацию проблем
Что дальше
Полный список изменений — в CHANGELOG. Релиз с собранным транспортным пакетом — v1.11.0-beta1.
Я наконец более-менее доволен полученным продуктом и решился опубликовать его в официальном репозитории MODX.com — через несколько дней компонент будет доступен еще и там.
Багрепорты и предложения — в issues, обсуждения — здесь.
Поблагодарить автора
Отправить деньги
Комментарии: 7
Спасибо за проделанную работу! MODX заиграл новыми красками и становится актуальнее.
issues со статусом bug будут закрыты до релиза, как я понимаю? )
Там есть критичные.
issues со статусом bug будут закрыты до релиза, как я понимаю? )
Там есть критичные.
Все баги обрабатываются можно сказать на ежедневной основе, всем багам и улучшениям будет уделено внимание!
Не стесняйтесь писать комментарии, создавать issue — мы все видим и обрабатываем.
Не стесняйтесь писать комментарии, создавать issue — мы все видим и обрабатываем.
Единственное, что хотелось бы добавить:
Open Source живёт благодаря вам
MiniShop3 развивается силами сообщества. Если новый релиз и предыдущие обновления оказались полезны — поддержите проект вашими донатами.
Все наши реквизиты есть на специальной странице modx.pro/about
Open Source живёт благодаря вам
MiniShop3 развивается силами сообщества. Если новый релиз и предыдущие обновления оказались полезны — поддержите проект вашими донатами.
Все наши реквизиты есть на специальной странице modx.pro/about
MODX 3.1.2, при попытке обновить miniShop3 до последней версии. Весь запрос длинный очень, но там в поле metadata действительно что-то очень длинное )
INSERT INTO `modx_transport_packages`…
Array
(
[0] => 22001
[1] => 1406
[2] => Data too long for column 'metadata' at row 1
)
INSERT INTO `modx_transport_packages`…
Array
(
[0] => 22001
[1] => 1406
[2] => Data too long for column 'metadata' at row 1
)
Чисто для себя, какой промт формирует такой issue?
У меня нет промта, я просто захожу в папку с исходниками — кидаю ссылку на проблему, пишу создай issue и указываю github.com/modx-pro/MiniShop3/blob/beta/.github/ISSUE_TEMPLATE/bug_report.md и все
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.