Итак, комментарии на AJAX. Перед написанием этого поста я потратил добрую половину дня на их разработку — хорошо, что я уже был с ними знаком. В самый первый раз, когда я ещё начинал изучать jQuery, на создание асинхронных комментариев с нуля у меня ушли первые две недели января.
Кстати, я долго думал, имеет ли смысл поставить комментарии со стороннего сервиса, например disqus — но в итоге решил что свои комментарии на AJAX будут покруче.
Требования к AJAX-комментам
Допустим, мы только что решили поставить асинхронные комментарии у себя на сайте. Какую функциональность, на наш взгляд, они должны иметь?
- самое главное — возможность работы со стандартными древовидными комментариями comment-reply.js,
- вывод ошибок, в том числе вордпрессовских, особо с этим заморачиваться не буду, сделаю через
alert()
пока что, - проверка комментария на наличие запрещенных HTML-тегов. Читайте о том, как изменить список разрешенных тегов,
- модерация комментария при необходимости,
- запоминание в кукисах значений полей «Имя» и «Email»,
- исключить возможность двойного нажатия на кнопку «Отправить»,
- не используем никакие плагины WordPress;
Шаг 1. Подготовка. Структура HTML.
Будем отталкиваться от стандартных тем WordPress, это Twenty Ten и Twenty Eleven. Разумеется, то, что представлено в следующем куске кода — всего лишь HTML-шаблон, который должен сориентировать вас по атрибутам class и id, а также по расположению элементов, а вообще все эти штуки делаются через php!
<!-- можно <ul> или <ol> --> <ol class="commentlist"> <!-- класс depth-1 показывает уровень вложенности --> <li class="comment depth-1" id="li-comment-4"> <div id="comment-4"> <!-- тут содержимое комментария --> <div class="reply"> <a class="comment-reply-link">Ответить</a> </div> </div> <!-- дальше идут ответы к предыдущему комментарию --> <ul class="children"> <!-- depth-2 - значит вложенность второго уровня --> <li class="comment depth-2" id="li-comment-5"> <div id="comment-5"> <!-- тут содержимое комментария --> <div class="reply"> <a class="comment-reply-link">Ответить</a> </div> </div> </li> </ul> </li> </ol> <div id="respond"> <!-- тут нужно обратить внимание также на атрибуты name --> <a id="cancel-comment-reply-link" style="display:none;">Отменить ответ</a> <form id="commentform"> <input name="author" id="author" type="text" /> <input name="email" id="email" type="text" /><!-- или type="email", как хотите --> <input name="url" id="url" type="text" /> <textarea name="comment" id="comment"></textarea> <input name="submit" type="submit" id="submit" value="Отправить" /> <!-- если у вас нет hidden-полей попробуйте вставить их через php-функцию comment_id_fields() --> <input type="hidden" name="comment_post_ID" /> <input type="hidden" name="comment_parent" /> </form> </div> |
Так что, если у вас что-то добавляется не туда, куда надо, сверяйтесь по этому листингу.
Примерно так это будет выглядеть:
В код моего блога советую не залазить, у меня там структура немного другая, она может вас только запутать ещё больше. Если что-то не получается или есть вопрос — просто задайте его мне прямо в комментариях к этому посту.
Шаг 2. CSS
Если у вас со структурой всё окей, то стили по сути и не понадобятся, за исключением оформления ошибок, возникающих в результате валидации полей. То есть, если кто-то ввёл неверный адрес email, поле должно стать красного цвета (например).
input.error, textarea.error{ background: #fe0000; /* или background:red или любой другой цвет, который больше вписывается в дизайн вашего блога */ } |
Добавляем этот код в основной файл стилей вашей темы, обычно это — style.css
.
Шаг 3. Подключение скриптов
Во-первых, давайте в папке с темой создадим какой-нибудь файл JavaScript, в который мы потом добавим весь наш код. У меня это будет файл comments.js
.
Теперь наша задача — правильно подключить библиотеку jQuery и файл comments.js
. Для этого воспользуемся функцией wp_enqueue_script().
Следующий код вставляем в файл functions.php
вашей текущей темы:
function true_include_my_comment_script() { wp_enqueue_script( 'jquery' ); wp_enqueue_script( 'commentjs', get_stylesheet_directory_uri() . '/comments.js', array('jquery'), null ); } add_action( 'wp_enqueue_scripts', 'true_include_my_comment_script' ); |
Зайдите в исходный код страницы (в Windows — Ctrl + U) и посмотрите, появился ли там comments.js,
если да — переходим к следующему шагу, если нет — открываем файлы header.php
и footer.php
и убеждаемся, что там присутствуют функции wp_head() и wp_footer() соответственно.
Шаг 4. Скрипты jQuery
Открываем наш файл comments.js
и вписываем туда:
jQuery.extend(jQuery.fn, { /* * функция проверки, что длина поля не меньше 3х символов */ checka: function () { if (jQuery(this).val().length < 3) {jQuery(this).addClass('error');return false} else {jQuery(this).removeClass('error');return true} }, /* * функция проверки правильности введенного email */ checke: function () { var emailReg = /^([w-.]+@([w-]+.)+[w-]{2,4})?$/; var emailaddressVal = jQuery(this).val(); if (!emailReg.test(emailaddressVal) || emailaddressVal == "") { jQuery(this).addClass('error');return false } else { jQuery(this).removeClass('error');return true } }, }); jQuery(function($){ $('#commentform').submit(function(){ // может такое случиться, что пользователь залогинен - нужно это проверить, иначе валидация не пройдет if($("#author").length) var author = $("#author").checka(); if($("#email").length) var email = $("#email").checke(); var comment = $("#comment").checka(); // небольшое условие для того, чтобы исключить двойные нажатия на кнопку отправки // в это условие также входит валидация полей if (!$('#submit').hasClass('loadingform') && !$("#author").hasClass('error') && !$("#email").hasClass('error') && !$("#comment").hasClass('error')){ $.ajax({ type : 'POST', url : 'http://' + location.host + '/wp-admin/admin-ajax.php', data: $(this).serialize() + '&action=ajaxcomments', beforeSend: function(xhr){ // действие при отправке формы, сразу после нажатия на кнопку #submit $('#submit').addClass('loadingform').val('Загрузка'); }, error: function (request, status, error) { if(status==500){ alert('Ошибка при добавлении комментария'); } else if(status=='timeout'){ alert('Ошибка: Сервер не отвечает, попробуй ещё.'); } else { // ворпдрессовские ошибочки, не уверен, что это самый оптимальный вариант // если знаете способ получше - поделитесь var errormsg = request.responseText; var string1 = errormsg.split("<p>"); var string2 = string1[1].split("</p>"); alert(string2[0]); } }, success: function (newComment) { // Если уже есть какие-то комментарии if($('.commentlist').length > 0){ // Если текущий комментарий является ответом if($('#respond').parent().hasClass('comment')){ // Если уже есть какие-то ответы if($('#respond').parent().children('.children').length){ $('#respond').parent().children('.children').append(newComment); } else { // Если нет, то добавляем <ul class="children"> newComment = '<ul class="children">'+newComment+'</ul>'; $('#respond').parent().append(newComment); } // закрываем форму ответа $("#cancel-comment-reply-link").trigger("click"); } else { // обычный коммент $('.commentlist').append(newComment); } }else{ // если комментов пока ещё нет, тогда newComment = '<ul class="commentlist">'+newComment+'</ol>'; $('#respond').before($(newComment)); } // очищаем поле textarea $('#comment').val(''); }, complete: function(){ // действие, после того, как комментарий был добавлен $('#submit').removeClass('loadingform').val('Отправить'); } }); } return false; }); }); |
Последний шаг. PHP-обработчик
Читайте подробнее о том, как обрабатываются асинхронные запросы в WordPress. Код обработчика:
<?php // если вы вставляете код не в новый файл, то <?php нужно удалить function true_add_ajax_comment(){ global $wpdb; $comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : 0; $post = get_post($comment_post_ID); if ( empty($post->comment_status) ) { do_action('comment_id_not_found', $comment_post_ID); exit; } $status = get_post_status($post); $status_obj = get_post_status_object($status); /* * различные проверки комментария */ if ( !comments_open($comment_post_ID) ) { do_action('comment_closed', $comment_post_ID); wp_die( __('Sorry, comments are closed for this item.') ); } elseif ( 'trash' == $status ) { do_action('comment_on_trash', $comment_post_ID); exit; } elseif ( !$status_obj->public && !$status_obj->private ) { do_action('comment_on_draft', $comment_post_ID); exit; } elseif ( post_password_required($comment_post_ID) ) { do_action('comment_on_password_protected', $comment_post_ID); exit; } else { do_action('pre_comment_on_post', $comment_post_ID); } $comment_author = ( isset($_POST['author']) ) ? trim(strip_tags($_POST['author'])) : null; $comment_author_email = ( isset($_POST['email']) ) ? trim($_POST['email']) : null; $comment_author_url = ( isset($_POST['url']) ) ? trim($_POST['url']) : null; $comment_content = ( isset($_POST['comment']) ) ? trim($_POST['comment']) : null; /* * проверяем, залогинен ли пользователь */ $user = wp_get_current_user(); if ( $user->exists() ) { if ( empty( $user->display_name ) ) $user->display_name=$user->user_login; $comment_author = $wpdb->escape($user->display_name); $comment_author_email = $wpdb->escape($user->user_email); $comment_author_url = $wpdb->escape($user->user_url); $user_ID = get_current_user_id(); if ( current_user_can('unfiltered_html') ) { if ( wp_create_nonce('unfiltered-html-comment_' . $comment_post_ID) != $_POST['_wp_unfiltered_html_comment'] ) { kses_remove_filters(); // start with a clean slate kses_init_filters(); // set up the filters } } } else { if ( get_option('comment_registration') || 'private' == $status ) wp_die( 'Вы должны зарегистрироваться или войти, чтобы оставлять комментарии.' ); } $comment_type = ''; /* * проверяем, заполнил ли пользователь все необходимые поля */ if ( get_option('require_name_email') && !$user->exists() ) { if ( 6 > strlen($comment_author_email) || '' == $comment_author ) wp_die( 'Ошибка: заполните необходимые поля (Имя, Email).' ); elseif ( !is_email($comment_author_email)) wp_die( 'Ошибка: введенный вами email некорректный.' ); } if ( '' == trim($comment_content) || '<p><br></p>' == $comment_content ) wp_die( 'Вы забыли про комментарий.' ); /* * добавляем новый коммент и сразу же обращаемся к нему */ $comment_parent = isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0; $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID'); $comment_id = wp_new_comment( $commentdata ); $comment = get_comment($comment_id); /* * выставляем кукисы */ do_action('set_comment_cookies', $comment, $user); /* * вложенность комментариев */ $comment_depth = 1; while($comment_parent){ $comment_depth++; $parent_comment = get_comment($comment_parent); $comment_parent = $parent_comment->comment_parent; } $GLOBALS['comment'] = $comment; $GLOBALS['comment_depth'] = $comment_depth; /* * ниже идет шаблон нового комментария, вы можете настроить его для себя, * а можете воспользоваться функцией(которая скорее всего уже есть в теме) для его вывода */ ?> <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>"> <div id="comment-<?php comment_ID(); ?>"> <div class="comment-author vcard"> <?php echo get_avatar( $comment, 40 ); ?> <cite class="fn"><?php echo get_comment_author_link(); ?></cite> </div> <?php if ( $comment->comment_approved == '0' ) : ?> <em class="comment-awaiting-moderation">Комментарий отправлен на проверку</em> <br /> <?php endif; ?> <div class="comment-meta commentmetadata"><a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>"> <?php printf('%1$s в %2$s', get_comment_date(), get_comment_time() ); ?></a><?php edit_comment_link('ред.', ' ' ); ?> </div> <div class="comment-body"><?php comment_text(); ?></div> </div> </li> <?php die(); } add_action('wp_ajax_ajaxcomments', 'true_add_ajax_comment'); // wp_ajax_{значение параметра action} add_action('wp_ajax_nopriv_ajaxcomments', 'true_add_ajax_comment'); // wp_ajax_nopriv_{значение параметра action} |
Комменты можете протестировать прямо на моем блоге, там совсем незначительные изменения в коде, также я протестировал весь код из статьи ничего не меняя, как есть, на теме Twenty Ten.
Со временем пост будет обновляться по мере совершенствования кода в нем, после появления каких-либо доработок.
Также есть доработки, которые я не буду добавлять, дабы не усложнять пост, но вам стоит попробовать сделать их самим:
- При добавлении нового комментария неплохо также обновлять цифру с количеством комментариев, которую обычно можно найти рядом с датой публикацией поста и в заголовке непосредственно перед самими комментами,
- Вы можете оформить ошибки в виде красивых всплывающих окон или в виде подсказок,
- Очень здорово, если при нажатии на кнопку отправки, на ней будет появляться анимация-прелоадер, как у меня на блоге.
Источник: misha.blog
Проверка Ajax комментариев, на твоем блоге.
Проверка
Test comments
Тест
asd
wegweh