Привет, коллеги. Меня зовут Александр Фролов, я Fullstack-разработчик в веб-студия «Цифра два» и с MODX работаю уже больше 12 лет. За это время я пережил, пожалуй, все крупные эволюции компонентов экосистемы. И вот, наконец-то, свершилось то, чего многие из нас ждали годами: FormIt получил нативную поддержку AJAX.
Но, как это часто бывает с фундаментальными изменениями, есть и обратная сторона: если вы обновляетесь со старой версии FormIt и на сайте были установлены AjaxForm или FetchIt, ваш сайт может просто «лечь». Давайте разберемся, почему так происходит и что с этим делать.
Что такое FormIt и почему он так важен
FormIt — это, без преувеличения, краеугольный камень MODX. Это динамический сниппет для обработки форм, который выполняет валидацию, отправку почты и другие действия после сабмита. Он не создает форму, а обрабатывает ее. Впервые он был выпущен еще в далеком 2009 году Шоном Маккормиком и с тех пор поддерживается командой Sterc.
Долгое время FormIt работал исключительно через стандартный механизм браузера — с перезагрузкой страницы. Это было надежно, просто и предсказуемо. Но мир менялся, и пользователи хотели отправлять формы «на лету», без перезагрузки. Так появились отдельные компоненты-прослойки.
Эра костылей: AjaxForm и FetchIt
Долгое время в MODX существовала странная ситуация: FormIt не умел работать через AJAX, и для этого приходилось использовать сторонние решения. Давайте вспомним каждого из них.
AjaxForm: старый добрый ветеран
AjaxForm — это, пожалуй, самый известный компонент для AJAX-отправки форм в MODX. Он работал как прослойка между формой и FormIt.
Принцип работы был прост: AjaxForm подключал jQuery, плагин jQuery.Form и jGrowl для уведомлений, перехватывал сабмит формы и отправлял данные через AJAX на специальный коннектор action.php.
Вызов выглядел примерно так:
[[!AjaxForm?
&form=`myFormTpl`
&snippet=`FormIt`
&hooks=`email`
&emailTo=`info@example.com`
]]
Сам компонент был довольно прожорливым: он тащил за собой jQuery и два плагина. Для своего времени это было нормально, но с приходом современных стандартов стало выглядеть тяжеловесно.
И вот, что важно: 13 июня 2023 года команда MODX RSC официально прекратила поддержку AjaxForm, рекомендовав всем переходить на FetchIt. Это был первый звонок.
FetchIt: современная альтернатива
FetchIt появился как ответ на запросы времени. Это легковесный компонент (всего около 5 КБ в минифицированном виде), который использует современный Fetch API вместо jQuery.
FetchIt на серверной стороне по-прежнему использует FormIt, но на клиенте работает на чистом JavaScript, без зависимостей. Он регистрирует свой скрипт с атрибутом defer, чтобы не блокировать загрузку страницы.
Вызов FetchIt выглядит так:
[[!FetchIt?
&form=`myFormTpl`
&snippet=`FormIt`
&hooks=`email`
&emailTo=`info@example.com`
&actionUrl=[[+assetsUrl]]action.php
&clearFieldsOnSuccess=`1`
]]
Разметка формы должна соответствовать определенным требованиям: селекторы ошибок должны быть [data-error="name"], а класс ajax_form больше не нужен — сниппет сам ставит data-fetchit.
FetchIt также имеет встроенную защиту от спама, включая токены, проверку времени заполнения, ловушки для ботов и rate limiting.
Но, несмотря на все свои преимущества, FetchIt оставался сторонним компонентом. А это значит: дополнительная точка отказа, необходимость следить за совместимостью, еще один слой абстракции.
FormIt 5.2: AJAX из коробки
И вот, наконец, случилось то, чего мы ждали. В версиях FormIt 5.2.0 и 5.2.1 появилась встроенная поддержка AJAX-отправки форм. Теперь никаких сторонних компонентов не нужно.
Как это работает?
Сниппет FormIt сохраняет свою конфигурацию (хуки, правила валидации и т.д.) в сессии или кэше и выводит токен в плейсхолдер [[!+fi.ajaxToken]]. Вы размещаете этот токен в атрибуте data-formit-ajax-token на теге <form>.
JavaScript-библиотека FormIt автоматически инициализирует все формы с этим атрибутом. При отправке формы JS перехватывает сабмит, отправляет данные через Fetch API на action.php, получает JSON-ответ и обновляет DOM: отображает ошибки полей, сообщения об успехе или выполняет редирект.
Вызов сниппета остается практически таким же, как для обычной формы:
[[!FormIt?
&hooks=`email,redirect`
&emailTpl=`MyEmailChunk`
&emailTo=`user@example.com`
&redirectTo=`123`
&validate=`name:required,
email:email:required,
subject:required,
text:stripTags`
]]
А разметка формы требует добавления специальных атрибутов:
<form action="[[~[[*id]]]]" method="post"
data-formit-ajax-token="[[!+fi.ajaxToken]]">
<div data-formit-validation-error-message>[[!+fi.validation_error_message]]</div>
<div data-formit-success-message>[[!+fi.successMessage]]</div>
<input type="text" name="name" value="[[!+fi.name]]" />
<span data-formit-error="name">[[!+fi.error.name]]</span>
<input type="text" name="email" value="[[!+fi.email]]" />
<span data-formit-error="email">[[!+fi.error.email]]</span>
<input type="submit" value="Отправить" />
</form>
Атрибут action остается как запасной вариант для случаев, когда JavaScript отключен. Без атрибута data-formit-ajax-token форма работает в обычном режиме — обратная совместимость полная.
Также в 5.2.1 обновлен хук recaptcha: он перешел с устаревшей reCAPTCHA v1 на современную v3.
Почему обновление может «положить» сайт
А теперь самое важное, и это, собственно, главная причина, по которой я пишу эту статью.
Если у вас на сайте установлены AjaxForm или FetchIt, и вы обновляете FormIt до версии 5.2, сайт может перестать работать. И вот почему.
Все три компонента — AjaxForm, FetchIt и новый FormIt — используют один и тот же коннектор action.php и один и тот же механизм обработки. Когда вы обновляете FormIt, вы обновляете и серверную логику, которая используется всеми компонентами.
Старые версии AjaxForm и FetchIt были написаны в расчете на старую архитектуру FormIt. После фундаментальной переработки в 5.2 они перестают быть совместимыми. Конфликты могут проявляться по-разному: от ошибок PHP до полного отказа обработки форм.
Вот почему важно перед обновлением:
- Проверить, какие компоненты используются на сайте. Если вы видите в вызовах
[[!AjaxForm?]]или[[!FetchIt?]], это красный флаг. - Решить, что делать с существующими формами. У вас есть два пути:
- Миграция на нативный AJAX FormIt. Это правильный, долгосрочный путь. Вы убираете зависимость от сторонних компонентов и получаете поддержку из коробки.
- Откат до старой версии FormIt. Если миграция сейчас невозможна, придется остаться на старых версиях. Но это тупик, потому что старые версии не получают обновлений безопасности.
- Удалить AjaxForm и FetchIt после миграции. Если вы перешли на нативный AJAX, старые компоненты нужно деинсталлировать, чтобы они не создавали конфликтов.
Как мигрировать на нативный AJAX
Процесс миграции с AjaxForm или FetchIt на новый FormIt не слишком сложен, но требует внимательности.
Шаг 1: Обновить FormIt
Обновите FormIt до версии 5.2.0 или выше через Управление пакетами.
Шаг 2: Заменить вызовы сниппетов
Вместо:
[[!AjaxForm?
&form=`myFormTpl`
&snippet=`FormIt`
&hooks=`email`
]]
Или:
[[!FetchIt?
&form=`myFormTpl`
&snippet=`FormIt`
&hooks=`email`
]]
Используйте:
[[!FormIt?
&hooks=`email`
&emailTpl=`MyEmailChunk`
&emailTo=`info@example.com`
&validate=`name:required,email:email:required`
]]
Обратите внимание: параметры form и snippet больше не нужны. FormIt теперь сам знает, как обрабатывать форму.
Шаг 3: Обновить разметку формы
Добавьте на тег <form> атрибут с токеном:
<form action="[[~[[*id]]]]" method="post"
data-formit-ajax-token="[[!+fi.ajaxToken]]">
Замените старые селекторы ошибок на новые:
Было (AjaxForm):
<span class="error_name">[[+fi.error.name]]</span>
Стало:
<span data-formit-error="name">[[!+fi.error.name]]</span>
Было (FetchIt):
<span data-error="name">[[+fi.error.name]]</span>
Стало:
<span data-formit-error="name">[[!+fi.error.name]]</span>
Добавьте контейнеры для сообщений:
<div data-formit-validation-error-message>[[!+fi.validation_error_message]]</div>
<div data-formit-success-message>[[!+fi.successMessage]]</div>
Шаг 4: Настроить системные настройки
Убедитесь, что системная настройка formit.frontend_js установлена в значение js/web/formit.js. Это включит автоматическое подключение JavaScript-файла FormIt.
Если вы хотите использовать свой JS-файл или отключить автоматическое подключение, измените эту настройку.
Шаг 5: Удалить старые компоненты
После успешной миграции деинсталлируйте AjaxForm и FetchIt через Управление пакетами. Это уберет их файлы и настройки, которые могут конфликтовать с новым FormIt.
Заключение
FormIt 5.2 — это огромный шаг вперед для экосистемы MODX. Наконец-то у нас есть нативная поддержка AJAX, современный подход к обработке форм и обновленный хук recaptcha.
Но, как и любое крупное обновление, оно требует внимания при миграции. Если вы используете AjaxForm или FetchIt, не обновляйтесь вслепую. Проверьте формы, проведите миграцию, убедитесь, что все работает.
Помните: AjaxForm официально мертв, FetchIt — это прошлый этап эволюции, а FormIt 5.2 — это будущее. И это будущее уже наступило.
Если у вас есть вопросы или вы столкнулись с проблемами при миграции — пишите, разберемся вместе.