转自:Yskin’s blog
我刚接触Wordpress的时候——大约在今年3月份或者更早吧——除了Wordpress自带的插件,最先装的插件应该就是桑葚的中文WordPress工具箱中文WordPress工具箱了。(一个小发现,我用紫光V5打出来的是“桑椹”,而他的网站上写出来的是“桑葚”,在金山词霸查了一下,好像紫光打出来的是正确的,桑椹——英文mulberry…汗了)
这个插件提供了很多功能,都是一些国人喜欢的功能——最新文章,最新评论,评论数最多的文章,发表评论最多的网友,随机文章以及适合中文环境的摘要功能。这些功能我感觉并不实用,虽然国内的大多BSP都提供这些功能。最新文章功能Wordpress自带,最新评论功能倒还有点用,随机文章功能对于专门讨论某个方面的Blog还行,而我一直的观点是一个Blog对应一个人,个人的所有文章应该发在同一个Blog上,文章的分类应该靠Blog系统的分类功能解决,而非建立多个Blog。我的研究方向比较多,所以我的Blog分类很广,这样的情况下,一个设计的比较好的相关文章功能可能比随机文章好的多。
最近一直困扰于百度的收录问题。我的策略是:存档页、分类页、tag页、搜索页都不应该被搜索引擎收录,因为搜索引擎会进行重复页面检测。(桑葚的网站好像没有做这方面的设置,经常在Google里搜到他的tag页)对于Google,可以在所有要禁止收录的页面设置meta标签robots为”noindex,follow”,这样Google就会只访问这些页面而不收录,既禁止了收录,又可以让Google顺着这些页面查找独立文章页面。不过,同样的办法对百度就行不通,因为百度不支持meta标签robots,所以只好用 robots.txt文件。分类页和tag页分别在category和tag目录下,只要禁止这两个目录就可以了,而存档页却是类似”http://yskin.net/2006/07/"这样的结构,禁了这些目录,下面的独立文章页面也会被一起禁掉,百度又只支持 Disallow,不支持Allow。
解决的办法嘛,狠一点的话就在存档页中检测来访的是不是百度,如果是就直接输出个404。我想的权宜之计是:由于存档页显示的是文章的摘要,想办法让摘要更短一些,这样可能就检测不出来重复了。我弟弟的Blog用了中文WordPress工具箱,他那儿显示的摘要就很短,所以跑去下了这个插件,研究一下Wordpress的摘要算法。
研究的结果是这样:在中文WordPress工具箱的说明里有提到:
某些情况下需要输出摘要,比如搜索结果、档案,还有 rss 输出,这样可以节省流量资源。但是,如果你的文章是中文的话,官方 WordPress 输出的其实并不是摘要,它只是把文章里的 html 代码过滤掉了,但所有文字都还是原样输出了。
激活这个插件后,输出的就是真正截断的摘要了。
(顺便提一下,rss输出还是不要用摘要方式的好,人家订阅了你的rss不是为了看个摘要的,节约流量可以用feedburner烧录一下嘛。当然,由于网站放置了广告而希望用户访问页面的除外,够狠的话也可以把广告加到rss里)
桑葚的这段话是有错误地。Wordpress输出摘要时,先将文章里的html代码过滤掉了,然后对文章进行了摘要并输出,并没有因为你写的是中文就不摘要了。不过,摘要算法只考虑了英文以及其他西方语言,因为这些语言用空格做单词的分隔符,所以就用空格做区分,截取前55个单词。但是这个算法对中文日文这些不用空格分隔单词的语言就不合适了,中文文章里很难找到一个空格,摘要算法要找够55个空格才截断,所以最终只会输出整篇文章。
Wordpress通过the_excerpt()函数输出摘要(rss里通过the_excerpt_rss()函数输出摘要),这个函数中只有一行代码:echo apply_filters(‘the_excerpt’, get_the_excerpt());就是说对get_the_excerpt()函数返回的字符串执行转换器操作并输出。the_excerpt有转换字符、转换表情、加
标签等几个默认转换器。get_the_excerpt()函数中检验了一下文章是否有密码,然后将用户自定的文章摘要传给 wp_trim_excerpt()函数。wp_trim_excerpt()函数收到用户自定的文章摘要则直接返回,否则根据文章内容生成摘要。他先把文章过一遍文章内容的转换器,再用strip_tags()函数去掉所有html和PHP标签,再用explode()函数以一个空格做分隔符,把文章分成最多56段。如果不够56段则原样输出,否则就把最后一段替换成”[…]”,用implode()函数以空格做分隔符重新组装起来。很明显,这个方法对英文文章很有效,而对不用空格做单词间分隔符的中文则没什么作用。很少有中文文章包含55个空格,所以给大家以中文文章摘要无效的印象。(好像代码里没有对标签进行处理,所以这个标签只在主页有效。)
桑葚的插件里使用了一个mul_excerpt()函数,加做the_excerpt和the_excerpt_rss的转换器。这个方法并不好,the_excerpt有转换字符、转换表情、加
标签等几个默认转换器,插件添加转换器的时候又没有设置等级,导致摘要被加上
标签才被substr,造成HTML错误。其实完全可以把这个函数加做get_the_excerpt的转换器,因为 the_excerpt和the_excerpt_rss最终都是要调用get_the_excerpt得到摘要的。另外,桑葚用substr($excerpt,0,255)将文章截取256个字节,由于采用UTF-8编码的中文字符占据两个字节,可能会造成最后有半个中文字符存在的现象。所以他用了一个utf8_trim() 函数,对摘要的最后进行处理。这个插件名叫中文WordPress工具箱,插件说明里也写道了:“用来解决官方 WordPress 没有照顾到的中文相关问题。”对于文章摘要也写道了:“真正的文章摘要,真正截断,没有乱码。”插件针对各种中文相关问题的解决办法就是这个 utf8_trim()函数。如果是在侧边栏显示的最新留言,使用这个办法,再配上等宽字体——每个英文字符相同宽度,并且等于中文字符宽度的一半,那么显示出来的一点非常整齐,非常好看。不过对于文章摘要来说,用这个函数就不必了吧,mb_substr()函数不是很好用么。
Update:有点小错误,GB2312里一个中文占两个字节,但是UTF-8里中文通常占3个字节。如果是GB2312编码的字符串,截取固定的几个字节,再配上等宽字体,可以保证最终显示的很整齐。但是UTF-8编码就不行了。
我写了一个小插件,用了一个新的摘要截断算法。由于wp_trim_excerpt()函数接收到非空字符串就直接返回,所以我把这个函数设置为 get_the_excerpt的转换器,并设置了一个更高的优先级,使他能够在wp_trim_excerpt()函数之前被执行。直接copy了 wp_trim_excerpt的前面几步,然后设置了两个变量fragmentnum和wordnum,为摘要的最大段落数和字符数。我觉得应该以段落为单位来做摘要,段落不被截断就不会被断章取义了。在摘要的最后添加了一个阅读全文的链接,就象大多数BSP系统那样。另外也加了全文字数,看起来和其他 BSP很象了吧 :)
起个名字,就叫wp-CJK-excerptwp-CJK-excerpt吧。
Update:应super37的要求——要我的这个wp-CJK-excerpt插件和桑葚的中文Wordpress工具箱能够一起使用,因为中文Wordpress工具箱还有其他功能嘛。找到了Wordpress提供的remove_filter()函数。想直接写在插件主体里,但是不知道Wordpress读取插件的顺序是怎么样的,如果是按照插件安装的顺序,那么只有我的插件后安装才能保证屏蔽。想来想去,反正如果执行the_excerpt()函数的话,我的插件先执行,干脆放在函数里了。应人之邀做的修改,桑葚你不要怪我…
Update2:好像有很多人的服务器不支持mb_strlen()函数,安装了这个插件后分类页会执行出错,提示Fatal error: Call to undefined function: mb_strlen()。如果打开了feed里显示摘要,那么feed也会出错。
一般商业PHP空间,Multibyte String函数库都应该是安装过的,否则程序怎么处理UTF-8编码的字符串啊。老实说,如果空间连这个函数库都没的话,你真的应该好好考虑下这个空间的质量了。我加了个检测,如果mb_strlen()函数不能用的话在后台管理页面上方显示一个警告框,提醒用户插件不能使用,请用户禁用插件。而且里面加了个return语句,检测到函数不能用就直接返回,不会再执行下面的操作,以免因该函数不能用而导致页面执行出错。这个警告框的代码抄自 akismet插件。
Update3:又想了点办法,在没有mb_strlen()函数的环境下自定义一个。我写的这个mb_strlen()函数很简单,只处理UTF-8编码的字符串。这段代码用正则表达式检测一个UTF-8编码字符串的长度,灵感来自这里。因为用的是正则表达式,好像对执行时间有所影响。一个10篇文章的页面,执行时间要增加大约0.5秒。所以如果您的空间上mb_strlen()函数不能用的话,请自行斟酌是否用这个插件。
另外,给显示“阅读全文”等字的那部分增加了一个叫readmore的class,因为我用的True Blue style定义了这个class。您也可以在自己的CSS文件里加入一些代码来控制这部分的显示。
最重要的内容:
需要在您所用的Theme的Index.Php中把 the_content() 替换为 the_excerpt()
就OK了。还要记得将插件上传到插件目录并激活