
Отправка комментариев без перезагрузки страницы — важный элемент современного пользовательского опыта. В WordPress по умолчанию комментарии отправляются через обычную форму с перезагрузкой, что может отпугнуть пользователей. Но с помощью AJAX мы можем сделать процесс плавным и удобным.
В этой статье вы узнаете, как сделать Ajax комментарии WordPress к записям, используя только PHP, jQuery и стандартные хуки WordPress. Решение будет работать на любой теме, совместимо с кэшированием и безопасно.
Обычная форма комментариев в WordPress отправляет данные через POST-запрос и перенаправляет пользователя на ту же страницу. Это создаёт:
AJAX-отправка решает эти проблемы:
WordPress уже включает jQuery, но нужно правильно подключить наш JS-файл и передать туда URL для обработки AJAX.
Добавьте в functions.php вашей темы:
// Подключение скриптов и локализация AJAX
function wp_ajax_comments_scripts() {
// Подключаем наш JS-файл (если он есть)
// Если файла нет — создадим его ниже
wp_enqueue_script(
'ajax-comments', // Уникальное имя скрипта
get_template_directory_uri() . '/js/ajax-comments.js', // Путь к файлу
['jquery'], // Зависит от jQuery
'1.0.0', // Версия
true // Выводить в футере
);
// Передаём переменные из PHP в JS
wp_localize_script('my-comment-system', 'myComment', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('my_comment_nonce'),
'user_logged_in' => is_user_logged_in(),
'current_user' => is_user_logged_in() ? [
'id' => get_current_user_id(),
'name' => wp_get_current_user()->display_name,
'email' => wp_get_current_user()->user_email
] : false,
'post_id' => get_the_ID(), // ← Добавлено!
'messages' => [
'empty' => 'Введите текст комментария.',
'error' => 'Ошибка отправки. Попробуйте позже.',
'moderated' => 'Ваш комментарий отправлен на модерацию.',
'success' => 'Комментарий добавлен!'
]
]);
}
add_action('wp_enqueue_scripts', 'wp_ajax_comments_scripts');Пояснение:
wp_enqueue_script() — безопасно подключает JS-файлwp_localize_script() — передаёт данные из PHP в JavaScript (включая ajax_url и защитный nonce)nonce — это токен безопасности, предотвращающий подделку запросовСоздайте файл:/wp-content/themes/ваша-тема/js/ajax-comments.js
jQuery(document).ready(function ($) {
// Обработчик отправки формы комментариев
$('#commentform').on('submit', function (e) {
// Предотвращаем стандартную отправку формы
e.preventDefault();
// Получаем форму
var form = $(this);
var parentId = parseInt($('#comment_parent').val()) || 0;
// Кнопка отправки
var submitBtn = form.find('input[type="submit"], button[type="submit"]');
// Сохраняем исходный текст кнопки
var originalText = submitBtn.val() || submitBtn.text();
// Отключаем кнопку и показываем "загрузку"
submitBtn.prop('disabled', true).val(ajax_comment_object.loading);
// Собираем данные формы
var formData = form.serialize(); // Все поля формы (комментарий, имя, email и т.д.)
if( ajax_comment_object.user_logged_in ){
formData += '&user_id=' + ajax_comment_object.current_user.id;
}
// Добавляем действие для обработчика WordPress
formData += '&action=ajax_submit_comment';
// Добавляем nonce для проверки безопасности
formData += '&nonce=' + ajax_comment_object.nonce;
// AJAX-запрос
$.post(
ajax_comment_object.ajax_url, // URL: /wp-admin/admin-ajax.php
formData,
function (response) {
// Возвращаем кнопку в нормальное состояние
submitBtn.prop('disabled', false).val(originalText);
// Проверяем результат
if (response.success) {
// Успешно: очищаем форму
form[0].reset();
const $newComment = $(response.data.html);
if (parentId > 0) {
const $parent = $('#comment-' + parentId);
let $children = $parent.next('ul.children');
if (!$children.length) {
$children = $('<ul class="children"></ul>').insertAfter($parent);
}
$children.append($newComment);
} else {
$('.comment-list').append($newComment);
}
} else {
// Ошибка: показываем сообщение
alert(response.data.message || ajax_comment_object.error);
}
}
).fail(function () {
// Ошибка соединения
submitBtn.prop('disabled', false).val(originalText);
alert(ajax_comment_object.error);
});
});
});Пояснение:
e.preventDefault() — останавливает стандартную отправкуform.serialize() — собирает все данные формыnonce — проверяется на сервере для безопасностиlocation.reload() — обновляет страницу, чтобы показать комментарий (если он не модерируется)Теперь нужно принять запрос в WordPress. Добавьте в functions.php:
// Обработка AJAX-запроса на отправку комментария
function ajax_submit_comment_callback() {
// Проверка безопасности: nonce
if (!wp_verify_nonce($_POST['nonce'], 'ajax_comment_nonce')) {
wp_die(json_encode(['success' => false, 'data' => __('Security check failed.', 'textdomain')]));
}
// Проверка, что запрос идёт с сайта (реферер)
if (!wp_get_referer()) {
wp_die(json_encode(['success' => false, 'data' => __('Invalid request.', 'textdomain')]));
}
// Подготовка данных комментария
$comment_data = [
'comment_post_ID' => intval($_POST['comment_post_ID']),
'comment_content' => wp_kses_post($_POST['comment']),
'comment_parent' => isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0,
];
if ( is_user_logged_in() && ! empty($_POST['user_id']) ) {
$user = get_userdata((int) $_POST['user_id']);
if ($user) {
$comment_data['user_ID'] = $user->ID;
$comment_data['comment_author'] = $user->display_name;
$comment_data['comment_author_email'] = $user->user_email;
}
} else {
// Гость
if ( empty($_POST['author']) || empty($_POST['email']) || empty($_POST['comment']) ) {
wp_send_json_error(['message' => 'Заполните все поля.']);
}
$comment_data['comment_author'] = sanitize_text_field($_POST['author']);
$comment_data['comment_author_email'] = sanitize_email($_POST['email']);
$comment_data['comment_author_url'] = !empty($_POST['url']) ? esc_url_raw($_POST['url']) : '';
}
// Проверка обязательных полей
if (empty($comment_data['comment_content'])) {
wp_send_json_error(['success' => false, 'data' => __('Comment field is required.', 'textdomain')]);
}
if (empty($comment_data['comment_author'])) {
wp_send_json_error(['success' => false, 'data' => __('Name is required.', 'textdomain')]);
}
if (empty($comment_data['comment_author_email']) || !is_email($comment_data['comment_author_email'])) {
wp_send_json_error(['success' => false, 'data' => __('Valid email is required.', 'textdomain')]);
}
// Проверка, можно ли вообще оставлять комментарии
if (!comments_open($comment_data['comment_post_ID'])) {
wp_send_json_error(['success' => false, 'data' => __('Comments are closed.', 'textdomain')]);
}
// Пытаемся добавить комментарий
$comment_id = wp_new_comment($comment_data);
// Проверяем результат
if (is_wp_error($comment_id)) {
wp_send_json_error(['success' => false, 'data' => $comment_id->get_error_message()]);
}
$html = ajax_comment_to_html($comment_id);
if (! $html) {
wp_send_json_error([
'success' => false,
'message' => 'Не удалось сгенерировать HTML комментария.'
]);
}
// Успех!
wp_send_json_success([
'success' => true,
'html' => $html,
'message' => wp_get_comment_status($comment_id),
]);
}
add_action('wp_ajax_ajax_submit_comment', 'ajax_submit_comment_callback');
add_action('wp_ajax_nopriv_ajax_submit_comment', 'ajax_submit_comment_callback');Пояснение:
wp_verify_nonce() — проверяет подлинность запросаsanitize_text_field(), sanitize_email(), esc_url_raw() — очистка данныхwp_kses_post() — безопасная фильтрация HTML в комментарииwp_new_comment() — добавляет комментарий и проходит все стандартные проверки WordPresswp_ajax_ (для авторизованных) и wp_ajax_nopriv_ (для гостей)Далее нам необходимо собрать HTML код собранного комментария и вставить его в DOM, без перезагрузки страницы.
function ajax_comment_to_html($comment_id) {
$comment = get_comment($comment_id);
if (!$comment) return '';
// Подготовка данных
$author_url = get_comment_author_url($comment);
$avatar = get_avatar($comment, 60);
$date = get_comment_date('j F Y', $comment->comment_ID);
$time = get_comment_time('H:i', true, $comment);
$content = apply_filters('comment_text', $comment->comment_content, $comment, []);
$author = get_comment_author_link($comment);
// Проверка, есть ли дети (опционально: можно упростить)
$has_children = (bool) get_comments([
'parent' => $comment->comment_ID,
'post_id' => $comment->comment_post_ID,
'number' => 1,
'count' => true
]);
// Формируем HTML
$html = '
<li id="comment-' . esc_attr($comment->comment_ID) . '" class="' . implode(' ', get_comment_class($has_children ? 'parent' : '', $comment)) . '">
<article class="comment-body" id="comment-body-' . esc_attr($comment->comment_ID) . '">
<div class="comment-author vcard">
' . $avatar . '
<b class="fn">' . $author . '</b>
<span class="comment-meta">
<a href="' . esc_url(get_comment_link($comment->comment_ID)) . '">
' . sprintf('%s в %s', $date, $time) . '
</a>';
if (current_user_can('edit_comment', $comment->comment_ID)) {
$html .= ' | <a href="' . esc_url(get_edit_comment_link($comment->comment_ID)) . '">Изменить</a>';
}
$html .= '
</span>
</div>';
if ('0' == $comment->comment_approved) {
$html .= '<p class="comment-awaiting-moderation">' . __('Ваш комментарий отправлен на модерацию.', 'textdomain') . '</p>';
}
$html .= '
<div class="comment-content">
' . $content . '
</div>
<div class="reply">
<span class="reply-button">
<a rel="nofollow" href="#respond" onclick="return addComment.moveForm(\'comment-' . $comment->comment_ID . '\', \'' . $comment->comment_ID . '\', \'respond\', \'' . $comment->comment_post_ID . '\')">Ответить</a>
</span>
</div>
</article>
</li>';
return $html;
}Убедитесь, что в вашем single.php или comments.php используется стандартная форма:
<?php comment_form(); ?>Или кастомная, но с правильными полями:
<form id="commentform" method="post" action="<?php echo site_url('/wp-comments-post.php'); ?>">
<input type="text" name="author" required>
<input type="email" name="email" required>
<textarea name="comment" required></textarea>
<input type="hidden" name="comment_post_ID" value="<?php the_ID(); ?>">
<input type="hidden" name="comment_parent" value="0">
<input type="submit" value="<?php _e('Post Comment', 'textdomain'); ?>">
</form>AJAX-отправка комментариев — простой способ улучшить UX на вашем WordPress-сайте. Мы использовали:
Решение полностью кастомизируемо: вы можете заменить alert на красивый тултип, добавить спиннер, интегрировать с reCAPTCHA и т.д.
sdjflsdjflskdfls sldjkflskjdhflsjdl