WordPress插件机制实现原理

1)WordPress读取全部可用的插件

在文件”/wp-admin/includes/plugin.php”中,函数 get_plugins() 用来从文件系统获得全部的插件。原理很简单,就是读取”wp-content/plugins”目录下的全部PHP文件。这个函数容许一级的子文件夹,也就是说在’wp-content/plugins’下面的PHP文件,以及因此在此目录下的一级子文件夹内部的PHP文件被列做插件的候选,用下面的函数 去进一步提取插件信息。这样的好处是方便用户利用文件夹来对插件进行管理和组织。而函数 get_plugin_data() 则用来获得插件的描述(Plugin Descriptor),主要包括插件的版本、名称、做者,等信息,而这些实际上是以注释的方式存在的。用WordPress中自带的Hello插件来举 例:php

01 <?php
02 /*
03     Plugin Name: Hello Dolly
04     Plugin URI: http://wordpress.org/#
05     Description: This is not just a plugin, it symbolizes the hope and enthusiasm of an entire generation summed up in two words sung most famously by Louis Armstrong: Hello, Dolly. When activated you will randomly see a lyric from <cite>Hello, Dolly</cite> in the upper right of your admin screen on every page.
06     Author: Matt Mullenweg
07     Version: 1.5
08     Author URI: http://ma.tt/
09 */
10 ?>

这样,在get_plugin_data函数中,就能够来获得插件的详细信息。html

01 <?php
02 function get_plugin_data( $plugin_file ) {
03     $plugin_data = implode( '', file( $plugin_file ));
04     preg_match( '|Plugin Name:(.*)$|mi'$plugin_data$plugin_name );
05     preg_match( '|Plugin URI:(.*)$|mi'$plugin_data$plugin_uri );
06     preg_match( '|Description:(.*)$|mi'$plugin_data$description );
07     preg_match( '|Author:(.*)$|mi'$plugin_data$author_name );
08     preg_match( '|Author URI:(.*)$|mi'$plugin_data$author_uri );
09     if ( preg_match( "|Version:(.*)|i"$plugin_data$version ))
10         $version = trim( $version[1] );
11     else
12         $version '';
13     $description = wptexturize( trim( $description[1] ));
14     $name $plugin_name[1];
15     $name = trim( $name );
16     $plugin $name;
17     if (" != trim($plugin_uri[1]) && " != $name ) {
18         $plugin '<a href="' . trim( $plugin_uri[1] ) . '" title="'.__('Visit plugin homepage' ).'">'.$plugin.'</a>';
19     }
20     if ('' == $author_uri[1] ) {
21         $author = trim( $author_name[1] );
22     else {
23         $author '<a href="' . trim( $author_uri[1] ) . '" title="'.__('Visit author homepage' ).'">' . trim( $author_name[1] ) . '</a>';
24     }
25     return array('Name' => $name'Title' => $plugin'Description' =>$description'Author' => $author'Version' => $version);
26 }
27 ?>

2)启用 & 禁用插件

启用(禁用)插件的操做都在Plugins.php中,好比我要Deactive “Hello”这个插件,最后的URL实际上是这个样子:数据库

http://localhost/blog/wp-admin/plugins.php?action=deactivate&plugin=hello.php数组

其中,”Action”表示动做,值为”active”或者”deactivate”,而”Plugin”表示动做的对象插件,此处为”hello.php”。获得动做指令后,首先 从数据库中取出当前已经激活的插件。架构

1 <?php $current = get_settings('active_plugins'); ?>

而后根据动做,从新生成已激活插件数组,存入数据库,并从新加载此页。加载的时候就须要考虑这些已经激活的插件是怎么工做的了。
BTW:附上数据库的Options表中0插件和只有1个插件的值:
没有插件:dom

1 a:1:{i:0;s:0:"";}

只有Hello插件:wordpress

1 a:2:{i:0;s:0:"";i:1;s:9:"hello.php";}

3)如何加载启用的插件到系统中

WordPress中的每页都会包含”wp-config.php”文件,而”wp-config.php”中也会自动加载”wp- settings.php”文件。在”wp-settings.php”文件中,能够找到如下与插件相关的代码片段:函数

01 <?php
02 if ( get_option('active_plugins') ) {
03     $current_plugins = get_option('active_plugins');
04     if is_array($current_plugins) ) {
05         foreach ($current_plugins as $plugin) {
06             if '' != $plugin && 0 == validate_file($plugin) &&file_exists(WP_PLUGIN_DIR . '/' $plugin) )
07                 include_once(WP_PLUGIN_DIR . '/' $plugin);
08         }
09     }
10 }
11 ?>

可见,这段代码会取出系统中全部启用的插件,并包含进来。因此在每页加载的时候,都会首先包含这些插件代码。那么,这些插件本身在加载的时候都作了 什么呢?post

4)插件的加载

插件的加载其实最重要的一个部分就是插件的事件注册机制,WordPress插件中的事件注册其实和Eclipse中的扩展点 (Extension-Point)机制很是相像,而这种相似”插销”、”插销座”的软件插拔方式也成为了最近软件组件架构方面应用最多的实践。
事件注册过程当中比较重要的几个函数分别是:do_action、add_action、add_filter。WordPress中默认定义了不少扩 展点(也能够叫作”钩子”),或者说注册了不少系统事件(WP中的正规叫法应该是”Action Tag”),好比”admin_head”表示Admin页面的Head输出事件,”publish_post”表示发布一篇帖子的事件等等。而插件要作 的就是扩展这些扩展点,或者说挂接这些钩子,从而实现系统的扩展功能。add_action就是一般插件扩展某个扩展点用到的函数,而do_action 是扩展点自己开始执行的函数。
刚才说过WordPress中的每一页执行前都会Include全部Active的插件代码,而这些代码一般都会用”add_action”来将本身 的函数注册到系统的扩展点中。这样,在扩展点执行的时候,就会找到系统中全部已经挂接到这个扩展点上的插件的函数来执行之,从而扩充系统的功能。
WordPress中的不少功能也都是经过这种插件结构来实现的,默认注册了不少系统事件,都在’default-filter.php’中。好比:ui

1 <?php add_action('publish_post''generic_ping'); ?>

这个是用来在发布每篇帖子的时候发送XML-RPC Ping的。再好比:

1 <?php add_filter('the_content''convert_smilies'); ?>

用来将正文(content)中的笑脸符号转换为图像。
仍是举”Hello”插件来讲。Hello插件会随机的在Admin Page的右上角显示一段话,它的工做原理是这样的:
在每个Admin page的前面都有

1 <?php require_once('admin-header.php'); ?>

而在”admin-head.php”中将会执行扩展点”admin-head”的全部扩展:

1 <?php do_action('admin_head', "); ?>

这样,就会执行全部挂接到admin_head的函数,Admin Page 的 Footer 部分也是相似。

5)若是插件中涉及UI

实际上是同样的。以WordPress FeedBurner Plugin中添加菜单为例。
若是想添加一个菜单,就须要注册”admin_menu”这个Action Tag(系统事件)便可:

1 <?php add_action('admin_menu''ol_add_feedburner_options_page'); ?>

插件中的这个函数为:

1 <?php
2 function ol_add_feedburner_options_page() {
3     if (function_exists('add_options_page')) {
4         add_options_page('FeedBurner''FeedBurner', 8, basename(__FILE__),'ol_feedburner_options_subpanel');
5     }
6 }
7 ?>

“add_options_page”这个函数就会在系统的”Options”菜单中添加”FeedBurner”这样一个子菜单。

6)其它

还有一些简单的插件就是只提供一些API函数。好比Most_Commented Plugin,它提供一个API “mdv_most_commented”:经过数据库查询获得评论最多的文章,并加以显示。由于这个插件已经被Include过,因此能够用这个API 来进行显示。

转载自:http://www.helloyi.cn/index.php/2010/02/09/wordpress-plugin/