Введение
В этой статье мы научимся создавать ajax-форму в WordPress с нуля, без плагинов, с использованием PHP. О внешнем виде думать не будем, сосредоточимся на технической части.
У этой статьи есть продолжение — «Защита ajax-формы WordPress от СПАМа» — там мы защитили форму от СПАМ-ботов при помощи сервисов капчи.
Где писать код
Если не уверены где писать код — то можете писать его в файле functions.php вашей темы. Если у вас скаченная тема — то лучше создайте дочернюю тему и работайте с ней, либо создайте плагин и пишите код в нем. О том, как создать плагин можно почитать в этой статье.
Создание и вывод формы
Напишем HTML-код простой формы:
<form method="POST" data-admin-ajax="<?php echo admin_url( "admin-ajax.php" ); ?>" action="<?php echo $_SERVER['REQUEST_URI']; ?>" id="recall_form">
<input type="text" name="your-name" value="">
<input type="email" name="your-email" value="">
<button>Отправить</button>
</form>
В атрибуте data-admin-ajax укажем ссылку на файл admin-ajax.php. Именно туда следует отправлять все ajax-запросы в WordPress.
Никогда не создавайте дополнительные файлы, в которые будут посылаться ajax-запросы. Такие запросы следует отправлять строго либо в файл admin-ajax.php, либо использовать REST API. Но REST API — тема для отдельной статьи.
Чтобы разместить такую форму на сайте, ее можно либо записать непосредственно в файл шаблона страницы, вывести через хук, либо использовать шорткоды. Остановимся на последнем варианте. Добавим в functions.php такой код:
<?php
/**
* Функция, которая будет исполняться на месте шорткода
* Такая функция всегда должна возвращать строку и никогда выводить контент сама.
* Т.е. функции типа echo использовать нельзя.
*/
function feodoraxis_recall_form() {
return '<form method="POST" data-admin-ajax="' . admin_url( "admin-ajax.php" ) . '" action="' . $_SERVER['REQUEST_URI'] . '" id="recall_form">
<input type="text" name="your-name" value="">
<input type="email" name="your-email" value="">
<button>Отправить</button>
</form>';
}
/**
* В первом параметре функции указываем название шорткода, а во втором - название функции, которую следует добавить к нему.
*/
add_shortcode( 'feodoraxis_recall_form', 'feodoraxis_recall_form' );
Хотя в комментарии я написал, что функции типа echo использовать нельзя, это не совсем так. Т.к. я предполагаю, что вы начинающий разработчик, то скорее всего не знакомы с функциями кеширования типа ob_start(), которые нужны для буферизации вывода, и с их помощью можно обойти запрет на использование функций типа echo. Но это тема для отдельной статьи, а вам — на заметку.
Теперь, если мы в любом месте в контенте сайта напишем [feodoraxis_recall_form] — то на месте этого шорткода исполнится функция feodoraxis_recall_form().
Создание ajax-запроса
Форма есть, теперь нужно создать и отправить ajax-запрос. Для этого напишем javascript-код и выведем его в подвале сайта. Хотя JS, конечно, лучше писать в отдельном файле и подключать его. Но для академ примера выведем в подвале через хук wp_footer. Добавим в functions.php следующий код:
<?php
function feodoraxis_show_js_for_form() {
?>
<script>
document.addEventListener("DOMContentLoaded", () => { //Исполняем скрипт только когда загрузится страница, заодно оборачиваем скрипт в свое пространство
const recallForm = document.querySelector('#recall_form');
//Если формы нет - то дальше ничего не делаем
if (!recallForm) {
return;
}
recallForm.addEventListener('submit', (event) => {
//Отменим стандартное поведение формы
event.preventDefault();
// Получим данные формы
const formData = new FormData(recallForm);
//Обязательно добавляем значение action, которое мы будем использовать для обработки запроса на стороне сервера
formData.append('action', 'recall_form');
//Создадим объект запроса
const request = new XMLHttpRequest();
//Откроем запрос, определим метод и адрес куда его отправить, из атрибута data-admin-ajax формы
request.open("POST", recallForm.getAttribute("data-admin-ajax"));
//Отпрвим запрос
request.send(formData);
//При получении ответа от сервера обработаем его
request.onload = () => {
//Получим ответ в виде JSON и преобразуем его в объект для удобства
const resultJson = request.responseText;
const result = JSON.parse(resultJson);
//При успешной обработке запроса выведем сообщение сервера
if (result.success === true) {
alert(result.data.message);
} else { //В случае неудачи выведем информацию об ошибке
alert(result.data.error);
}
};
});
});
</script>
<?php
}
add_action( "wp_footer", "feodoraxis_show_js_for_form", 1000 );
Обработка запроса
Запрос отправили, теперь обработаем информацию, которая приходит из формы через скрипт. Добавим следующий код, куда вы думаете? Правильно — в functions.php!
<?php
//Обработка запроса от авторизованных на сайте пользователей
add_action( 'wp_ajax_' . 'recall_form', 'feodoraxis_recall_form_request' );
//Обработка запроса от неавторизованных на сайте пользователей
add_action( 'wp_ajax_nopriv_' . 'recall_form', 'feodoraxis_recall_form_request' );
function feodoraxis_recall_form_request() {
//Функция должна обрабатываться исключительно по POST-запросу и только в рамках AJAX-запросов
if ( $_SERVER['REQUEST_METHOD'] != 'POST' || ! wp_doing_ajax() ) {
//С помощью этой функции можем отправить ошибку и завершить исполнение функции
wp_send_json_error();
}
//Валидация полей формы на backend
if ( ! isset( $_POST['your-name'] ) || ! isset( $_POST['your-email'] ) || empty( trim( $_POST['your-name'] ) ) || empty( trim( $_POST['your-email'] ) ) ) {
//Внутри функции можно отправлять любые данные. Они будут в параметре data, к которому мы обращаемся из JS
wp_send_json_error( [
'error' => "Необходимо заполнить все поля формы"
] );
}
//Проверим, что пользователь передал email
if ( ! is_email( $_POST['your-email'] ) ) {
wp_send_json_error( [
'error' => "Указан некорректный email"
] );
}
//Сохраним наши данные. sanitize_text_field очищает строку и делает ее безопасней
$your_name = sanitize_text_field( $_POST['your-name'] );
$your_email = sanitize_text_field( $_POST['your-email'] );
//Укажем заголовки письма
$headers = "MIME-Version: 1.0\r\n";
//Сделаем так, чтобы в сообщении письма можно было указывать HTML
$headers .= "Content-type: text/html; charset=utf-8\r\n";
//Укажем имя и Email отправителя письма
$headers .= "From: Андрей Смородин <no-reply@" . $_SERVER["HTTP_HOST"] . ">\r\n";
//Оформим содержимое письма
$message = '<b>Имя:</b> ' . $your_name . '<br>';
$message .= '<b>Email:</b> ' . $your_email . '<br>';
//Отправляем письмо
$result = wp_mail( 'info@feodoraxis.ru', 'Заявка из формы обратной связи', $message, $headers )
//Проверяем, отправилось-ли письмо
if ( $result ) {
//Аналогичная функция как wp_send_json_error, но уведомляет об успехе
wp_send_json_success( [
'message' => "Сообщение отправлено. Мы свяжемся с вами в ближайшее время."
] );
}
wp_send_json_error( [
'error' => "Письмо не было отправлено"
] );
}
Важно: в конце функции, которая исполняется по ajax, всегда нужно вызывать функцию exit или die(). Также можно обойтись одной из функций wp_send_json_success() и wp_send_json_error() — они в конце сами вызывают функцию die, но помогают удобно отправлять информацию на сторону клиента: указывают правильные заголовки в ответе сервера, выводят массив в виде json-строки, сообщают об успехе или неудаче, и вызывают в конце функцию die;
Отлично! Если вы все сделали правильно, то форма уже должна работать!
Скоро выйдет вторая часть этой статьи, где мы рассмотрим защиту этой формы от СПАМа, при помощи Yandex Smart Captcha и Google reCaptcha.
Желаю вам успехов!
Листинг всего кода
<?php
/**
* Функция, которая будет исполняться на месте шорткода
* Такая функция всегда должна возвращать строку и никогда выводить контент сама.
* Т.е. функции типа echo использовать нельзя.
*/
function feodoraxis_recall_form() {
return '<form method="POST" data-admin-ajax="' . admin_url( "admin-ajax.php" ) . '" action="' . $_SERVER['REQUEST_URI'] . '" id="recall_form">
<input type="text" name="your-name" value="">
<input type="email" name="your-email" value="">
<button>Отправить</button>
</form>';
}
/**
* В первом параметре функции указываем название шорткода, а во втором - название функции, которую следует добавить к нему.
*/
add_shortcode( 'feodoraxis_recall_form', 'feodoraxis_recall_form' );
/**
* Функция для вывода в подвале сайта JavaScript, отправляющего ajax-запрос
*/
function feodoraxis_show_js_for_form() {
?>
<script>
document.addEventListener("DOMContentLoaded", () => { //Исполняем скрипт только когда загрузится страница, заодно оборачиваем скрипт в свое пространство
const recallForm = document.querySelector('#recall_form');
//Если формы нет - то дальше ничего не делаем
if (!recallForm) {
return;
}
recallForm.addEventListener('submit', (event) => {
//Отменим стандартное поведение формы
event.preventDefault();
// Получим данные формы
const formData = new FormData(recallForm);
//Обязательно добавляем значение action, которое мы будем использовать для обработки запроса на стороне сервера
formData.append('action', 'recall_form');
//Создадим объект запроса
const request = new XMLHttpRequest();
//Откроем запрос, определим метод и адрес куда его отправить, из атрибута data-admin-ajax формы
request.open("POST", recallForm.getAttribute("data-admin-ajax"));
//Отпрвим запрос
request.send(formData);
//При получении ответа от сервера обработаем его
request.onload = () => {
//Получим ответ в виде JSON и преобразуем его в объект для удобства
const resultJson = request.responseText;
const result = JSON.parse(resultJson);
//При успешной обработке запроса выведем сообщение сервера
if (result.success === true) {
alert(result.data.message);
} else { //В случае неудачи выведем информацию об ошибке
alert(result.data.error);
}
};
});
});
</script>
<?php
}
add_action( "wp_footer", "feodoraxis_show_js_for_form", 1000 );
//Обработка запроса от авторизованных на сайте пользователей
add_action( 'wp_ajax_' . 'recall_form', 'feodoraxis_recall_form_request' );
//Обработка запроса от неавторизованных на сайте пользователей
add_action( 'wp_ajax_nopriv_' . 'recall_form', 'feodoraxis_recall_form_request' );
//Функция, которая обрабатывает входящий ajax-запрос
function feodoraxis_recall_form_request() {
//Функция должна обрабатываться исключительно по POST-запросу и только в рамках AJAX-запросов
if ( $_SERVER['REQUEST_METHOD'] != 'POST' || ! wp_doing_ajax() ) {
//С помощью этой функции можем отправить ошибку и завершить исполнение функции
wp_send_json_error();
}
//Валидация полей формы на backend
if ( ! isset( $_POST['your-name'] ) || ! isset( $_POST['your-email'] ) || empty( trim( $_POST['your-name'] ) ) || empty( trim( $_POST['your-email'] ) ) ) {
//Внутри функции можно отправлять любые данные. Они будут в параметре data, к которому мы обращаемся из JS
wp_send_json_error( [
'error' => "Необходимо заполнить все поля формы"
] );
}
//Проверим, что пользователь передал email
if ( ! is_email( $_POST['your-email'] ) ) {
wp_send_json_error( [
'error' => "Указан некорректный email"
] );
}
//Сохраним наши данные. sanitize_text_field очищает строку и делает ее безопасней
$your_name = sanitize_text_field( $_POST['your-name'] );
$your_email = sanitize_text_field( $_POST['your-email'] );
//Укажем заголовки письма
$headers = "MIME-Version: 1.0\r\n";
//Сделаем так, чтобы в сообщении письма можно было указывать HTML
$headers .= "Content-type: text/html; charset=utf-8\r\n";
//Укажем имя и Email отправителя письма
$headers .= "From: Андрей Смородин <no-reply@" . $_SERVER["HTTP_HOST"] . ">\r\n";
//Оформим содержимое письма
$message = '<b>Имя:</b> ' . $your_name . '<br>';
$message .= '<b>Email:</b> ' . $your_email . '<br>';
//Отправляем письмо
$result = wp_mail( 'info@feodoraxis.ru', 'Заявка из формы обратной связи', $message, $headers )
//Проверяем, отправилось-ли письмо
if ( $result ) {
//Аналогичная функция как wp_send_json_error, но уведомляет об успехе
wp_send_json_success( [
'message' => "Сообщение отправлено. Мы свяжемся с вами в ближайшее время."
] );
}
wp_send_json_error( [
'error' => "Письмо не было отправлено"
] );
}