AJAX-запросы
Кнопка «Нравится», подгрузка записей, отправка формы без перезагрузки — всё это запросы из JavaScript к серверу. В WordPress для них есть старый проверенный механизм: файл admin-ajax.php и хуки wp_ajax_.
Обработчик
Каждый запрос несёт параметр action. По нему WordPress вызывает хук с таким же названием:
// functions.php
add_action('wp_ajax_mytheme_like', 'mytheme_handle_like');
add_action('wp_ajax_nopriv_mytheme_like', 'mytheme_handle_like');
function mytheme_handle_like(): void
{
check_ajax_referer('mytheme_like', 'nonce');
$postId = absint($_POST['post_id'] ?? 0);
if (!$postId || get_post_status($postId) !== 'publish') {
wp_send_json_error(['message' => 'Запись не найдена'], 404);
}
$likes = (int) get_post_meta($postId, 'likes', true) + 1;
update_post_meta($postId, 'likes', $likes);
wp_send_json_success(['likes' => $likes]);
}Хук wp_ajax_ срабатывает для вошедших пользователей, wp_ajax_nopriv_ — для гостей. Чтобы действие работало для всех, подключают оба.
Ответ
wp_send_json_success() и wp_send_json_error() выводят JSON и сразу завершают программу:
{ "success": true, "data": { "likes": 12 } }Адрес и токен для скрипта
Скрипту нужно знать адрес admin-ajax.php и токен. Их передают при подключении:
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script('mytheme-like', get_template_directory_uri() . '/assets/like.js', [], '1.0.0', true);
wp_add_inline_script('mytheme-like', 'const mythemeLike = ' . wp_json_encode([
'url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('mytheme_like'),
]) . ';', 'before');
});Кнопка
<?php
// template-parts/like.php
?>
<button class="like" data-post="<?php echo esc_attr(get_the_ID()); ?>">
♥ <span><?php echo (int) get_post_meta(get_the_ID(), 'likes', true); ?></span>
</button>Запрос из JavaScript
// assets/like.js
document.querySelectorAll('.like').forEach((button) => {
button.addEventListener('click', async () => {
const body = new FormData();
body.append('action', 'mytheme_like');
body.append('nonce', mythemeLike.nonce);
body.append('post_id', button.dataset.post);
const response = await fetch(mythemeLike.url, { method: 'POST', body });
const result = await response.json();
if (result.success) {
button.querySelector('span').textContent = result.data.likes;
}
});
});Данные отправляются как обычная форма: обработчик читает их из $_POST.
Возврат разметки
Для подгрузки записей обработчик может вернуть готовый HTML:
add_action('wp_ajax_nopriv_mytheme_more', 'mytheme_handle_more');
add_action('wp_ajax_mytheme_more', 'mytheme_handle_more');
function mytheme_handle_more(): void
{
$query = new WP_Query(['paged' => absint($_GET['page'] ?? 1)]);
ob_start();
while ($query->have_posts()) {
$query->the_post();
get_template_part('template-parts/card');
}
wp_send_json_success(['html' => ob_get_clean(), 'pages' => $query->max_num_pages]);
}AJAX или REST API
admin-ajax.php | REST API | |
|---|---|---|
| Адрес | Один на все действия | Свой у каждого маршрута |
| Проверка параметров | Вручную | Описывается в маршруте |
| Когда выбирать | Небольшие действия в теме | API для приложений, много маршрутов |
Частая ошибка
Если на запрос приходит ответ 0, обработчик не найден. Причин обычно три: в запросе нет параметра action или он назван иначе; забыт хук wp_ajax_nopriv_, а проверяете вы как гость; код с add_action лежит в шаблоне страницы и при запросе к admin-ajax.php не загружается — его место в functions.php или плагине.