FormIt — это мощный компонент MODX Revolution для создания и обработки форм любой сложности. От простой формы обратной связи до сложных многошаговых анкет — FormIt справится со всеми задачами благодаря гибкой системе валидации, хуков обработки и защиты от спама.
Что такое FormIt и зачем он нужен
FormIt — это процессор форм, который обрабатывает данные на серверной стороне, проводит валидацию и выполняет различные действия с полученными данными: отправка email, сохранение в базе данных, интеграция с внешними API.
Ключевые возможности
- Валидация данных — проверка email, номеров телефонов, обязательных полей
- Защита от спама — встроенная поддержка reCAPTCHA и других методов
- Хуки обработки — отправка email, сохранение в БД, интеграция с CRM
- Многошаговые формы — создание сложных процессов заполнения
- Файловые загрузки — прикрепление документов и изображений
Преимущества FormIt
- Безопасность из коробки
- Гибкая настройка валидации
- Простота интеграции с шаблонами MODX
- Большое количество готовых хуков
- Активное сообщество и документация
Установка и базовая настройка
Установка через менеджер пакетов
- Зайдите в Управление → Установщики пакетов
- Найдите “FormIt” в официальном репозитории
- Нажмите “Загрузить” и затем “Установить”
Системные настройки
После установки настройте основные параметры в Система → Настройки системы:
formit.email_transport = mail
formit.email_transport_host = smtp.gmail.com
formit.email_transport_port = 587
formit.email_transport_username = your-email@gmail.com
formit.email_transport_password = your-password
Проверка работоспособности
Создайте тестовую страницу с простой формой:
[[!FormIt?
&submitVar=`submit-contact`
&successMessage=`Спасибо! Ваше сообщение отправлено.`
&validate=`name:required,email:required:email,message:required`
&hooks=`email`
&emailTo=`admin@yoursite.com`
&emailSubject=`Новое сообщение с сайта`
]]
<form action="" method="post">
<label>Имя: <input type="text" name="name" value="[[+fi.name]]" /></label>
<label>Email: <input type="email" name="email" value="[[+fi.email]]" /></label>
<label>Сообщение: <textarea name="message">[[+fi.message]]</textarea></label>
<input type="submit" name="submit-contact" value="Отправить" />
[[+fi.validation_error_message]]
</form>
Базовое использование FormIt
Простая форма обратной связи
[[!FormIt?
&submitVar=`submit-contact`
&successMessage=`Ваше сообщение успешно отправлено!`
&errorMessage=`Пожалуйста, исправьте ошибки в форме.`
&validate=`name:required:minLength=^2^,
email:required:email,
message:required:minLength=^10^`
&hooks=`email,redirect`
&emailTo=`info@example.com`
&emailFrom=`noreply@example.com`
&emailSubject=`Новое сообщение с сайта`
&emailTpl=`ContactEmailTpl`
&redirectTo=`thanks`
]]
HTML-форма
<form class="contact-form" action="" method="post">
<div class="form-group">
<label for="name">Имя *</label>
<input type="text" id="name" name="name" value="[[+fi.name]]"
class="form-control [[+fi.error.name:notempty=`error`]]" required>
<span class="error">[[+fi.error.name]]</span>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" value="[[+fi.email]]"
class="form-control [[+fi.error.email:notempty=`error`]]" required>
<span class="error">[[+fi.error.email]]</span>
</div>
<div class="form-group">
<label for="phone">Телефон</label>
<input type="tel" id="phone" name="phone" value="[[+fi.phone]]"
class="form-control [[+fi.error.phone:notempty=`error`]]">
<span class="error">[[+fi.error.phone]]</span>
</div>
<div class="form-group">
<label for="subject">Тема</label>
<select id="subject" name="subject" class="form-control">
<option value="">Выберите тему</option>
<option value="general" [[+fi.subject:FormItIsSelected=`general`]]>
Общий вопрос
</option>
<option value="support" [[+fi.subject:FormItIsSelected=`support`]]>
Техническая поддержка
</option>
<option value="sales" [[+fi.subject:FormItIsSelected=`sales`]]>
Отдел продаж
</option>
</select>
<span class="error">[[+fi.error.subject]]</span>
</div>
<div class="form-group">
<label for="message">Сообщение *</label>
<textarea id="message" name="message" rows="5"
class="form-control [[+fi.error.message:notempty=`error`]]"
required>[[+fi.message]]</textarea>
<span class="error">[[+fi.error.message]]</span>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="agree" value="1"
[[+fi.agree:FormItIsChecked]] required>
Согласие на обработку персональных данных *
</label>
<span class="error">[[+fi.error.agree]]</span>
</div>
<div class="form-actions">
<input type="submit" name="submit-contact" value="Отправить"
class="btn btn-primary">
</div>
<div class="form-messages">
[[+fi.validation_error_message:notempty=`
<div class="alert alert-danger">[[+fi.validation_error_message]]</div>
`]]
[[+fi.successMessage:notempty=`
<div class="alert alert-success">[[+fi.successMessage]]</div>
`]]
</div>
</form>
Валидация данных
Основные правила валидации
Обязательное поле:
&validate=`name:required`
Email:
&validate=`email:required:email`
Минимальная длина:
&validate=`password:required:minLength=^8^`
Максимальная длина:
&validate=`message:required:maxLength=^500^`
Числовые значения:
&validate=`age:required:isNumber:minValue=^18^:maxValue=^100^`
Регулярные выражения:
&validate=`phone:required:regex=^/^[+]?[0-9\s\-\(\)]+$/^`
Подтверждение пароля:
&validate=`password:required:minLength=^8^,
password_confirm:required:confirmValue=^password^`
Кастомные сообщения об ошибках
&customValidators=`phone:phone_validator`
&validationErrorMessage=`Пожалуйста, исправьте следующие ошибки:`
&errTpl=`<span class="error">[[+error]]</span>`
Кастомные сообщения:
&validate=`email:required:email`
&validate.email.required=`Email обязательно к заполнению`
&validate.email.email=`Укажите корректный email адрес`
Валидация телефонов
// Создайте сниппет phone_validator
$value = trim($value);
if (empty($value)) return true; // не обязательное поле
// Российские номера
$pattern = '/^(\+7|7|8)?[\s\-]?\(?([489][0-9]{2})\)?[\s\-]?([0-9]{3})[\s\-]?([0-9]{2})[\s\-]?([0-9]{2})$/';
if (!preg_match($pattern, $value)) {
$validator->addError($key, 'Укажите корректный номер телефона');
return false;
}
return true;
Email уведомления
Настройка отправки email
[[!FormIt?
&hooks=`email`
&emailTo=`manager@example.com`
&emailFrom=`noreply@example.com`
&emailFromName=`Сайт Example.com`
&emailSubject=`Новое сообщение: [[+subject:default=`Общий вопрос`]]`
&emailTpl=`ContactEmailTpl`
&emailReplyTo=`[[+email]]`
&emailReplyToName=`[[+name]]`
]]
Шаблон email сообщения
ContactEmailTpl:
<h2>Новое сообщение с сайта</h2>
<p><strong>Время:</strong> [[+formit.now:strtotime:date=`%d.%m.%Y в %H:%M`]]</p>
<p><strong>Имя:</strong> [[+name]]</p>
<p><strong>Email:</strong> [[+email]]</p>
<p><strong>Телефон:</strong> [[+phone:default=`не указан`]]</p>
<p><strong>Тема:</strong> [[+subject:default=`Общий вопрос`]]</p>
<h3>Сообщение:</h3>
<p>[[+message:nl2br]]</p>
<hr>
<p><small>IP адрес: [[+formit.ip]]<br>
User Agent: [[+formit.user_agent]]</small></p>
Автоответ клиенту
[[!FormIt?
&hooks=`email,autoresponder`
&emailTo=`admin@example.com`
&emailTpl=`AdminEmailTpl`
&autoresponderTo=`[[+email]]`
&autoresponderFrom=`noreply@example.com`
&autoresponderFromName=`Служба поддержки`
&autoresponderSubject=`Ваше сообщение получено`
&autoresponderTpl=`AutoresponderTpl`
]]
AutoresponderTpl:
<p>Здравствуйте, [[+name]]!</p>
<p>Спасибо за ваше обращение. Мы получили ваше сообщение и постараемся ответить в течение 24 часов.</p>
<p><strong>Ваше сообщение:</strong></p>
<blockquote>[[+message:nl2br]]</blockquote>
<p>Если у вас возникли срочные вопросы, звоните по телефону: +7 (495) 123-45-67</p>
<p>С уважением,<br>
Команда поддержки Example.com</p>
Защита от спама
reCAPTCHA v2
- Получите ключи на https://www.google.com/recaptcha/
- Установите дополнение “ReCaptcha”
- Настройте в системных параметрах:
recaptcha.public_key = 6Lc...
recaptcha.private_key = 6Lc...
- Добавьте в форму:
&validate=`name:required,email:required:email,recaptcha:required`
&customValidators=`recaptcha:recaptcha.recaptcha_v2`
<!-- В HTML форме -->
<div class="g-recaptcha" data-sitekey="6Lc..."></div>
<script src="https://www.google.com/recaptcha/api.js"></script>
Math CAPTCHA
&validate=`mathcaptcha:required`
&customValidators=`mathcaptcha:mathcaptcha`
<!-- В форме -->
<label>[[+formit.mathcaptcha.question]] = ?</label>
<input type="text" name="mathcaptcha" value="[[+fi.mathcaptcha]]" required>
Honeypot (скрытое поле)
<!-- Скрытое поле для ботов -->
<div style="display:none;">
<label>Не заполнять это поле:</label>
<input type="text" name="nospam" value="[[+fi.nospam]]">
</div>
<!-- Проверка в хуке -->
&hooks=`spam,email`
Сниппет spam:
$nospam = $hook->getValue('nospam');
if (!empty($nospam)) {
$hook->addError('nospam', 'Обнаружен спам');
return false;
}
return true;
Многошаговые формы
Настройка FormItWizard
[[!FormItWizard?
&submitVar=`wizard-submit`
&prevVar=`wizard-prev`
&nextVar=`wizard-next`
&successMessage=`Регистрация завершена!`
&steps=`1||2||3`
&numSteps=`3`
&validate.step1=`name:required,email:required:email`
&validate.step2=`phone:required,company:required`
&validate.step3=`agree:required`
&hooks.step3=`email,FormItSaveForm`
&emailTo=`admin@example.com`
&emailTpl=`WizardEmailTpl`
]]
Шаблоны шагов
Шаг 1 - Личные данные:
[[+formit.wizard_step:is=`1`:then=`
<div class="wizard-step step-1">
<h3>Шаг 1 из 3: Личные данные</h3>
<div class="form-group">
<label>Имя *</label>
<input type="text" name="name" value="[[+fi.name]]" required>
<span class="error">[[+fi.error.name]]</span>
</div>
<div class="form-group">
<label>Email *</label>
<input type="email" name="email" value="[[+fi.email]]" required>
<span class="error">[[+fi.error.email]]</span>
</div>
<button type="submit" name="wizard-next" value="1">Далее →</button>
</div>
`:else=``]]
Загрузка файлов
Настройка загрузки
[[!FormIt?
&hooks=`attachment,email`
&attachmentFileTypes=`jpg,jpeg,png,gif,pdf,doc,docx`
&attachmentMaxSize=`5242880` // 5MB
&attachmentPath=`assets/uploads/attachments/`
&attachmentAllowOverwrite=`0`
&emailTo=`admin@example.com`
&emailAttachments=`1`
]]
HTML для загрузки файлов
<form action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>Прикрепить резюме (PDF, DOC, DOCX)</label>
<input type="file" name="resume"
accept=".pdf,.doc,.docx"
class="form-control">
<span class="error">[[+fi.error.resume]]</span>
<small>Максимальный размер файла: 5MB</small>
</div>
<div class="form-group">
<label>Портфолио (изображения)</label>
<input type="file" name="portfolio[]"
accept="image/*"
multiple
class="form-control">
<span class="error">[[+fi.error.portfolio]]</span>
</div>
<input type="submit" name="submit-resume" value="Отправить">
</form>
Сохранение данных в базу
FormItSaveForm
[[!FormIt?
&hooks=`FormItSaveForm,email`
&formName=`ContactForm`
&formFields=`name,email,phone,message,createdon`
&fieldNames=`name==Имя,email==Email,phone==Телефон,message==Сообщение`
]]
Просмотр сохраненных форм
[[!FormItRetriever?
&form=`ContactForm`
&limit=`20`
&sort=`createdon`
&dir=`DESC`
&tpl=`FormRetrieveTpl`
&where=`{"published": 1}`
]]
FormRetrieveTpl:
<div class="form-entry">
<h4>Заявка от [[+createdon:date=`%d.%m.%Y в %H:%M`]]</h4>
<p><strong>Имя:</strong> [[+name]]</p>
<p><strong>Email:</strong> [[+email]]</p>
<p><strong>Телефон:</strong> [[+phone]]</p>
<p><strong>Сообщение:</strong></p>
<blockquote>[[+message:nl2br]]</blockquote>
<hr>
</div>
Интеграция с CRM-системами
amoCRM
// Хук для отправки в amoCRM
$name = $hook->getValue('name');
$email = $hook->getValue('email');
$phone = $hook->getValue('phone');
$amocrm_api = 'https://domain.amocrm.ru/api/v4/';
$access_token = 'your_access_token';
$contact_data = [
'name' => $name,
'custom_fields_values' => [
[
'field_code' => 'EMAIL',
'values' => [['value' => $email, 'enum_code' => 'WORK']]
],
[
'field_code' => 'PHONE',
'values' => [['value' => $phone, 'enum_code' => 'WORK']]
]
]
];
// Отправка данных в amoCRM
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $amocrm_api . 'contacts');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $access_token,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([$contact_data]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return true;
Bitrix24
// Webhook для Bitrix24
$webhook = 'https://domain.bitrix24.ru/rest/1/webhook_key/crm.lead.add';
$lead_data = [
'TITLE' => 'Заявка с сайта от ' . $hook->getValue('name'),
'NAME' => $hook->getValue('name'),
'EMAIL' => [['VALUE' => $hook->getValue('email'), 'VALUE_TYPE' => 'WORK']],
'PHONE' => [['VALUE' => $hook->getValue('phone'), 'VALUE_TYPE' => 'WORK']],
'COMMENTS' => $hook->getValue('message'),
'SOURCE_ID' => 'WEB'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $webhook);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['fields' => $lead_data]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
Продвинутые техники
Условная логика в формах
<script>
document.addEventListener('DOMContentLoaded', function() {
const subjectSelect = document.getElementById('subject');
const companyField = document.getElementById('company-field');
subjectSelect.addEventListener('change', function() {
if (this.value === 'b2b') {
companyField.style.display = 'block';
companyField.querySelector('input').required = true;
} else {
companyField.style.display = 'none';
companyField.querySelector('input').required = false;
}
});
});
</script>
<div class="form-group">
<label>Тип обращения</label>
<select id="subject" name="subject">
<option value="general">Общий вопрос</option>
<option value="b2b">Корпоративное сотрудничество</option>
</select>
</div>
<div id="company-field" class="form-group" style="display:none;">
<label>Название компании</label>
<input type="text" name="company" value="[[+fi.company]]">
</div>
AJAX отправка форм
<script>
document.getElementById('ajax-form').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const submitBtn = this.querySelector('input[type="submit"]');
submitBtn.disabled = true;
submitBtn.value = 'Отправка...';
fetch(window.location.href, {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(html => {
// Парсим ответ и обновляем форму
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const newForm = doc.querySelector('#ajax-form');
this.parentNode.replaceChild(newForm, this);
})
.catch(error => {
console.error('Error:', error);
submitBtn.disabled = false;
submitBtn.value = 'Отправить';
});
});
</script>
Автосохранение черновиков
// Автосохранение данных формы в localStorage
function saveFormDraft() {
const form = document.getElementById('contact-form');
const formData = new FormData(form);
const data = Object.fromEntries(formData);
localStorage.setItem('contact-form-draft', JSON.stringify(data));
}
// Восстановление из черновика
function loadFormDraft() {
const draft = localStorage.getItem('contact-form-draft');
if (draft) {
const data = JSON.parse(draft);
Object.keys(data).forEach(key => {
const field = document.querySelector(`[name="${key}"]`);
if (field && field.type !== 'submit') {
field.value = data[key];
}
});
}
}
// Автосохранение каждые 30 секунд
setInterval(saveFormDraft, 30000);
// Загрузка при открытии страницы
document.addEventListener('DOMContentLoaded', loadFormDraft);
// Очистка черновика после успешной отправки
if (document.querySelector('.alert-success')) {
localStorage.removeItem('contact-form-draft');
}
Оптимизация и безопасность
Защита от злоупотреблений
&validate=`email:required:email`
&customValidators=`email:email_whitelist,formit:rate_limit`
// Сниппет rate_limit
$ip = $_SERVER['REMOTE_ADDR'];
$cacheKey = 'formit_' . md5($ip);
$submissions = $modx->cacheManager->get($cacheKey);
if ($submissions >= 5) {
$hook->addError('formit', 'Превышен лимит отправок. Попробуйте позже.');
return false;
}
$modx->cacheManager->set($cacheKey, $submissions + 1, 3600); // 1 час
return true;
Логирование отправок
// Хук для логирования
$logData = [
'timestamp' => date('Y-m-d H:i:s'),
'ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'form_data' => $hook->getValues()
];
$logFile = MODX_CORE_PATH . 'cache/logs/formit.log';
file_put_contents($logFile, json_encode($logData) . "\n", FILE_APPEND | LOCK_EX);
return true;
Типовые формы
Больше информации о различных типах дополнений для MODX можно найти в статье Топ дополнений MODX.
Форма записи на консультацию
<form class="consultation-form" action="" method="post">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Имя *</label>
<input type="text" name="name" value="[[+fi.name]]" required>
<span class="error">[[+fi.error.name]]</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Телефон *</label>
<input type="tel" name="phone" value="[[+fi.phone]]" required>
<span class="error">[[+fi.error.phone]]</span>
</div>
</div>
</div>
<div class="form-group">
<label>Удобное время для звонка</label>
<select name="call_time">
<option value="">Любое время</option>
<option value="morning">Утром (9:00-12:00)</option>
<option value="afternoon">Днем (12:00-17:00)</option>
<option value="evening">Вечером (17:00-20:00)</option>
</select>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="agree" value="1" required>
Согласен на обработку персональных данных *
</label>
</div>
<button type="submit" name="submit-consultation"
class="btn btn-primary btn-lg">
Записаться на консультацию
</button>
</form>
Форма скачивания прайс-листа
[[!FormIt?
&submitVar=`download-price`
&validate=`email:required:email,phone:required,company:required`
&hooks=`email,redirect`
&emailTpl=`PriceDownloadTpl`
&redirectTo=`price-download`
&store=`1`
]]
Аналитика и отслеживание
Интеграция с Google Analytics
<script>
// Отслеживание успешной отправки формы
[[+fi.successMessage:notempty=`
gtag('event', 'form_submit', {
'event_category': 'engagement',
'event_label': 'contact_form'
});
`]]
</script>
Яндекс.Метрика
<script>
[[+fi.successMessage:notempty=`
ym(123456789, 'reachGoal', 'contact_form_send');
`]]
</script>
Заключение
FormIt — это мощный и гибкий инструмент для создания форм в MODX Revolution. Он покрывает практически все потребности по сбору и обработке данных от пользователей:
Основные возможности:
- Валидация любой сложности
- Защита от спама и ботов
- Email-уведомления и автоответы
- Сохранение данных в базу
- Интеграция с CRM-системами
- Многошаговые формы
- Загрузка файлов
Лучшие практики:
- Всегда используйте валидацию на стороне сервера
- Защищайтесь от спама с помощью CAPTCHA и скрытых полей
- Настройте автоответы для улучшения пользовательского опыта
- Логируйте отправки для анализа и безопасности
- Тестируйте формы перед публикацией
FormIt превращает создание форм из сложной задачи в простой процесс, позволяя сосредоточиться на дизайне и пользовательском опыте, а не на технических аспектах обработки данных.