提醒:本文最后更新于 3426 天前,文中所描述的信息可能已发生改变,请仔细核实。

在前期文章《全新WordPress评论管理系统》,我提到了为何写这个插件,最主要的原因,还是因为后台评论编辑管理页面慢。想想显示20条评论要近6秒时间,这谁能忍。所以只能自己做一个轮子。
但作为一个爱折腾,愿解决实事的人,逃避不是我的风格(这句纯属胜利者装逼)。
我新建了Wordpress,使用原始主题,将现有主题的所有文章、评论、附件、类别移到这个新Wordpress。
发现后台评论编辑管理页面速度特别快,即便设置显示100条也0.11秒左右显示。
启用Memcached外部对象缓存,发现速度依然如旧,飞快。
这说明两种可能,我想到的两种:第一种主题问题,第二种WP升级遗留问题。
所以在新Wordpress启用了新主题,测试后台评论编辑管理页面,速度慢下来了,要5秒多。
因为主题模块化了,并且把功能分类后,归类到文件。
所以很好排除,二分法禁用这些模块,发现是Wordpress钩子模块出问题,其中只有几个是关于评论的。最终定位是一个“清除评论里的其他计数”的函数,hook对象是get_comments_number。
add_filter('get_comments_number', 'comment_count', 0); function comment_count( $count ) { global $id; $comments_by_id = get_comments('status=approve&post_id=' . $id); $comments_by_type = separate_comments($comments_by_id); return count($comments_by_type['comment']); }
因为get_comments_number本身获取的是该文章的所有评论计数,而一篇文章的评论计数,不单只是评论,还有Trackbacks、Pingbacks,而评论还有已通过、待审核、垃圾评论等。
所以这个函数主要就是为了修复这一问题,因为我们一般只为了获取已通过审核的评论,其他都不要。
好,那么来看看这个函数,初看没什么大问题。但是不知从哪个版本开始,那个id参数回值是空。也就是说不知什么时候Wordpress不主动全局定义这个参数了。我看了下,貌似只在文章主循环会传递,其他留空。
这可就捅破了天了,因为id是空,那么post_id就是空了。
get_comments就会获取所有通过评论的数量,然后返回计数给get_comments_number,而后台评论编辑管理页面以get_comments_number得到的数量,请求这些评论的所有缓存,如果缓存不存在就创建。
这本来是好事,但因为一个微小的错误,加上我们后台是显示20条评论。也就是相当于要20次缓存的判断、建立等动作,虽然Wordpress会合并id后然后再去请求数据库,但对id却不去重,也就是数据库会返回20*通过评论总数量的请求,然后php再一一进行缓存判断,不存在的建立,这花费了大量时间(这是我猜测的,因为那一瞬间MySQL发送了大量数据,而php单进程也占用100%)。而显示越多评论,各应用压力就更大。
知道原因就好办了,直接查到Wordpress的get_comments_number原始函数,发现其过滤器为:
return apply_filters( 'get_comments_number', $count, $post_id );
也就是说他可以传递两个参数,其中就有我们需要的重要参数,$post_id。
于是修改下“清除评论里的其他计数”函数,改成如下:
add_filter('get_comments_number', 'comment_count', 0, 2); function comment_count( $count, $post_id ) { $comments_by_id = get_comments('status=approve&post_id=' . $post_id); $comments_by_type = separate_comments($comments_by_id); return count($comments_by_type['comment']); }
如此,便解决了该问题。
目前设置显示100条评论,只要1/3秒,这速度能接受。用了这个函数慢0.2秒,能接受的。
Had 3 queries, using 14.30MB memory, page to load in 0.349 seconds
这个函数算是历史遗留函数,基本上旧版的大多数主题都会用到,比较实用。
我的主题一直继承这个函数,所以就出现这一问题。各位老哥们,还用这个函数,注意要脱坑啊。
原始作者已经不知是谁,但当时可能没考虑太多,又能用,写成这样已经不错了。
出现这种问题,主要还是升级遗留问题,没去更新这个函数(当然,也不会想到这个问题)。
不过好在发现并解决了。
而且刚刚的“清除评论里的其他计数”函数还不是最原始的模样,我留存中这个函数最原始的模样如下(爱收藏的命,这是3.3版本时的记录):
add_filter('get_comments_number', 'comment_count', 0); function comment_count( $count ) { global $id; $comments = get_approved_comments($id); $comment_count = 0; foreach($comments as $comment){ if($comment->comment_type == ""){ $comment_count++; } } return $comment_count; }
在Wordpress跟踪了下get_comments_number的原始函数,发现从2.9版本开始,开始传递两个参数,count和post_id,而在2.8.6还只传递一个参数,number。
也就是说可以看出当时那个写“清除评论里的其他计数”函数的作者,并不会利用和使用get_comments_number原始函数的第二个参数。
id什么时候没全局就不知道了,这个没追踪,太多依赖函数了。不管了。
转载请注明转自: kn007的个人博客 的《解决后台评论编辑管理页面慢的问题》

@liwanglin12:
这个只能说,必要性降低了。
但最近更新又加了几个功能,只能在功能上考虑完善了。
@liwanglin12: 起码管理上,我那个还是有优势的,WP删除评论,还要去回收站删除。麻烦。
我这个反正按钮都分好了。编辑和回复也快,全AJAX加载评论及强力搜索,也无可代替啊。
@kn007: 我都在想可以vuejs来搞
@牧风: 有技能树啥都好说。我没点这项天赋
@kn007: 我来fork一份
@牧风: 哈哈,好的~
@liwanglin12: 新版本有个实验性功能:可以让公众搜索评论
@kn007: 加个置顶评论好吧
@haguo: 不好
作者不会用函数....
WP开发者啊,临时工?
@be.truth: 不知道,谁都新手的时候。。应该也是主题编写者写的。
我之前为了写评论管理系统的时候,阅读过WordPress的源码,真是吐血
很多源码都是各个时代的,判断的写法在同一个函数里都能见到不同风格。。
而且很多历史遗留问题,好在都不大影响,但提交issue,都不怎么鸟。我感觉没什么也就这样了。
@be.truth: 我把原句改下,才发现发生歧义,导致你理解错了。
代码抄了,用上了,不知有没有用。
副作用是把你的wcms插件给冷冻了。
@老虎: WPCM。。兄弟。。。人家WordPress推荐我这样简写的。。
这副作用挺大的。。我其实比较满意插件的搜索能力。。
@kn007: 主要是搜索留言也没啥用啊……而且插件在手机上看不是很舒服
@老虎: 大家需求不一样。。。
因为分享很多东西,有些人问的经常是同一个问题,搜索还是方便。
左下角聊天室,我可以通过搜索,看到匿名的你会是谁。
还有很多,只能说需求不同。
@老虎: 不舒服,这个问题,我上次说过了。
框架就这样,全部从零开始没时间,只能借助,框架缺陷在这里,只能有空再完善了。
我比较习惯 WordPress 手机客户端来管理评论,感觉效率还是可以的!
@明月登楼:
挺好。
我偏喜欢网页多点。
貌似我用的不是遗留的那个 和你写的这个函数差不多
@World: 是么
评论过滤了html标签

@World: 默认会过滤的。
看来我的评论不多啊,感觉不是很明显。
@夜枫:
评论慢慢就多了
你越来越专业了
@尽欢: 还行
@kn007:
所以写新主题还得在最新的twentyXXX上操作,不专业干这个谁有精力去跟踪一版一版的更新履历啊!
不过我觉得默认的get_comments_number()挺好用的啊,加钩子干啥?有特殊需求改用get_comments()不就行了?
@大致: 你说的完全是两个函数,get_comments_number为什么要勾的原因,我想文章已经表达清楚了。
@kn007: 我想你没明白.
get_comments的count参设为true时,返回值就是count.
get_comments('count=true&type=comment&status=approve&post_id=' . get_the_ID());直接就出来了。
我的意思是get_comments_number这样带参不足的,用钩子的方式进行修改太麻烦了,不如改成别的函数。
@大致: 哥们,我首页和文章页都有评论计数。我用get_comments_number_text搞定的事,你要我用get_comment?
然后用了再用个判断,0条输出no comment,1条输出1 comment,多条输出% comments???我理解不了。。。
@kn007: 你说的对,是我没理解。get_comments_number_text这个函数好久不见了,而且你正文里也没说用的是这个。
因为我特别讨厌中文包,所以凡是带__()的用法都被我换掉了。
我一般加filter的时候都会习惯弄个!is_admin()之类的限制一下。
@大致: 主要get_comments_number很多东西在用,包括wordpress很多核心和主题。如果没必要,wordpress也无需去构建这一函数及其附属。
正文是没提到,但没用,我何必去勾。对吧。
is_admin只是控制后台的。
我很多东西都是按需加载的,这一方面很早就这样追求了。
@老杨: 嗯,那肯定兼容性好。
为了追求,总会有所付出的。
@kn007: 也是,鱼与熊掌不可兼得。
@老杨: 默认主题对中文的博客来讲太丑了。。。
@老虎: 哈哈哈,要改改
@老虎: 嗯,改改改改就好了