Wordpress 中文
Advertisement

撰写插件

简介[ | ]

WordPress 试图保持一个简单,快速,轻量级的核心代码,它把大量的新功能作为WordPress 标准代码的扩展部分。用户可以通过Plugins来扩展,增强WordPress提供的功能。你也可以书写你自己的插件,以此弥补发现的不足,也可以个性化你的blog。这篇文章将教给你理解以及处理这方面要求的基本知识,而且还有几个例子哦。

嗯,开始之前,先让我们描述一个插件,怎么定义呢?

WordPress Plugin
一个 WordPress 插件就是一个程序,或者说是一组单一或多种功能函数的集合,一般都是用 PHP 语言书写的,其目的是为给 WordPress Weblog 添加一些特殊的功能或服务,而且这些功能能够通过WordPress 的 Plugin 应用程序接口(API)所提供的访问入口和方法实现同 weblog的无缝对接。

也就是说,不是随便什么文件包含了几个函数都可以自称 WordPress 插件。


需求[ | ]

下面描述WordPress 插件的一些重要原则:

The following are essential requirements of a WordPress Plugin:

  1. plugin 的代码必须遵循WordPress 代码规范。可以参考Inline Documentation-一个标准范本。
  2. 一个插件可以仅包含一个文件,也可以包含一堆文件。插件主文件本身需要放置在wp-content/plugins/目录下(比如: wp-content/plugins/plugin.php),或者其下不超过一层的目录下(比如:wp-content/plugins/BAStats/BAStats.php)。其他附属文件可以放在 WordPress weblog 的wp-content/目录下,这样当WordPress 升级时不会覆盖掉这些文件。如果你的插件有多个文件(代码或图片等),你可能更希望把所有东西放到一个目录下,比如类似/wp-content/plugins/{yourplugin}这种。遵照这些原则把所有东西归类放到一个目录下也会给最终用户的使用带来极大的方便。而且对于在wp-content下建立子目录也没有什么严格的约束。
  3. 文件头几行会是本文中Plugin 文件组织结构标准中的标准代码。
  4. 用户可以使用 weblog 的管理界面中的 "Plugin" 菜单来激活和使用插件。理想状态下,插件的使用应该不需要用户修改 WordPress 源代码。附加的插件钩子(plugin hooks)在WP-Hackers 邮件列表中讨论。
  5. 用户应该可以在插件自身的选项页设置所有的参数和变量,而不需要编辑一行插件代码。参考本文中的将插件数据存入数据库中添加管理面板两节,了解详细信息。
  6. 确保你在插件中的函数使用的是唯一的名字空间。如果你的插件中的函数与另一个插件中的同名,插件就会崩溃 WordPress也会拒绝执行它,直到其中一个插件被删除。避免名字空间冲突的一个有效办法是使用静态类方法。参考避免函数名冲突一节,了解详细信息。


依据这些原则本文随后会推荐一些具体的操作方法和标准。在开始介绍关键性的"插件文件组织结构"知识前,让我们先了解一下如何在 WordPress 社区提交和推进你的插件。4423494936504729186653

Plugin 的提交和推进[ | ]

要将你的插件提交推广到 WordPress 社区,首先在你的站点上为你的插件创建一个页面,取名叫complete and well written instructions。在你要编写的插件头部包含一个指向这个解释性页面的链接,其他人可以据此很容易的找到插件更新以及其他的帮助信息。包含以下指令:

  • 清晰明确的描述插件的用途及使用方法。
  • 清晰地描述安装指令。
  • 清晰地描述如何修改模板文件或者在模板文件中使用标签(tags)符号。要明确在什么模板文件以及文件的什么地方放置标签(tags)符号,并明确说明要使其生效需要放置到WordPress Loop循环中。
  • 代码清晰易读,容易完整copy,不包含特殊引用或者独特的省略语或缩写。
  • 提供清晰的使用范例,包含标签符号参数示例,或者是一个指向插件使用以及运行结果示例的链接。
  • 如果可能的话,提供多于一处的插件下载。A phps/text file is fine (with instructions on how to copy and paste and upload), 同时提供zip压缩文件作为备选。
  • 插件更新或修改时,不要为插件创建新的页面,除非有充分的理由。只需要简单的编辑原有页,在帖子的底部添加Updated信息,其他人就知道了。
  • 如果你对插件不提供支持,那末在描述信息中一定要声明这点。这意味着用户使用你的插件风险自负,你也不会回应用户疑问,插件也不见得会定期更新。确定关闭页面的评论。这并不会抵消你的插件的可用性,它只是给用户足够的知情权。


如果你不想在自己的网站上发布插件信息,而是利用WordPress Plugin Repository,那末在Repository 中你的插件主页面上按照上述原则描述你的插件信息。

如果你选择将你的插件提交到WordPress Plugins Database,同样需要尽可能清晰的描述插件信息,这样便于插件归类,同时有助于其他人更好的理解和使用插件。

注意: 如果你希望其他 WordPress 用户可以搜索到你的插件,那要确保插件的描述信息中包含你希望用户搜索的关键词。不要将"WordPress"缩写成"WP",因为人们通常不会用"wp plugins"做关键字进行搜索。要帮助搜索引擎更好的搜索你的插件,那你需要有一个很好的描述,明确的目的和准确的用法。

发布你的插件[ | ]

发布插件有几种方式。

提交到 wp-plugins.net 和 wp-plugins.org
Submissions to these two websites (http://www.wp-plugins.net and http://www.wp-plugins.org) are monitored by feeds and other WordPress websites which make announcements about WordPress activities. They may make a mention on their site if they see a new posting. Many WordPress users start looking for plugins at these two sites.
Submit to WordPress Activities and Announcement Sites
While these sites often monitor other WordPress sites for new plugins, consider submitting information about your new plugin directly to them. They include:
WordPress Forum Plugins and Hacks
The WordPress Forum Plugins and Hacks section is a good place to announce your plugin. Provide a link and a good explanation of the plugin's purpose and usage. Search engines scan the WordPress Forum frequently and if you want your plugin to get noticed, include the words that will help people find your plugin when they search, either within the Forum or with search engines.

插件文件结构[ | ]

一个WordPress 插件文件具有如下的文件结构:

<?php
/*
插件名称:Plugin Name: Name_Of_The_Plugin
下载地址:Plugin URI: URI_Of_Page_Describing_Plugin_and_Updates
插件描述:Description: A_Brief_Description_Of_The_Plugin
插件版本:Version: The_Plugin's_Version_Number
插件作者:Author: Name_Of_The_Plugin_Author
作者地址:Author URI: URI_Of_The_Plugin_Author
*/

你可能希望添加一个GPL模板,更直接地说明此插件使用同 WordPress 相同的授权许可协议。

/*  Copyright 2006  PLUGIN_AUTHOR_NAME  (email : PLUGIN AUTHOR 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

对于你的插件应该采用何种授权,你应该仔细衡量。这个问题还不够明晰,但尽量还是服从 WordPress 社区的讨论意见。 大多数人的意见是插件应该在 GPL 或者 compatible with the GPL 协议下发布,但是这并非是书写和发布插件的强制性的法律规定。

Regardless, these two sections can then be followed by the function definitions and the actual plugin code.

如果插件由超过一个文件构成,上述注释信息必须放置到每一个 wp-content/ 目录下的 .php 文件的开头部分。这个文件通常有一个 "main" 函数,而且通过 includes or requires 包含其他该插件需要的文件。

Plugin 元数据(Metadata)[ | ]

最近 WordPress 的核心开发者呼吁要通过 http://wp-plugins.org 发布各插件的作者们将他们插件的元数据(metadata)包含在 readme.txt 文件中。下面是个例子,来自Staticize Reloaded 插件:


==== Staticize Reloaded ====

Tags: caching, performance
Contributors: matt, billzeller 

Staticize Reloaded is a plugin to make your site faster by caching the output of some WordPress pages.

"Contributors" 一栏填写维护人(来自 WordPress 支持论坛,或其他什么地方)。Attribution 一栏填写贡献者名单,比如谁帮你测试了插件。如果你的插件源自 WordPress 支持论坛某个人的请求(或其它什么地方), 将倡议者作为插件源头罗列于此是个不错的注意。

"Tags" 一栏填写插件关键信息。理想的标签(tags)应该使用人们搜索插件时最常用到的词汇;但是需要提醒你的是目前还没有一种仅仅通过标签来搜索你的插件的办法。

你也可以在插件元数据中包含截屏,这里是一个例子, http://svn.wp-plugins.org/staticize-reloaded/trunk/ 下的 screenshot-1.gif 文件。截屏文件的名字最好采用 screenshot-#.(png|jpg|jpeg|gif),然后在 readme 文件中的 Screenshots 一节中使用一个带编号的列表文件来准确表述截屏信息。

这些文件对于你部署插件十分有益,虽然WordPress 并不会使用它。目前来说只有在你发布插件到 http://wp-plugins.org 的时候才会用到这些。

插件 API[ | ]

WordPress 通过Plugin API 定义了一些钩子 ('hooks') ,用来让你的插件钩入 ('hook into')。这些钩子就是你的插件同 WordPress 交互的接口。

有两种类型的钩子:

过滤式钩子(Filter Hooks):

过滤式钩子会添加一些额外的可卸载的文本过滤函数,它作用于特定数据(通常是文本)。这些开启的插件会在系统运作中动态修改数据内容。(为便于理解,下面保留原文。英文的特殊文法似乎更便于理解。)

Filter Hooks
Filter Hooks enable the addition and removal of text-formatting filter-functions which act upon specified data (usually text). These enable plugins to modify content or text on-the-fly.
主动式钩子(Action Hooks):

主动式钩子会添加一些额外的可卸载的函数,这些函数在触发 WordPress 核心事件时执行。这些插件用在事件发生时执行某些动作。

Action Hooks
Action Hooks enable the addition and removal of functions whose execution will be triggered by a core WordPress event. These enable plugins to execute functions each time the specified event occurs.

基于钩子的用途,插件函数可以被分为两类:

过滤器(Filters)
过滤器函数是通过 WordPress 过滤式钩子来修改文本或内容数据。
主动动作(Actions)
主动动作函数用来处理特定事件,这些事件由WordPress 核心事件触发。

要完整了解 API 信息以及各种钩子,参考 Plugin API

避免Function 名字冲突[ | ]

很有可能某人创建 plugin 时同你的 plugin 函数同名!

问题根源在于 PHP 不允许多个函数同名。如果两个插件函数名称相同,或者插件同 WordPress 函数名字相同,blog 会中止函数。有两个办法解决这个问题。

第一个办法是在你的插件中每个函数名前添加一个唯一的前缀。如果你的名字叫 John Q 。习惯上,你可以声明你的函数为 function jqp_output() {...},如此等等。虽然还是存在某人使用相同前缀定义相同函数的可能性,但是几率极底。

第二个办法,可能更简易,把你的插件函数封装成类,通过静态方法调用来实现。这听起来比较复杂,其实不然。

思考下面这个类,它来自文章 Plugin APIAdding Actions小节中提供的例子。

class emailer {
   function send($post_ID)  {
     $friends = 'bob@example.org,susie@example.org';
     mail($friends,"sally's blog updated",'I just put 
something on my blog: http://blog.example.com');
     return $post_ID;
   }
 }
 
 add_action('publish_post', array('emailer', 'send'));

这个类叫 emailer,拥有一个方法 send 实现具体的插件功能。

类的定义外面的 add_action() 函数用来实现当一个帖子发布时,使 WordPress 调用 send方法。第二个参数使用的 array 告诉插件系统调用的静态方法是类 'emailer' 的 'send'。

函数 send 在类声明时保护在全局名字空间之外。直接调用 send() 是不可能的,而且其他的 send函数也不会同它冲突。如果你想调用 send(),那你需要一个作用范围限定符号(scope resolution operator),就像这个:emailer->send()

你也可以将插件钩子传递到一个对象实例上。下面就是一个使用上面定义的类来完成的例子:

$mailer = new emailer();
add_action('publish_post', array(&$mailer, 'send'));

只要帖子状态被置为 "Plublish",WordPress 将执行 $mailer 对象的 send() 方法。通过这个办法,类可以使用 $this-> 引用,然而要象上面一样静态的调用类方法还是需要使用作用范围限定符。(翻译的不确切,保留下面原文) Whenever a post's status is set to "Publish", WordPress will execute the send() method of the $mailer object. Used this way, the class can make use of $this-> references, whereas the static calling method above can only call the class methods statically using the scope resolution operator.

上面的例子很简单,类还可以完成更复杂的工作。了解更多信息,参考PHP documentation on classes.

==将插件数据存入数据库==


你可能需要在脚本运行期间保存变量。WordPress 允许你定义,更新,提取任何变量,这些变量作为 'option' 保存在它自己的 database 中。通过将 option 数据储存在database, 并且通过你的插件在面板中创建一个管理页,你可以让使用者定制插件的参数而无需修改源代码。The functions that enable you to manipulate these options are listed below.

你的插件应该使用数据库中一个全新的表。更多信息参考Creating Tables with Plugins 页面。

注意: 作为你的函数专用的参数,你的 option 名字要避免同 WordPress 在用的名字冲突。一个好办法是加上唯一性前缀,比如用程序的缩写名或你名字的大写开头作为前缀。

Adding 选项[ | ]

add_option($name, $value, $description, $autoload);
$name
必需 (string). 添加的 option 名字.
$value
可选, 缺省为 " (string). 此变量用来保存有别于你的函数名字唯一性前缀的值。The variable to be stored against your function's name key.
$description
可选, 缺省为 " (string). 对 option 的描述.
$autoload
可选, 缺省为 'yes' (枚举类型: 'yes' or 'no'). 设为 'yes' 时,会通过 get_alloptions 函数自动获取设置。

如果某个指定的 option 已经存在了,这个已经存在的选项的值不会被修改,database 中也不会。add_option()只是 添加 options,它不会置换它。

$value 可以是字符串 string, 数组 array, 或对象 object. WordPress 会在存储它之前自动的将 $value 值串行化(serialize),在呼出它时又会反串行化(unserialize )。如果你的插件要保存多个option,传递一个选项数组 (array of option )给 add_option() 进行处理将更为高效,在数据库里会被保存为一条单行记录。

注意如果 option 不存在的话使用 update_option() 函数,将会调用 add_option() 。这种用法仅限于你希望设置附加的$description$autoload参数,用来取代 缺省设置。

Retrieving 选项[ | ]

get_option($option);
$option
必需 (string). 你想要取出其值的 option 名字。

此函数取出数据库中该选项的值。如果该选项原本为一个数组或是对象,WordPress会在该数组/对象返回前自动反串行化。

Updating 选项[ | ]

update_option($option_name, $newvalue);
$option_name
必需 (string). 要修改的选项名称.
$newvalue
必需(string). 你想对该选项修改的值.

$value 可以是字符串 string, 数组 array, 或对象 object. WordPress 会在存储它之前自动的将 $value 值串行化(serialize),在呼出它时又会反串行化(unserialize )。如果你的插件要保存多个option,传递一个选项数组 (array of option )给 add_option() 进行处理将更为高效,在数据库里会被保存为一条单行记录。

注意如果 option 不存在的话使用 update_option() 函数,将会调用 add_option() 。这种用法仅限于你希望设置附加的$description$autoload参数,用来取代 缺省设置。

用户接口[ | ]

使功能在模板(Templates)中可用[ | ]

缺省情况下,所有 plugin 函数都是全程范围(global scope)可见的,它可以被模板Templates 随便使用。

插件中声明的类和对象也同样对模板是有效的。然而,包含在类中的函数还是需要一个作用范围限定符(::)来进行解析。但这为最终用户提供了一个函数封装从而简化全程范围(global scope)调用,所以说也是值得的。

增加管理面板[ | ]

添加一个新的管理面板,你就可以让用户自定义插件参数而毋需修改插件源码。简单的创建一个 HTML 表单就可以获取和设置你的插件变量 options.

为 WordPress 管理界面添加子面板,一般来说会放到 Options 面板下。在 Options 菜单下添加新面板一般来说有几条基本指令。参考 Adding Administration Menus,获取完整信息。

在你的插件源代码的某处,添加如下函数:

function your_function_name_here() {
    if (function_exists('add_options_page')) {
add_options_page('subpaneltitle', 'submenuitemname', minuserlevel, basename(__FILE__), 'my_options_subpanel');
    }
 }

在添加全部钩子的插件底部,添加:

add_action('admin_menu', 'your_function_name_here');

这会添加一个新的条目 'subpaneltitle' 到 Options 菜单。 'subpaneltitle' 菜单激活后面板显示的内容是由函数 my_options_subpanel() 生成,这个函数需要由你在插件里书写。 my_options_subpanel() 函数格式一般如下:

function my_options_subpanel() {
  if (isset($_POST['info_update'])) {
    ?><div class="updated"><p><strong><?php 
_e('Process completed fields in this if-block, 
and then print warnings, errors or success information.',
  'Localization name')
    ?></strong></p></div><?php
	} ?>
<div class=wrap>
  <form method="post">
    <h2>Manager window name</h2>
     <fieldset name="set1">
	<legend><?php _e('Options set 1', 'Localization name') ?></legend>
	Put some form input areas here.
     </fieldset>
     <fieldset name="set2">
	<legend><?php _e('Options set 2', 'Localization name') ?></legend>
	Put some more form input areas here.
     </fieldset>
<div class="submit">
  <input type="submit" name="info_update" value="<?php
    _e('Update options', 'Localization name')
	?> »" /></div>
  </form>
 </div><?php
}

就这么简单。

有时,你的插件还需要知道它是否已经作为一个管理面板被载入。这个可以通过检查函数 is_plugin_page() 的布尔返回值来确定。它唯一的用途就是往管理界面上添加内容。现在,用上面基于方法的函数会处理得更好(见上面例子中的 my_options_subpanel())。

插件国际化[ | ]

一旦你的插件编程工作已结束,另一个值得考虑的方面就是怎样将你的插件国际化(当然,这是建立在你想把你的作品发布给公众的前提上)。“国际化”就是一个建设你的软件使之能被本地化的过程;而“本地化”就是将你软件显示文本翻译成各种语言的过程。WordPress 已被来自全世界各个地方的爱好者使用,所以它以将国际化和本地化功能融入其结构,包括插件程序的本地化功能。想了解更多的 GNU gettext 本地化的背景知识,请参照翻译 WordPress

极力推荐你将你的插件进行国际化,这样来自五湖四海的用户名都可以本地化它。而且这整个过程也是十分直接明了:

  • 先给你的插件选一个翻译用的“文本域”名称。这一般同你的插件文件名称相同,当然不包括.php后缀名,而且必须是具有唯一性,至少保证不要同使用者已安装的其他插件同名。
  • 不管任何时候你的插件要使用文字来显示给网页读者(也即“信息文”),都尽量将它们嵌入在如下两个 WordPress gettext 函数程序段的任一之中。记住,不同于 WordPress 核心代码,在你插件里的国际化函数里你应该使用第二个参数来传递你自选的文本域。而在 WordPress 核心代码,这个参数默认为空。

__() 用来将 message 作为一个参数传递给另外一个函数。 _e() 用来直接把 message 写到页面上。

__($message, $domain) : 用本地化的语言为 $domain 翻译 $message 。输出的字符串可以继续被其他函数调用。
_e($message, $domain) :用本地化的语言为 $domain 翻译 $message ,然后显示到用户的屏幕。如果你的文字将直接显示给读者,就可以使用该函数。
  • 为你的插件创建一个 POT 文件 (这个一个列有所有文字条的翻译条目文件),随你的插件一起发布。插件用户将需要生成一个翻译本地化好的 MO 文件,然后把它放在你插件的同一文件夹里。并且这个 mo 文件的取名也有讲究,应该是象 domain-ll_CC.mo,这里 ll_CC 就是本地国家和语言代码(如 zh_CN)。参照 翻译 WordPress 上更多关于 POT 文件、MO 文件及本地化的信息。
  • 在你插件里加入一个 load_plugin_textdomain 子程序用以调用你的插件翻译。这个子程序一定需要在你 gettext 函数的前面,但最好是越晚越好(因为一些多语言插件在调用时会改变一些地域设置)。一个可行的方法就是在你所有插件的子程序前面增加一个初始子程序。例如,假设你的文本域叫 "fabfunc",则:


$fabfunc_domain = 'fabfunc';
$fabfunc_is_setup = 0;

function fabfunc_setup()
{
   global $fabfunc_domain, $fabfunc_is_setup;

   if($fabfunc_is_setup) {
      return;
   } 

   load_plugin_textdomain($fabfunc_domain, 'wp-content/plugins');
}

假如你的插件是放在它自己的目录里,则你应该把它的目录名加到 load_plugin_textdomain 函数的第二个参数里。


日期翻译[ | ]

翻译你的日期输出可以使用函数 wp-function mysql2date. 在文件 functions.php 中有函数原型.它将月份、日期以及时间简写翻译成你的本地语言。

Coding Best Practices[ | ]

这里有一些小帖士帮助你加深对书写你自己插件的理解;列举一些应极力避免的缺陷以及如何回避它。

  • 不要将系统表前缀 $table_prefix (通常是 "wp_") 写死在你的plugins 代码中。确保任何时候需要引用这些数据时都通过 $table_prefix 变量来实现。

PHP 小贴士[ | ]

自提交Scripts[ | ]

创建一个显示表单同时处理自身的脚本,该脚本完成这样一个工作,检查是否有变量,如果有且变量有效,则调用处理函数。

To make a form-displaying script process itself, check for form variables and, if they're available, call the processing function.

检查是否有表单动作 (form action) 触发了一个页面,一个办法就是使用表单的隐藏域(举例来说,比如命名为 'submitted'的域). 在你的 PHP 脚本第一行,可以使用 isset($foo)(如果变量已经被初始化则返回 TRUE ),也可以使用is(empty($foo))(基本上它也干一样的事) 来检测它(参考 PHP 文档了解其中区别)。(不大通畅,下面保留原文)

To check if a page is being requested as a result of a form action, one way is to use a hidden field in the form (named 'submitted', for example). Then in the first lines of your PHP script, use either isset($foo), which returns TRUE if a variable has been initialized, or is(empty($foo)), which is almost the same thing (see PHP documentation for the distinction).

含隐藏元素的表单:

<?php
echo '
<form name="example" action="' . $_SERVER[PHP_SELF] . '" method="post">
Text: <input type="text" name="text" /><br />
<input type="hidden" name="submitted" />
<input type="submit" value="Go!" />
<form>
'; ?>

检查你的表单的隐藏元素:

isset($_POST['submitted']) /* For method=POST */
isset($_GET['submitted']) /* For method=GET */
isset($_REQUEST['submitted']) /* For either type of form */

数据库小贴士[ | ]

读-开销很小,写-开销很大[ | ]

数据库在提取数据方面表现异乎寻常的好,象闪电一样快(一般来说)。但要向数据库写入数据嘛,处理就要复杂些,计算开销也要大的多。所以,尽量减少数据库的写操作。所有东西先在代码里准备好,只保留必要的写操作。

仅仅选择你需要的[ | ]

尽管数据库读操作非常快,但你还是要尽量减少提取数据的动作。如果你要统计表的记录数,千万不要使用SELECT * FROM,那会把所有数据都取出来,浪费内存。 同样的,如果你仅仅是要在插件中提取 post_id 和 post_author 信息,那就只对那几个字段进行 SELECT操作,这样会降低数据库开销。

记住:同一时间内可能会有上百个进程同时访问数据库。而数据库和服务器只有有限资源分配给所有这些进程。学习一下如何优化数据库操作可以保证你的插件不会成为资源杀手。

回顾[ | ]

  1. General
    1. use your initials to ensure your functions don't clash with others
    2. if ( !function_exists('dys_function_al') ) {....}
  2. Adding Options
    1. add_options_page($page_title, $menu_title, $access_level, $file)
    2. add_option() and delete_option()
  3. Internationalization
    1. load_plugin_textdomain($domain) see Ryan Boren's Localizing Plugins and Themes
    2. $foo = __('Some String', $domain);
    3. _e('Some String', $domain);
  4. Pluggable Functions: (Version 1.5.1+) included in /wp-includes/pluggable-functions.php
    1. get_currentuserinfo()
    2. get_userdata($userid)
    3. get_userdatabylogin($user_login)
    4. wp_mail($to, $subject, $message, $headers = )
    5. wp_login($username, $password, $already_md5 = false)
    6. auth_redirect()
    7. wp_redirect($location)
    8. wp_setcookie($username, $password, $already_md5 = false, $home = , $siteurl = )
    9. wp_clearcookie()
    10. wp_notify_postauthor($comment_id, $comment_type=)
    11. wp_notify_moderator($comment_id)

扩展资源[ | ]

Template:Copyedit

Advertisement