Dissect WordPress Themes

还是想用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

  1. <?php 
  2. function get_themes()
  3. ?>

这个函数用来从文件系统得到所有的Themes。首先列出’wp-content/themes’的文件夹,然后跳过”.’、’..’、’CVS’(跳过CVS目录,这个在Xerdoc DSearch的Theme中也遇到过,因为都是采用CVS进行源码管理 :-) ):

  1. <?php 
  2. if ($theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS') {
  3.     continue;
  4. }
  5. ?>

然后会判断每个目录中是否有Stylesheet ‘style.css’文件,如果有,列为Theme候选目录,否则加入到’$wp_broken_themes’中。

接下来,就利用函数

  1. <?php 
  2. function get_theme_data($theme_file);
  3. ?>

来从’style.css’中提取Theme的描述信息,包括’Theme Name’、’Version’、’Author’等等。同WordPress中的插件类似,这些描述信息是存在’style.css’中的。

  1. <?php 
  2. Theme Name: WordPress Default
  3. Theme URI: http://wordpress.org/
  4. Description: The default WordPress theme based on the famous Kubrick.
  5. Version: 1.5
  6. Author: Michael Heilemann
  7. Author URI: http://binarybonsai.com/
  8. ?>

第三步,需要判断命名冲突。这种情况发生的原因是:将一个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)放在不同目录的情况。

  1. <?php 
  2. if (isset($_GET['template'])) {
  3.     update_option('template', $_GET['template']);
  4. }
  5.  
  6. if (isset($_GET['stylesheet'])) {
  7.     update_option('stylesheet', $_GET['stylesheet']);
  8. }
  9. ?>

3)Theme的加载

首先看看我们访问WordPress的过程。当我们访问’http://yoursite/blog/’的时候,访问的是’index.php’文件:

  1. <?php 
  2. define('WP_USE_THEMES', true);
  3. require('./wp-blog-header.php');
  4. ?>

在’wp-blog-header.php’文件中,可以看到下面的重定向过程:

  1. <?php 
  2. // Template redirection
  3. if ( defined('WP_USE_THEMES') && constant('WP_USE_THEMES') ) {
  4.     do_action('template_redirect');
  5.     if ( is_feed() && empty($doing_rss) ) {
  6.         include(ABSPATH . '/wp-feed.php');
  7.         exit;
  8.     } else if ( is_trackback() && empty($doing_trackback) ) {
  9.         include(ABSPATH . '/wp-trackback.php');
  10.         exit;
  11.     } else if ( is_404() && get_404_template() ) {
  12.         include(get_404_template());
  13.         exit;
  14.     } else if ( is_search() && get_search_template() ) {
  15.         include(get_search_template());
  16.         exit;
  17.     } else if ( is_home() && get_home_template() ) {
  18.         include(get_home_template());
  19.         exit;
  20.     } else if ( is_single() && get_single_template() ) {
  21.         include(get_single_template());
  22.         exit;
  23.     } else if ( is_page() && get_page_template() ) {
  24.         include(get_page_template());
  25.         exit;
  26.     } else if ( is_category() && get_category_template()) {
  27.         include(get_category_template());
  28.         exit;       
  29.     } else if ( is_author() && get_author_template() ) {
  30.         include(get_author_template());
  31.         exit;
  32.     } else if ( is_date() && get_date_template() ) {
  33.         include(get_date_template());
  34.         exit;
  35.     } else if ( is_archive() && get_archive_template() ) {
  36.         include(get_archive_template());
  37.         exit;
  38.     } else if ( is_comments_popup() && get_comments_popup_template() ) {
  39.         include(get_comments_popup_template());
  40.         exit;
  41.     } else if ( is_paged() && get_paged_template() ) {
  42.         include(get_paged_template());
  43.         exit;
  44.     } else if ( file_exists(TEMPLATEPATH . "/index.php") ) {
  45.         include(TEMPLATEPATH . "/index.php");
  46.         exit;
  47.     }
  48. } else {
  49.     // Process feeds and trackbacks even if not using themes.
  50.     if ( is_feed() && empty($doing_rss) ) {
  51.         include(ABSPATH . '/wp-feed.php');
  52.         exit;
  53.     } else if ( is_trackback() && empty($doing_trackback) ) {
  54.         include(ABSPATH . '/wp-trackback.php');
  55.         exit;
  56.     }
  57. }
  58. ?>

可以看到,根据访问的不同,会定向到不同的页面。比如访问首页的时候,’is_home’返回为true,这样,将会利用get_home_template(),重定向到home template。

  1. <?php 
  2. function get_home_template() {
  3.     $template = '';
  4.  
  5.     if ( file_exists(TEMPLATEPATH . "/home.php") )
  6.         $template = TEMPLATEPATH . "/home.php";
  7.     else if ( file_exists(TEMPLATEPATH . "/index.php") )
  8.         $template = TEMPLATEPATH . "/index.php";
  9.  
  10.     return apply_filters('home_template', $template);
  11. }
  12. ?>

在’wp-setting.php’中,可以找到’TEMPLATEPATH’的定义:

  1. <?php 
  2. define('TEMPLATEPATH', get_template_directory());
  3. ?>

get_template_directory()的定义为:

  1. <?php 
  2. function get_template_directory() {
  3.     $template = get_template();
  4.     $template_dir = get_theme_root() . "/$template";
  5.     return apply_filters('template_directory', $template_dir, $template);
  6. }
  7. ?>

get_template则是从数据库中取出现在使用的Theme,再加上Theme Root的路径,即可得到我们选择的Theme的路径。

  1. <?php 
  2. function get_template() {
  3.     return apply_filters('template', get_settings('template'));
  4. }
  5. ?>

因此,这样就定位到所选择Theme的目录,并访问相应的文件。

4)Template的模式

其实对于一个能够提供Theme的程序而言,在程序的构架上必须要实现数据和表现的分离。通常我们所说的MVC(Model、View、Controller)架构就是这个意思。

在WordPress中,是这样来实现数据和实现的分离的。

  1. XHTML。用Div等用来表现数据,CSS来描述这些数据的表现形式,用这种方式来实现数据和表现的分离;
  2. 在程序内部,采用Template来进行数据展现。

以 ‘Default’ Theme为例:

  1. <?php
  2. <?php get_header(); ?>
  3.  
  4.     <div id="content" class="narrowcolumn">
  5.  
  6.     <?php if (have_posts()) : ?>
  7.        
  8.         <?php while (have_posts()) : the_post(); ?>
  9.                
  10.             <div class="post" id="post-<?php the_ID(); ?>">
  11.                 <h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
  12.                 <small><?php the_time('F jS, Y') ?> <!-- by <?php the_author() ?> --></small>
  13.                
  14.                 <div class="entry">
  15.                     <?php the_content('Read the rest of this entry &raquo;'); ?>
  16.                 </div>
  17.        
  18.                 <p class="postmetadata">Posted in <?php the_category(', ') ?> <strong>|</strong> <?php edit_post_link('Edit','','<strong>|</strong>'); ?>  <?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?></p>
  19.             </div>
  20.    
  21.         <?php endwhile; ?>
  22.  
  23.         <div class="navigation">
  24.             <div class="alignleft"><?php next_posts_link('&laquo; Previous Entries') ?></div>
  25.             <div class="alignright"><?php previous_posts_link('Next Entries &raquo;') ?></div>
  26.         </div>
  27.        
  28.     <?php else : ?>
  29.  
  30.         <h2 class="center">Not Found</h2>
  31.         <p class="center">Sorry, but you are looking for something that isn't here.</p>
  32.         <?php include (TEMPLATEPATH . "/searchform.php"); ?>
  33.  
  34.     <?php endif; ?>
  35.  
  36.     </div>
  37.  
  38. <?php get_sidebar(); ?>
  39.  
  40. <?php get_footer(); ?>
  41. ?>

"get_header"和"get_footer"分别用来得到该页的Header和Footer,其实就是两个DIV块儿。Post的主体同样是一个大的Div(<div id="content" class="narrowcolumn">),在该Theme的CSS中即可以看到对这个DIV的表现定义,包括字体、背景颜色、边距等等。

  1. .narrowcolumn {
  2.     float: left;
  3.     padding: 0 0 20px 45px;
  4.     margin: 0px 0 0;
  5.     width: 450px;
  6. }

Post的内容由"have_posts()", "the_post()", "the_ID()"得到,具体见,风格同样定义在CSS文件中。

Popularity: 41% [?]

Related entries:

3 Responses to “Dissect WordPress Themes”

  1. TreeFrog Says:

    Awesome blog you have. I enjoyed reading it this evening.
    Peace
    TreeFrog

  2. GoTop’s Blog » Blog Archive » 两篇关于 WordPress的plugin和theme原理的文章 Says:

    [...] http://www.mengyan.org/blog/archives/2005/07/26/39.html [...]

  3. cocobear Says:

    看了这篇文章,对wordpress的构架方式了解了很多,不错。

Leave a comment

(required)

(required)


Information for comment users
Line and paragraph breaks are implemented automatically. Your e-mail address is never displayed. Please consider what you're posting.

Use the buttons below to customise your comment.


RSS feed for comments on this post | TrackBack URI