
- MODX 3
- PHP 8.2
- miniShop3


После [[!msFastOrder]] браузер получает скрипты, window.msfoConfig, форму в модалке и AJAX.
Сниппет msFastOrder при каждом вызове:
msProduct).tplBtn, по умолчанию msfo_button).{msfastorder_assets_url}css/msfo.min.css?v={mtime}.{msfastorder_assets_url}js/msfo.min.js?v={mtime} (версия по mtime файла при обновлении через ModStore).window.msfoConfig с CSRF (ClientConfig::getConfigScript()).Плагин msfastorder_web (события OnLoadWebPageCache, OnWebPagePrerender) удаляет застывший конфиг из кэша страницы и подставляет свежий window.msfoConfig перед msfo.min.js.
Опционально на шаблоне можно вывести сниппет msFastOrderClientConfig — тот же ClientConfig::getConfigScript() без кнопки.
Генерируется классом MsFastOrder\ClientConfig (PHP). Пример структуры:
{
connectorUrl: '/assets/components/msfastorder/connector.php',
csrfToken: '64hex...',
modalLibrary: 'native', // native | bootstrap | fancybox
phoneMask: '+7 (999) 999-99-99',
successRedirect: '', // URL или пусто
copyCount: true, // msfastorder_copy_count
requiredFields: ['receiver', 'phone'], // те же поля, что msfastorder_required_fields
lexicon: {
modal_title: '...',
submit_button: '...',
field_receiver: '...',
field_phone: '...',
error_required: 'Поле "[[+field]]" обязательно...',
error_rate_limit: '...',
total: 'Итого',
currency: '₽',
// ...
}
}Расширение до загрузки msfo.min.js (или после сниппета, если скрипт ниже):
<script>
window.msfoConfig = Object.assign(window.msfoConfig || {}, {
successRedirect: '/spasibo/',
modalLibrary: 'fancybox'
});
</script><script>
window.msfoConfig = Object.assign(window.msfoConfig || {}, {
successRedirect: '/spasibo/',
modalLibrary: 'fancybox'
});
</script>| Поле | Источник (настройка MODX) |
|---|---|
connectorUrl | msfastorder_connector_url |
modalLibrary | msfastorder_modal_library |
phoneMask | msfastorder_phone_mask |
successRedirect | msfastorder_success_redirect |
requiredFields | msfastorder_required_fields (JS ставит required и валидирует) |
copyCount | msfastorder_copy_count |
lexicon.* | lexicon msfastorder:* (ключ order_number в конфиг не попадает — на экране успеха подпись номера может остаться «Order») |
Доступен после msfo.min.js: window.msFastOrder.
| Метод | Описание |
|---|---|
openOrderModal(productId) | Загрузить товар, открыть модалку с формой |
closeModal() | Закрыть текущую модалку |
getModalLibrary() | Текущая библиотека (native / bootstrap / fancybox) |
setModalLibrary(name) | Переключить библиотеку; при отсутствии BS/Fancybox — запасной вариант native |
on(event, callback) | Подписка на EventBus |
off(event, callback) | Отписка |
Обязательные атрибуты (делегирование клика на document):
| Атрибут | Обязательно | Описание |
|---|---|---|
data-msfo-trigger | да | Маркер кнопки быстрого заказа |
data-msfo-product-id | да | ID ресурса-товара MS3 |
Опционально:
| Атрибут / класс | Описание |
|---|---|
msfo-trigger--primary | Стиль кнопки (&primary=1 в сниппете) |
Нужно, когда кнопка «в 1 клик» не из сниппета msFastOrder: своя вёрстка в каталоге, ссылка «Купить сейчас», виджет, сравнение товаров, открытие из другого скрипта.
| Условие | Зачем |
|---|---|
Подключены msfo.min.css и msfo.min.js | Модалка и AJAX |
На странице есть window.msfoConfig с csrfToken и connectorUrl | Запросы к connector |
Загружен msfo.min.js до вызова API | Иначе msFastOrder ещё не создан |
Конфиг и CSRF дают:
[[!msFastOrder]] на этой же странице (кнопка необязательна, но сниппет подключает assets и конфиг), или[[!msFastOrderClientConfig]] + ручное подключение CSS/JS в шаблоне — см. msFastOrderClientConfig.Без свежего CSRF запросы вернут 403. На кэшируемых страницах помогает плагин msfastorder_web.
openOrderModal(productId) // productId — ID ресурса msProduct (число или строка)
await window.msFastOrder.openOrderModal(123);| Параметр | Тип | Описание |
|---|---|---|
productId | number | string | ID товара MODX (msProduct) для action=product/get |
Метод асинхронный (async). Явного return с результатом нет: при ошибке загрузки товара показывается alert() с текстом из ответа connector.
Закрыть модалку программно: msFastOrder.closeModal().
modal:beforeLoad / msfo:modal:beforeLoad — { productId }.product/get (токен из msfoConfig.csrfToken).success: false — alert, модалка не открывается.MiniShop3Integration.copyFromProductPage(productId) — со страницы берутся count (класс msfastorder-count-{id} или input[name="count"]) и options (форма .ms3variants-product-{id}).renderForm(), модалка открывается (modal:beforeOpen → modal:open).FormHandler (маска телефона, submit, success).modal:loaded — { productId, product, form } (form — элемент .msfo-form или null, если форма не нашлась за ~3 с). Точка для правки DOM формы.Полный список событий: События JavaScript.
В layout один раз — конфиг и assets. На карточке — только разметка и вызов API.
{* head / footer шаблона *}
{'!msFastOrderClientConfig' | snippet}
<link rel="stylesheet" href="{'assets_url' | option}components/msfastorder/css/msfo.min.css">
<script src="{'assets_url' | option}components/msfastorder/js/msfo.min.js"></script>
{* карточка товара или каталог *}
<button type="button" class="btn-buy-now" data-fast-order-id="{$id}">
Купить в 1 клик
</button>
<script>
document.addEventListener('click', function (e) {
var btn = e.target.closest('[data-fast-order-id]');
if (!btn || !window.msFastOrder) return;
e.preventDefault();
window.msFastOrder.openOrderModal(btn.getAttribute('data-fast-order-id'));
});
</script>[[!msFastOrderClientConfig]]
<link rel="stylesheet" href="[[++assets_url]]components/msfastorder/css/msfo.min.css">
<script src="[[++assets_url]]components/msfastorder/js/msfo.min.js"></script>
<button type="button" class="btn-buy-now" data-fast-order-id="[[+id]]">
Купить в 1 клик
</button>
<script>
document.addEventListener('click', function (e) {
var btn = e.target.closest('[data-fast-order-id]');
if (!btn || !window.msFastOrder) return;
e.preventDefault();
window.msFastOrder.openOrderModal(btn.getAttribute('data-fast-order-id'));
});
</script>Эквивалент без отдельного скрипта — атрибуты msFastOrder (делегирование встроено в msfo.js):
<button type="button" class="msfo-trigger" data-msfo-trigger data-msfo-product-id="{$id}">
Купить в 1 клик
</button><button type="button" class="msfo-trigger" data-msfo-trigger data-msfo-product-id="[[+id]]">
Купить в 1 клик
</button>На странице при этом всё равно нужен вызов msFastOrder или msFastOrderClientConfig (CSRF).
Открытие после выбора варианта (синхронизация _variant_id → variant_id перед загрузкой):
document.addEventListener('msfo:modal:beforeLoad', function () {
var src = document.querySelector('input[name="_variant_id"]');
var dst = document.querySelector('input[name="variant_id"], input[name="ms3variant_id"]');
if (src && dst && src.value) dst.value = src.value;
});Проверка, что API готов (скрипт в конце страницы):
document.addEventListener('DOMContentLoaded', function () {
if (!window.msFastOrder || typeof msFastOrder.openOrderModal !== 'function') {
console.warn('[msFastOrder] msfo.min.js или msfoConfig не подключены');
}
});Открытие с карточки в каталоге — productId из data-атрибута строки. На странице списка задайте поле count с классом msfastorder-count-{id} для каждого товара (см. Быстрый старт).
Смена библиотеки модалки на лету (если на странице есть bootstrap.Modal или Fancybox):
msFastOrder.setModalLibrary('bootstrap'); // или 'fancybox', 'native'
msFastOrder.openOrderModal(42);| Симптом | Причина |
|---|---|
msFastOrder is not defined | msfo.min.js не подключён или вызов до его загрузки |
403 в Network на connector.php | Нет свежего csrfToken — добавьте сниппет на страницу или проверьте msfastorder_web |
alert при открытии | Товар не msProduct, неверный productId, ошибка connector — смотрите JSON ответа |
| Неверное количество / вариант | Нет формы ms3variants-product-{id} или класса msfastorder-count-{id} на странице |
См. также: FAQ, Интеграция, Сниппет msFastOrder.
По умолчанию HTML формы не берётся из чанка msfo_form на сервере. Его собирает JavaScript — метод MsFastOrder.renderForm() в msfo.js (после product/get).
| Чанк / шаблон | Используется в рантайме по умолчанию |
|---|---|
msfo_button | Да (сниппет) |
msfo_form | Нет (эталон для копирования; правки только в чанке не изменят модалку) |
msfo_success | Нет (success рисуется FormHandler.renderSuccess() в JS) |
msfo_modal | Нет (оболочка создаётся ModalManager) |
msfo_email_* | Да (только режим MAIL) |
Чтобы изменить форму на фронте без правки ядра пакета:
msfo:modal:loaded меняйте DOM формы (добавление полей, разметка, валидация на клиенте).msfo:form:submit и дополняйте отправку (UTM, метки) — см. События JavaScript.msfo_form / msfo_success (Чанки). Сами чанки в стандартном потоке на сервере не подставляются.order/create) name | Тип | Описание |
|---|---|---|
product_id | hidden | ID товара |
count | number | Количество, min 1 |
options | hidden, JSON | { "variant_id": N, "color": "...", ... } |
receiver | text | ФИО |
phone | tel | Телефон (маска PhoneMask) |
email | ||
city | text | Город |
comment | textarea | Комментарий |
Устаревшее: count_display — если есть, JS подменяет на count перед отправкой.
count в модалке; пересчёт Итого = data-unit-price × count (см. [data-msfo-order-total]).MiniShop3Integration.copyFromProductPage): input.msfastorder-count-{productId};input[name="count"] (на каталоге может быть чужой товар — задавайте класс с ID).При msfastorder_copy_count=Нет (copyCount: false в msfoConfig) количество в модалке всегда 1, со страницы не копируется.
Ищется форма:
.ms3variants-product-{productId}
.ms3_form[data-product-id="{productId}"]Из неё читаются:
input[name="ms3variant_id"] или input[name="variant_id"] → options.variant_id;input[name^="options["] → ключи в options.Итог уходит в hidden options как JSON, например:
{"variant_id": 42, "options": {"color": "red"}}или плоский объект опций — сервер нормализует в OrderProcessor::parseOptions().
Подробнее: Интеграция → ms3Variants.
novalidate на форме — браузерная валидация отключена.required и клиентская проверка идут по списку msfoConfig.requiredFields (тот же, что msfastorder_required_fields).formatRequiredError() подставляет подпись из msfoConfig.lexicon.field_*.Все запросы: POST, Content-Type: application/x-www-form-urlencoded, поле csrf_token обязательно.
| action | Кто вызывает | Назначение |
|---|---|---|
product/get | ProductLoader.load | Данные товара для модалки |
order/create | FormHandler.sendRequest | Создание заказа |
order/validate | вручную / тесты | Проверка без заказа |
rate-limit/reset | только при msfastorder_debug | Сброс лимита в сессии |
При HTTP 429 показывается lexicon.error_rate_limit.
Полное описание ответов: AJAX API.
После order/create с success: true:
order:success (и msfo:order:success).renderSuccess(data) (не чанк msfo_success).successRedirect: data.payment_link — редирект на оплату через ~2 с;successRedirect.Кнопка «Оплатить» появляется при непустом data.payment_link.
msfastorder_modal_library | Зависимости на странице |
|---|---|
native | нет |
bootstrap | глобальный bootstrap.Modal |
fancybox | window.Fancybox; подключайте msfo.min.css после CSS Fancybox |
ModalManager блокирует скролл страницы (msfo-modal-open на body/html) и снимает блокировку при closeModal() / closeAll().
Файл: assets/components/msfastorder/css/msfo.min.css.
Переопределение переменных в теме:
:root {
--msfo-primary: #007bff;
--msfo-modal-radius: 8px;
--msfo-gray-300: #dee2e6;
}Классы ошибок: msfo-field--error, msfo-field__error, msfo-form__error.
После успешного MS-заказа вызывается MiniShop3Integration.reinitCart() (ms3:cart:updated). Полный список и payload: События JavaScript.