首先说下使用 ajax 提交评论的好处,提升交互体验就不谈了,最重要的是可以防止垃圾评论,所以我们建议所有 WordPress 用户来使用这个方法提交评论。要知道一般垃圾评论都是通过表单机器人提交的,如果使用了 ajax 评论提交我们就可以禁用 wordpress 的表单提交,也就是删除或者清空 wp 根目录下的 wp-comment-post.php 这个文件。

当然你可能会说我可以使用 akismet 插件啊,是的,你完全可以,但是这个插件一来会拖慢评论提交的速度,二来会在数据库中的 commentmeta 中插入大量的无用数据,所以强烈建议使用 ajax 评论提交。

当然你又可以说,我可以使用多说,但是你知道会把你的网站同步过去么?就好比你害怕自己女朋友受到伤害,然后把女朋友放到了一个不属于你的 “安全” 的地方,所以再次强烈建议使用 ajax 评论提交。

此方法的优点

  • 防止垃圾评论。
  • 增强交互体验。
  • 使用 wordpress 自带的 admin-ajax.php 进行数据提交。
  • 支持评论修改,同时消除了匿名用户可篡改任意评论内容。

实现方法

下面的代码加到 functions.php 中,注意修改成你自己的评论样式

add_action(‘wp_ajax_nopriv_ajax_comment’, ‘ajax_comment’);
add_action(‘wp_ajax_ajax_comment’, ‘ajax_comment’);
function ajax_comment(){
global $wpdb;
//nocache_headers();
$comment_post_ID = isset($_POST[‘comment_post_ID’]) ? (int) $_POST[‘comment_post_ID’] : 0;
$post = get_post($comment_post_ID);
$post_author = $post->post_author;
if ( empty($post->comment_status) ) {
do_action(‘comment_id_not_found’, $comment_post_ID);
ajax_comment_err(‘Invalid comment status.’);
}
$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);
ajax_comment_err(‘Sorry, comments are closed for this item.’);
} elseif ( ‘trash’ == $status ) {
do_action(‘comment_on_trash’, $comment_post_ID);
ajax_comment_err(‘Invalid comment status.’);
} elseif ( !$status_obj->public && !$status_obj->private ) {
do_action(‘comment_on_draft’, $comment_post_ID);
ajax_comment_err(‘Invalid comment status.’);
} elseif ( post_password_required($comment_post_ID) ) {
do_action(‘comment_on_password_protected’, $comment_post_ID);
ajax_comment_err(‘Password Protected’);
} 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;
$edit_id = ( isset($_POST[‘edit_id’]) ) ? $_POST[‘edit_id’] : null; // 提取 edit_id
$user = wp_get_current_user();
if ( $user->exists() ) {
if ( empty( $user->display_name ) )
$user->display_name=$user->user_login;
$comment_author = esc_sql($user->display_name);
$comment_author_email = esc_sql($user->user_email);
$comment_author_url = esc_sql($user->user_url);
$user_ID = esc_sql($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();
kses_init_filters();
}
}
} else {
if ( get_option(‘comment_registration’) || ‘private’ == $status )
ajax_comment_err(‘Sorry, you must be logged in to post a comment.’);
}
$comment_type = ”;
if ( get_option(‘require_name_email’) && !$user->exists() ) {
if ( 6 > strlen($comment_author_email) || ” == $comment_author )
ajax_comment_err( ‘Error: please fill the required fields (name, email).’ );
elseif ( !is_email($comment_author_email))
ajax_comment_err( ‘Error: please enter a valid email address.’ );
}
if ( ” == $comment_content )
ajax_comment_err( ‘Error: please type a comment.’ );
$dupe = “SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = ‘$comment_post_ID’ AND ( comment_author = ‘$comment_author’ “;
if ( $comment_author_email ) $dupe .= “OR comment_author_email = ‘$comment_author_email’ “;
$dupe .= “) AND comment_content = ‘$comment_content’ LIMIT 1”;
if ( $wpdb->get_var($dupe) ) {
ajax_comment_err(‘Duplicate comment detected; it looks as though you’ve already said that!’);
}
if ( $lasttime = $wpdb->get_var( $wpdb->prepare(“SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_author = %s ORDER BY comment_date DESC LIMIT 1″, $comment_author) ) ) {
$time_lastcomment = mysql2date(‘U’, $lasttime, false);
$time_newcomment = mysql2date(‘U’, current_time(‘mysql’, 1), false);
$flood_die = apply_filters(‘comment_flood_filter’, false, $time_lastcomment, $time_newcomment);
if ( $flood_die ) {
ajax_comment_err(‘You are posting comments too quickly. Slow down.’);
}
}
$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’);

if ( $edit_id )
{
$comment_id = $commentdata[‘comment_ID’] = $edit_id;
if( ihacklog_user_can_edit_comment($commentdata,$comment_id) )
{
wp_update_comment( $commentdata );
}
else
{
ajax_comment_err( ‘Cheatin’ uh?’ );
}

}
else
{
$comment_id = wp_new_comment( $commentdata );
}

$comment = get_comment($comment_id);
do_action(‘set_comment_cookies’, $comment, $user);
$comment_depth = 1;
$tmp_c = $comment;
while($tmp_c->comment_parent != 0){
$comment_depth++;
$tmp_c = get_comment($tmp_c->comment_parent);
}
$GLOBALS[‘comment’] = $comment;
//这里修改成你的评论结构
?>
<li <?php comment_class(); ?> <?php if( $depth > 2){ echo ‘ style=”margin-left:-50px;”‘;} ?> id=”li-comment-<?php comment_ID() ?>” itemtype=”http://schema.org/Comment” itemscope=”” itemprop=”comment”>
<div class=”comment-block”>
<div class=”comment-info”>
<div class=”comment-avatar”>
<?php
if(get_comment_meta(get_comment_ID(), ‘_avatar’)){
echo ‘<img src=”‘.get_comment_meta(get_comment_ID(), ‘_avatar’,true).’”>’;
}else{
echo get_avatar( $comment, $size = ’40’);
}
?><?php is_friend_link($comment->comment_author_url); ?>
</div>
<div class=”comment-meta fontSmooth”>
<div class=”name” itemprop=”author”><?php echo get_comment_author_link();?></div>
<div class=”time” itemprop=”datePublished”><?php echo get_comment_date(); ?></div>
</div>
</div>
<div class=”comment-content” itemprop=”description”>
<?php comment_text(); ?>
</div>
</div>
<?php die();

}
function ajax_comment_err($a) {
header(‘HTTP/1.0 500 Internal Server Error’);
header(‘Content-Type: text/plain;charset=UTF-8’);
echo $a;
exit;
}
function ihacklog_user_can_edit_comment($new_cmt_data,$comment_ID = 0) {
if(current_user_can(‘edit_comment’, $comment_ID)) {
return true;
}
$comment = get_comment( $comment_ID );
$old_timestamp = strtotime( $comment->comment_date);
$new_timestamp = current_time(‘timestamp’);
// 不用 get_comment_author_email($comment_ID) , get_comment_author_IP($comment_ID)
$rs = $comment->comment_author_email === $new_cmt_data[‘comment_author_email’]
&& $comment->comment_author_IP === $_SERVER[‘REMOTE_ADDR’]
&& $new_timestamp – $old_timestamp < 3600;
return $rs;
}

js 代码

jQuery(document).ready(function(jQuery) {
var jQuerycommentform = jQuery(‘#commentform’),
txt1 = ‘<div id=”loading”><img src=”wp-includes/images/spinner.gif”> 正在提交, 请稍候…</div>’,
txt2 = ‘<div id=”error”>#</div>’,
txt3 = ‘”> 提交成功’,
edt1 = ‘, 刷新页面之前可以<a rel=”nofollow” class=”comment-reply-link” href=”#edit” onclick=’return addComment.moveForm(“‘,
edt2 = ‘)’> 再编辑</a>’,
cancel_edit = ‘ 取消编辑’,
edit,
num = 1,
jQuerycomments = jQuery(‘#comments-title’),
jQuerycancel = jQuery(‘#cancel-comment-reply-link’),
cancel_text = jQuerycancel.text(),
jQuerysubmit = jQuery(‘#commentform #submit’);
jQuerysubmit.attr(‘disabled’, false),
jQuerybody = (window.opera) ? (document.compatMode == “CSS1Compat” ? jQuery(‘html’) : jQuery(‘body’)) : jQuery(‘html,body’),
comm_array = [];
comm_array.push(”);
jQuery(‘#comment’).after(txt1 + txt2);
jQuery(‘#loading’).hide();
jQuery(‘#error’).hide();
jQuery(document).on(“submit”, “#commentform”,
function() {
if (edit) jQuery(‘#comment’).after(‘<input type=”text” name=”edit_id” id=”edit_id” value=”‘ + edit + ‘” style=”display:none;” />’);
editcode();
jQuerysubmit.attr(‘disabled’, true).fadeTo(‘slow’, 0.5);
jQuery(‘#loading’).slideDown();
jQuery.ajax({
url: ‘/admin-ajax.php’,
data: jQuery(this).serialize() + “&action=ajax_comment”,
type: jQuery(this).attr(‘method’),
error: function(request) {
jQuery(‘#loading’).hide();
jQuery(“#error”).slideDown().html(request.responseText);
setTimeout(function() {
jQuerysubmit.attr(‘disabled’, false).fadeTo(‘slow’, 1);
jQuery(‘#error’).slideUp();
},
3000);
},
success: function(data) {
jQuery(‘#loading’).hide();
comm_array.push(jQuery(‘#comment’).val());
jQuery(‘textarea’).each(function() {
this.value = ”
});
var t = addComment,
cancel = t.I(‘cancel-comment-reply-link’),
temp = t.I(‘wp-temp-form-div’),
respond = t.I(t.respondId),
post = t.I(‘comment_post_ID’).value,
parent = t.I(‘comment_parent’).value;
if (!edit && jQuerycomments.length) {
n = parseInt(jQuerycomments.text().match(/d+/));
jQuerycomments.text(jQuerycomments.text().replace(n, n + 1));
}
new_htm = ‘” id=”new_comm_’ + num + ‘”></’;
new_htm = (parent == ‘0’) ? (‘
<ol style=”clear:both;” class=”commentlist’ + new_htm + ‘ol>’) : (‘
<ul class=”children’ + new_htm + ‘ul>’);
ok_htm = ‘
<div class=”ajax-notice” id=”success_’ + num + txt3;
div_ = (document.body.innerHTML.indexOf(‘div-comment-‘) == -1) ? ”: ((document.body.innerHTML.indexOf(‘li-comment-‘) == -1) ? ‘div-‘: ”);
ok_htm = ok_htm.concat(edt1, div_, ‘comment-‘, parent, ‘”, “‘, parent, ‘”, “respond”, “‘, post, ‘”, ‘, num, edt2);
ok_htm += ‘</span><span></span>
’;
ok_htm += ‘</div>
’;
jQuery(‘#respond’).before(new_htm);
jQuery(‘#new_comm_’ + num).append(data);
jQuery(‘#new_comm_’ + num + ‘ li’).append(ok_htm);
jQuerybody.animate({
scrollTop: jQuery(‘#new_comm_’ + num).offset().top – 200
},
900);
countdown();
num++;
edit = ”;
jQuery(‘*’).remove(‘#edit_id’);
cancel.style.display = ‘none’;
cancel.onclick = null;
t.I(‘comment_parent’).value = ‘0’;
if (temp && respond) {
temp.parentNode.insertBefore(respond, temp);
temp.parentNode.removeChild(temp)
}
}
});
return false;
});
addComment = {
moveForm: function(commId, parentId, respondId, postId, num) {
var t = this,
div,
comm = t.I(commId),
respond = t.I(respondId),
cancel = t.I(‘cancel-comment-reply-link’),
parent = t.I(‘comment_parent’),
post = t.I(‘comment_post_ID’);
if (edit) exit_prev_edit();
num ? (t.I(‘comment’).value = comm_array[num], edit = t.I(‘new_comm_’ + num).innerHTML.match(/(comment-)(d+)/)[2], jQuerynew_sucs = jQuery(‘#success_’ + num), jQuerynew_sucs.hide(), jQuerynew_comm = jQuery(‘#new_comm_’ + num), jQuerynew_comm.hide(), jQuerycancel.text(cancel_edit)) : jQuerycancel.text(cancel_text);
t.respondId = respondId;
postId = postId || false;
if (!t.I(‘wp-temp-form-div’)) {
div = document.createElement(‘div’);
div.id = ‘wp-temp-form-div’;
div.style.display = ‘none’;
respond.parentNode.insertBefore(div, respond)
} ! comm ? (temp = t.I(‘wp-temp-form-div’), t.I(‘comment_parent’).value = ‘0’, temp.parentNode.insertBefore(respond, temp), temp.parentNode.removeChild(temp)) : comm.parentNode.insertBefore(respond, comm.nextSibling);
jQuerybody.animate({
scrollTop: jQuery(‘#respond’).offset().top – 180
},
400);
if (post && postId) post.value = postId;
parent.value = parentId;
cancel.style.display = ”;
cancel.onclick = function() {
if (edit) exit_prev_edit();
var t = addComment,
temp = t.I(‘wp-temp-form-div’),
respond = t.I(t.respondId);
t.I(‘comment_parent’).value = ‘0’;
if (temp && respond) {
temp.parentNode.insertBefore(respond, temp);
temp.parentNode.removeChild(temp);
}
this.style.display = ‘none’;
this.onclick = null;
return false;
};
try {
t.I(‘comment’).focus();
}
catch(e) {}
return false;
},
I: function(e) {
return document.getElementById(e);
}
};
function exit_prev_edit() {
jQuerynew_comm.show();
jQuerynew_sucs.show();
jQuery(‘textarea’).each(function() {
this.value = ”
});
edit = ”;
}
var wait = 15,
submit_val = jQuerysubmit.val();
function countdown() {
if (wait > 0) {
jQuerysubmit.val(wait);
wait–;
setTimeout(countdown, 1000);
} else {
jQuerysubmit.val(submit_val).attr(‘disabled’, false).fadeTo(‘slow’, 1);
wait = 15;
}
}
function editcode() {
var a = “”,
b = jQuery(“#comment”).val(),
start = b.indexOf(“<code>”),
end = b.indexOf(“</code>”);
if (start > -1 && end > -1 && start < end) {
a = “”;
while (end != -1) {
a += b.substring(0, start + 6) + b.substring(start + 6, end).replace(/<(?=[^>]*?>)/gi, “&lt;”).replace(/>/gi, “&gt;”);
b = b.substring(end + 7, b.length);
start = b.indexOf(“<code>”) == -1 ? -6: b.indexOf(“<code>”);
end = b.indexOf(“</code>”);
if (end == -1) {
a += “</code>” + b;
jQuery(“#comment”).val(a)
} else if (start == -6) {
myFielde += “&lt;/code&gt;”
} else {
a += “</code>”
}
}
}
var b = a ? a: jQuery(“#comment”).val(),
a = “”,
start = b.indexOf(“<pre>”),
end = b.indexOf(“</pre>”);
if (start > -1 && end > -1 && start < end) {
a = a
} else return;
while (end != -1) {
a += b.substring(0, start + 5) + b.substring(start + 5, end).replace(/<(?=[^>]*?>)/gi, “&lt;”).replace(/>/gi, “&gt;”);
b = b.substring(end + 6, b.length);
start = b.indexOf(“<pre>”) == -1 ? -5: b.indexOf(“<pre>”);
end = b.indexOf(“</pre>”);
if (end == -1) {
a += “</pre>” + b;
jQuery(“#comment”).val(a)
} else if (start == -5) {
myFielde += “&lt;/pre&gt;”
} else {
a += “</pre>”
}
}
}
function grin(a) {
var b;
a = ” ” + a + ” “;
if (document.getElementById(“comment”) && document.getElementById(“comment”).type == “textarea”) {
b = document.getElementById(“comment”)
} else {
return false
}
if (document.selection) {
b.focus();
sel = document.selection.createRange();
sel.text = a;
b.focus()
} else if (b.selectionStart || b.selectionStart == “0”) {
var c = b.selectionStart;
var d = b.selectionEnd;
var e = d;
b.value = b.value.substring(0, c) + a + b.value.substring(d, b.value.length);
e += a.length;
b.focus();
b.selectionStart = e;
b.selectionEnd = e
} else {
b.value += a;
b.focus()
}
}
});

以上。