如何添加WordPress插件的后台菜单

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

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

参考函数

一般函数

菜单页面

  • add_menu_page()
  • add_object_page()
  • add_utility_page()
  • remove_menu_page()

子菜单页面

  • add_submenu_page()
  • remove_submenu_page()

WordPress后台菜单

  • add_dashboard_page()
  • add_posts_page()
  • add_media_page()
  • add_links_page()
  • add_pages_page()
  • add_comments_page()
  • add_theme_page()
  • add_plugins_page()
  • add_users_page()
  • add_management_page()
  • add_options_page()

一切皆需钩子

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

定义一个函数,使其能够创建菜单选项,并调出配置界面
将这个函数挂载到名为admin_menu的Action钩子上。(如果你需要创建的是与网络相关的菜单选项,那么就需要将该函数挂载到network_admin_menu钩子上)。
编写当用户点击菜单选项时,需要显示出的配置页面的内容。
第二步是新手们往往会忽略掉的步骤。必须要记住:光写出代码是不够的,你还必须要把这段代码放到一个函数中,并且把这个函数挂载到相应的钩子上,它才能发挥相应的作用。

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

注意:这些代码应当被写到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钩子中!这样你的整个代码流程才能正确的运行。

确定新菜单的位置

在创建新菜单之前,首先确定该菜单应该是顶级菜单还是子级菜单项。顶级菜单在管理菜单中显示为新部分,并包含子菜单项。子级菜单表示菜单项是现有菜单的成员。

很少有插件需要创建顶级菜单。如果插件向WordPress引入了一个全新的概念或功能,并且需要很多屏幕才能做到这一点,那么该插件可能需要一个新的顶级菜单。只有当你真的需要多个相关的屏幕来让WordPress做一些它最初设计不是要完成的事情时,才应该考虑添加一个顶级菜单。新的顶级菜单的示例可能包括作业管理或会议管理。请注意,使用原生的帖子类型注册,WordPress会自动创建顶级菜单来管理这些功能。

如果不需要创建顶级菜单,请决定将子菜单项放置在哪个顶级菜单下。作为参考,大多数插件在现有的WordPress顶级菜单下添加子级菜单项。例如,备份插件向工具顶层菜单添加了一个子级菜单选项。请注意,在进行分类注册时,WordPress会自动在适用的顶级菜单下创建子级菜单来管理这些功能。

使用WordPress顶级菜单的此指南来确定子菜单项的正确位置:

仪表盘

信息集中于您的站点,并包括更新WordPress核心、插件和主题的更新选项。

文章

显示用于编写日志(面向时间的内容)的工具。

媒体

上传和管理您的图片、视频和音频。

链接

管理对其他感兴趣的博客和站点的引用。

页面

显示用于编写称为页面的静态内容的工具。

评论

控制和调节读者对帖子的回应。

外观

显示用于处理主题/样式文件、侧边栏等的控件。

插件

显示处理插件管理的控件,而不是插件本身的配置选项。

用户

显示用于用户管理的控件。

工具

管理博客数据的导出、导入甚至备份。

设置

显示只有管理员才能查看的插件选项(另请参阅创建设置页)。

网络管理员

显示网络上设置的插件选项。不应使用“ADMIN_MENU”,而应使用“NETWORK_ADMIN_MENU”(另请参阅创建网络)。

管理菜单功能

既然您已经决定了在哪里添加顶级菜单或子级菜单,下一步就是告诉WordPress您的新页面。所有这些都将在注册到“ADMIN_MENU”操作的函数中发生。本节的末尾提供了一个工作示例。

顶层菜单

如果您已经决定您的插件需要一个全新的顶级菜单,那么您需要做的第一件事就是使用add_menu_page函数创建一个。注意:如果不需要顶级菜单,请跳到子菜单。

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

参数值:

page_title

选择菜单时要在页面的标题标签中显示的文本。

menu_title

菜单的屏幕名称文本。

capability

向用户显示此菜单所需的功能。在使用设置API处理表单时,您应该在此处使用“Manage_Options”,因为如果没有它,用户将无法保存选项。用户级别已弃用,不应在此处使用!

menu_slug

引用此菜单的辅助程序名称(对于此菜单应该是唯一的)。在3.0版之前,这称为文件(或句柄)参数。如果省略了函数参数,则MENU_SLUG应该是处理菜单页面内容显示的php文件。

function

显示菜单页的页面内容的函数。从技术上讲,function参数是可选的,但是如果没有提供它,那么WordPress基本上会假设包含PHP文件将生成管理屏幕,而不调用函数。页面生成代码可以在主插件文件内的函数中编写。如果指定了Function参数,则可以使用任何字符串作为FILE参数。这允许使用?page=my_superplugin_page这样的页面,而不是?page=my-Super-plugin/admin-options.php。

必须以以下两种方式之一引用该函数:

如果函数是插件中某个类的成员,则应将其引用为数组($this,‘function_name’)。

在所有其他情况下,使用函数名本身就足够了。

icon_url

要用于此菜单的图标的URL。此参数是可选的。

position

此菜单应出现的菜单顺序中的位置。默认情况下,如果省略此参数,菜单将显示在菜单结构的底部。要查看当前菜单位置,请在菜单加载后使用print_r($GLOBALS[‘menu’])。

子菜单

一旦定义了顶级菜单,或者选择使用现有的WordPress顶级菜单,就可以使用add_submenu_page函数定义一个或多个子菜单项。确保按您希望的显示顺序添加子级别菜单项。

使用 add_submenu_page

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

参数值:

parent_slug

父菜单的插件名称,或标准WordPress管理文件的文件名,该文件提供您要在其中插入子菜单的顶级菜单,如果此子菜单将进入自定义顶级菜单,则提供插件文件。
例如:

  • 对于仪表板:add_submenu_page(‘index.php’,…)。
  • 对于文章:add_submenu_page(‘edit.php’,…)。
  • 对于媒体:add_submenu_page(‘upload.php’,…)。
  • 对于链接:add_submenu_page(‘link-manager.php’,…)。
  • 对于页面:add_submenu_page(‘edit.php?post_type=page’,…)。
  • 对于评论:add_submenu_page(‘edit-comments.php’,…)。
  • 对于自定义类型:add_submenu_page(‘edit.php?post_type=your_post_type’,…)。
  • 外观:add_submenu_page(‘themes.php’,…)。
  • 插件:add_submenu_page(‘plugins.php’,…)。
  • 对于用户:add_submenu_page(‘users.php’,…)。
  • 对于工具:add_submenu_page(‘tools.php’,…)。
  • 对于设置:add_submenu_page(‘options-general.php’,…)。

page_title

当子菜单处于活动状态时将进入页面的页面标题的文本。

menu_title

选择菜单时要在页面的标题标签中显示的文本。

capability

向用户显示此菜单所需的功能。用户级别已弃用,不应在此处使用!

menu_slug

对于现有的wordpress菜单,是处理菜单页面内容显示的php文件。对于自定义顶级菜单的子菜单,该子菜单页的唯一标识符。
在插件创建自己的顶级菜单的情况下,第一个子菜单通常与顶级菜单具有相同的链接标题,因此链接将被复制。第一次调用ADD_SUBMENU_PAGE函数,同时为parent_slug和mena_slug参数赋予相同的值,可以避免重复的链接标题。

function

显示菜单页的页面内容的函数。
从技术上讲,就像在ADD_MENU_PAGE函数中一样,function参数是可选的,但是如果没有提供它,那么WordPress基本上会假设包含PHP文件将生成管理屏幕,而不调用函数。大多数插件作者选择将页面生成代码放在其主插件文件内的函数中。

如果指定了函数参数,则可以使用任何字符串作为文件参数。这允许使用?page=my_super_plugin_page这样的页面,而不是?page=my-super-plugin/admin-options.php。

有关如何将类成员引用为函数参数的说明,请参见顶级菜单。

示例

下面是一个快速示例,说明如何插入顶级菜单页面和子菜单页面,其中子菜单页面上的标题与顶级页面不同。在此示例中,‘my_magic_function’是显示第一个子菜单页面的函数的名称:

<?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');
?>

下面是在自定义页面类型菜单块下添加选项日志的示例(另请参阅此处):

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

使用包装函数

由于大多数子级菜单都属于“设置”、“工具”或“外观”菜单,WordPress提供了包装器功能,使向这些顶级菜单添加子级菜单项变得更容易。请注意,函数名称可能与管理用户界面中看到的名称不匹配,因为它们会随着时间的推移而更改:

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); ?>

插入页面

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

<?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>";
}

?>

示例菜单页面

上面的示例包含几个伪函数,如mt_settings_page,作为实际页面内容的占位符。我们需要把它们变成真正的菜单页面。因此,让我们假设我们的插件有一个名为mt_favorite_color的选项,并且我们希望允许站点所有者通过设置页面输入他/她喜欢的颜色。mt_options_page 函数需要在屏幕上放置一个数据输入表单以启用此功能,并处理输入的数据。下面是一个执行此操作的函数:

// 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
 
}

以下是几点注意事项:

  • 诸如add_menu_page 和add_submenu_page 这样的WordPress函数具有一个功能,该功能将用于确定是显示顶级菜单还是显示子级菜单。
  • 挂接以处理页面输出的函数必须检查用户是否也具有所需的功能。
  • WordPress管理函数负责验证用户登录,因此您不必在函数中担心这一点。
  • 上面的函数示例已经国际化–有关更多信息,请参阅编写插件的国际化部分。
  • 该函数在将数据输入表单放到屏幕上之前处理所有输入的数据,因此新值将显示在表单中(而不是数据库中的值)。
  • 您不必担心第一次会正常工作,因为WordPress update_option函数会自动向数据库添加一个选项(如果该选项不存在)。
  • 每次导航到管理中的页面时,都会解析这些管理菜单添加过程。因此,如果您正在编写一个没有选项页面的插件,但稍后添加一个选项页面,您可以使用上面的说明添加它,然后重新上传,然后进行调整,直到您满意为止。换句话说,菜单不会在激活插件时“永久添加”或放入数据库。它们是动态解析的,因此您可以随意添加或删减菜单项,重新上传,更改将立即反映出来。

页面 Hook Suffix

添加新管理菜单(add_menu_page()、add_submenu_page()及其专用版本(如add_options_page()的每个函数都返回一个称为Page Hook Suffix的特殊值。以后可以将其用作仅在该特定页面上调用的操作可以注册到的挂钩。

一个这样的操作钩子是 load-{page_hook},其中{page_hook} 是这些add_*_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>';
}
?>

资源

发表评论

电子邮件地址不会被公开。 必填项已用*标注