Codex

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

Difference between revisions of "Administration Menus"

(Every Plot Needs a Hook)
m (Using add_submenu_page)
 
(79 intermediate revisions by 46 users not shown)
Line 1: Line 1:
  +
{{Languages|
  +
{{en|Adding Administration Menus}}
  +
{{zh-cn|Adding Administration Menus}}
  +
{{ja|Adding Administration Menus}}
  +
{{ru|Добавление административных меню}}
  +
}}
  +
  +
__TOC__
 
== Introduction ==
 
== Introduction ==
   
  +
Usually, plugin and theme authors need to provide access to a settings (options) screen so users can customize how the plugin or theme is used. The best way to present the user with such a screen is to create an administration menu item that allows the user to access that settings screen from all the [[Administration Screens]]. This article explains how plugin authors can add administration menus and screens. Note: the following information assumes a knowledge of the basics of [[Writing a Plugin]] and using the [[Plugin API]] of Actions and Filters.
Many plugins give their users options or settings, which allow the users a way to customize how the plugin is used. As a plugin author, you have several choices in how to set this up. One way is to have the user edit information in the plugin's PHP file, but this makes many users uncomfortable (to say the least). So, a better way is usually to create administration screens that let the plugin user set options in a more familiar manner.
 
   
  +
== Function Reference ==
This article explains how to add custom administration screens to WordPress in a plugin. It assumes you are already familiar with the basics of [[Writing a Plugin]] and the [[Plugin API]] of Actions and Filters.
 
  +
  +
{| cellspacing="10" width="68%"
  +
|- valign="top"
  +
| width="44%" |
  +
  +
{| class="widefat"
  +
|- style="background:#464646; color:#d7d7d7;"
  +
! '''General Functions'''
  +
|-
  +
|
  +
'''Menu Pages'''
  +
* <tt>[[Function Reference/add_menu_page | add_menu_page()]]</tt>
  +
* <tt>[[Function Reference/add_object_page | add_object_page()]]</tt>
  +
* <tt>[[Function Reference/add_utility_page | add_utility_page()]]</tt>
  +
* <tt>[[Function Reference/remove_menu_page | remove_menu_page()]]</tt>
  +
'''SubMenu Pages'''
  +
* <tt>[[Function Reference/add_submenu_page | add_submenu_page()]]</tt>
  +
* <tt>[[Function Reference/remove_submenu_page | remove_submenu_page()]]</tt>
  +
|}
  +
  +
| width="56%" |
  +
  +
{| class="widefat"
  +
|- style="background:#464646; color:#d7d7d7;"
  +
! '''WordPress Administration Menus'''
  +
|-
  +
|
  +
* <tt>[[Function Reference/add_dashboard_page | add_dashboard_page()]]</tt>
  +
* <tt>[[Function Reference/add_posts_page | add_posts_page()]]</tt>
  +
* <tt>[[Function Reference/add_media_page | add_media_page()]]</tt>
  +
* <tt>[[Function Reference/add_pages_page | add_pages_page()]]</tt>
  +
* <tt>[[Function Reference/add_comments_page | add_comments_page()]]</tt>
  +
* <tt>[[Function Reference/add_theme_page | add_theme_page()]]</tt>
  +
* <tt>[[Function Reference/add_plugins_page | add_plugins_page()]]</tt>
  +
* <tt>[[Function Reference/add_users_page | add_users_page()]]</tt>
  +
* <tt>[[Function Reference/add_management_page | add_management_page()]]</tt>
  +
* <tt>[[Function Reference/add_options_page | add_options_page()]]</tt>
  +
|}
  +
|}
   
 
== Every Plot Needs a Hook ==
 
== Every Plot Needs a Hook ==
   
To add an admin menu, you must do three things:
+
To add an administration menu, you must do three things:
#Create a function which contains the menu-building code
 
#Register the above function using the "admin_menu" action hook
 
#Create the HTML output for the page displayed when the menu item is clicked
 
   
  +
# Create a function that contains the menu-building code
Code should be added in the main plugin php file or a separate php include.
 
  +
# Register the above function using the [[Plugin_API/Action_Reference/admin_menu|admin_menu]] action hook. (If you are adding an admin menu for the [[Create A Network|Network]], use [[Plugin_API/Action_Reference/network_admin_menu|network_admin_menu]] instead).
  +
# Create the HTML output for the page (screen) displayed when the menu item is clicked
   
The second step is often overlooked by new plugin developers. You cannot simply call the menu code described below; you must put it '''inside a function''' and then register the function.
+
It is that second step that is often overlooked by new developers. You cannot simply call the menu code described; you must put it '''inside a function''', and then register the function.
  +
  +
Here is a very simple example of the three steps just described. This plugin will add a sub-level menu item under the Settings top-level menu in [[Administration Screens]], and when selected, that menu item will cause a very basic screen to display. Note: this code should be added to a [[Writing a Plugin#Plugin_Files|main plugin PHP file]] or a separate PHP include file.
   
A very simple example of the above three steps:
 
 
<pre>
 
<pre>
 
<?php
 
<?php
  +
/** Step 2 (from text above). */
add_action('admin_menu', 'my_plugin_menu');
 
  +
add_action( 'admin_menu', 'my_plugin_menu' );
   
  +
/** Step 1. */
 
function my_plugin_menu() {
 
function my_plugin_menu() {
add_options_page('My Plugin Options', 'My Plugin', 8, __FILE__, 'my_plugin_options');
+
add_options_page( 'My Plugin Options', 'My Plugin', 'manage_options', 'my-unique-identifier', 'my_plugin_options' );
 
}
 
}
   
  +
/** Step 3. */
 
function my_plugin_options() {
 
function my_plugin_options() {
  +
if ( !current_user_can( 'manage_options' ) ) {
echo '<div class="wrap">';
 
  +
wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
echo '<p>Here is where the form would go if I actually had options.</p>';
 
  +
}
echo '</div>';
 
  +
echo '<div class="wrap">';
  +
echo '<p>Here is where the form would go if I actually had options.</p>';
  +
echo '</div>';
 
}
 
}
 
?>
 
?>
 
</pre>
 
</pre>
   
As you can see, we have a function, <tt>my_plugin_menu</tt>, which adds a new item to the Admin menu (via the <tt>add_options_page</tt> function, described in the next section--more complicated multiple menu items can be added, as seen below). Then, we invoke the Wordpress hook which "registers" this function. ''Without that, a PHP error for "undefined function" will be thrown when you attempt to activate the plugin.'' Lastly, we create a function which contains the actual page to be displayed (and PHP code to be processed) when someone clicks the menu item.
+
In this example, the function <tt>my_plugin_menu()</tt> adds a new item to the ''Settings'' administration menu via the <tt>[[Function_Reference/add_options_page|add_options_page()]]</tt> function. Note: more complicated multiple menu items can be added, but that will be described later.
  +
Notice the <tt>[[Function_Reference/add_action|add_action()]]</tt> call in ''Step 2'' that ''registers'' the <tt>my_plugin_menu()</tt> function under the [[Plugin_API/Action_Reference/admin_menu|admin_menu]] hook. '''Without that <tt>add_action()</tt> call, a PHP error for ''undefined function'' will be thrown when attempting to activate the plugin.''' Finally, the <tt>add_options_page()</tt> call refers to the <tt>my_plugin_options()</tt> function which contains the actual page to be displayed (and PHP code to be processed) when someone clicks the menu item.
   
The actual processes for the last two of these three steps are described in the sections below. But do not forget that you must enclose them in functions, and invoke that <tt>admin_menu</tt> hook to get the whole process started!
+
These processes are described in more detail in the sections below. Remember to enclose the creation of the menu and the page in functions, and use the ''admin_menu'' [[Plugin_API#Current_Hooks_For_Actions|hook]] to get the whole process started at the right time!
   
  +
== Determining Location for New Menus ==
== Menus and Submenus ==
 
   
Before creating custom administration screens you must figure out where in the WordPress administration menu system they belong. Most plugins add their screens as submenus underneath the existing WordPress top-level menus. Here is a guide to what belongs in which top-level menu:
+
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 [[Glossary#Post Type|post type]] registration, WordPress automatically creates top-level menus to manage those features.
;[[Administration_Panels#Settings_-_Configuration_Settings|Settings]]:Displays plugin options that only administrators should view (also see [[Creating_Options_Pages|Creating Settings Pages]]).
 
;[[Administration_Panels#Manage_-_Change_your_content|Manage]]:Displays management controls for links, posts, categories, images, etc.
 
;[[Administration_Panels#Plugins_-_Add_Functionality_to_your_Blog|Plugins]]:Displays controls dealing with plugin management, not configuration options for a plugin itself.
 
;[[Administration_Panels#Presentation_-_Change_the_Look_of_your_Blog|Presentation]]:Displays controls for manipulation of theme/style files, sidebars, etc.
 
;[[Administration_Panels#Write_-_Make_some_content|Write]]:Displays tools for writing content (posts and pages).
 
;[[Administration_Panels#Users_-_Your_Blogging_Family|Users]]:Displays controls for user management.
 
   
  +
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 [https://wordpress.org/plugins/wp-db-backup/ Backup plugin] adds a sub-level menu option to the Tools top-level menu. Please note with the [[Function_Reference/register_taxonomy|taxonomy]] registration, WordPress automatically creates sub-level menus under the applicable top-level menu to manage those features.
If your plugin introduces an entirely new concept or feature to WordPress, and needs many screens to do it, another option is to create a new top-level menu for your plugin. This should only be considered if you really need multiple, related screens to make WordPress do something it was not originally designed to do. Examples might include management of image galleries, database administration, or conference management.
 
   
  +
Use this guide of the WordPress top-level menus to determine the correct location for your sub-level menu item:
With the [http://barunsingh.com/software/custom-admin-menu/ Custom Admin Menu plugin], users now also have the ability to decide for themselves if they want your plugin to occupy a top-level menu item or not -- you may want to make clear to users that they have that option, particularly if you've decided to create a top-level menu item.
 
   
  +
;[[Dashboard Screen|Dashboard]] : Information central for your site and include the Updates option for updating WordPress core, plugins, and themes.
== Admin Menu Functions ==
 
  +
;[[Administration_Screens#Posts_-_Make_some_content|Posts]] : Displays tools for writing posts (time oriented content).
  +
;[[Administration_Screens#Media - Add pictures and movies to your posts|Media]] : Uploading and managing your pictures, videos, and audio.
  +
;[[Administration_Screens#Pages - Your Static Content|Pages]] :Displays tools for writing your static content called pages.
  +
;[[Administration_Screens#Comments|Comments]] : Controlling and regulation reader to responses to posts.
  +
;[[Administration_Screens#Appearance_-_Change_the_Look_of_your_Blog|Appearance]]:Displays controls for manipulation of theme/style files, sidebars, etc.
  +
;[[Administration_Screens#Plugins_-_Add_Functionality_to_your_Blog|Plugins]]:Displays controls dealing with plugin management, not configuration options for a plugin itself.
  +
;[[Administration_Screens#Users_-_Your_Blogging_Family|Users]]:Displays controls for user management.
  +
;[[Administration_Screens#Tools - Managing your Blog|Tools]] : Manage the export, import, and even backup of blog data.
  +
;[[Administration_Screens#Settings_-_Configuration_Settings|Settings]] : Displays plugin options that only administrators should view (also see [[Creating_Options_Pages|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]])
   
  +
== Admin Menu Functions ==
Now that you have decided where to add your menu/submenu, the next step is to tell WordPress about your new pages. All of this will take place in a function you have registered as an <tt>'admin_menu'</tt> action (see example at bottom of this section).
 
   
  +
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 <tt>'admin_menu'</tt> action. A working example is presented at the end of this section.
=== Top-Level menu ===
 
   
  +
=== Top-Level Menus ===
If for some reason you have decided that your plugin really needs a brand-new top-level menu, the first thing you'll need to do is to create one. Otherwise, skip to Sub-Menus below.
 
   
To add a new top-level menu, you'll use the <tt>add_menu_page</tt> function:
+
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 <tt>[[Function_Reference/add_menu_page|add_menu_page]]</tt> function. Note: skip to [[#Sub-Level_Menus|Sub-Level Menus]] if you don't need a top-level menu.
   
add_menu_page(''page_title'', ''menu_title'', ''access_level/capability'', ''file'', ''[function]'', ''[icon_url]'');
+
%%%<?php add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position ); ?>%%%
   
 
Parameter values:
 
Parameter values:
;page_title:Text that will go into the HTML page title for the page when the menu is active.
+
;page_title : The text to be displayed in the title tags of the page when the menu is selected.
;menu_title:The on-screen name text for the menu.
 
;access_level/capability:The minimum [[User Levels|user level]] or the [[Roles_and_Capabilities|capability]] required to display and use this menu page.
 
;file:The PHP file that handles the display of the menu page content.
 
;function: The function that displays the page content for the menu page.
 
   
  +
;menu_title : The on-screen name text for the menu.
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. Most plugin authors choose to put the page-generating code in a function within their main plugin file.
 
   
  +
;capability : The [[Roles and Capabilities|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|User levels]] are deprecated and should not be used here!
;icon_url:This only works in WordPress 2.7. It's places a custom icon in the menu for you.
 
   
  +
;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 page content.
=== Sub-Menus ===
 
Once you have a top-level menu defined, or have chosen to use an existing WordPress top-level menu, you are ready to define one or more sub-menu pages using the <tt>add_submenu_page</tt> function. Make sure to add the submenu pages in the order you want them displayed.
 
   
  +
;function: The function that displays the page content for the menu page.
add_submenu_page(''parent'', ''page_title'', ''menu_title'', ''access_level/capability'', ''file'', ''[function]'');
 
  +
  +
: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 ''menu_slug'' 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:
  +
:# if the function is a member of a class within the plugin it should be referenced as <tt>array( $this, 'function_name' )</tt>
  +
:# 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 <tt>print_r($GLOBALS['menu'])</tt> after the menu has loaded.
  +
  +
=== Sub-Level Menus ===
  +
  +
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 <tt>add_submenu_page</tt> function. Make sure to add the sub-level menu items in the order you want them displayed.
  +
  +
==== Using add_submenu_page ====
  +
  +
%%%<?php add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
   
 
Parameter values:
 
Parameter values:
;parent:The filename of the core 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.
+
;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.
Commonly-used examples:
 
#For ''Write'': add_submenu_page('post-new.php',...)
 
#For ''Manage'': add_submenu_page('edit.php',...)
 
#For ''Design'': add_submenu_page('themes.php',...)
 
#For ''Comments'': add_submenu_page('edit-comments.php',...)
 
#For ''Settings'': add_submenu_page('options-general.php',...)
 
#For ''Plugins'': add_submenu_page('plugins.php',...)
 
#For ''Users'': add_submenu_page('users.php',...)
 
;page_title:Text that will go into the HTML page title for the page when the submenu is active.
 
;menu_title:The on-screen name text for the submenu.
 
;access_level/capability:The minimum [[User Levels|user level]] or the [[Roles_and_Capabilities|capability]] required to display and use this submenu page.
 
;file:For existing WordPress menus, the PHP file that handles the display of the menu page content. For submenus of a custom top-level menu, a '''unique''' identifier for this sub-menu page.
 
   
  +
:Examples:
''In situations where a plugin is creating it's 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 and file parameters being given the same value.
 
  +
:#For ''Dashboard'': add_submenu_page('index.php',...)
  +
:#For ''Posts'': add_submenu_page('edit.php',...)
  +
:#For ''Media'': add_submenu_page('upload.php',...)
  +
:#For ''Pages'': add_submenu_page('edit.php?post_type=page',...)
  +
:#For ''Comments'': add_submenu_page('edit-comments.php',...)
  +
:#For ''Custom Post Types'': add_submenu_page('edit.php?post_type=your_post_type',...)
  +
:#For ''Appearance'': add_submenu_page('themes.php',...)
  +
:#For ''Plugins'': add_submenu_page('plugins.php',...)
  +
:#For ''Users'': add_submenu_page('users.php',...)
  +
:#For ''Tools'': add_submenu_page('tools.php',...)
  +
:#For ''Settings'': add_submenu_page('options-general.php',...)
  +
  +
;page_title : Text that will go into the HTML page title for the page when the submenu is active.
  +
;menu_title : The text to be displayed in the title tags of the page when the menu is selected.
  +
;capability : The [[Roles and Capabilities|capability]] required for this menu to be displayed to the user. [[User Levels|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 page 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 page content for the menu page.
+
;function : The function that displays the page content for the menu page.
   
Technically, as in the <tt>add_menu_page</tt> 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.
+
:Technically, as in the <tt>add_menu_page</tt> 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 ''menu_slug'' parameter. This allows usage of pages such as ''?page=my_super_plugin_page'' instead of ''?page=my-super-plugin/admin-options.php''.
Here's a quick example, illustrating how to insert a top-level menu page and a sub-menu page, where the title on the sub-menu page 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:
 
  +
<pre>
 
  +
: See the [[#Top-Level_Menus|Top-Level Menus]] for notes about how to reference class members as ''function'' parameters.
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');
 
  +
===== Example =====
</pre>
 
  +
  +
Here's a quick example illustrating how to insert a top-level menu page and a sub-menu page, where the title on the sub-menu page 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 page under a '''custom post type''' menu block ([http://www.billrobbinsdesign.com/custom-post-type-admin-page/ 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 [[Administration Screens]] as they have changed over time:
  +
  +
[[Dashboard Screen|Dashboard]]
  +
%%%<?php add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Posts_-_Make_some_content|Posts]]
  +
%%%<?php add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Media - Add pictures and movies to your posts|Media]]
  +
%%%<?php add_media_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Pages - Your Static Content|Pages]]
  +
%%%<?php add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Comments|Comments]]
  +
%%%<?php add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Appearance_-_Change_the_Look_of_your_Blog|Appearance]]
  +
%%%<?php add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Plugins_-_Add_Functionality_to_your_Blog|Plugins]]
  +
%%%<?php add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Users_-_Your_Blogging_Family|Users]]
  +
%%%<?php add_users_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
  +
  +
[[Administration_Screens#Tools - Managing your Blog|Tools]]
  +
%%%<?php add_management_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
   
  +
[[Administration_Screenss#Settings_-_Configuration_Settings|Settings]]
Since most submenus go into WordPress's Options, Management, or Presentation menus, WordPress supplies three wrapper functions that make adding a submenu to those pages easier:
 
  +
%%%<?php add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function); ?>%%%
   
;For the Options top-level menu (see [[Creating Options Pages]] for more on this):
+
Also see [[Creating Options Pages]] for more on this.
add_options_page(''page_title'', ''menu_title'', ''access_level/capability'', ''file'', ''[function]'');
 
;For Management:
 
add_management_page(''page_title'', ''menu_title'', ''access_level/capability'', ''file'', ''[function]'');
 
;For Presentation:
 
add_theme_page( ''page_title'', ''menu_title'', ''access_level/capability'', ''file'', ''[function]'');
 
   
 
=== Inserting the Pages ===
 
=== Inserting the Pages ===
Line 124: Line 242:
 
/*
 
/*
 
Plugin Name: Menu Test
 
Plugin Name: Menu Test
Plugin URI: http://wordpress.org
+
Plugin URI: http://codex.wordpress.org/Adding_Administration_Menus
 
Description: Menu Test
 
Description: Menu Test
Author: Nobody
+
Author: Codex authors
 
Author URI: http://example.com
 
Author URI: http://example.com
 
*/
 
*/
Line 135: Line 253:
 
// action function for above hook
 
// action function for above hook
 
function mt_add_pages() {
 
function mt_add_pages() {
// Add a new submenu under Options:
+
// Add a new submenu under Settings:
add_options_page('Test Options', 'Test Options', 8, 'testoptions', 'mt_options_page');
+
add_options_page(__('Test Settings','menu-test'), __('Test Settings','menu-test'), 'manage_options', 'testsettings', 'mt_settings_page');
   
// Add a new submenu under Manage:
+
// Add a new submenu under Tools:
add_management_page('Test Manage', 'Test Manage', 8, 'testmanage', 'mt_manage_page');
+
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 a new top-level menu (ill-advised):
add_menu_page('Test Toplevel', 'Test Toplevel', 8, __FILE__, 'mt_toplevel_page');
+
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 a submenu to the custom top-level menu:
add_submenu_page(__FILE__, 'Test Sublevel', 'Test Sublevel', 8, 'sub-page', 'mt_sublevel_page');
+
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 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');
+
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_options_page() displays the page content for the Test Options submenu
+
// mt_settings_page() displays the page content for the Test Settings submenu
function mt_options_page() {
+
function mt_settings_page() {
echo "<h2>Test Options</h2>";
+
echo "<h2>" . __( 'Test Settings', 'menu-test' ) . "</h2>";
 
}
 
}
   
// mt_manage_page() displays the page content for the Test Manage submenu
+
// mt_tools_page() displays the page content for the Test Tools submenu
function mt_manage_page() {
+
function mt_tools_page() {
echo "<h2>Test Manage</h2>";
+
echo "<h2>" . __( 'Test Tools', 'menu-test' ) . "</h2>";
 
}
 
}
   
 
// mt_toplevel_page() displays the page content for the custom Test Toplevel menu
 
// mt_toplevel_page() displays the page content for the custom Test Toplevel menu
 
function mt_toplevel_page() {
 
function mt_toplevel_page() {
echo "<h2>Test Toplevel</h2>";
+
echo "<h2>" . __( 'Test Toplevel', 'menu-test' ) . "</h2>";
 
}
 
}
   
Line 169: Line 287:
 
// of the custom Test Toplevel menu
 
// of the custom Test Toplevel menu
 
function mt_sublevel_page() {
 
function mt_sublevel_page() {
echo "<h2>Test Sublevel</h2>";
+
echo "<h2>" . __( 'Test Sublevel', 'menu-test' ) . "</h2>";
 
}
 
}
   
Line 175: Line 293:
 
// of the custom Test Toplevel menu
 
// of the custom Test Toplevel menu
 
function mt_sublevel_page2() {
 
function mt_sublevel_page2() {
echo "<h2>Test Sublevel 2</h2>";
+
echo "<h2>" . __( 'Test Sublevel2', 'menu-test' ) . "</h2>";
 
}
 
}
   
Line 182: Line 300:
   
 
=== Sample Menu Page ===
 
=== Sample Menu Page ===
  +
<strong>Note: See the [[Settings API]] for information on creating settings pages.</strong>
   
The example above contains several dummy functions, such as <tt>mt_options_page</tt>, as placeholders for actual page content. We need to turn them into real menu pages. So, let's assume that our plugin has an option called mt_favorite_food, and that we want to allow the site owner to type in his/her favorite food on the plugin's Option page. The <tt>mt_options_page</tt> 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:
+
The example above contains several dummy functions, such as <tt>mt_settings_page</tt>, as placeholders for actual page 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 <tt>mt_options_page</tt> 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:
   
 
<pre>
 
<pre>
   
// mt_options_page() displays the page content for the Test Options submenu
+
// mt_settings_page() displays the page content for the Test Settings submenu
function mt_options_page() {
+
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
 
// variables for the field and option names
$opt_name = 'mt_favorite_food';
+
$opt_name = 'mt_favorite_color';
 
$hidden_field_name = 'mt_submit_hidden';
 
$hidden_field_name = 'mt_submit_hidden';
$data_field_name = 'mt_favorite_food';
+
$data_field_name = 'mt_favorite_color';
   
 
// Read in existing option value from database
 
// Read in existing option value from database
Line 200: Line 325:
 
// See if the user has posted us some information
 
// See if the user has posted us some information
 
// If they did, this hidden field will be set to 'Y'
 
// If they did, this hidden field will be set to 'Y'
if( $_POST[ $hidden_field_name ] == 'Y' ) {
+
if( isset($_POST[ $hidden_field_name ]) && $_POST[ $hidden_field_name ] == 'Y' ) {
 
// Read their posted value
 
// Read their posted value
 
$opt_val = $_POST[ $data_field_name ];
 
$opt_val = $_POST[ $data_field_name ];
Line 207: Line 332:
 
update_option( $opt_name, $opt_val );
 
update_option( $opt_name, $opt_val );
   
// Put an options updated message on the screen
+
// Put a "settings saved" message on the screen
   
 
?>
 
?>
<div class="updated"><p><strong><?php _e('Options saved.', 'mt_trans_domain' ); ?></strong></p></div>
+
<div class="updated"><p><strong><?php _e('settings saved.', 'menu-test' ); ?></strong></p></div>
 
<?php
 
<?php
   
 
}
 
}
   
// Now display the options editing screen
+
// Now display the settings editing screen
   
 
echo '<div class="wrap">';
 
echo '<div class="wrap">';
Line 221: Line 346:
 
// header
 
// header
   
echo "<h2>" . __( 'Menu Test Plugin Options', 'mt_trans_domain' ) . "</h2>";
+
echo "<h2>" . __( 'Menu Test Plugin Settings', 'menu-test' ) . "</h2>";
   
// options form
+
// settings form
 
 
 
?>
 
?>
   
<form name="form1" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>">
+
<form name="form1" method="post" action="">
 
<input type="hidden" name="<?php echo $hidden_field_name; ?>" value="Y">
 
<input type="hidden" name="<?php echo $hidden_field_name; ?>" value="Y">
   
<p><?php _e("Favorite Color:", 'mt_trans_domain' ); ?>
+
<p><?php _e("Favorite Color:", 'menu-test' ); ?>
 
<input type="text" name="<?php echo $data_field_name; ?>" value="<?php echo $opt_val; ?>" size="20">
 
<input type="text" name="<?php echo $data_field_name; ?>" value="<?php echo $opt_val; ?>" size="20">
 
</p><hr />
 
</p><hr />
   
 
<p class="submit">
 
<p class="submit">
<input type="submit" name="Submit" value="<?php _e('Update Options', 'mt_trans_domain' ) ?>" />
+
<input type="submit" name="Submit" class="button-primary" value="<?php esc_attr_e('Save Changes') ?>" />
 
</p>
 
</p>
   
Line 247: Line 372:
   
 
A few notes:
 
A few notes:
* The WordPress administration functions take care of validating the user, so you don't have to worry about it in your function.
+
* The WordPress functions such as <tt>add_menu_page</tt> and <tt>add_submenu_page</tt> 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 page must check that the user has the required capability as well.
* The function example above has been internationalized -- see [[Writing_a_Plugin#Internationalizing_Your_Plugin|the Internationalization section of Writing a Plugin]] for more information
 
  +
* 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 [[Writing_a_Plugin#Internationalizing_Your_Plugin|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).
 
* 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 <tt>update_option</tt> function will automatically add an option to the database if it doesn't already exist.
 
* You don't have to worry about this working the first time, because the WordPress <tt>update_option</tt> 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 page 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.
 
* These admin-menu-adding procedures are parsed every single time you navigate to a page 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.
   
  +
== Page Hook Suffix ==
==Resources==
 
  +
*[http://comox.textdrive.com/pipermail/wp-hackers/2009-February/024632.html Top Level Menu discussion on wp-hackers]
 
  +
Every function that adds a new administration menu (<tt>add_menu_page()</tt>, <tt>add_submenu_page()</tt> and its specialized versions such as <tt>add_options_page()</tt>) 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 page can be registered.
  +
  +
One such action hook is ''load-'''{page_hook}''''', where ''{page_hook}'' is the value returned by one of these <tt>add_'''*'''_page()</tt> functions. This hook is called when the particular page 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:
  +
  +
<pre>
  +
<?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 page 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 page is loaded
  +
add_action( 'load-' . $hook_suffix , 'my_load_function' );
  +
}
  +
  +
function my_load_function() {
  +
// Current admin page is the options page 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>';
  +
}
  +
?>
  +
</pre>
  +
  +
== Resources ==
  +
* [https://wordpress.org/plugins/admin-menu-editor/ Admin Menu Editor Plugin] - allows adding, deleting, hiding, and re-ordering of administration items
   
 
[[Category:Plugins]]
 
[[Category:Plugins]]

Latest revision as of 21:11, 29 August 2019

Introduction

Usually, plugin and theme authors need to provide access to a settings (options) screen so users can customize how the plugin or theme is used. The best way to present the user with such a screen is to create an administration menu item that allows the user to access that settings screen from all the Administration Screens. This article explains how plugin authors can add administration menus and screens. Note: the following information assumes a knowledge of the basics of Writing a Plugin and using the Plugin API of Actions and Filters.

Function Reference

General Functions

Menu Pages

SubMenu Pages

WordPress Administration Menus

Every Plot Needs a Hook

To add an administration menu, you must do three things:

  1. Create a function that contains the menu-building code
  2. Register the above function using the admin_menu action hook. (If you are adding an admin menu for the Network, use network_admin_menu instead).
  3. Create the HTML output for the page (screen) displayed when the menu item is clicked

It is that second step that is often overlooked by new developers. You cannot simply call the menu code described; you must put it inside a function, and then register the function.

Here is a very simple example of the three steps just described. This plugin will add a sub-level menu item under the Settings top-level menu in Administration Screens, and when selected, that menu item will cause a very basic screen to display. Note: this code should be added to a main plugin PHP file or a separate PHP include file.

<?php
/** Step 2 (from text above). */
add_action( 'admin_menu', 'my_plugin_menu' );

/** Step 1. */
function my_plugin_menu() {
	add_options_page( 'My Plugin Options', 'My Plugin', 'manage_options', 'my-unique-identifier', 'my_plugin_options' );
}

/** Step 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>';
}
?>

In this example, the function my_plugin_menu() adds a new item to the Settings administration menu via the add_options_page() function. Note: more complicated multiple menu items can be added, but that will be described later. Notice the add_action() call in Step 2 that registers the my_plugin_menu() function under the admin_menu hook. Without that add_action() call, a PHP error for undefined function will be thrown when attempting to activate the plugin. Finally, the add_options_page() call refers to the my_plugin_options() function which contains the actual page to be displayed (and PHP code to be processed) when someone clicks the menu item.

These processes are described in more detail in the sections below. Remember to enclose the creation of the menu and the page in functions, and use the admin_menu hook to get the whole process started at the right time!

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 posts (time oriented content).
Media 
Uploading and managing your pictures, videos, and audio.
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)

Admin Menu Functions

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.

Top-Level Menus

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-Level 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 page 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 page content.
function
The function that displays the page 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 menu_slug 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.

Sub-Level Menus

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.

Using 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 Pages: add_submenu_page('edit.php?post_type=page',...)
  5. For Comments: add_submenu_page('edit-comments.php',...)
  6. For Custom Post Types: add_submenu_page('edit.php?post_type=your_post_type',...)
  7. For Appearance: add_submenu_page('themes.php',...)
  8. For Plugins: add_submenu_page('plugins.php',...)
  9. For Users: add_submenu_page('users.php',...)
  10. For Tools: add_submenu_page('tools.php',...)
  11. For Settings: add_submenu_page('options-general.php',...)
page_title 
Text that will go into the HTML page title for the page when the submenu is active.
menu_title 
The text to be displayed in the title tags of the page 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 page 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 page 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 menu_slug 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 page and a sub-menu page, where the title on the sub-menu page 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 page under a custom post 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 Administration Screens 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); ?>

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 page content for the Test Settings submenu
function mt_settings_page() {
    echo "<h2>" . __( 'Test Settings', 'menu-test' ) . "</h2>";
}

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

// mt_toplevel_page() displays the page content for the custom Test Toplevel menu
function mt_toplevel_page() {
    echo "<h2>" . __( 'Test Toplevel', 'menu-test' ) . "</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', 'menu-test' ) . "</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 Sublevel2', 'menu-test' ) . "</h2>";
}

?>

Sample Menu Page

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 page 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 page 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 a "settings saved" 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 page 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 page 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.

Page 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 page 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 page 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 page 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 page is loaded
	add_action( 'load-' . $hook_suffix , 'my_load_function' );
}

function my_load_function() {
	// Current admin page is the options page 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