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

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

再去掉几个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填写您的邮件地址,订阅我们的精彩内容:

相关日志

回复 (32)

  1. iSayme  / 回复

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

  2. 泊风  / 回复

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

  3. Microhu  / 回复

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

  4. francis  / 回复

    学习啦,呵呵。 :razz:

  5. Ludou  / 回复

    又可以了。

    其实我想说的是

    1
    die()

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

    • 荒野无灯  / 回复

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

  6. Ludou  / 回复

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

  7. dfdf  / 回复

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

  8. erico  / 回复

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

  9. erico  / 回复

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

  10. XiaoYao  / 回复

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

  11. 踏浪者  / 回复

    那我来试试

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

  12. licream  / 回复

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

  13. 追云  / 回复

    学习了

  14. licream  / 回复

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

  15. youchen007  / 回复

    :razz: 很不错的效果

  16. 皇家元林  / 回复

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

  17. isay  / 回复

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

  18. lvlcj  / 回复

    我来看看学习下~~

  19. picc  / 回复

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

  20. zjoyo  / 回复

    那我也来测试

  21. Fantasy  / 回复

    测试下~

  22. 朵未  / 回复

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

  23. willin  / 回复

    果然檢查出錯

  24. willin  / 回复

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

    • 荒野无灯  / 回复

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

发表评论 修改评论取消编辑

允许使用的标签 - 您可以在评论中使用如下的 HTML 标签以及属性。

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

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

引用通告 (0)

› 尚无引用通告。

开灯