Ajax нужен почти во всех современных проектах.
С самописными проектами все относительно просто: создаешь файл, обращаешься к нему ajax-запросом, получаешь ответ и работаешь с данными. В WordPress принцип такой-же, но есть нюансы, о которых я расскажу.
Чтобы понимать эту статью, нужно знать, что такое Ajax и что такое хуки (hooks) в WordPress, хотя я постарался объяснить всё наглядно.
Сначала рассмотрим теорию: принципы и важные нюансы Ajax в WP. Но если вам не терпится и хочется живой пример — переходите сразу к практике 🙂
Теория
Все ajax-запросы в WP принимаются через файл /wp-admin/admin-ajax.php. Т.е. обращаться всегда нужно к нему.
Получить ссылку к файлу можно при помощи функции:
admin_url( 'admin-ajax.php' );
Эта функция возвращает путь к файлу в вашем проекте. Лучше использовать ее, а не прописывать путь вручную по двум причинам:
- Путь к файлу admin-ajax.php в будущих версиях WP может измениться. В этом случае, если вы пропишете путь вручную, после обновления, ajax перестанет работать и вы с ходу не поймете, почему. А клиент будет терять деньги. Если вы укажете путь через admin_url(), то такой проблемы не возникнет.
- Если проект находится не в корне сайта, и/или может менять директорию. В этом случае функция также будет всегда указывать верный путь к файлу, а вам не придется его переписывать каждый раз.
Часто в боевых проектах вижу такую картину: разработчики создают произвольные файлы в теме, или вовсе в корне сайта, подключают в них ядро системы и обрабатывают ajax-запросы. Это засоряет систему ненужными файлами и создаёт серьёзную угрозу безопасности.
Не надо так!
Запрос отправляется методом POST с обязательным параметром action. В параметре action указываем имя хука, который вызывает нужную функцию.
Например: мы отправляем сообщение из формы обратной связи. Тогда пусть у переменной action будет значение form_recall. В этом случае, в файле functions.php укажем следующий код:
add_action( 'wp_ajax_' . 'form_recall', 'form_recall' );
add_action( 'wp_ajax_nopriv_' . 'form_recall', 'form_recall' );
function form_recall() {
/**
* В этой функции обрабатываем данные из ajax, и выводим результат
**/
}
При помощи функции add_action() мы добавили хуки wp_ajax_{$action_name} и wp_ajax_nopriv_{$action_name}, где $action_name = ‘form_recall’; а также указали к исполнению при обращении к ним функцию form_recall(). Название функции может быть любым.
Теперь при ajax-запросе к файлу admin-ajax.php, с параметром action = form_recall, будет выполняться PHP функция form_recall().
Что за «wp_ajax_{$action_name}» и «wp_ajax_nopriv_{$action_name}»?
Это два хука, в конце названия которых ($action_name) мы указываем название действия, с которым хотим работать. Название может быть любым, но лучше писать что-то понятное для нас.
- wp_ajax_{$action_name} — обрабатывает запросы, которые приходят от авторизованных пользователей.
- wp_ajax_nopriv_{$action_name} — обрабатывает запросы, которые приходят от неавторизованных пользователей.
Практика
Если с теорией могло быть сложно, то с практикой должно быть по-легче 🙂
Для начала поставим задачу.
Задача
Необходимо создать форму обратной связи, которая будет отправлять данные из формы на почту без перезагрузки, при помощи Ajax. После отправки мы должны получить сообщение либо об успешной отправке, либо об ошибке.
Решение
Предположим, что на странице уже есть такая форма:
<form
action="<?php echo $_SERVER['REQUEST_URI']; ?>"
data-url="<?php echo admin_url( 'admin-ajax.php' ); ?>"
method="POST" id="form_recall">
<input type="text" name="user_name" placeholder="Ваше имя">
<input type="text" name="user_phone" placeholder="Ваш телефон">
<button>Отправить</button>
</form>
Обратите внимание, что в атрибуте data-url у формы мы уже вывели ссылку на файл-обработчик ajax-запросов. Это важно, потому что JS мы будем писать в отдельном файле.
Далее, в файле JS напишем код:
/**
* Должен быть подключен JQuery
**/
jQuery(function($) {
$("#form_recall").on('submit', function(e) {
e.preventDefault();
const self = $(this); // Сохраним объект формы в переменную
const userName = self.find('input[name="user_name"]').val(); //Получим имя
const userPhone = self.find('input[name="user_phone"]').val(); //Получим телефон
$.ajax({
/**
* Укажем ссылку на файл
**/
url: self.attr('data-url'),
/**
* Укажем данные, которые передадим с запросом
* Обязательно указываем параметр action
* Прочие данные я предпочитаю передавать через параметр form
**/
data: {
action: 'form_recall',
form: {
user_name: userName,
user_phone: userPhone,
}
},
/**
* Тип запроса - POST
**/
type: 'POST',
/**
* Действие при успешном запросе
**/
success: function(json) {
self.append(`<p>${json.data.message}</p>`);
setTimeout(function() {
self.find('p').detach();
}, 3000);
},
/**
* Действие при ошибке
**/
fail: function() {
self.append('<p>Произошла неизвестная ошибка</p>');
setTimeout(function() {
self.find('p').detach();
}, 3000);
});
});
});
});
Отлично! Мы научились отправлять ajax-запрос.
Конечно, тут нет валидации, но это академический пример. В реальном проекте все данные должны пройти валидацию, а форма не должна отправляться, если есть ошибки.
Также обязательно делать валидацию на стороне Backend, потому что валидацию на стороне Frontend можно легко обойти. Валидация Frontend нужна только для удобства пользователя.
Дальше нам нужно научить сайт принимать и обрабатывать данные. Для этого, в файле functions.php пропишем следующий код:
<?php
add_action( 'wp_ajax_' . 'form_recall', 'form_recall' );
add_action( 'wp_ajax_nopriv_' . 'form_recall', 'form_recall' );
function form_recall() {
/**
* Сохраним нужные данные в переменную. Для удобства.
**/
$form_data = $_POST['form'];
/**
* Back-end валидация
**/
if ( empty( $form_data['user_name'] ) || empty( $form_data['user_phone'] ) ) {
wp_send_json_error( array(
'message' => 'Необходимо заполнить все поля'
) );
}
/**
* Обработаем и сохраним нужные данные
**/
$user_name = sanitize_text_field( $form_data['user_name'] );
$user_phone = sanitize_text_field( $form_data['user_phone'] );
/**
* Дальше - всё как при обычно отправке сообщения в PHP :)
**/
$mail_theme = "Сообщение из формы обратной связи";
$email_to = 'example@feodoraxis.ru';
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=utf-8\r\n";
$headers .= "From: boot@" . $_SERVER["HTTP_HOST"] . "\r\n";
$multipart = "<h1>" . $mail_theme . "</h1>";
$multipart .= "<p><b>Имя пользователя:<b> " . $user_name . "</p>";
$multipart .= "<p><b>Телефон:<b> " . $user_phone . "</p>";
if ( wp_mail( $email_to, $mail_theme, $multipart, $headers ) ) {
wp_send_json_success( array(
'message' => 'Спасибо! Ваше сообщение отправлено'
) );
}
wp_send_json_error( array(
'message' => 'Произошла ошибка'
) );
}
Вот и всё. Ajax-форма готова!
Функции wp_send_json_success() и wp_send_json_error(), как json_encode(), конвертируют массив в JSON-строку, добавляют к нему параметр «result» со значением error — если вызвали wp_send_json_error() — или success — если вызвали функцию wp_send_json_success(). Также обе эти функции добавляют заголовок application/json в ответ запроса, благодаря чему на стороне Frontend мы сразу можем работать с полученными данными как с объектом. В конце обе функции вызывают функцию exit, поэтому после них не нужно дополнительно вызывать функции exit или die().