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();
let thi = $(this), // Сохраним объект формы в переменную
user_name = thi.find('input[name="user_name"]').val(), //Получим имя
user_phone = thi.find('input[name="user_phone"]').val(); //Получим телефон
$.ajax({
/**
* Укажем ссылку на файл
**/
url: thi.attr('data-url'),
/**
* Укажем данные, которые передадим с запросом
* Обязательно указываем параметр action
* Прочие данные я предпочитаю передавать через параметр form
**/
data: {
action: 'form_recall',
form: {
user_name: user_name,
user_phone: user_phone,
}
},
/**
* Тип запроса - POST
**/
type: 'POST',
/**
* Действие при успешном запросе
**/
success: function(json) {
let data = JSON.parse(json);
thi.append('<p>' + data.message + '</p>');
setTimeout(function() {
thi.find('p').detach();
}, 3000);
},
/**
* Действие при ошибке
**/
fail: function() {
thi.append('<p>Произошла неизвестная ошибка</p>');
setTimeout(function() {
thi.find('p').detach();
}, 3000);
});
});
});
});
Отлично! Мы научились отправлять ajax-запрос.
Конечно, тут нет валидации, но это академический пример. В реальном проекте все данные должны пройти валидацию, а форма не должна отправляться, если есть ошибки.
Также обязательно делать валидацию на беке, потому что валидацию фронта можно легко обойти. Валидация фронта нужна только для удобства пользователя.
Дальше нам нужно научить сайт принимать и обрабатывать данные. Для этого, в файле 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'] ) ) {
die( json_encode( array(
'result' => false,
'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 ( mail( $email_to, '=?UTF-8?B?' . base64_encode( $mail_theme ) . '?=', $multipart, $headers ) ) {
echo json_encode( array(
'result' => true,
'message' => "Спасибо! Ваше сообщение отправлено"
));
} else {
echo json_encode( array(
'result' => false,
'message' => 'Произошла ошибка'
) );
}
/**
* Обязательно в конце выполнения функции пишем exit() или die();
**/
exit;
}
Вот и всё. Ajax-форма готова!
Возможно, у вас возник вопрос: почему в беке мы выводим данные в формате JSON (передаем в json_encode() массив) и в JS принимаем их при помощи JSON.parse?
Все очень просто 🙂
Данные в виде массива проще обрабатывать. Благодаря такому подходу вы можете передать и вернуть любые данные формате, благодаря чему выполнять многие задачи будет легче.