Как сделать AJAX-отправку комментариев к постам в WordPress

1 комментарий
36
Как сделать AJAX-отправку комментариев к постам в WordPress

Отправка комментариев без перезагрузки страницы — важный элемент современного пользовательского опыта. В WordPress по умолчанию комментарии отправляются через обычную форму с перезагрузкой, что может отпугнуть пользователей. Но с помощью AJAX мы можем сделать процесс плавным и удобным.

В этой статье вы узнаете, как сделать Ajax комментарии WordPress к записям, используя только PHP, jQuery и стандартные хуки WordPress. Решение будет работать на любой теме, совместимо с кэшированием и безопасно.

Почему стоит использовать AJAX комментарии WordPress?

Обычная форма комментариев в WordPress отправляет данные через POST-запрос и перенаправляет пользователя на ту же страницу. Это создаёт:

  • Мерцание экрана
  • Потерю фокуса (например, после отправки курсор не остаётся в поле)
  • Возможность двойной отправки
  • Плохое UX

AJAX-отправка решает эти проблемы:

  • Нет перезагрузки
  • Мгновенная обратная связь
  • Можно показать ошибки или успех без перехода
  • Лучше для восприятия

Шаг 1: Подключаем jQuery и локализуем скрипт

WordPress уже включает jQuery, но нужно правильно подключить наш JS-файл и передать туда URL для обработки AJAX.

Добавьте в functions.php вашей темы:

JavaScript
// Подключение скриптов и локализация 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 — это токен безопасности, предотвращающий подделку запросов

Шаг 2: Создаём JavaScript для AJAX-отправки

Создайте файл:
/wp-content/themes/ваша-тема/js/ajax-comments.js

JavaScript
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() — обновляет страницу, чтобы показать комментарий (если он не модерируется)

Шаг 3: Обработка AJAX-запроса в PHP

Теперь нужно принять запрос в WordPress. Добавьте в functions.php:

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() — добавляет комментарий и проходит все стандартные проверки WordPress
  • Два хука: wp_ajax_ (для авторизованных) и wp_ajax_nopriv_ (для гостей)

Шаг 4: Функция сборки HTML созданного комментария

Далее нам необходимо собрать HTML код собранного комментария и вставить его в DOM, без перезагрузки страницы.

PHP
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;
}
Открыть

Шаг 4: Проверка формы комментариев

Убедитесь, что в вашем single.php или comments.php используется стандартная форма:

PHP
<?php comment_form(); ?>

Или кастомная, но с правильными полями:

HTML
<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-сайте. Мы использовали:

  • Стандартные хуки WordPress
  • Безопасную передачу данных
  • Валидацию и фильтрацию
  • Поддержку гостей и авторизованных пользователей

Решение полностью кастомизируемо: вы можете заменить alert на красивый тултип, добавить спиннер, интегрировать с reCAPTCHA и т.д.

guest
1 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
GobliN
GobliN
2 месяцев назад

sdjflsdjflskdfls sldjkflskjdhflsjdl