В современных проектах на WordPress часто возникает необходимость создавать динамические формы, которые обрабатываются асинхронно без перезагрузки страницы. Это повышает удобство пользователя и расширяет функционал сайта. В этой статье мы подробно разберём, как создавать такие формы с помощью встроенного REST API WordPress, обеспечивая при этом безопасность и удобство разработки.
Что такое динамические формы и зачем использовать REST API
Динамические формы — это формы, которые отправляют данные на сервер и получают ответ без перезагрузки страницы. В WordPress это удобно реализовать через REST API, который позволяет взаимодействовать с сервером по современному протоколу HTTP, используя методы GET, POST, PUT и DELETE.
Использование REST API для обработки форм даёт следующие преимущества:
- Асинхронная отправка и получение данных — улучшается UX.
- Гибкость в реализации логики обработки данных.
- Возможность создавать SPA-подобные интерфейсы.
- Использование стандартных механизмов безопасности WordPress.
Создание REST API эндпоинта для обработки формы
Первый шаг — зарегистрировать свой собственный REST API маршрут, который будет принимать данные формы и обрабатывать их. Для этого используем хук rest_api_init и функцию register_rest_route.
add_action('rest_api_init', function () {
register_rest_route('wptips/v1', '/submit-form', [
'methods' => 'POST',
'callback' => 'wptips_handle_form_submission',
'permission_callback' => '__return_true', // Добавим проверку позже
]);
});
function wptips_handle_form_submission(WP_REST_Request $request) {
$params = $request->get_json_params();
$name = sanitize_text_field($params['name'] ?? '');
$email = sanitize_email($params['email'] ?? '');
$message = sanitize_textarea_field($params['message'] ?? '');
if (empty($name) || empty($email) || empty($message)) {
return new WP_REST_Response(['error' => 'Все поля обязательны для заполнения'], 400);
}
// Здесь можно сохранить данные, отправить письмо и т.д.
return new WP_REST_Response(['success' => 'Форма успешно отправлена'], 200);
}Обратите внимание, что пока permission_callback возвращает true, то есть эндпоинт доступен всем. Позже мы добавим nonce для безопасности.
Добавление защиты через nonce для безопасности
Чтобы предотвратить CSRF-атаки, нужно использовать nonce — специальный токен безопасности, который проверяется на сервере.
Добавим генерацию nonce в PHP и передадим его в JavaScript:
function wptips_enqueue_scripts() {
wp_enqueue_script('wptips-form', get_template_directory_uri() . '/js/wptips-form.js', ['jquery'], null, true);
wp_localize_script('wptips-form', 'wptipsForm', [
'nonce' => wp_create_nonce('wp_rest'),
'rest_url' => esc_url_raw(rest_url('wptips/v1/submit-form'))
]);
}
add_action('wp_enqueue_scripts', 'wptips_enqueue_scripts');В обработчике REST API добавим проверку nonce:
function wptips_handle_form_submission(WP_REST_Request $request) {
$nonce = $request->get_header('X-WP-Nonce');
if (!wp_verify_nonce($nonce, 'wp_rest')) {
return new WP_REST_Response(['error' => 'Неверный nonce'], 403);
}
// Остальной код обработки...
}Создание фронтенда динамической формы с JavaScript
Теперь создадим простую форму и опишем логику её отправки через fetch API, используя nonce и REST API URL из локализованного объекта.
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('wptips-dynamic-form');
const result = document.getElementById('wptips-form-result');
form.addEventListener('submit', function(e) {
e.preventDefault();
const data = {
name: form.name.value.trim(),
email: form.email.value.trim(),
message: form.message.value.trim()
};
fetch(wptipsForm.rest_url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wptipsForm.nonce
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if (data.success) {
result.textContent = data.success;
form.reset();
} else if (data.error) {
result.textContent = data.error;
}
})
.catch(() => {
result.textContent = 'Ошибка отправки формы';
});
});
});HTML-форма может выглядеть так:
<form id="wptips-dynamic-form">
<label>Имя:<input type="text" name="name" required></label>
<label>Email:<input type="email" name="email" required></label>
<label>Сообщение:<textarea name="message" required></textarea></label>
<button type="submit">Отправить</button>
</form>
<div id="wptips-form-result"></div>Дополнительные советы: валидация, обработка и расширение функционала
Для реальных проектов важно расширить логику валидации как на клиенте, так и на сервере. Можно использовать регулярные выражения для проверки email, длины сообщений и других параметров.
Если нужно сохранить данные, можно воспользоваться пользовательскими таблицами базы данных или стандартными типами записей WordPress (custom post types) для хранения отправленных форм.
Для уведомлений удобно использовать функцию wp_mail или интегрировать популярные SMTP-плагины, чтобы обеспечить доставку писем.
Также можно подключить плагин Clearfy Pro (https://wpshop.ru/clearfy-pro/?utm_source=wptips.ru&utm_medium=article&utm_campaign=kak-sozdat-dinamicheskie-formy-v-wordpress-s-pomoshchyu-rest-api) для оптимизации безопасности и производительности сайта, что положительно скажется на работе REST API.
Пример отправки email при получении формы
function wptips_handle_form_submission(WP_REST_Request $request) {
$nonce = $request->get_header('X-WP-Nonce');
if (!wp_verify_nonce($nonce, 'wp_rest')) {
return new WP_REST_Response(['error' => 'Неверный nonce'], 403);
}
$params = $request->get_json_params();
$name = sanitize_text_field($params['name'] ?? '');
$email = sanitize_email($params['email'] ?? '');
$message = sanitize_textarea_field($params['message'] ?? '');
if (empty($name) || empty($email) || empty($message)) {
return new WP_REST_Response(['error' => 'Все поля обязательны для заполнения'], 400);
}
$to = get_option('admin_email');
$subject = 'Новое сообщение с формы на сайте';
$body = "Имя: $name\nEmail: $email\nСообщение: $message";
$headers = ['Content-Type: text/plain; charset=UTF-8'];
wp_mail($to, $subject, $body, $headers);
return new WP_REST_Response(['success' => 'Форма успешно отправлена'], 200);
}