定制插件管理菜单

1条评论

定制插件管理菜单

简介

目前市面上有很多插件能够让用户自行对插件进行设置。插件开发人员可以通过几种方法来实现插件的这一功能。其中一个方法就是,允许用户编辑插件的PHP文件,但很多用户并不适应这种方式(这是比较礼貌的说法)。因此,插件开发人员可以为用户创建一个插件管理界面,让用户能够以更自然更熟悉的方式设置插件。

本文首先假设读者对编写插件的基本知识以及动作和过滤器的插件API有一定了解,在此基础上向读者说明怎样在WordPress中为插件添加自定义管理界面。

Hook钩子

要添加管理菜单,首先要进行以下三项操作:

1. 创建一个函数,函数中包含创建菜单的代码

2. 用“admin_menu”动作钩子记录上述函数

3. 为(点击菜单项后需要显示的)页面编写HTML代码

将代码存储在主插件php文件或独立的php包含文件中。

插件开发新手经常会忽略第二个操作。我们不能直接调用菜单代码,必须要将代码放入某个函数,然后再记录这个函数。

下面是一个关于以上三项操作的简单实例:

<?php
add_action('admin_menu', 'my_plugin_menu');

function my_plugin_menu() {
  add_options_page('My Plugin Options', 'My Plugin', 8, 'your-unique-identifier', 'my_plugin_options');
}

function my_plugin_options() {
  echo '<div class="wrap">';
  echo '<p>Here is where the form would go if I actually had options.</p>';
  echo '</div>';
}
?>

这个例子用my_plugin_menu函数为管理菜单添加新条目(通过add_options_page函数,下文中有介绍)。然后调用WordPress的钩子来“登记”这个函数。如果不调用钩子,激活插件时WordPress会抛出“函数未定义”PHP错误。最后创建出一个函数,函数中含有点击菜单选项后将要显示的页面(以及需要操作的PHP代码)。

下面会介绍到后两步的实际操作过程。不要忘记在函数中围绕这两步操作,然后调用admin_menu钩子开始操作。

菜单和子菜单

创建自定义管理界面前,我们需要断定该管理界面属于WordPress管理菜单系统的哪个部分。大多数插件将自己的管理界面作为子菜单项,放在WordPress已有的顶级菜单下。下面分别介绍各个顶级菜单:

设置

该菜单显示只有管理员可见的插件设置(参见创建设置/选项页面

插件

该菜单显示插件管理的相关控件,而非插件本身的配置设置

外观

该菜单显示用以管理主题/样式文件、工具栏等内容的相关控件

写日志

该菜单显示用以编辑日志/页面的工具

用户

该菜单显示用于管理用户的控件

如果我们开发的插件对WordPress来说是个新概念,完全异于其它插件,并且需要很多页面来实现这个插件,那么我们可以为插件创建一个顶级菜单。不过之前一定要确定,我们的确需要多个相关页面来实现插件的功能,并且这功能是WordPress本身不具备的。类似插件可能包括图库管理插件、数据库管理插件以及会议管理插件等。

在自定义管理菜单插件的帮助下,用户可以自己决定插件是否出现在顶级菜单选项中——插件开发人员需要向用户表明自己所开发的插件可以进行此类设置,尤其是那些决定创建顶级菜单项的开发人员。

管理菜单相关函数

决定好在什么位置添加管理菜单/子菜单后,接着就应该让WordPress知道新页面的存在了。我们会在'admin_menu' 动作函数(见本段最后部分的示例)中完成通知过程。

顶级菜单

出于某些原因,我们可能会决定让自己开发的插件使用一个新的顶级菜单。首先我们要创建菜单,否则插件会自动转入子菜单中。

我们需要用add_menu_page函数来添加新的顶级菜单:

add_menu_page(page_title, menu_title, access_level/capability, file, [function], [icon_url]);

参数值:

page_title

激活菜单后,出现在页面上的HTML页面标题

menu_title

(显示在屏幕上的)菜单名

access_level/capability

(显示并使用该菜单页所需要的)最低用户级别或权限

file

PHP文件,处理菜单页所显示的内容

function

为菜单页显示页面内容的函数

从技术层面上来说,function参数是可选的,但如果不采用该参数,WordPress会认为包含PHP文件就可以生成管理页面,于是不再调用函数。大多数插件开发人员都会将生成页面的代码放在主插件文件的函数中。

icon_url

该参数仅用于WordPress 2.7。参数在菜单中加入一个自定义图标。

子菜单

对顶级菜单定义完毕或决定使用某个已有的WordPress顶级菜单后,我们用 add_submenu_page函数来定义子菜单页面。添加页面时,请按照自己希望的页面显示顺序进行添加。

add_submenu_page(parent, page_title, menu_title, access_level/capability, file, [function]);

参数值:

parent

核心WordPress管理文件的文件名,该文件为我们提供所有顶级菜单,我们可以在顶级菜单中加入我们的子菜单,也可以在自定义顶级菜单的子菜单下加入插件文件。

常用示例:

1. 用于编辑日志:add_submenu_page('post-new.php',...)

2. 用于管理:add_submenu_page('edit.php',...)

3. 用于设计:add_submenu_page('themes.php',...)

4. 用于评论:add_submenu_page('edit-comments.php',...)

5. 用于设置:add_submenu_page('options-general.php',...)

6. 用于插件:add_submenu_page('plugins.php',...)

7.用于用户设置:add_submenu_page('users.php',...)

page_title

激活子菜单后,出现在页面上的HTML页面标题

menu_title

(显示在屏幕上的)子菜单名

access_level/capability

(显示并使用该子菜单页所需要的)最低用户级别或权限

file

对现有的WordPress菜单来说,file参数值为:处理菜单页所显示的内容的PHP文件。对自定义的顶级菜单的子菜单来说,file参数值为:该子菜单页的唯一标识符。

若某插件创建出属于自己的顶级菜单,正常情况下其首个子菜单的链接标题与顶级菜单相同。因此我们设置首个子菜单链接标题时只需要复制顶级菜单的链接。parent参数和file参数首次被赋予相同值时,我们可以通过调用add_submenu_page函数来避免复制链接标题。

function

为菜单页显示页面内容的函数

从技术层面上来说,在add_menu_page函数中,function参数是可选的。但如果不采用该参数,WordPress会认为包含PHP文件就可以生成管理页面,于是不再调用函数。大多数插件开发人员都会将生成页面的代码放在主插件文件的函数中。

下面的例子向我们展示了在子菜单页标题异于顶级菜单页时,如何插入顶级菜单页和子菜单页。在这个例子中,用以显示第一个子菜单页的函数是'my_magic_function':

add_menu_page('Page title', 'Top-level menu title', 8, __FILE__, 'my_magic_function');
add_submenu_page(__FILE__, 'Page title', 'Sub-menu title', 8, __FILE__, 'my_magic_function');

大多数子菜单都会进入WordPress的设置、管理、外观菜单,因此WordPress专门给出三个包装器函数,简化这些菜单页添加子菜单的过程:

用于设置”顶级菜单

add_options_page(page_title, menu_title, access_level/capability, file, [function]);  

用于“管理”菜单

add_management_page(page_title, menu_title, access_level/capability, file, [function]);  

用于“外观”菜单

add_theme_page( page_title, menu_title, access_level/capability, file, [function]);  

插入页面

下面是一个能将新菜单项插入不同位置的WordPress插件示例:

<?php
/*
Plugin Name: Menu Test
Plugin URI: http://wordpress.org
Description: Menu Test
Author: Nobody
Author URI: http://example.com
*/

// Hook for adding admin menus
add_action('admin_menu', 'mt_add_pages');

// action function for above hook
function mt_add_pages() {
    // Add a new submenu under Options:
    add_options_page('Test Options', 'Test Options', 8, 'testoptions', 'mt_options_page');

    // Add a new submenu under Manage:
    add_management_page('Test Manage', 'Test Manage', 8, 'testmanage', 'mt_manage_page');

    // Add a new top-level menu (ill-advised):
    add_menu_page('Test Toplevel', 'Test Toplevel', 8, __FILE__, 'mt_toplevel_page');

    // Add a submenu to the custom top-level menu:
    add_submenu_page(__FILE__, 'Test Sublevel', 'Test Sublevel', 8, 'sub-page', 'mt_sublevel_page');

    // Add a second submenu to the custom top-level menu:
    add_submenu_page(__FILE__, 'Test Sublevel 2', 'Test Sublevel 2', 8, 'sub-page2', 'mt_sublevel_page2');
}

// mt_options_page() displays the page content for the Test Options submenu
function mt_options_page() {
    echo "<h2>Test Options</h2>";
}

// mt_manage_page() displays the page content for the Test Manage submenu
function mt_manage_page() {
    echo "<h2>Test Manage</h2>";
}

// mt_toplevel_page() displays the page content for the custom Test Toplevel menu
function mt_toplevel_page() {
    echo "<h2>Test Toplevel</h2>";
}

// mt_sublevel_page() displays the page content for the first submenu
// of the custom Test Toplevel menu
function mt_sublevel_page() {
    echo "<h2>Test Sublevel</h2>";
}

// mt_sublevel_page2() displays the page content for the second submenu
// of the custom Test Toplevel menu
function mt_sublevel_page2() {
    echo "<h2>Test Sublevel 2</h2>";
}

?>

菜单页面样例

上面的例子中含有几个虚构函数,例如mt_options_page等,这些虚构函数可以作为实际页面内容的占位符。我们要将这些占位符转换为真正的菜单页面。首先假设插件有一个名为mt_favorite_food的选项,然后让网站主人在插件的设置页面中输入自己最喜欢的食物。mt_options_page函数需要在界面上输入一张数据输入表才能激活mt_favorite_food并处理输入的数据。下面有一个函数可以帮助mt_options_page完成以上任务:

// mt_options_page() displays the page content for the Test Options submenu
function mt_options_page() {

    // variables for the field and option names 
    $opt_name = 'mt_favorite_food';
    $hidden_field_name = 'mt_submit_hidden';
    $data_field_name = 'mt_favorite_food';

    // Read in existing option value from database
    $opt_val = get_option( $opt_name );

    // See if the user has posted us some information
    // If they did, this hidden field will be set to 'Y'
    if( $_POST[ $hidden_field_name ] == 'Y' ) {
        // Read their posted value
        $opt_val = $_POST[ $data_field_name ];

        // Save the posted value in the database
        update_option( $opt_name, $opt_val );

        // Put an options updated message on the screen

?>
<div class="updated"><p><strong><?php _e('Options saved.', 'mt_trans_domain' ); ?></strong></p></div>
<?php

    }

    // Now display the options editing screen

    echo '<div class="wrap">';

    // header

    echo "<h2>" . __( 'Menu Test Plugin Options', 'mt_trans_domain' ) . "</h2>";

    // options form
    
    ?>

<form name="form1" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
<input type="hidden" name="<?php echo $hidden_field_name; ?>" value="Y">

<p><?php _e("Favorite Color:", 'mt_trans_domain' ); ?> 
<input type="text" name="<?php echo $data_field_name; ?>" value="<?php echo $opt_val; ?>" size="20">
</p><hr />

<p class="submit">
<input type="submit" name="Submit" value="<?php _e('Update Options', 'mt_trans_domain' ) ?>" />
</p>

</form>
</div>

<?php
 

注意事项:

  • WordPress管理函数会对用户进行验证,因此我们无需担心函数的验证功能
  • 上面的函数样例已经国际化——详细信息参见插件开发的“插件国际化”部分
  • 函数会在数据被输入数据输入表前,对数据进行处理,因此出现在数据输入表中的数据都是经过处理的新值(而不是数据库中的值)。
  • 即使第一次进行操作也不必担心,如果某个设置选择不存在,WordPress update_option函数能够自动在数据库中加入选项。
  • 每次转入管理页面时WordPress都会解析以上管理菜单定制过程。因此如果我们编写的插件没有设置页面,打算稍后添加时,可以根据本文介绍的定制过程进行操作、修改,直到完全满意。换句话说,我们创建的管理菜单不是“永久性”的,所有菜单都会被即时解析,我们可以随时添加或除去某个菜单项,重新加载页面后,我们所做的改动会立刻显示在页面上。
#1
"> " value="Y"> <?php _e("Favorite Color:", 'mt_trans_domain' ); ?> " value="<?php echo $opt_val; ?>" size="20"> " /> <?php 有点小bug,主要在最后两行,标签没有开始的,只写了闭合,<?php 后面应该是 <?php }