构造 WordPress 插件管理员面板
任何需要用户输入(诸如改变一个变量)的插件,都需要某种管理面板。建立一个管理面板,并不是那么难的,所以,一个插件作者决定不创建管理面板,而是让用户自己去修改PHP 代码的行为让我很是苦恼。让一个用户去修改代码通常来说不是一个好主意。本文将深入探讨成功地为你的插件创建管理面板,到底需要些什么。
存储变量的地方
当你想要给你的插件创建一个管理面板的时候,你首先会碰到的问题之一就是到底在哪里存储变量值。非常幸运,WordPress 通过options 使得这件事变得非常容易。我将会在后续的系列文章中解释options 和数据库存储。现在来说,所有你需要做的事情就是点点你的头,然后跟着我的指导,把你自己的管理变量存储到WordPress 数据库中。
通常我考虑到options 的时候做的第一件事情就是,给我的管理options 取一个独特的名字。我把这个名字以成员变量的形式存储在我的类中。在这个Devlounge Plugin Series 插件的例子中,我把这个变量声明添加到DevloungePluginSerieDevloungePluginSeries
类中。
命名你的管理Options
class DevloungePluginSeries { var $adminOptionsName = "DevloungePluginSeriesAdminOptions"; function DevloungePluginSeries() { //constructor } }
第2 行显示了我存储我的成员变量的地方。我将我的变量命名为adminOptionsName并且给予它一个很长而且独特的值DevloungePluginSeriesAdminOptions。
给你的管理Options设定缺省值
你需要一个地方来初始化你的管理选项,尤其是当一个用户第一次激活你的插件的时候。然而,你还必须包正这些options 在升级中是安全的,以防万一你决定将来添加更多的options。我使用的技巧是,提供一个专门的函数来调用你的管理options。
你的插件的需求可能不一样,但是绝大多数的管理面板不会难以置信地复杂,所以一个函数对你的管理options 来说,已经足够了。
下面这个函数是我插入到类DevloungePluginSeries 中的:
//Returns an array of admin options function getAdminOptions() { $devloungeAdminOptions = array('show_header' => 'true', 'add_content' => 'true', 'comment_author' => 'true', 'content' => ''); $devOptions = get_option($this->adminOptionsName); if (!empty($devOptions)) { foreach ($devOptions as $key => $option) $devloungeAdminOptions[$key] = $option; } update_option($this->adminOptionsName, $devloungeAdminOptions); return $devloungeAdminOptions; }
这个函数做的事情是:
- 给你的管理options 赋默认值(3-6 行)
- 尝试从数据库中找出以前存储过的值(第7 行)
- 如果options 曾经存储过,那么存储的值会覆盖默认值(8-11 行)
- options 被存储到WordPress 数据库中(第12 行)
- options 被返回供你使用(第13 行)
初始化管理Options
getAdminOptions 函数可以在任何时候调用来获得管理options。然而,当插件第一次安装的时候呢?应该有某个函数被调用也能获得管理options。我在DevloungePluginSeries 类中添加了这个函数:
function init() { $this->getAdminOptions(); }
短小简单。但是必须有一个action 来调用这个函数。
add_action('activate_devlounge-plugin-series/devlounge-plugin-series.php', array(&$dl_pluginSeries, 'init'));
这个action 有些复杂,但是很容易理清楚。下面是这个action 做的事情:
- 当一个插件被激活的时候你告诉它运行
- 你给它主要的插件PHP 文件,就是devlounge-plugin-series/devlounge-plugin-series.php。这当然是假设你把插件放到了wp-content/plugins /目录中。
- 你传递了一个引用给实例变量dl_pluginSeries 并且调用了init 函数。
所以,任何时候插件被激活,init 函数都会被调用。
管理面板怎样工作
在我深入到创建实际的管理面板的代码的时候,描述一下管理面板的行为是有好处的。这里有一些你设定你管理面板的步骤:
- 检查任何表单数据是否已经被提交。
- 如果表单数据存在,输出提醒。
- 显示管理面板Options。
在管理面板中,一个非常困扰你的问题可能是_e 的使用。_e 函数允许WordPress 搜索你文本的本地化版本。这将帮助WordPress 在将来翻译你的插件。这个函数的工作类似一个普通的echo,但是你传给它的是你的文本和一个标识变量(典型的是你的插件名称)。一个例子:
_e('Update Settings','DevloungePluginSeries');
这句代码和:
echo "Update Settings";
是相同的。
设置你的管理面板函数
我们想要做的第一件事情就是设定一个函数,来真正地打印出一个管理面板。函数名字叫做printAdminPage。下一段代码将要读入我们早先设定的options 并且检查是否所有的发布options 已经被提交。这一段的所有代码假设写在printAdminPage函数中。
//Prints out the admin page function printAdminPage() { $devOptions = $this->getAdminOptions(); if (isset($_POST['update_devloungePluginSeriesSettings'])) { if (isset($_POST['devloungeHeader'])) { $devOptions['show_header'] = $_POST['devloungeHeader']; } if (isset($_POST['devloungeAddContent'])) { $devOptions['add_content'] = $_POST['devloungeAddContent']; } if (isset($_POST['devloungeAuthor'])) { $devOptions['comment_author'] = $_POST['devloungeAuthor']; } if (isset($_POST['devloungeContent'])) { $devOptions['content'] = apply_filters('content_save_pre', $_POST['devloungeContent']); } update_option($this->adminOptionsName, $devOptions); ?> <div class="updated"><p><strong><?php _e("Settings Updated.", "DevloungePluginSeries");?></strong></p></div> <?php }
上面所有代码做的是装载options 并且测试是否表单的每个部分都已经被正确提交。if 语句并不是必须的,但是有的时候对于调试来说很有用。第一被测试的表单变量是update_devloungePluginSeriesSettings。这个变量被赋值给我们的“提交”按钮。
如果它没有被设定,那么说明这个表单没有被提交。
就像说好的一样,在第16 行,我使用了apply_filters 函数来格式化内容,以便存入数据库。
下一段代码将会显示一个HTML 表单,那是管理面板锁必须的。它有一些复杂,所以我会这里概括一下。所有的代码做的事情,就是显示表单元素和读入options。
<div class=wrap> <form method="post" action="<?php echo $_SERVER["REQUEST_URI"]; ?>"> <h2>Devlounge Plugin Series</h2> <h3>Content to Add to the End of a Post</h3> <textarea name="devloungeContent" style="width: 80%; height: 100px;"><?php _e(apply_filters ('format_to_edit',$devOptions['content']), 'DevloungePluginSeries') ?></textarea> <h3>Allow Comment Code in the Header?</h3> <p>Selecting "No" will disable the comment code inserted in the header.</p> <p><label for="devloungeHeader_yes"><input type="radio" id="devloungeHeader_yes" name="devloungeHeader" value="true" <?php if ($devOptions['show_header'] == "true") { _e('checked="checked"', "DevloungePluginSeries"); }?> /> Yes</label> <label for="devloungeHeader_no"><input type="radio" id="devloungeHeader_no" name="devloungeHeader" value="false" <?php if ($devOptions['show_header'] == "false") { _e('checked="checked"', "DevloungePluginSeries"); }?>/> No</label></p> <h3>Allow Content Added to the End of a Post?</h3> <p>Selecting "No" will disable the content from being added into the end of a post.</p> <p><label for="devloungeAddContent_yes"><input type="radio" id="devloungeAddContent_yes" name="devloungeAddContent" value="true" <?php if ($devOptions['add_content'] == "true") { _e('checked="checked"', "DevloungePluginSeries"); }?> /> Yes</label> <label for="devloungeAddContent_no"><input type="radio" id="devloungeAddContent_no" name="devloungeAddContent" value="false" <?php if ($devOptions['add_content'] == "false") { _e('checked="checked"', "DevloungePluginSeries"); }?>/> No</label></p> <h3>Allow Comment Authors to be Uppercase?</h3> <p>Selecting "No" will leave the comment authors alone.</p> <p><label for="devloungeAuthor_yes"><input type="radio" id="devloungeAuthor_yes" name="devloungeAuthor" value="true" <?php if ($devOptions['comment_author'] == "true") { _e('checked="checked"', "DevloungePluginSeries"); }?> /> Yes</label> <label for="devloungeAuthor_no"><input type="radio" id="devloungeAuthor_no" name="devloungeAuthor" value="false" <?php if ($devOptions['comment_author'] == "false") { _e('checked="checked"', "DevloungePluginSeries"); }?>/> No</label></p> <div class="submit"> <input type="submit" name="update_devloungePluginSeriesSettings" value="<?php _e('Update Settings', 'DevloungePluginSeries') ?>" /></div> </form> </div> <?php }//End function printAdminPage()
需要在上述代码中观察的是options 的引用,和HTML 和PHP 是怎样集成的。
设置管理面板Action现在,printAdminPage 函数已经添加了,我们需要通过一个action 调用它。首先函数必须被设定在正好在action 的上面,在类的范围之外。
//Initialize the admin panel if (!function_exists("DevloungePluginSeries_ap")) { function DevloungePluginSeries_ap() { global $dl_pluginSeries; if (!isset($dl_pluginSeries)) { return; } if (function_exists('add_options_page')) { add_options_page('Devlounge Plugin Series', 'Devlounge Plugin Series', 9, basename(__FILE__), array(&$dl_pluginSeries, 'printAdminPage')); } } }
上面的代码做了下面这些事:
- 创建了一个叫做DevloungePluginSeries_ap 的函数。
- 测试变量dl_pluginSeries 是否存在(4-7 行)。这个变量是我们的类的引用。
- 一个叫做“Devlounge Plugin Series”的管理页面被初始化了,并且,我们的printAdminPage 函数被引用了。(8-10 行)。
add_options_page 函数的调用方法为:
add_options_page(page_title,menu_title,access_level/capability,file,[function]);
访问级别(在这个例子中是9)在WordPress Codex 的Users Levels page 页面有详细的描述。
必须设置一个action 来调用DevloungePluginSeries_ap 函数:
add_action('admin_menu', 'DevloungePluginSeries_ap');