Skip to content

折腾WordPress內置嵌套评论专用Ajax comments

2010 四月 24
by 荒野无灯

前阵子折腾这个没有成功,今天搞定了。
文章有点长,边听下歌边看吧:
电台情歌 – <莫文蔚>


再去掉几个WP插件:
0×01
中文 WordPress 工具箱 (mulberrykit) 这个插件用了好久了,自从我建WP那天起就一直在用,今天突然打开它的源文件,看见它的代码 ,发现其实很久以来我只用到它的一个功能,就是截取UTF-8字符。
去掉这个插件,然后把以下代码加入functions.php即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// A trim function to remove the last character of a utf-8 string
// by following instructions on http://en.wikipedia.org/wiki/UTF-8
// dotann

function utf8_trim($str) {

    $len = strlen($str);

    for ($i=strlen($str)-1; $i>=0; $i-=1){
        $hex .= ' '.ord($str[$i]);
        $ch = ord($str[$i]);
        if (($ch & 128)==0) return(substr($str,0,$i));
        if (($ch & 192)==192) return(substr($str,0,$i));
    }
    return($str.$hex);
}


function mul_excerpt ($excerpt) {
     $myexcerpt = substr($excerpt,0,255);
     return utf8_trim($myexcerpt) . '... ';
}

add_filter('the_excerpt', 'mul_excerpt');
add_filter('the_excerpt_rss', 'mul_excerpt');

0×02
wordpress-thread-comment 这个专门用来实现嵌套评论功能的插件也被我残忍地去掉了。感谢willin童鞋的折腾,呵呵,现在我的任务是继续他的折腾。 :eek:
用了willin大师的 《WordPress 內置嵌套評論專用 Ajax comments》《Comment Mail Notify》

对于willin的 WordPress 內置嵌套評論專用 Ajax comments 中的 comments-ajax.php文件,我也做了些修改:
willin是把原版的wp-comments-post.php文件中的wp_die修改为err函数,然后再自定义一个名为err的函数,个人觉得无论从哪方面说这都是没必要的。
首先405 Method Not Allowed表示 提交方式不允许,并不是所有的错误都是由非法提交方式引起的,所以,我们不需要自定义函数了。只要简单了把wp_die修改为die就可以了。
另外,还发现willin的comments-ajax.php与wp原版的wp-comments-post.php文件不同的地方是添加了两个东东:

增加: 檢查評論太快功能

增加: 檢查重覆評論功能

其实这两个也是没有必要添加的。看下WP的代码就知道了:

在wp的default-filters.php文件中你可以看到以下代码:
//default-filters.php

1
2
add_action( 'check_comment_flood',  'check_comment_flood_db',       10, 3 );
add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood',    10, 3 );

再在wp的comments.php等文件可以看到如下相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// wp_throttle_comment_flood函数用来检查评论者提交留言的时间是否满足是恶意灌水的条件
function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
    if ( $block ) // a plugin has already blocked... we'll let that decision stand
        return $block;
    if ( ($time_newcomment - $time_lastcomment) < 15 )
        return true;
    return false;
}

//用来检测灌水的函数,对于管理员它是不检测的。
function check_comment_flood_db( $ip, $email, $date ) {
    global $wpdb;
    if ( current_user_can( 'manage_options' ) )
        return; // don't throttle admins
    $hour_ago = gmdate( 'Y-m-d H:i:s', time() - 3600 );
    if ( $lasttime = $wpdb->get_var( $wpdb->prepare( "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( `comment_author_IP` = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1", $hour_ago, $ip, $email ) ) ) {
        $time_lastcomment = mysql2date('U', $lasttime, false);
        $time_newcomment  = mysql2date('U', $date, false);
               //这里调用了 wp_throttle_comment_flood  函数
        $flood_die = apply_filters('comment_flood_filter', false, $time_lastcomment, $time_newcomment);
        if ( $flood_die ) {
            do_action('comment_flood_trigger', $time_lastcomment, $time_newcomment);

            if ( defined('DOING_AJAX') )
                die( __('You are posting comments too quickly.  Slow down.') );

            wp_die( __('You are posting comments too quickly.  Slow down.'), '', array('response' => 403) );
        }
    }
}


//检测重复评论 和 恶意灌水
function wp_allow_comment($commentdata) {
    global $wpdb;
    extract($commentdata, EXTR_SKIP);
/检测重复评论
    // Simple duplicate check
    // expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
    $dupe = "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = '$comment_post_ID' AND comment_approved != 'trash' 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) ) {
        if ( defined('DOING_AJAX') )
            die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );

        wp_die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
    }

//恶意灌水检测,在这里会调用 check_comment_flood_db (此函数属于check_comment_flood action)等函数
    do_action( 'check_comment_flood', $comment_author_IP, $comment_author_email, $comment_date_gmt );

    if ( isset($user_id) && $user_id) {
        $userdata = get_userdata($user_id);
        $user = new WP_User($user_id);
        $post_author = $wpdb->get_var($wpdb->prepare("SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1", $comment_post_ID));
    }

    if ( isset($userdata) && ( $user_id == $post_author || $user->has_cap('moderate_comments') ) ) {
        // The author and the admins get respect.
        $approved = 1;
     } else {
        // Everyone else's comments will be checked.
        if ( check_comment($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent, $comment_type) )
            $approved = 1;
        else
            $approved = 0;
        if ( wp_blacklist_check($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent) )
            $approved = 'spam';
    }

    $approved = apply_filters('pre_comment_approved', $approved);
    return $approved;
}


//新建评论的函数
function wp_new_comment( $commentdata ) {
    $commentdata = apply_filters('preprocess_comment', $commentdata);

    $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
    if ( isset($commentdata['user_ID']) )
        $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
    elseif ( isset($commentdata['user_id']) )
        $commentdata['user_id'] = (int) $commentdata['user_id'];

    $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
    $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
    $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;

    $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
    $commentdata['comment_agent']     = substr($_SERVER['HTTP_USER_AGENT'], 0, 254);

    $commentdata['comment_date']     = current_time('mysql');
    $commentdata['comment_date_gmt'] = current_time('mysql', 1);

    $commentdata = wp_filter_comment($commentdata);

    $commentdata['comment_approved'] = wp_allow_comment($commentdata);

    $comment_ID = wp_insert_comment($commentdata);

    do_action('comment_post', $comment_ID, $commentdata['comment_approved']);

    if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
        if ( '0' == $commentdata['comment_approved'] )
            wp_notify_moderator($comment_ID);

        $post = &get_post($commentdata['comment_post_ID']); // Don't notify if it's your own comment

        if ( get_option('comments_notify') && $commentdata['comment_approved'] && $post->post_author != $commentdata['user_id'] )
            wp_notify_postauthor($comment_ID, $commentdata['comment_type']);
    }

    return $comment_ID;
}

由此可见WP本身就有检测重复评论和恶意灌水的功能,没有必要重复添加代码了。 :razz: 呵呵。
注意我添加了这个:

1
define('DOING_AJAX', true);

这是为什么?呵呵,肯定是有用的。由于我们是ajax获取返回数据,因此要让wordpress做die这个动作而不是wp_die,看下wp_allow_comment和check_comment_flood_db函数就知道了。

经我修改后的comments-ajax.php文件内容全部如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<?php
/**
 * Handles Comment Post to WordPress and prevents duplicate comment posting.
 *
 * @package WordPress
 */


if ( 'POST' != $_SERVER['REQUEST_METHOD'] ) {
    header('Allow: POST');
    header('HTTP/1.1 405 Method Not Allowed');
    header('Content-Type: text/plain');
    exit;
}

//定义AJAX提交
define('DOING_AJAX', true);

/** Sets up the WordPress Environment. */
//这个文件是放在主题目录下面的
require( dirname(__FILE__) . '/../../../wp-load.php' );

nocache_headers();

$comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : 0;

$status = $wpdb->get_row( $wpdb->prepare("SELECT post_status, comment_status FROM $wpdb->posts WHERE ID = %d", $comment_post_ID) );

if ( empty($status->comment_status) ) {
    do_action('comment_id_not_found', $comment_post_ID);
    die( __('Invalid comment status.') );
   
} elseif ( !comments_open($comment_post_ID) ) {
    do_action('comment_closed', $comment_post_ID);
    die( __('Sorry, comments are closed for this item.') );
} elseif ( in_array($status->post_status, array('draft', 'future', 'pending') ) ) {
    do_action('comment_on_draft', $comment_post_ID);
    die( __('The post you are trying to comment is not published currently.') );
} elseif ( 'trash' == $status->post_status ) {
    do_action('comment_on_trash', $comment_post_ID);
    die( __('Sorry, this post has been moved to trash.') );
} elseif ( post_password_required($comment_post_ID) ) {
    do_action('comment_on_password_protected', $comment_post_ID);
    die( __('Sorry, this post is 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


// If the user is logged in
$user = wp_get_current_user();
if ( $user->ID ) {
    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);
    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->post_status )
        die( __('Sorry, you must be logged in to post a comment.') );
}

$comment_type = '';

if ( get_option('require_name_email') && !$user->ID ) {
    if ( 6 > strlen($comment_author_email) || '' == $comment_author )
        die( __('Error: please fill the required fields (name, email).') );
    elseif ( !is_email($comment_author_email))
        die( __('Error: please enter a valid email address.') );
}

if ( '' == $comment_content )
    die( __('Error: please type a comment.') );

$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;
wp_update_comment( $commentdata );
}
    else
{
$comment_id = wp_new_comment( $commentdata );
}



$comment = get_comment($comment_id);
if ( !$user->ID ) {
    $comment_cookie_lifetime = apply_filters('comment_cookie_lifetime', 30000000);
    setcookie('comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
    setcookie('comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
    setcookie('comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
}

/*
$location = empty($_POST['redirect_to']) ? get_comment_link($comment_id) : $_POST['redirect_to'] . '#comment-' . $comment_id;
$location = apply_filters('comment_post_redirect', $location, $comment);

wp_redirect($location);
*/


$comment_depth = 1;   //为评论的 class 属性准备的
$tmp_c = $comment;
while($tmp_c->comment_parent != 0){
$comment_depth++;
$tmp_c = get_comment($tmp_c->comment_parent);
}

//以下是評論式樣, 不含 "回覆". 要用你模板的式樣 copy 覆蓋.
?>


<div class="<?php echo $oddcomment; ?><?php if ($first) { echo ' first'; $first = false; } ?>" id="comment-<?php comment_ID() ?>">
    <div class="commentdetails">
        <p class="commentauthor"><?php comment_author_link() ?></p>
        <?php if ($comment->comment_approved == '0') : ?>
        <em>Your comment is awaiting moderation.</em>
        <?php endif; ?>
        <p class="commentdate"><?php comment_date('F jS, Y') ?> at <?php comment_time() ?>
        &nbsp; &nbsp; <?php edit_comment_link('Edit Comment','',''); ?>
        </p>
    </div>
    <?php echo get_avatar($comment, 32); ?>
    <br class="break" />
    <?php comment_text() ?>
</div>

关于AJAX信息返回问题,我已经经过测试了,可以正常返回。
有图有真相:
(灌水测试,AJAX可以正常返回信息)

喜欢这篇文章吗?

请订阅本站 RSS feed填写您的邮件地址,订阅我们的精彩内容:,欢迎点击这里捐赠以支持荒野无灯转播到腾讯微博 转播到腾讯微博

作者:荒野无灯
出处:Hacklog【Hacklog】

声明: 本站遵循 署名-非商业性使用-相同方式共享 3.0 共享协议. 转载请注明转自Hacklog【荒野无灯weblog】

本文链接: http://ihacklog.com/?p=3705

36 Responses Post a comment
  1. 四月 17, 2012

    再次受教~

  2. 二月 17, 2012

    (我错了,没能在相应的页面留下评论。希望博主不要鄙视我把评论复制过来的行为……)

    果然还是建立在willin博客制作的ajax评论的基础之上。

    我直接将willin的comments-ajax.php文件替换成博主的,其余一切按照willin的说明进行操作,却出现了错误:我以访客身份在自己的博客上留言(下同),刷新页面之前无法再编辑(没有提示与按钮)评论,而且评论显示起来没有任何样式,是彻头彻尾的纯文本;刷新之后,依旧无法再编辑评论,不过评论能正常显示了。

    后来我将comments-ajax.php文件替换回willin的,没有再遇到评论显示方面的问题,但是很遗憾,刷新之后是不可再编辑评论的,这与我在博主博客上体验到的“刷新前后都能‘编辑’”情况相去甚远。不用说,这肯定是代码上的问题了,博主能再提示一下吗?

    • 二月 17, 2012

      @3qsami
      呵呵,这也不能算错误了。可能是很多人会觉得置顶的文章里的评论会容易看到一些吧~~不过我一般是在后台看评论的。再者,“知错能改 善莫大焉”啦。 :)
      不显示编辑按钮这个问题我也遇到过,以前我用的greenthewebnews主题就一直没办法显示。可能是js方面的一些冲突吧(不确定)。
      “评论显示起来没有任何样式”的问题,其实只要你仔细看下 comments-ajax.php文件源码就会发现,willin特别在那里加上了注释“要用你模板的式樣 copy 覆蓋” ,也就是说,要用你的模板的comments.php 文件中调用显示评论时代码样式来重新覆盖掉这段代码。因为每个主题可能用的不同的CSS评论样式,没有css样式的评论,当然是非常有可能是看上去像“纯文本”。

      • 二月 17, 2012

        @荒野无灯
        非常感谢荒野无灯这么细致的回答。
        不过如果非要把一些细节讲清楚,估计你一言我一语地永远不会有个头,所以,我觉得我的问题还是留待我学成相应背景知识后再来讨教,那样才皆大欢喜~

  3. 六月 19, 2011

    还是不明白那句define(‘DOING_AJAX’, true);是什么意思?
    不知道博主能否简单讲解一下 .看到好多主题都用这个,但是我不是很明白

  4. 五月 26, 2011

    过来学习,搞这个回复再编辑头大了。。。

  5. 四月 18, 2011

    为什么截图上有两排一样重复发表评论的提示:

  6. 四月 12, 2011

    学习啦,呵呵。 :razz:

  7. 四月 9, 2011

    又可以了。

    其实我想说的是

    1
    die()

    返回的 http code 并不能触发jquery ajax的error,而是触发了success,错误结果只能当做一条新评论插入到评论列表中,并不是willin原来的错误处理机制。你的图,你的真相也是这样的结果。我现在想到的处理方法在是在success中加个判断,不知道你有没有更换的方法。

    • 四月 9, 2011

      嗯,有返回肯定是触发success的啦。不过重复评论是不会入库的,WP给挡住了。

  8. 四月 9, 2011

    为什么刚才用这个昵称无法评论,封杀了?

  9. dfdf permalink
    四月 9, 2011

    字体好酷啊.我想知道这是什么字体..有什么办法改不- -

  10. 三月 19, 2011

    救命稻草啊,我之前用的 我一直被提示您的评论太快,不知道什么造成的,根据你的思路我重新整了我的代码,现在算是解决问题了

  11. 三月 19, 2011

    我的账户在我自己的blog一真提示你的评论太快 我快崩溃了

  12. 一月 30, 2011

    博主你好,我有一个问题想请问您。我用的是仿BlogBus主题,win主机,我的博客只能用IE浏览器发表评论,换默认主题就好了,本地测试也没事,我觉得是win主机不支持的comments-ajax?我也不知道!想请您帮忙解决 :oops:

  13. 十二月 31, 2010

    那我来试试

    诚祝来年快乐、家庭幸福!
    平安,如意!

  14. 九月 30, 2010

    那个输入用户信息的字体.

    • marcusyong permalink
      十月 7, 2010

      尝试一下博主的comments系统吧!!!

      • marcusyong permalink
        十月 7, 2010

        感觉jquery效果还可以!

  15. 追云 permalink
    九月 29, 2010

    学习了

  16. 九月 29, 2010

    字体好酷啊.我想知道这是什么字体..有什么办法改不- -

  17. 九月 22, 2010

    :razz: 很不错的效果

  18. 九月 13, 2010

    真的很佩服,看到这么乱的代码头晕。。。

  19. isay permalink
    八月 17, 2010

    测试结果是无论是否需要审核都显示审核。。。。比较郁闷

  20. 八月 9, 2010

    我来看看学习下~~

  21. picc permalink
    六月 14, 2010

    噢, 那我来试试呢,我正好想用到

  22. 六月 11, 2010

    那我也来测试

  23. 五月 21, 2010

    测试下~

  24. 四月 26, 2010

    荒野大哥,这个应该大部分主题都通用的吧?

  25. 四月 24, 2010

    果然檢查出錯

  26. 四月 24, 2010

    增加檢查評論太快和重覆評論功能, 修改 err 函数, 才能從 Ajax 回傳錯誤訊息啊~
    當然不要也可以, 錯誤直接 die…

    • 四月 24, 2010

      没有,我这里并不是直接die,和你的效果是一样的,可以返回信息的。wordpress本身已经考虑到AJAX提交信息的返回问题了。 :mrgreen:

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <q cite=""> <strong>

 :wink:  :-|  :-x  :twisted:  :)  8-O  :(  :roll:  :-P  :oops:  :-o  :mrgreen:  :lol:  :idea:  :-D  :evil:  :cry:  8)  :arrow:  :-?  :?:  :!:

Note: You may use basic HTML in your comments. Your email address will not be published.

Subscribe to this comment feed via RSS