В стандартной установке WordPress система комментариев тесно связана с базой данных и встроенными функциями. Однако бывают случаи, когда необходимо создать полностью автономную систему комментирования — например, для кастомных страниц, специфических постов или когда стандартный функционал не подходит по техническим или дизайнерским требованиям. В этой статье мы подробно разберём, как создать такую систему без использования сторонних плагинов, используя только возможности PHP, AJAX и WordPress API.
Почему стоит создавать собственную систему комментирования
Стандартные комментарии WordPress отлично подходят для большинства сайтов, но иногда они имеют ограничения:
- Ограниченная кастомизация — сложно изменить структуру хранения комментариев или их внешний вид без глубокого погружения;
- Производительность — на больших сайтах с тысячами комментариев стандартная система может замедляться;
- Независимость — хотелось бы отделить комментарии от основной базы данных WordPress или реализовать независимый функционал;
- Особые требования — например, поддержка вложенных форматов, кастомных полей, или интеграция с внешними сервисами.
Создание собственной системы позволит гибко управлять процессом, оптимизировать под задачи и реализовать любые дополнительные функции.
Создание таблицы для хранения комментариев
Первый шаг — создать собственную таблицу в базе данных для хранения комментариев. Это даст возможность полностью контролировать структуру и оптимизацию.
Добавим функцию wordpresses_create_comments_table, которая создаст таблицу при активации темы или плагина:
function wordpresses_create_comments_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'custom_comments';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
post_id BIGINT(20) UNSIGNED NOT NULL,
user_name VARCHAR(100) NOT NULL,
user_email VARCHAR(100) NOT NULL,
comment_text TEXT NOT NULL,
parent_id BIGINT(20) UNSIGNED DEFAULT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY post_id (post_id),
KEY parent_id (parent_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// Вызов функции при инициализации темы или плагина
add_action('after_switch_theme', 'wordpresses_create_comments_table');
Это создаст таблицу wp_custom_comments с полями для хранения ID поста, имени и email пользователя, текста комментария, ссылки на родительский комментарий и времени создания.
Создание формы и обработка комментариев через AJAX
Чтобы система была удобной, реализуем отправку комментариев без перезагрузки страницы, используя AJAX. Сначала создадим форму:
<form id="wordpresses-comment-form" data-post-id="<?php the_ID(); ?>">
<input type="text" name="user_name" placeholder="Ваше имя" required />
<input type="email" name="user_email" placeholder="Ваш email" required />
<textarea name="comment_text" placeholder="Комментарий" required></textarea>
<input type="hidden" name="parent_id" value="0" />
<button type="submit">Отправить</button>
</form>
<div id="wordpresses-comments-list"></div>
Далее добавим JavaScript для отправки данных:
jQuery(document).ready(function($) {
$('#wordpresses-comment-form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
var data = {
action: 'wordpresses_submit_comment',
post_id: form.data('post-id'),
user_name: form.find('[name="user_name"]').val(),
user_email: form.find('[name="user_email"]').val(),
comment_text: form.find('[name="comment_text"]').val(),
parent_id: form.find('[name="parent_id"]').val(),
security: wordpresses_ajax_object.nonce
};
$.post(wordpresses_ajax_object.ajax_url, data, function(response) {
if(response.success) {
alert('Комментарий добавлен!');
loadComments(data.post_id);
form[0].reset();
} else {
alert('Ошибка: ' + response.data);
}
});
});
function loadComments(postId) {
$.get(wordpresses_ajax_object.ajax_url, { action: 'wordpresses_load_comments', post_id: postId }, function(response) {
if(response.success) {
$('#wordpresses-comments-list').html(response.data);
}
});
}
loadComments($('#wordpresses-comment-form').data('post-id'));
});
Для корректной работы AJAX нужно зарегистрировать скрипт и локализовать переменные в PHP:
function wordpresses_enqueue_scripts() {
wp_enqueue_script('wordpresses-comments', get_template_directory_uri() . '/js/comments.js', array('jquery'), '1.0', true);
wp_localize_script('wordpresses-comments', 'wordpresses_ajax_object', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('wordpresses_nonce')
));
}
add_action('wp_enqueue_scripts', 'wordpresses_enqueue_scripts');
Обработка отправки комментариев в PHP
Создадим обработчик wordpresses_submit_comment, который будет валидировать данные, сохранять комментарий и возвращать ответ:
function wordpresses_handle_submit_comment() {
check_ajax_referer('wordpresses_nonce', 'security');
global $wpdb;
$table_name = $wpdb->prefix . 'custom_comments';
$post_id = intval($_POST['post_id']);
$user_name = sanitize_text_field($_POST['user_name']);
$user_email = sanitize_email($_POST['user_email']);
$comment_text = sanitize_textarea_field($_POST['comment_text']);
$parent_id = intval($_POST['parent_id']);
if(empty($user_name) || empty($user_email) || empty($comment_text) || !is_email($user_email)) {
wp_send_json_error('Некорректные данные');
}
$inserted = $wpdb->insert($table_name, array(
'post_id' => $post_id,
'user_name' => $user_name,
'user_email' => $user_email,
'comment_text' => $comment_text,
'parent_id' => $parent_id > 0 ? $parent_id : null,
'created_at' => current_time('mysql', 1)
));
if($inserted) {
wp_send_json_success();
} else {
wp_send_json_error('Ошибка при сохранении комментария');
}
}
add_action('wp_ajax_wordpresses_submit_comment', 'wordpresses_handle_submit_comment');
add_action('wp_ajax_nopriv_wordpresses_submit_comment', 'wordpresses_handle_submit_comment');
Загрузка и отображение комментариев
Для загрузки комментариев создадим функцию, которая будет получать комментарии из таблицы и выводить их в виде вложенного списка:
function wordpresses_load_comments() {
$post_id = intval($_GET['post_id']);
global $wpdb;
$table_name = $wpdb->prefix . 'custom_comments';
$comments = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table_name WHERE post_id = %d ORDER BY created_at ASC",
$post_id
));
if(!$comments) {
wp_send_json_success('<p>Комментариев пока нет.</p>');
}
// Формируем иерархию комментариев
$tree = array();
$refs = array();
foreach ($comments as $comment) {
$comment->children = array();
$refs[$comment->id] = $comment;
if ($comment->parent_id) {
$refs[$comment->parent_id]->children[] = $comment;
} else {
$tree[] = $comment;
}
}
$output = wordpresses_render_comments_tree($tree);
wp_send_json_success($output);
}
add_action('wp_ajax_wordpresses_load_comments', 'wordpresses_load_comments');
add_action('wp_ajax_nopriv_wordpresses_load_comments', 'wordpresses_load_comments');
function wordpresses_render_comments_tree($comments) {
$html = '<ul class="wordpresses-comments">';
foreach ($comments as $comment) {
$html .= '<li>';
$html .= '<strong>' . esc_html($comment->user_name) . '</strong> <em>' . esc_html($comment->created_at) . '</em>';
$html .= '<p>' . nl2br(esc_html($comment->comment_text)) . '</p>';
if (!empty($comment->children)) {
$html .= wordpresses_render_comments_tree($comment->children);
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
Дополнительные улучшения и безопасность
Для повышения безопасности и удобства можно добавить следующие улучшения:
- Валидация и фильтрация на стороне клиента и сервера (уже частично реализована);
- Реализация защиты от спама — например, капча или ограничение частоты отправки;
- Отображение кнопки «Ответить» для вложенных комментариев и передача
parent_idв форму; - Кэширование комментариев для уменьшения нагрузки на базу;
- Интеграция с REST API для расширенного взаимодействия и мобильных приложений.
Также в качестве альтернативы кастомной реализации можно рассмотреть легковесные плагины, например, Clearfy Pro, который позволяет оптимизировать стандартную систему комментариев и добавлять расширенные настройки безопасности и производительности.