Blog
Feedsky新版
by Meng Yan on May.29, 2006, under Blog
欣欣上周MSG我让我看看Feedsky的新版,初一看,吓了一大跳,ASP.NET竟然变成了PHP,这个变化实在不小。且不说这两种技术孰优孰略,看来Feedsky是下了功夫要重新架构一番。
首先,界面比以前清爽整洁了许多,也规范了很多。其实我在Feedsky刚出来的时候就注册了一个,不过一直没有公布,其中的一个原因就是用户名和密码的输入框大小不一样(还是没对齐?忘了),虽说是小问题,但是这样的小问题往往能反映一个团队的实力和态度。细节决定成败!
再说功能上的减法,确实,烧制和统计是RSS Burner的两个最基本也是最重要的功能,Feedsky删除了不少用处不大的噱头,这样挺好,减少了系统的复杂性。问题是,现在没有原因让我放弃Feedburner而转而使用Feedsky,因为没有特殊的地方。差异化生存,作为一个后来者,更要有超越前者的优势才行。加入本地Service(比如豆瓣,土豆)合烧是最容易想到的一个可以改进的地方。
Crawler的问题解决了,访问的时候已经带上了ETag,没有仔细分析Log,不知道对于其它Feed Platform应该遵循的规范考虑了没有。URL的重新设计也更加合理,feed.feedsky.com/user明显比www.feedsky.com/user更好。
团队Blog,终于加上了,这可以Web2.0服务的标志啊:P。我订阅了Feedburner的Blog,可以感觉那是一个充满激情,而且技术非常优秀的团队,希望欣欣和他的同事也能Build up一个这样的团队。
最后说说一些问题:
- 还是一些细节方面,比如Login.php Load出来后,焦点应该放在Username输入框;
- Feed预览,显示英文是"an RSS feed powered by Feedsky";
- 比较严重的问题,登陆页面没有采用HTTPS。对于WEB应用,如果不能很好的保护PII(Personal Identity Information),一切都明文的传来传去,非常危险;
- 安全设计考虑的还不够,比如,举两个简单的例子。第一,Login的时候,输入不存在的用户名,会显示"对不起,用户不存在",输入存在的用户名和密码,会显示"登陆失败!",有时候,给用户的信息不是越Detail越好,登陆系统就是这样的例子。因为给用户信息的同时,你也把这些信息暴露给了Hacker,通常的设计要求,这时候的信息要尽量简单一致(Generic Error Messages),尽量少暴露系统信息;第二,连续N次Login错误后,没有任何方法加以限制。通常常用的方法是增加图形验证界面,或者甚至禁止继续试探。
- 功能上,Burn后还不能完全按照时间排序。
总的来说,还是不错的,希望Skyer们越做越好,也正好公布一下我的Feedsky的Feed:http://feed.feedsky.com/dreamwords。
Popularity: 57%
Subscribe My Most Popular Post
by Meng Yan on Apr.22, 2006, under Blog
还是在上周末的时候,看到了Microsoft RSS Team的SLE(Simple List Extensions)扩展。三个单词中,最重要的是List,SLE主要是用来解决Feed订阅阅读模式的某种特定需求而产生的:
- Treat Feed as List
- Define customized sorting functions
- Define customized filting functions
从订阅者的角度来说,订阅了这种Feed,本地的Feed列表将完全和Feed服务器提供的保持同步。这种同步包括几个方面:
- Feed Item的次序与服务器上完全相同,如果有更新,则Feed Reader也会更新顺序
- Feed Reader不会缓存过期的Feed Item,如果某一个Item从Feed中删除,本地Feed Reader也会将它从本地(或者在线Feed Reader Storage)删除。
简单的说,你通过Feed Reader看到的Feed应该与Feed Publisher发布的完全一致。
这种特定应用的需求会有很多,比如典型的几种应用:
- Top 10 Best Seller - 比如Top 10 畅销书籍,Top 10 Music等等,对这种Feed的关注通常是更加关注于当前那10个;
- Wish List - 如果我已经得到了某个东西,就会把它从SLE中拿去,这样,订阅了我的Wish List的人也就不会再看到这个,不会送重复的东西了:);
- Open Positions - 当前职位列表,过期的职位通常意义不大。
可以看到,这些应用都有一些共同的特点,就是Feed本身更倾向于一种通知(Notification),过期的Item意义不大,而且,通常,这个List本身的次序是很重要的。
Specification很简单,通过以下这个声明来确定某个Feed是否是SLE(支持RSS2.0 & Atom),下面是一个RSS 2.0中的例子:
- <rss version="2.0" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005">
- <channel>
- <cf:treatAs>list</cf:treatAs>
- <title> Top 10 Popular Post </title>
- ..........
- ..........
- </channel>
- </rss>
Sorting和Grouping(Filtering)的规则举例:
- <cf:listinfo>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="date" label="Publish Date" data-type="date"/>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="rank" label="Popular Rank" data-type="number"/>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="comments" label="Comments" data-type="number"/>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="pingbacks" label="Pingbacks" data-type="number"/>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="trackbacks" label="Trackbacks" data-type="number"/>
- <cf:sort ns="http://www.xerdoc.com/rss/pl/" element="pageviews" label="Page Views" data-type="number"/>
- <cf:group ns="http://www.xerdoc.com/rss/pl/" element="author" label="Author"/>
- </cf:listinfo>
当然,SLE不止是一个针对于Feed Publisher的标准,还需要Feed Reader的支持。与一般的Feed不同,Feed Reader在处理SLE的时候会有一些特殊处理,现有的Feed Reader还基本上不支持SLE,除了IE7 Beta2。
为了试验,我做了一个简单的WordPress Most Popular Post的插件。基本的打分是采用Popular Context插件,根据留言数量,Pingback、Trackback数量,浏览数量等因素来确定一篇文章的受欢迎程度,最后,提供一个WordPress的Top 10 Popular Post的SLE,可以用IE7 Beta2订阅来看看效果。

右面可以根据Comments,Pingback,Pageview来排序,也可以Filter来选择某个作者的Post。
订阅:
Most Popular Post @ Xerdoc’s Weblog
Most Popular Post @ Meng Yan’s Weblog
相关阅读:
Simple List Extensions Specification
Simple List Extensions in action
Popularity: 53%
Trackback, Pingback & Backlink
by Meng Yan on Mar.20, 2006, under Blog
今天看到王建硕的文章《如果过得去那个临界点》
做Ping,需要发的人要支持,收的人也要支持,这种分布的方式的唯一问题是,你需要很多人的协作。不是每个人都愿意协作的,圣经里的通天塔Babel就是一种努力。这就形成了网络外部性--就像一个对讲机没有用,多个才有用处。
网络外部性的东西(email, TCP/IP协议,MSN Messenger,电话)必然需要强大的外因(或者极好的运气),才可形成,但一旦形成,就会病毒性复制。
这个就像核反应堆。谁有能力击破第一个原子,以后的事情就不用你管了。这个点,有人叫做引爆点(tipping point),有人叫做临界点(Critical Mass)。
所以,搜索引擎不需要被爬的网站的配合,就可以工作,所以成功。如果依赖于别人的ping, 就像有了C2C的交易平台,却没有那足够市场经费(这是一种办法),或者经过几年的积累(这是另外一种做法)轰击原子核,很难达到Critical mass。这个和技术无关无关了。
不久前曾有过一场关于Trackback是否会死去的大讨论,我也恰巧想过这个问题。于是,昨天仔细看了Trackback,Pingback,以及Backlink。
从使用的难度来说,Trackback > Pingback > Backlink。Trackback的使用方法实在太过Geek,你需要到对方的Blog上找到Trackback
URI(虽然Trackback支持Auto-Discovery,但是真正用的似乎并不多),然后把它Paste到Blog软件的Trackback
Field里面去,我觉得,这个过程对于普通用户来说绝对不可忍受。即使你做到了这点,不同Blog程序间标准的不统一,对国际化支持不佳,使得Trackback的送出是如此之难。
相比之下,Pingback要好很多,如果你的Blog软件和对方的Blog都支持了的话,用户什么都不需要做。比如WordPress,会自动的向文章引用的每一个URL发送Pingback,当然,只有对方支持才会Ping成功。支持Pingback的Blog程序也很多,包括WordPress,Dupral,其它像是MSDN
Blog也都支持(用的是.Text?)。
这里废话一下Pingback的实现,其实很简单,每个客户端负责对指定的URL发送Pingback。而服务器端有两种办法来提供Pingback的地址:HTTP Header和Link Element。
HTTP/1.1 200 OK Date: Sun, 08 Sep 2002 15:05:37 GMT Server: Apache/1.3.26 (Unix) Last-Modified: Thu, 28 Dec 2000 03:18:26 GMT ETag: "65044-15b9c-3a4ab102" Accept-Ranges: bytes Content-Length: 88988 Connection: close Content-Type: image/png X-Pingback: Pingback Server URI<link rel="pingback" href="Pingback Server URI">
可惜,标准总是好的,现实总是残酷的,并不是每个人都愿意遵循标准。显然,Trackback的提出者MT就不愿意支持Pingback。因此,我认可建硕说的,“当一件事情有赖于多于一个人的努力才能成功的话,他成功的可能性就小很多”。
这样看下来,Backlink就是最简单的了。如果你不知道什么是Backlink,就去看看Google的官方Blog。哦,对,这个。。。,那就拿Google中国黑板报来说吧,每篇文章后面会有一个“引用此贴的链接:”,就好比MT中Trackback到此篇文章的链接一样。下面列出的是一些链接到这篇文章的Blog。看看代码,你会发现,其实很简单:
- <script
- type="text/javascript" src="http://www.blogger.com/dyn-js/backlink.js?blogID=20904277&postID=113976536783718339" defer="true">
- </script>
- <noscript>
- <a href="
- http://search.blogger.com/blogsearch?q=link:http%3A%2F%2Fgooglechinablog.com%2F2006%2F02%2Fgoogle.html">See links to this post</a>
- </noscript>
正是Google Blog Search中的反向链接查询结果。
就像建硕所说的那样,搜索引擎不需要被爬的网站配合,就可以自己工作。有的时候,与其花费时间去推广一个标准,真的不如另辟蹊径,去找执行力更好的解决方案。
我觉得,无论从实现者的角度,还是从最终用户的角度,Backlink都是最简单的,事实上,他也确实成为我现在查看Backlink,进行Ego
Surfing的主要工具了。
还有,如果你希望Backlink成为文章的一部分,要展现给读者,那么就学习GoogleChinaBlog吧。Google Blog Search提供了Backlink的RSS,然后再用RSS -> JavaScript的工具生成一个JavaScript,嵌入你的页面中,就可以了。
其它:
Popularity: 53%
coComment Preview
by Meng Yan on Feb.06, 2006, under Blog
一直希望有一个很好的Comments解决方案,帮我解决以下几个问题:
- 帮我追踪我所有的留言,记录这些留言的痕迹;
- 更进一步的追踪这些留言的Post,来看看Blog的主人对我的留言有什么反馈。
有一段曾经用Trackback来解决问题,这样做的结果是只有长篇大论才被记住,很多一两句的留言就不自觉地放弃了,反正也无法跟踪反馈 :P。久而久之,积极性越来越低,已经很少留言了。
Herock曾经建议采用社会化书签来对留言进行统一管理,可是关键在于,Bookmark下这些URL只是一些静态的信息,留言的组织和追踪还是靠你自己,还是很麻烦。
这两天偶尔看到coComment这个服务,看起来能够帮我解决我所面临的问题,就想试试。昨晚留下了Email,没想到一早就收到了invitation code。
用起来说简单也简单,说复杂也复杂,需要你在Browser中添加一个Bookmarklet,在点击留言提交的按钮前,点击这个Bookmarklet,然后点击的时候就同时把留言提交到coComment去了。
简单看了一下它的Bookmarklet代码,发现它是根据各种Blog系统的特征找到Comments的Form,然后在这个Form的提交Button后面添加一个个人信息的Logo,然后在修改Form的提交部分,让留言同时提交到coComments去。
看了一下代码,现在支持的Blog系统包括:
xanga.com
myspace.com
msn.com
blogger.com
typepad
blogs.com
wordpress.com
kaywa.com
这种做法够Hack的,不过想想也没办法。本来最好的办法是弄一个标准,然后大家都按照这个标准把留言Ping到某一个服务,不过,这似乎是不可能的,于是,就Hack这个提交的Form了。
不过,这种太过Geek的做法能够被普通用户所接纳么?我很担心。
最后的Conversation组织的不错,Fancy,而且也提供RSS来让我追踪我留言的各条Post,目前还没有收到更新,只能看看再说了,呵呵。对了,还提供Share的功能,把自己的留言Share出来。
还有,就是要提两个意见:
- 能不能做的更彻底一点儿,点击这个Bookmarklet的时候能自动帮我填留言的Form呢?我指的当然是Name,Blog这些信息,可以把它存在coComments的帐户里面。
- 把针对各种Blog系统的模版尽量抽象,然后提供一个可以方便扩充的Plugin机制(或者叫做Provider,Add-on),毕竟,coComments根本没精力提供所有系统的Comments模版,可以把这些工作留给社区来做,比如,吉子就可以做一个针对Sohu Blog的,嘿嘿。
Update:
- 简单测试了一下,发现coComment只能追踪同样是通过coComments服务的留言,不爽,不过也没有太好的办法,除非各家都提供自己的Comments RSS;
- 昨天用的时候就像可以写一个GreaseMonkey的脚本,来自动干这件事儿,结果这不,今儿就有了,这下更方便了;
- 还有一点想说的就是,这个服务的一个让我用的原因就是他不会让你失去什么,你的留言只是拷贝了一份在他那儿,所以,得到的就算是赚得吧。
Popularity: 41%
IE7 Beta2 Preview
by Meng Yan on Feb.04, 2006, under Blog
距离上次装Beta1已经有半年的时间了,这半年,用IE的时间大大的增加,不舍Firefox的主要原因是开放的架构和丰富的插件。
昨晚装上了IE7 Beta2试了试(这回也是英文版,不过不需要像上次那样Hack了:P),注意到一些细小的地方,比如:
- 上次的CSS Fixed的问题得到了解决;
- Tab上的Close按钮(据说这是得到了Blog中的反馈而加上的功能);
- Alt键开/关菜单;
- Quick Tabs预览,这个太Cool了(估计Firefox会很快出来类似的插件吧);
- "Delete Browse History"(虽然是已有功能的汇总,不过这个功能应该会有很多人需要);
- Full Screen的处理非常好,比Firefox的处理更加方便和人性化;
- Search Engine中默认为MSN Search,不过可以很方便的设置为Google或者其它;
- Native XMLHTTPRequest Object的支持,这样,今后写AJAX代码不用再区分浏览器了。
最让我印象深刻的是IE Blog这次的宣传攻势:
Native XMLHTTPRequest object - IE7中对XMLHTTPRequest的Native支持
Frequently Asked Questions for the IE7 Beta 2 Preview - IE7中的常见问题
Windows RSS Platform - RSS的支持,期待API的公开
Security issue in IE7? - 第一个漏洞?
A New Look for IE - IE7 UI的变化
Part 1: Hello feeds - 对Feed的支持,Feed Reading Page不错,非常方便
Part 2: Discover and Subscribe to Feeds
What’s New for CSS in Beta 2 Preview? - IE7对CSS支持的进展
A quick note on the Beta 2 Preview user agent string - IE7的User Agent String
ClearType Text in IE7 - ClearType的支持,很多人对这个抱怨不少,不过在我的LCD上,表现还不错
看完这些,深刻的感受到Blog对于互联网产品所起到的作用,无论是Feature,Security Issue,FAQ,Comments,都可以利用Blog传播出去,也可以利用Comments来得到很多有价值的反馈。
另外还有两点感受就是:
- IE正在变的越来越Open,这是一个好的开始(插件部分似乎没有大的变化,不知道是不是有Firefox那么多的Extension Point)
- 有竞争真好,越来越好的Firefox和IE正在让我的互联网体验越来越棒
Popularity: 44%
解决WordPress 2.0的comments始终为0的问题
by Meng Yan on Jan.21, 2006, under Blog
升级到WordPress2.0后,只有少数插件遇到了问题,都与Permalinks有关。不过,最近发现,SK2也有些问题,留言数目总是0,今晚有时间Debug了一下,发现WordPress2.0中”wp-posts”表里面新增了一个”comment-count”字段,这其实是”wp-comments”中取出的这个Post所有留言之和。之所以做这样违反范式的冗余设计,应该是效率上的考虑。这就带来了更新上的问题。SK2做的时候当然不会知道这个,所以就带来了问题。
发现了一个SK2的插件,用于解决这个问题 - SK2-WP2Compatibility (注意,这是SK2的插件,而不是WordPress的插件,有时间我要研究一下SK2的插件机制)。这个插件很简单,看看代码就知道了。
- $c = $wpdb->get_row( "SELECT count(*) as c FROM {$wpdb->comments} WHERE comment_post_ID = '$cmt_object->post_ID' AND comment_approved = '1'" );
- if( is_object( $c ) ) {
- $this->log_msg(__(" Wordpress 2.0 detected - going to update comment counts" ), 4);
- $wpdb->query( "UPDATE $wpdb->posts SET comment_count = '$c->c' WHERE ID = '$cmt_object->post_ID'" );
- }
不过,SK最新的2.1版本中已经解决了这个问题,所以,只需要升级到SK2.1就可以了。
Popularity: 27%
升级到WordPress2.0
by Meng Yan on Dec.31, 2005, under Blog
前两天升级到了WordPress 2.0,可惜Jerome’s Keywords不能正常工作,点击会出现404的错误。看了一下代码,发现WP2.0对底层Permalinks的实现作了很大的改动,郁闷。正巧看到有人推荐Ultimate Tag Warrior,决定元旦的时候换一下。昨天下午把这个插件推荐给Robin,没想到这家伙手脚真快,晚上就升级了。结果今天早晨来就看到Jerome’s Keywords升级到1.9,兼容WP2.0,呵呵。
Update: 同样是由于Permalinks的原因,WordPress Feedburner Plugin的作者也给出了最新的版本。
昨晚升级的时候看了一下Archives,这两个月的Post真是少得可怜,忙是一种借口。手头想干的事情很多,却还都没有开始或者进展缓慢,还是得给自己加油 。
Popularity: 26%
Flock
by Meng Yan on Oct.21, 2005, under Blog
今早收到Flock的邀请,下了一个体验一下。
Flock最大的特色就是加入了对Delicious, Flickr, Blog等社会化软件的支持,将他们集成到这个浏览器中。
1) Delicious
Flock的Favorite管理默认就是采用Delicious,第一次导入需要的时间长一些,这样,可以直接用Favorite中的”Star and Tag …”将你感兴趣的内容贴到Delicious上面去,不过我觉得原来的Bookmarklet也很方便 :P。
2) Flickr
试了一下,可以把Flickr的图片拖入到Blog Editor窗口中来,确实挺方便。
3) Blog
很简单,还是利用开放的XML-RPC接口,来远程的进行Blog发送,并且支持Ping到Technorati的Tag。
总的感觉是像一个装了各种社会化插件的Firefox,这些确实都是我平常经常用到的,其实原来的Firefox + Extension + Bookmarklet已经能很好的满足我的需求,不知道能不能用起来这个浏览器。
Technorati Tags: Flock, Firefox, Delicious, Flickr, Browser
Popularity: 26%
Some hacking to support Baidu and Sogou in StatTraq
by Meng Yan on Aug.30, 2005, under Blog
一直用Stattraq插件来统计Blog的访问信息,使用起来还不错。后来发现,我的Blog上很多关键词都是来自Baidu,而Stattraq根本没有对Baidu的特殊处理,于是Hack一下,让Stattraq也能统计百度的信息。
1)BaiduRobot
在"stattraq.php"的函数"statTraqGetBrowser"中,添加对Baidu Robot的识别(顺便也识别一下Sogou的Robot吧):
- <?php
- }else if(strpos($ua, "Baiduspider") !== false){
- $browser_type = ST_BOT;
- $s_id = "Baiduspider";
- return "Baiduspider";
- }else if(strpos($ua, "sohu-search") !== false){
- $browser_type = ST_BOT;
- $s_id = "SogouBot";
- return "SogouBot";
- }
- ?>
原理很简单,就是分析HTTP头中的"HTTP_USER_AGENT"信息,负责任的搜索引擎都会给出自己的标志,比如Google的"Googlebot",MSN的"msnbot"等等,对于那些把自己伪装成浏览器的搜索引擎,不统计也罢。
一个需要注意的问题是大小写不能搞错。
然后再修改一下"stattraq-install.php",主要是为了今后的升级:
- <?php
- $sqlQuery = "UPDATE {$tablestattraq} SET user_agent_type=1
- WHERE browser = 'Googlebot' OR
- browser = 'msnbot' OR
- browser = 'Baiduspider' OR
- browser = 'SogouRobot' OR
- ... "
- ?>
2) SE Saturation
在StatTraq的SE Saturation中,可以看到对各个搜索引擎收录你文章的统计,同样,加上百度和Sogou。
在"search_engine_stat.php"中,找到相应的代码段,并添加如下信息:
- <?php
- $baidu = getPageDBResults("Baiduspider", $date_format, $time_frame, $betweenClause, $orderBy);
- $sogou = getPageDBResults("SogouBot", $date_format, $time_frame, $betweenClause, $orderBy);
- ...
- if($baidu)
- {
- $baidu_count = $baidu->cnt;
- }
- if($sogou)
- {
- $sogou_count = $sogou->cnt;
- }
- ...
- echo '<tr><td>Number of Pages Indexed</td><td class="right">' . $google_count . '</td><td class="right">' . $yahoo_count . '</td><td class="right">' . $msn_count . '</td><td class="right">' . $baidu_count . '</td><td class="right">' . $sogou_count . '</td></tr>';
- echo '<tr><td>Number of Pages <em>Not</em> Indexed</td><td class="right">' . ($total - $google_count) . '</td><td class="right">' . ($total - $yahoo_count) . '</td><td class="right">' . ($total - $msn_count) . '</td><td class="right">' . ($total - $baidu_count) . '</td><td class="right">' . ($total - $sogou_count) . '</td></tr>';
- echo '<tr><td>Percent Saturation</td><td class="right">' . floor(($google_count/$total)*100) . '%</td><td class="right">' . floor(($yahoo_count/$total)*100) . '%</td><td class="right">' . floor(($msn_count/$total)*100) . '%</td><td class="right">' . floor(($baidu_count/$total)*100) . '%</td><td class="right">' . floor(($sogou_count/$total)*100) . '%</td></tr>';
- ...
- <dt>Baidu.com</dt>
- <dd><a href="http://www.baidu.com/search/url_submit.html">http://www.baidu.com/search/url_submit.html</a></d>
- <dt>Sogou.com</dt>
- <dd><a href="http://db.sohu.com/regurl/regform.asp?Step=REGFORM&class=">http://db.sohu.com/regurl/regform.asp?Step=REGFORM&class=</a></d>
- ?>
显然,这里的"BaiduSpider"和"SogouRobot"就是我们刚才修改的那个函数的返回值。
3)统计用Baidu访问的关键词(Search Team)
在"stattraq.php"的函数"statTraqGetSearchPhrase"中,添加针对Baidu和Sogou的解析:
- <?php
- }else if(strpos($referrer, "baidu.")!== false){
- $key = "wd";
- }else if(strpos($referrer, "sogou.")!== false){
- $key = "query";
- ?>
原理很简单,就是分析referrer中的Query串(Baidu默认是采用GB2312来传递,这个比较烦人)。
比如:
http://www.google.com/search?hl=zh-CN&q=xerdoc&…
"q"就是Key。
Update (2005.11.04)
修改一下StatTraq中文乱码的错误:
1) Summary页面中的乱码:
1.打开/wp-stattraq/reporter/summary.php,找到第140行
<?php echo htmlentities(stripslashes($row->post_title));?> ,修改为
<?php echo htmlentities(stripslashes($row->post_title),ENT_NOQUOTES,’utf-8′);?>2.打开/wp-stattraq/reporter/query_strings.php,找到第88行
htmlentities($row->search_phrase) ,修改为
htmlentities($row->search_phrase,ENT_NOQUOTES,’utf-8′)
2) Baidu, Sogou等query串的转码:
用iconv来进行转码
- if($gb2312 == true && extension_loaded("iconv"))
- $phrase = iconv("gb2312","UTF-8",$phrase);
Popularity: 43%
Dissect WordPress Themes
by Meng Yan on Jul.26, 2005, under Blog
还是想用Nat在OOS上的一段话来作为开头:
You have to give people work to do.
Create an “architecture of participation” as Tim O’Reilly says.
要想真正成功,必须能够提供一个可以供人参与的架构,Eclipse如此,Firefox亦如此。与Plugin一样,WordPress中的Theme机制也非常灵活和强大,社区贡献出的一个个漂亮的Theme都是这个良好架构下的杰作。
1)读取系统中所有可用Themes
- <?php
- function get_themes()
- ?>
这个函数用来从文件系统得到所有的Themes。首先列出’wp-content/themes’的文件夹,然后跳过”.’、’..’、’CVS’(跳过CVS目录,这个在Xerdoc DSearch的Theme中也遇到过,因为都是采用CVS进行源码管理 :-)):
- <?php
- if ($theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS') {
- continue;
- }
- ?>
然后会判断每个目录中是否有Stylesheet ’style.css’文件,如果有,列为Theme候选目录,否则加入到’$wp_broken_themes’中。
接下来,就利用函数
- <?php
- function get_theme_data($theme_file);
- ?>
来从’style.css’中提取Theme的描述信息,包括’Theme Name’、’Version’、’Author’等等。同WordPress中的插件类似,这些描述信息是存在’style.css’中的。
- <?php
- Theme Name: WordPress Default
- Theme URI: http://wordpress.org/
- Description: The default WordPress theme based on the famous Kubrick.
- Version: 1.5
- Author: Michael Heilemann
- Author URI: http://binarybonsai.com/
- ?>
第三步,需要判断命名冲突。这种情况发生的原因是:将一个Theme拷贝,然后做修改,可是Theme的Descriptor并没有修改。可见,WordPress在人性化上真是做足了功夫,值得学习。
这样,合格的Theme就读取完毕了。不合格的Theme会被放到"Broken Theme"这个Section中,需要重新进行修改才能使用。
2)更换Theme
更换Theme很简单,先来看看当Active一个Theme的时候我们所Access的URL:
http://localhost/blog/wp-admin/themes.php?action=activate&template=sixties-datetitle&stylesheet=sixties-datetitle
同Plugin一样,Active Theme的信息(其实就是目录名称)也保存在数据库中。但是需要存两项,分别是"template"和"stylesheet"。这是为了处理Style的CSS文件与模板文件(比如index.php)放在不同目录的情况。
- <?php
- if (isset($_GET['template'])) {
- update_option('template', $_GET['template']);
- }
- if (isset($_GET['stylesheet'])) {
- update_option('stylesheet', $_GET['stylesheet']);
- }
- ?>
3)Theme的加载
首先看看我们访问WordPress的过程。当我们访问’http://yoursite/blog/’的时候,访问的是’index.php’文件:
- <?php
- define('WP_USE_THEMES', true);
- require('./wp-blog-header.php');
- ?>
在’wp-blog-header.php’文件中,可以看到下面的重定向过程:
- <?php
- // Template redirection
- if ( defined('WP_USE_THEMES') && constant('WP_USE_THEMES') ) {
- do_action('template_redirect');
- if ( is_feed() && empty($doing_rss) ) {
- include(ABSPATH . '/wp-feed.php');
- exit;
- } else if ( is_trackback() && empty($doing_trackback) ) {
- include(ABSPATH . '/wp-trackback.php');
- exit;
- } else if ( is_404() && get_404_template() ) {
- include(get_404_template());
- exit;
- } else if ( is_search() && get_search_template() ) {
- include(get_search_template());
- exit;
- } else if ( is_home() && get_home_template() ) {
- include(get_home_template());
- exit;
- } else if ( is_single() && get_single_template() ) {
- include(get_single_template());
- exit;
- } else if ( is_page() && get_page_template() ) {
- include(get_page_template());
- exit;
- } else if ( is_category() && get_category_template()) {
- include(get_category_template());
- exit;
- } else if ( is_author() && get_author_template() ) {
- include(get_author_template());
- exit;
- } else if ( is_date() && get_date_template() ) {
- include(get_date_template());
- exit;
- } else if ( is_archive() && get_archive_template() ) {
- include(get_archive_template());
- exit;
- } else if ( is_comments_popup() && get_comments_popup_template() ) {
- include(get_comments_popup_template());
- exit;
- } else if ( is_paged() && get_paged_template() ) {
- include(get_paged_template());
- exit;
- } else if ( file_exists(TEMPLATEPATH . "/index.php") ) {
- include(TEMPLATEPATH . "/index.php");
- exit;
- }
- } else {
- // Process feeds and trackbacks even if not using themes.
- if ( is_feed() && empty($doing_rss) ) {
- include(ABSPATH . '/wp-feed.php');
- exit;
- } else if ( is_trackback() && empty($doing_trackback) ) {
- include(ABSPATH . '/wp-trackback.php');
- exit;
- }
- }
- ?>
可以看到,根据访问的不同,会定向到不同的页面。比如访问首页的时候,’is_home’返回为true,这样,将会利用get_home_template(),重定向到home template。
- <?php
- function get_home_template() {
- $template = '';
- if ( file_exists(TEMPLATEPATH . "/home.php") )
- $template = TEMPLATEPATH . "/home.php";
- else if ( file_exists(TEMPLATEPATH . "/index.php") )
- $template = TEMPLATEPATH . "/index.php";
- return apply_filters('home_template', $template);
- }
- ?>
在’wp-setting.php’中,可以找到’TEMPLATEPATH’的定义:
- <?php
- define('TEMPLATEPATH', get_template_directory());
- ?>
get_template_directory()的定义为:
- <?php
- function get_template_directory() {
- $template = get_template();
- $template_dir = get_theme_root() . "/$template";
- return apply_filters('template_directory', $template_dir, $template);
- }
- ?>
get_template则是从数据库中取出现在使用的Theme,再加上Theme Root的路径,即可得到我们选择的Theme的路径。
- <?php
- function get_template() {
- return apply_filters('template', get_settings('template'));
- }
- ?>
因此,这样就定位到所选择Theme的目录,并访问相应的文件。
4)Template的模式
其实对于一个能够提供Theme的程序而言,在程序的构架上必须要实现数据和表现的分离。通常我们所说的MVC(Model、View、Controller)架构就是这个意思。
在WordPress中,是这样来实现数据和实现的分离的。
- XHTML。用Div等用来表现数据,CSS来描述这些数据的表现形式,用这种方式来实现数据和表现的分离;
- 在程序内部,采用Template来进行数据展现。
以 ‘Default’ Theme为例:
- <?php
- <?php get_header(); ?>
- <div id="content" class="narrowcolumn">
- <?php if (have_posts()) : ?>
- <?php while (have_posts()) : the_post(); ?>
- <div class="post" id="post-<?php the_ID(); ?>">
- <h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
- <small><?php the_time('F jS, Y') ?> <!-- by <?php the_author() ?> --></small>
- <div class="entry">
- <?php the_content('Read the rest of this entry »'); ?>
- </div>
- <p class="postmetadata">Posted in <?php the_category(', ') ?> <strong>|</strong> <?php edit_post_link('Edit','','<strong>|</strong>'); ?> <?php comments_popup_link('No Comments »', '1 Comment »', '% Comments »'); ?></p>
- </div>
- <?php endwhile; ?>
- <div class="navigation">
- <div class="alignleft"><?php next_posts_link('« Previous Entries') ?></div>
- <div class="alignright"><?php previous_posts_link('Next Entries »') ?></div>
- </div>
- <?php else : ?>
- <h2 class="center">Not Found</h2>
- <p class="center">Sorry, but you are looking for something that isn't here.</p>
- <?php include (TEMPLATEPATH . "/searchform.php"); ?>
- <?php endif; ?>
- </div>
- <?php get_sidebar(); ?>
- <?php get_footer(); ?>
- ?>
"get_header"和"get_footer"分别用来得到该页的Header和Footer,其实就是两个DIV块儿。Post的主体同样是一个大的Div(<div id="content" class="narrowcolumn">),在该Theme的CSS中即可以看到对这个DIV的表现定义,包括字体、背景颜色、边距等等。
- .narrowcolumn {
- float: left;
- padding: 0 0 20px 45px;
- margin: 0px 0 0;
- width: 450px;
- }
Post的内容由"have_posts()", "the_post()", "the_ID()"得到,具体见此,风格同样定义在CSS文件中。
Popularity: 46%


