Codex

Interested in functions, hooks, classes, or methods? Check out the new WordPress Code Reference!

zh-cn:开发一个插件

简介

WordPress 插件 允许你通过一种简单的方式来修改、定义和强化博客的功能。你可以在不修改WordPress的核心代码的情况下,通过插件来直接向WordPress中增加功能。以下是对 WordPress 插件的基本定义:

WordPress 插件:WordPress插件可以是一个程序,也可以是PHP语言编写的一个或一组函数。它可以通过插件 API提供的一系列方法和接口,来向WordPress博客中增加一些特定的功能或服务,并且让它们看上去就像是WordPress原有的功能一样。

想要为你的博客添加一些新的或者不一样的功能?你可以先去WordPress插件库搜索一下,看看是不是有人已经开发了一个符合你要求的WordPress插件。如果很不幸——没有,那么这篇文章会指导你自己开发一个。

要想读懂本文中的内容,你需要对 WordPress 的基本功能和 PHP 编程有一定的了解。

资源

  • 如果想要了解WordPress插件应当如何安装,以及它们是怎样工作的,去插件资源集合里看看,这里有许多插件开发者的文章和资源,包括如何编写WordPress插件,以及其它特定主题的文章等。
  • 如果想要知道WordPress插件是如何编写的,你可以查看一些插件的源代码,例如WordPress中自带的Hello Dolly插件。
  • 如果你的插件已经写完了,并且感觉良好的话,你可以阅读插件提交以及推广来学习如何把它发布出去,与他人分享你的劳动成果。

创建插件

这个部分告诉你怎么把开发插件的理想变为现实。

名字,文件和位置

名字

首先你需要想好这个插件是用来做什么的,然后你就可以为它起一个独一无二的名字。如果你不确定这个名字是否被使用过,你可以通过Google或者其他的方式来搜索一下。大多数插件开发者为插件起的名字都能很直观地描述它的功能,例如,一个与天气有关的插件的名字中就应当包含“天气”两个字。插件的名字可以由多个字词组成。

文件

下一步就是根据你插件的名字,创建一个PHP主文件。举个例子,如果插件的名字叫做 "Fabulous Functionality",那么PHP主文件的名字就可以是 "functionality.php",当然,还要注意重名的问题。因为用户在安装你的插件的时候,会默认把你的插件安装到一个叫wp-content/plugins/的目录下,如果两个插件的文件名冲突了,那就杯具了。

你的插件中至少应当包含一个PHP主文件(当然你也可以把它拆分成多个文件),还可以包含Javascript文件、CSS文件、图片文件以及语言文件等。如果你的插件中包含多个文件,你还需要建立一个文件夹,并把插件包含的所有文件放到这个文件夹中,这样你只要让其他人把整个文件夹放到wp-content/plugins/目录下就可以了。插件文件夹的名称通常和插件PHP文件的名称相同,例如PHP文件的名称叫做functionality.php的话,文件夹的名称就可以叫做functionality。

需要注意的是,由于在WordPress中可以配置wp-content/plugins/目录的位置,所以你必须使用plugin_dir_path()和plugins_url()两个函数来获取插件的路径。

查看http://codex.wordpress.org/Determining_Plugin_and_Content_Directories 以获取更多信息

  • 在这篇文章之后的部分,如果再提到“PHP主文件”这个概念的话,指的就是插件中最主要的php文件,这个文件通常位于wp-content/plugins/目录或其子目录下。

自述文件

如果你想将你的插件发布到http://wordpress.org/extend/plugins/, 你必须在插件包中建立一个标准格式的readme.txt文件. 文件格式参见http://wordpress.org/extend/plugins/about/readme.txt.

你可以访问http://wordpress.org/extend/plugins/about/readme.txt 查看如何去格式化自述文件,或者访问http://generatewp.com/plugin-readme/ 来使用文档自动生成器

需要注意的是,WordPress是通过自述文件来判断这个插件是处于“必要”还是“测试”状态的。

主页

为你的插件建立一个主页会非常有用,你可以在插件的主页上对插件的功能、安装方法、使用说明、适用的WordPress版本以及插件更新信息等进行介绍。

文件头

现在开始吧,首先让我们向PHP主文件中加入一些信息

标准插件信息

插件的主文件顶部必须包括一个标准插件信息头。WordPress通过标准信息头识别插件的存在,并把它加入到控制面板的插件管理页面,这样插件才能激活,载入插件,并运行里面的函数;如果没有信息头,插件将无法激活和使用。标准信息插件头的格式为:

<?php
/*
Plugin Name: 插件名称
Plugin URI: http://URI_Of_Page_Describing_Plugin_and_Updates
Description: 插件的简单描述
Version: 插件版本号, 例如: 1.0
Author: 插件作者
Author URI: http://URI_Of_The_Plugin_Author作者地址
*/
?>

标准信息头至少要包括插件名称,这样WordPress才能识别你的插件。其他信息将显示在控制面板插件管理页面中。标准插件信息对各行顺序没有要求。

版权信息

通常我们还要在标准信息头中加入插件的许可证信息。大多数插件使用GPLGPLCompatibleLicenses许可。如果使用GPL许可,要求插件中包含以下信息:

<?php
/*  Copyright 年份  作者名  (email : 你的邮箱)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
?>

开始编写插件

现在是时候让你的插件做些事情了。这部分内容包括插件开发的一般思路,以及需要完成的工作。

WordPress插件钩子

在WordPress中,“插件钩子”是一个非常重要的概念。许多WordPress插件都是通过与插件钩子相关联的方式,来完成他们的功能的。插件钩子的工作原理是:在WordPress运行期间,有许多特定的时间点,WordPress会在这些时间点检测相应的插件钩子,如果检测到有函数与当前的插件钩子相关联的话,就会运行这些函数。正是这些函数改变了WordPress的默认功能。

例如,当WordPress在发表一篇文章之前,会首先检测一个名为"the_title"的插件钩子(过滤器类型的钩子),如果此时有任何插件的函数与这个钩子相关联的话,那么文章的标题就会首先被这些函数依次进行处理,最后再把函数处理的结果显示到屏幕上。所以,如果你的插件想要对文章的标题进行处理的话,就需要将对应的处理函数注册到名为"the_title"的过滤器钩子上。

再举个例子,在WordPress即将生成</HTML>标签之前,会检测一个名为"wp_footer"的插件钩子(动作类型的钩子),如果此时有插件的函数与这个钩子相关联的话,那么WordPress就会先依次执行这些函数,然后再继续生成</HTML>标签。

如果想要了解动作类型钩子和过滤器钩子的区别、如何向钩子上注册函数,以及WordPress在什么时间点会调用哪些插件钩子,你可以参阅Plugin API。如果您发现了一个想要对其进行处理的时间点,但是WordPress并未对这个时间点提供插件钩子的话,您也可以通过Reporting Bugs向我们提出建议,您的建议通常都会被我们采纳。

模版标签

另一个向WordPress中加入插件的方式就是建立自定义的模板标签Template Tags。这样如果有人想要使用你的插件,就可以把这些标签添加到他们的主题、侧边栏、文章内容以及任何合适的地方。例如,可以为插件定义一个名为geotag_list_states()的模板标签函数,该函数可以为侧边栏的文章添加地理位置标签,当点击这个标签时,还可以打开这个地理位置标签下所有对应的文章。

要定义一个自定义模板标签,你只需要写一个PHP函数,然后把它通过文档、插件的主页或是在PHP主文件中声明的方式告诉插件的使用者就可以了。当你为这个函数编写文档的时候,如果还能够提供一个该函数的使用示例,来告诉用户在主题中应当如何调用这个函数,就再好不过了。

保存插件数据到数据库

大多数WordPress插件都需要获取管理员或用户输入的一些信息,并保存在会话中,以便在过滤器函数(filter)、动作函数(action)和模板函数(template)中使用。若需要在下次会话中继续使用这些信息,就必须将它们保存到WordPress数据库中。以下是将插件数据保存到数据库的4种方法:

1. 使用WordPress的"选项"机制(稍后会有介绍)。这种方式适合储存少量静态的、具有特定名称的数据——这类数据通常是网站所有者在创建插件时设置的一些初始化参数,并且以后很少会进行改动。

2、使用文章元数据(又名自定义域)。这种方式适合保存与个人文章、页面或附件相关的数据。若需要了解更多,请参阅post_meta函数示例,以及与add_post_meta()相关的函数。

3、使用自定义分类。这种方式适合保存那些需要分门别类存放的数据,如用户信息、评论内容以及用户可编辑的数据等,特别适合于当你想要根据某个类型去查看相关的文章和数据的情况。若需要了解更多,请参阅Custom Taxonomies

4、创建一个新的,自定义的数据库表。这种方式适合保存那些与个人文章、页面或附件无关的,会随着时间逐渐增长的,并且没有特定名称的数据。关于如何使用,你可以阅读Creating Tables with Plugins以获取更多信息。

WordPress 选项机制

参阅Creating Options Pages,你将学会如何去创建一个自动保存选项数据的页面。

WordPress有一个"选项"机制,用于保存、更新以及检索那些独立的,具有特定名称的数据。选项的值可以是字符串、数组,甚至是PHP对象(当然,PHP对象在保存时必须能够被序列化或转换成字符串,检索的时候也必须能够被反序列化)。选项的名称必须是字符串,且必须是唯一的,这样才能够确保它们不会和WoredPress或其它插件产生冲突。

通常情况下,你最好能够对插件选项的数量进行一下精简。例如,如果你有10个不同名称的选项需要保存到数据库中,那么,你就可以考虑将这10个数据作为一个数组,并保存到数据库的同一个选项中。

以下是让你的插件使用选项机制的主要函数:

add_option($name, $value, $deprecated, $autoload);
创建一个新的选项并保存到数据库中,若选项已存在,则不进行任何操作。
$name
必要参数(string)。要创建的选项的名称。
$value
可选参数(string)。要创建的选项的值。默认值为空字符串。
$deprecated
可选参数(string)。该选项是否已经过期。若需要让后面的$autoload参数生效,则该参数必须传入空字符串或null。
$autoload
可选参数(enum: 'yes' or 'no')。是否自动加载该选项。若设置为 'yes',则该选项会被get_alloptions 函数自动检索到。默认值为 'yes'。
get_option($option);
从数据库中获取指定选项的值。
$option
必要参数(string)。选项的名称。你可以在Option Reference中找到与WordPress一同安装的默认选项列表。
update_option($option_name, $newvalue);
更新数据库中的选项值,若选项不存在,则创建该选项。
(注意:如果你用不到$deprecated$autoload参数的话,那么大可不必使用add_option函数)。
$option_name
必要参数(string)。要更新/创建的选项名称。
$newvalue
必要参数(string|array|object)。要更新/创建的选项的值。

管理面板

假定你的插件有一些选项(option)存储于WordPress的数据库中(参看上一节),你可能会想要一个主控面板来允许你的插件用户查看和编辑选项值。实现这一目标的方法阐述于Adding Administration Menus

插件国际化

在你完成了你的插件的编写工作之后,另一个需要考虑的问题(假设你准备跟大家分享你的插件的话)就是将其国际化。国际化就是将你的软件设置成能够本地化的过程;本地化是将软件中显示的语言翻译成其他语言的过程。Wordpress正在被全球的人们使用,所以全球化和本地化是他内在的特性,这其中就包括了插件的本地化。

我们十分希望你能够将你的插件国际化,这样其他国家的用户就可以在自己的本地使用它了。我们有一个关于国际化的综合说明在 I18n for WordPress Developers,这其中就包括了一个描述插件国际化的部分。

更新你的插件

这个部分描述必要的步骤来更新你在http://wordpress.org/extend/plugins 上的插件,还包括在wordpress.org中使用Subversion (SVN)的细节。

假设你已经提交了你的插件到WordPress插件存储库。随着时间的推移,你可能会发现需要并希望将添加新的功能到您的插件或修正错误。你常常想要完成这些改变并提交它们到你的插件的主干。变化将是公开可见的,但只有专业人员通过SVN才能查看你的插件,其他用户通过网站或他们的WordPress插件管理下载的将不会改变。

当你准备发布一个新版本的插件时:

  • 确保一切都被提交并且新版本可以正常工作。注意测试所有你的插件所支持的Wordpress版本。也不只是测试新特性,确保你没有不小心破坏一些老的功能插件。
  • 更新主PHP文件中头注释的版本号(在主文件夹)。
  • 更新readme.txt文件中的'Stable tag'的版本号(在主文件夹)。
  • 在readme.txt文件中添加一个新的部分——“更新日志(changelog)”,简要描述相比于最后一个版本的变化。它将被列在插件页中。
  • 提交这些更改。
  • 创建一个新的SVN标签作为主干的副本,参见这里

给系统几分钟去工作,然后检查wordpress.org插件页面和Wordpress上安装你的插件的页面,看看一切是否正确更新和是否在你安装的Wordpress中显示了插件更新(更新检查可能会被缓存,这可能需要一些时间,试着访问“可用更新”的页面在你安装的WordPress中)。

故障排除:

  • 在wordpress.org上的插件页面仍然列出了旧版本。你是否更新主文件夹中的'stable tag'?只是创建一个标签,更新readme.txt在标签文件夹中是不够的!
  • 插件页面提供了一个新版本的zip文件,但按钮仍然列出了旧版本号并且在你的安装WordPress中并没有更新通知。你是否记得更新“版本(Version)”的注释在主PHP文件中?
  • 对于其他问题请参考Otto的关于常见问题的页面:The Plugins directory and readme.txt files

插件开发建议

最后这个部分是关于开发插件的一些建议。

  • Wordpress插件的代码应该遵循 WordPress Coding Standards. 另外请同时参考Inline Documentation
  • 你的插件中所有函数的名称都应该与现存的Wordpress Core函数,其他插件或主题的任何名称不同。基于这个原因,我们建议你在你的插件的所有函数的名称之前加上一个你自己选择的前缀,或者把你的插件的函数都写在一个类里面(当然这个类的名字也必须是唯一的)。
  • 请不要把Wordpress数据库表格前缀(通常是“wp_”)直接写在你的插件里,请使用$wpdb->prefix
  • 虽然数据库的读取相对便宜,但它的写入是相当昂贵的。数据库十分擅长获取信息并呈现给用户,而且这些操作(通常)是非常迅速的。然而对数据库进行改动就是一个非常复杂的过程了,而且需要使用更长的计算时间。因此,请尽量减少你对数据库进行写入的次数。在你编写程序的时候就做好所有的准备,这样就可以只在必须的时候再进行写入了。
  • 在数据库里只SELECT你需要的东西。尽管数据库的读取十分便捷,我们依然推荐你只查找真正需要的数据,来尽量减少数据库的负载。例如,如果你只想获得表格的行数,不要使用 SELECT * FROM, 因为这样的话每一行中的所有数据都会被读出,导致内存的浪费。同样的,如果在插件中你只想获得post_id和post_author,请只 SELECT 这两项来减少数据库的负载。记住:在某一个操作的同时可能有其他上百个进程需要使用数据库,而数据库和服务器都必须同时满足所有这些进程的需求。学习怎样尽量减少你的插件对数据库的使用可以避免对这些资源的滥用。
  • 不要让你的PHP出错。在你的wp_config.php文件中添加define('WP_DEBUG',true);,对你的所有函数进行测试来确定是否有任何的错误或者警告。有多少,就修复多少,直到再也不出现为止。

外部资源

本文已被标记为未完成状态。您可以将其补充或翻译完整,以此帮助完善 Codex。