Привет, коллеги. Меня зовут Александр Фролов, я 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 до полного отказа обработки форм.

Вот почему важно перед обновлением:

  1. Проверить, какие компоненты используются на сайте. Если вы видите в вызовах [[!AjaxForm?]] или [[!FetchIt?]], это красный флаг.
  2. Решить, что делать с существующими формами. У вас есть два пути:
    • Миграция на нативный AJAX FormIt. Это правильный, долгосрочный путь. Вы убираете зависимость от сторонних компонентов и получаете поддержку из коробки.
    • Откат до старой версии FormIt. Если миграция сейчас невозможна, придется остаться на старых версиях. Но это тупик, потому что старые версии не получают обновлений безопасности.
  3. Удалить 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 — это будущее. И это будущее уже наступило.

Если у вас есть вопросы или вы столкнулись с проблемами при миграции — пишите, разберемся вместе.