Codex

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

zh-cn:Adding Administration Menus

概述

通常情况下,插件和主题的作者都需要为其提供一个配置界面,以方便用户去自定义它们。将这个配置界面展示给用户的最好方式,就是在后台管理员界面的配置菜单中添加一个选项,然后当用户点击这个选项的时候再去打开它。这篇文章将会告诉你如何去实现这样的事情。

注意:在继续阅读之前,你应当对如何写一个插件,以及Actions和Filters的插件API函数有一定的了解。

参考函数

General Functions

Menu Pages

SubMenu Pages

WordPress Administration Menus

一切皆需钩子

想要向管理员界面的配置菜单中添加一个选项,你必须要完成三件事:

  1. 定义一个函数,使其能够创建菜单选项,并调出配置界面
  2. 将这个函数挂载到名为admin_menu的Action钩子上。(如果你需要创建的是与网络相关的菜单选项,那么就需要将该函数挂载到network_admin_menu钩子上)。
  3. 编写当用户点击菜单选项时,需要显示出的配置页面的内容。

第二步是新手们往往会忽略掉的步骤。必须要记住:光写出代码是不够的,你还必须要把这段代码放到一个函数中,并且把这个函数挂载到相应的钩子上,它才能发挥相应的作用。

以下是包含这三个步骤的简单示例。这个插件将会在设置菜单的主选项下创建一个子选项,当该选项被点击时,将会显示出一个非常简单的页面。

注意:这些代码应当被写到PHP主文件中,或是一个单独的PHP文件中。

<?php
/** 第1步:定义添加菜单选项的函数 */
function my_plugin_menu() {
     add_options_page( 'My Plugin Options', 'My Plugin', 'manage_options', 'my-unique-identifier', 'my_plugin_options' );
}

/** 第2步:将函数注册到钩子中 */
add_action( 'admin_menu', 'my_plugin_menu' );

/** 第3步:定义选项被点击时打开的页面 */
function my_plugin_options() {
     if ( !current_user_can( 'manage_options' ) )  {
          wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
     }
     echo '<div class="wrap">';
     echo '<p>Here is where the form would go if I actually had options.</p>';
     echo '</div>';
}
?>

在第1步中,my_plugin_menu()函数的作用是通过调用add_options_page()函数,向管理员界面的配置菜单中添加一个新的菜单选项(关于更复杂的多级选项,将在之后进行详述)。

在第2步中,add_action()函数的作用就是将第1步中定义的my_plugin_menu()函数,挂载到名为admin_menu的钩子下。此时如果忘了调用add_action()函数的话,那么在你试图激活这个插件时就会提示'undefined function'错误。

在最后一步中,my_plugin_options()函数的作用就是显示一个配置页面,并显示出用户可配置的内容(可以由PHP的代码编写),这个函数也是在第1步中的add_action()函数中被调用的。这样当用户点击菜单选项的时候,就会弹出这个配置页面。

在下面的章节中,将会对这些步骤进行更详细的说明。再重复一遍:切记要把创建菜单选项的代码放到函数中!并且记得将函数挂载到admin_menu钩子中!这样你的整个代码流程才能正确的运行。

Determining Location for New Menus

Before creating a new menu, first decide if the menu should be a top-level menu, or a sub-level menu item. A top-level menu displays as new section in the administration menus and contains sub-level menu items. A sub-level menu means the menu item is a member of an existing menu.

It is rare that a plugin would require the creation of a top-level menu. If the plugin introduces an entirely new concept or feature to WordPress, and needs many screens to do it, then that plugin may warrant a new top-level menu. Adding a top-level menu should only be considered if you really need multiple, related screens to make WordPress do something it was not originally designed to accomplish. Examples of new top-level menus might include job management or conference management. Please note with the native post type registration, WordPress automatically creates top-level menus to manage those features.

If the creation of a top-level menu is not necessary, decide under what top-level menu to place your sub-level menu item. As a point of reference, most plugins add sub-level menu items underneath existing WordPress top-level menus. For example, the Backup plugin adds a sub-level menu option to the Tools top-level menu. Please note with the taxonomy registration, WordPress automatically creates sub-level menus under the applicable top-level menu to manage those features.

Use this guide of the WordPress top-level menus to determine the correct location for your sub-level menu item:

Dashboard 
Information central for your site and include the Updates option for updating WordPress core, plugins, and themes.
Posts 
Displays tools for writing 日志 (time oriented content).
Media 
Uploading and managing your pictures, videos, and audio.
Links 
Manage references to other blogs and sites of interest.
Pages 
Displays tools for writing your static content called pages.
Comments 
Controlling and regulation reader to responses to posts.
Appearance
Displays controls for manipulation of theme/style files, sidebars, etc.
Plugins
Displays controls dealing with plugin management, not configuration options for a plugin itself.
Users
Displays controls for user management.
Tools 
Manage the export, import, and even backup of blog data.
Settings 
Displays plugin options that only administrators should view (also see Creating Settings Pages).
Network Admin 
Displays plugin options that are set on the Network. Instead of "admin_menu", you should use "network_admin_menu" (see also Create A Network)

管理菜单功能

Now that you have decided where to add your top-level or sub-level menu, the next step is to tell WordPress about your new pages. All of this will take place in a function registered to the 'admin_menu' action. A working example is presented at the end of this section.

顶层菜单

If you have decided your plugin requires a brand-new top-level menu, the first thing you'll need to do is to create one with the add_menu_page function. Note: skip to Sub-Menus if you don't need a top-level menu.

<?php add_menu_page$page_title$menu_title$capability$menu_slug$function$icon_url$position ); ?>

Parameter values:

page_title 
The text to be displayed in the title tags of the 页面 when the menu is selected.
menu_title 
The on-screen name text for the menu.
capability 
The capability required for this menu to be displayed to the user. When using the Settings API to handle your form, you should use 'manage_options' here as the user won't be able to save options without it. User levels are deprecated and should not be used here!
menu_slug
The slug name to refer to this menu by (should be unique for this menu). Prior to Version 3.0 this was called the file (or handle) parameter. If the function parameter is omitted, the menu_slug should be the PHP file that handles the display of the menu 页面 content.
function
The function that displays the 页面 content for the menu page. Technically, the function parameter is optional, but if it is not supplied, then WordPress will basically assume that including the PHP file will generate the administration screen, without calling a function. The page-generating code can be written in a function within the main plugin file. In the event that the function parameter is specified, it is possible to use any string for the file parameter. This allows usage of pages such as ?page=my_super_plugin_page instead of ?page=my-super-plugin/admin-options.php.
The function must be referenced in one of two ways:
  1. if the function is a member of a class within the plugin it should be referenced as array( $this, 'function_name' )
  2. in all other cases, using the function name itself is sufficient
icon_url
The url to the icon to be used for this menu. This parameter is optional.
position
The position in the menu order this menu should appear. By default, if this parameter is omitted, the menu will appear at the bottom of the menu structure. To see the current menu positions, use print_r($GLOBALS['menu']) after the menu has loaded.

子菜单

Once your top-level menu is defined, or you have chosen to use an existing WordPress top-level menu, you are ready to define one or more sub-level menu items using the add_submenu_page function. Make sure to add the sub-level menu items in the order you want them displayed.

使用 add_submenu_page

<?php add_submenu_page$parent_slug$page_title$menu_title$capability$menu_slug$function); ?>

Parameter values:

parent_slug 
The slug name for the parent menu, or the file name of a standard WordPress admin file that supplies the top-level menu in which you want to insert your submenu, or your plugin file if this submenu is going into a custom top-level menu.
Examples:
  1. For Dashboard: add_submenu_page('index.php',...)
  2. For Posts: add_submenu_page('edit.php',...)
  3. For Media: add_submenu_page('upload.php',...)
  4. For Links: add_submenu_page('link-manager.php',...)
  5. For Pages: add_submenu_page('edit.php?post_type=page',...)
  6. For Comments: add_submenu_page('edit-comments.php',...)
  7. For Custom 日志 Types: add_submenu_page('edit.php?post_type=your_post_type',...)
  8. For Appearance: add_submenu_page('themes.php',...)
  9. For Plugins: add_submenu_page('plugins.php',...)
  10. For Users: add_submenu_page('users.php',...)
  11. For Tools: add_submenu_page('tools.php',...)
  12. For Settings: add_submenu_page('options-general.php',...)
page_title 
Text that will go into the HTML 页面 title for the 页面 when the submenu is active.
menu_title 
The text to be displayed in the title tags of the 页面 when the menu is selected.
capability 
The capability required for this menu to be displayed to the user. User levels are deprecated and should not be used here!
menu_slug 
For existing WordPress menus, the PHP file that handles the display of the menu 页面 content. For submenus of a custom top-level menu, a unique identifier for this sub-menu page.
In situations where a plugin is creating its own top-level menu, the first submenu will normally have the same link title as the top-level menu and hence the link will be duplicated. The duplicate link title can be avoided by calling the add_submenu_page function the first time with the parent_slug and menu_slug parameters being given the same value.

function 
The function that displays the 页面 content for the menu page.
Technically, as in the add_menu_page function, the function parameter is optional, but if it is not supplied, then WordPress will basically assume that including the PHP file will generate the administration screen, without calling a function. Most plugin authors choose to put the page-generating code in a function within their main plugin file.
In the event that the function parameter is specified, It's possible to use any string for the file parameter. This allows usage of pages such as ?page=my_super_plugin_page instead of ?page=my-super-plugin/admin-options.php.
See the Top-Level Menus for notes about how to reference class members as function parameters.
Example

Here's a quick example illustrating how to insert a top-level menu 页面 and a sub-menu page, where the title on the sub-menu 页面 is different from the top-level page. In this example, 'my_magic_function' is the name of the function that displays the first sub-menu page:

<?php
add_menu_page
('Page title''Top-level menu title''manage_options''my-top-level-handle''my_magic_function');
add_submenu_page'my-top-level-handle''Page title''Sub-menu title''manage_options''my-submenu-handle''my_magic_function');
?>

Here's an example of adding an option 页面 under a custom 日志 type menu block (see also here):

<?php add_submenu_page('edit.php?post_type=wiki''Options''Options''manage_options''wiki-options', array(&$this'options_page') ); ?>

Using Wrapper Functions

Since most sub-level menus belong under the Settings, Tools, or Appearance menus, WordPress supplies wrapper functions that make adding a sub-level menu items to those top-level menus easier. Note that the function names may not match the names seen in the admin UI as they have changed over time:

Dashboard <?php add_dashboard_page$page_title$menu_title$capability$menu_slug$function); ?>

Posts <?php add_posts_page$page_title$menu_title$capability$menu_slug$function); ?>

Media <?php add_media_page$page_title$menu_title$capability$menu_slug$function); ?>

Links <?php add_links_page$page_title$menu_title$capability$menu_slug$function); ?>

Pages <?php add_pages_page$page_title$menu_title$capability$menu_slug$function); ?>

Comments <?php add_comments_page$page_title$menu_title$capability$menu_slug$function); ?>

Appearance <?php add_theme_page$page_title$menu_title$capability$menu_slug$function); ?>

Plugins <?php add_plugins_page$page_title$menu_title$capability$menu_slug$function); ?>

Users <?php add_users_page$page_title$menu_title$capability$menu_slug$function); ?>

Tools <?php add_management_page$page_title$menu_title$capability$menu_slug$function); ?>

Settings <?php add_options_page$page_title$menu_title$capability$menu_slug$function); ?>

Also see Creating Options Pages for more on this.

Inserting the Pages

Here is an example of a WordPress plugin that inserts new menus into various places:

<?php
/*
Plugin Name: Menu Test
Plugin URI: http://codex.wordpress.org/Adding_Administration_Menus
Description: Menu Test
Author: Codex authors
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 Settings:
    add_options_page(__('Test Settings','menu-test'), __('Test Settings','menu-test'), 'manage_options', 'testsettings', 'mt_settings_page');

    // Add a new submenu under Tools:
    add_management_page( __('Test Tools','menu-test'), __('Test Tools','menu-test'), 'manage_options', 'testtools', 'mt_tools_page');

    // Add a new top-level menu (ill-advised):
    add_menu_page(__('Test Toplevel','menu-test'), __('Test Toplevel','menu-test'), 'manage_options', 'mt-top-level-handle', 'mt_toplevel_page' );

    // Add a submenu to the custom top-level menu:
    add_submenu_page('mt-top-level-handle', __('Test Sublevel','menu-test'), __('Test Sublevel','menu-test'), 'manage_options', 'sub-page', 'mt_sublevel_page');

    // Add a second submenu to the custom top-level menu:
    add_submenu_page('mt-top-level-handle', __('Test Sublevel 2','menu-test'), __('Test Sublevel 2','menu-test'), 'manage_options', 'sub-page2', 'mt_sublevel_page2');
}

// mt_settings_page() displays the 页面 content for the Test settings submenu
function mt_settings_page() {
    echo "<h2>" . __( 'Test Settings', 'menu-test' ) . "</h2>";
}

// mt_tools_page() displays the 页面 content for the Test Tools submenu
function mt_tools_page() {
    echo "<h2>" . __( 'Test Tools', 'menu-test' ) . "</h2>";
}

// mt_toplevel_page() displays the 页面 content for the custom Test Toplevel menu
function mt_toplevel_page() {
    echo "<h2>" . __( 'Test Toplevel', 'menu-test' ) . "</h2>";
}

// mt_sublevel_page() displays the 页面 content for the first submenu
// of the custom Test Toplevel menu
function mt_sublevel_page() {
    echo "<h2>" . __( 'Test Sublevel', 'menu-test' ) . "</h2>";
}

// mt_sublevel_page2() displays the 页面 content for the second submenu
// of the custom Test Toplevel menu
function mt_sublevel_page2() {
    echo "<h2>" . __( 'Test Sublevel2', 'menu-test' ) . "</h2>";
}

?>

Sample Menu 页面

Note: See the Settings API for information on creating settings pages.

The example above contains several dummy functions, such as mt_settings_page, as placeholders for actual 页面 content. We need to turn them into real menu pages. So, let's assume that our plugin has an option called mt_favorite_color, and that we want to allow the site owner to type in his/her favorite color via a Settings page. The mt_options_page function will need to put a data entry form on the screen to enable this, and also process the entered data. Here is a function that does this:


// mt_settings_page() displays the 页面 content for the Test settings submenu
function mt_settings_page() {

    //must check that the user has the required capability 
    if (!current_user_can('manage_options'))
    {
      wp_die( __('You do not have sufficient permissions to access this page.') );
    }

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

    // 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( isset($_POST[ $hidden_field_name ]) && $_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 settings updated message on the screen

?>
<div class="updated"><p><strong><?php _e('settings saved.', 'menu-test' ); ?></strong></p></div>
<?php

    }

    // Now display the settings editing screen

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

    // header

    echo "<h2>" . __( 'Menu Test Plugin Settings', 'menu-test' ) . "</h2>";

    // settings form
    
    ?>

<form name="form1" method="post" action="">
<input type="hidden" name="<?php echo $hidden_field_name; ?>" value="Y">

<p><?php _e("Favorite Color:", 'menu-test' ); ?> 
<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" class="button-primary" value="<?php esc_attr_e('Save Changes') ?>" />
</p>

</form>
</div>

<?php
 
}

A few notes:

  • The WordPress functions such as add_menu_page and add_submenu_page take a capability which will be used to determine whether the top-level or sub-level menu is displayed.
  • The function which is hooked in to handle the output of the 页面 must check that the user has the required capability as well.
  • The WordPress administration functions take care of validating the user login, so you don't have to worry about it in your function.
  • The function example above has been internationalized -- see the Internationalization section of Writing a Plugin for more information.
  • The function processes any entered data before putting the data entry form on the screen, so that the new values will be shown in the form (rather than the values from the database).
  • You don't have to worry about this working the first time, because the WordPress update_option function will automatically add an option to the database if it doesn't already exist.
  • These admin-menu-adding procedures are parsed every single time you navigate to a 页面 in Admin. So if you are writing a plugin which has no options page, but add one later, you can just add it using the instructions above and re-upload, and tweak until you're happy with it. In other words, menus are not "permanently added" or put into a database upon activating a plugin. They're parsed on the fly, so you can add or subtract menu items at will, re-upload, and the change will be reflected right away.

页面 Hook Suffix

Every function that adds a new administration menu (add_menu_page(), add_submenu_page() and its specialized versions such as add_options_page()) returns a special value called Page Hook Suffix. It can be used later as a hook to which an action called only on that particular 页面 can be registered.

One such action hook is load-{page_hook}, where {page_hook} is the value returned by one of these add_*_page() functions. This hook is called when the particular 页面 is loaded. In the example below, it is used to display the "Plugin is not configured" notice on all admin pages except for plugin's options page:

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

// Here you can check if plugin is configured (e.g. check if some option is set). If not, add new hook. 
// In this example hook is always added.
add_action( 'admin_notices', 'my_plugin_admin_notices' );

function my_plugin_menu() {
	// Add the new admin menu and 页面 and save the returned hook suffix
	$hook_suffix = add_options_page('My Plugin Options', 'My Plugin', 'manage_options', 'my-unique-identifier', 'my_plugin_options');
	// Use the hook suffix to compose the hook and register an action executed when plugin's options 页面 is loaded
	add_action( 'load-' . $hook_suffix , 'my_load_function' );
}

function my_load_function() {
	// Current admin 页面 is the options 页面 for our plugin, so do not display the notice
	// (remove the action responsible for this)
	remove_action( 'admin_notices', 'my_plugin_admin_notices' );
}

function my_plugin_admin_notices() {
	echo "<div id='notice' class='updated fade'><p>My Plugin is not configured yet. Please do it now.</p></div>\n";
}

function my_plugin_options() {
	if (!current_user_can('manage_options'))  {
		wp_die( __('You do not have sufficient permissions to access this page.') );
	}
	echo '<div class="wrap">';
	echo '<p>Here is where the form would go if I actually had options.</p>';
	echo '</div>';
}
?>

Resources