Plugin Development: How to Add Custom Menu Items to the WordPress Admin Settings

Organized Desk Items
Order Amongst Chaos

As a plugin author, you will inevitably run into the situation of where to place your admin menu items. Fortunately, there are many different options when it comes to placing your settings. Let’s go over some common locations, and I’ll show you how to get styles and scripts loaded as well.

Initializing the admin options

To add an admin menu, you’ll want to take advantage of the admin_menu WordPress action. From there, you can use a variety of methods to add your admin panel settings.

<?php

/**
 * Add menus to the WordPress admin.
 */

function my_prefix_add_admin_menus() {
	// Register admin code here.
}
add_action( 'admin_menu', 'my_prefix_add_admin_menus' );Code language: PHP (php)

Let’s go over the several locations where you can place your admin menu items.

Adding a top-level menu item

Top-level menus provide the means to add a prominent sidebar menu item in the WordPress admin. For example, prominent Core top-level menus include Comments, Tools, Settings, and Plugins.

A tongue-in-cheek flowchart.
Decisions…

The majority of plugins I’ve encountered live under the Settings menu item, also known as options-general.php. This is also where your plugin would live if you choose to use the Settings API, for example.

Sample Settings Menu Items
Sample Settings Menu Items

The problem comes down to space and a huge amount of choices. You want your admin found quickly, which is understandable. But in the admin as a top-level item, it’s often difficult to spot, especially as many other plugins add top-level menu items too.

A screenshot of a WordPress dashboard with a ton of top-level menu items.
Example of Numerous Top Menu Items

As more and more plugins add top-level items, the result is a lot of menu items, which nullifies any factor of importance or order.

If everything’s important, then nothing is important.

In addition to a clutter-full admin panel, people can be quite animated over what goes in their top-level menu items.

This is a modest proposal by Derek.
John minces no words about top-level menu items.
This fella has issues.

With all that being said, let’s go over how to create that top-level item.

Let’s add a menu to our callback using WordPress function add_menu_page.

<?php

/**
 * Add menus to the WordPress admin.
 */

/**
 * Initialize the admin menus.
 */
function my_prefix_add_admin_menus() {
	add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top because why not) */
	);
}
add_action( 'admin_menu', 'my_prefix_add_admin_menus' );

/**
 * Callback function to render the menu page.
 */
function my_prefix_add_menu_page_callback() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'My Admin Menu', 'dlx-admin-menu' ); ?></h1>
		<p><?php esc_html_e( 'This is a custom admin menu page.', 'dlx-admin-menu' ); ?></p>
	</div>
	<?php
}Code language: PHP (php)

Let’s go over the arguments for add_menu_page.

  1. Page Title: This will be the title of the admin panel settings.
  2. Menu Title: This will be the menu item title.
  3. Capability: Determine what level of permissions are needed in order to access the menu.
  4. Menu Slug: A unique slug that should identify your admin menu item.
  5. A Callback: A callable callback is needed in order to output the menu in the admin.
  6. An Icon: A dashicon name, icon URL, or encoded SVG.
  7. A Position: Determine where and in what order your admin panel menu should appear. Setting a position of 99 would place the menu item toward the bottom.
The Top-Level Menu Item Shown in the Admin Sidebar
The Top-Level Menu Item Shown in the Admin Sidebar

Enqueueing scripts for your top-level menu item

You’ll inevitably run into the issue of needing scripts and styles for your admin panel. Fortunately, it’s fairly simple to make sure the scripts and styles load in the right place.

Let’s revisit the code for adding the top-level menu item.

function my_prefix_add_admin_menus() {
	add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top) */
	);
}Code language: PHP (php)

When you call add_menu_page, it returns a hook value, which represents your admin screen. Let’s modify the function slightly to capture this hook value.

function my_prefix_add_admin_menus() {
	$hook = add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top) */
	);
}Code language: PHP (php)

In this case, the hook value is: toplevel_page_dlx-admin-menu

You don’t have to go memorizing hook locations in order to load your scripts, but you can enqueue your scripts by referencing the hook and calling a variation of admin_print_scripts. In this case, it’ll be admin_print_scripts-{$hook}, where {$hook} is the value of the hook created with add_menu_page.

Normally admin_print_scripts is for outputting scripts directly, but you can also use this action to enqueue your scripts like normal as not all of the scripts have been printed at this point in execution. Let’s see how this looks in the code.

function my_prefix_add_admin_menus() {
	$hook = add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top) */
	);

	add_action( 'admin_print_scripts-' . $hook, 'my_prefix_add_my_scripts' );
}Code language: PHP (php)

I’m grabbing the $hook value and using it below in the add_action so that scripts will only load on the admin page that was added.

In the callback, my_prefix_add_my_scripts, you would enqueue the script as normal.

/**
 * Callback for the admin_print_scripts hook.
 */
function my_prefix_add_my_scripts() {
	wp_enqueue_script(
		'my-prefix-admin-script',
		plugin_dir_url( __FILE__ ) . 'myjs.js',
		array(),
		'1.0.0',
		false
	);
}Code language: PHP (php)

Another technique is to use admin_enqueue_scripts, which passes a $hook variable, which represents the current screen.

/**
 * Initialize the admin menus.
 */
function my_prefix_add_admin_menus() {
	$hook = add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top) */
	);
}
add_action( 'admin_menu', 'my_prefix_add_admin_menus' );
add_action( 'admin_enqueue_scripts', 'my_prefix_add_my_scripts' );

/**
 * Callback for the admin_print_scripts hook.
 *
 * @param string $hook The current admin page.
 */
function my_prefix_add_my_scripts( $hook ) {
	if ( 'toplevel_page_dlx-admin-menu' !== $hook ) {
		return;
	}
	wp_enqueue_script(
		'my-prefix-admin-script',
		plugin_dir_url( __FILE__ ) . 'myjs.js',
		array(),
		'1.0.0',
		false
	);
}Code language: PHP (php)

In this particular scenario, you’ll need to know what the hook value of your admin page is. This can be achieved easily by doing a var_dump of the $hook value when on your admin screen.

Let’s move on to other locations where you can add your admin panel options.

Adding a submenu to a top-level menu item

Now that we’ve gotten top-level menus out of the way, let’s go over how to add a submenu to a top-level item.

For the submenu, we’ll be using WordPress function add_submenu_page. In this example, we’ll be adding a submenu to our previously created top-level admin menu.

function my_prefix_add_admin_menus() {
	add_menu_page(
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu', /* Unique Menu slug */
		'my_prefix_add_menu_page_callback', /* Callback */
		'dashicons-admin-generic', /* Icon */
		1 /* Position 1 (very top) */
	);
	add_submenu_page(
		'dlx-admin-menu', /* Parent slug */
		esc_html__( 'DLX Admin Menu Subpage', 'dlx-admin-menu' ), /* Page title */
		esc_html__( 'DLX Admin Menu Subpage', 'dlx-admin-menu' ), /* Menu title */
		'manage_options', /* Capability */
		'dlx-admin-menu-subpage', /* Unique Menu slug */
		'my_prefix_add_submenu_page_callback' /* Callback */
	);
}
add_action( 'admin_menu', 'my_prefix_add_admin_menus' );Code language: PHP (php)

The arguments for add_submenu_page are broken down below:

  1. Parent Slug: This is the slug that the parent registered their admin menu with.
  2. Page Title: This will be the title of the admin panel settings.
  3. Menu Title: This will be the menu item title.
  4. Capability: Determine what level of permissions are needed in order to access the menu.
  5. Menu Slug: A unique slug that should identify your admin menu item.
  6. A Callback: A callable callback is needed in order to output the menu in the admin.
  7. A Position: Determine where and in what order your admin panel menu should appear. Setting a position of 99 would place the menu item on the bottom.

Here’s our new submenu admin item.

Admin Submenu Example
Admin Submenu Example

Another example is adding a submenu to an existing plugin. Let’s use WooCommerce as an example.

The slug for the WooCommerce admin menu is just “woocommerce.”

We can use this as a slug to add in our own WooCommerce submenu item.

<?php
/**
 * Add a submenu item to the post type menu.
 */
function my_prefix_add_woo_submenu() {
	add_submenu_page(
		'woocommerce',
		__( 'Taxes', 'my-prefix' ),
		__( 'Taxes', 'my-prefix' ),
		'manage_options',
		'my-woocommerce-taxes',
		'my_prefix_render_tax_settings'
	);
}
add_action( 'admin_menu', 'my_prefix_add_woo_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_tax_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Tax Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

Here’s how the new submenu item looks.

Taxes Submenu Added to WooCommerce Menu Item
Taxes Submenu Added to WooCommerce Menu Item

Adding a submenu to a post type

Say, for example, you have registered a post type using register_post_type.

<?php
function my_prefix_add_post_type() {
	register_post_type(
		'movies',
		array(
			'labels'       => array(
				'name'          => __( 'Movies', 'my-prefix' ),
				'singular_name' => __( 'Movie', 'my-prefix' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
		)
	);
}
add_action( 'init', 'my_prefix_add_post_type' );Code language: PHP (php)

In order to access your post type, you’d use the brand new “Movies” menu item that the post type creates.

Movies Post Type
Movies Post Type

In order to add a menu item to the post type, we’ll need to know the admin location. In this case, the location is wp-admin/edit.php?post_type=movies. We can use this location and make use of add_submenu_page to add in our menu.

/**
 * Add a submenu item to the post type menu.
 */
function my_prefix_add_post_type_submenu() {
	add_submenu_page(
		'edit.php?post_type=movies',
		__( 'Movie Settings', 'my-prefix' ),
		__( 'Settings', 'my-prefix' ),
		'manage_options',
		'movie-settings',
		'my_prefix_render_movie_settings'
	);
}
add_action( 'admin_menu', 'my_prefix_add_post_type_submenu' );
Code language: PHP (php)

We use the admin location of the post type as the “parent” slug. The result is a new submenu item under the Movies menu.

Submenu in a Post Type
Submenu in a Post Type

Here’s the full code for adding a submenu to a post type.

<?php
/**
 * Register the post type.
 */
function my_prefix_add_post_type() {
	register_post_type(
		'movies',
		array(
			'labels'       => array(
				'name'          => __( 'Movies', 'my-prefix' ),
				'singular_name' => __( 'Movie', 'my-prefix' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
		)
	);
}
add_action( 'init', 'my_prefix_add_post_type' );

/**
 * Add a submenu item to the post type menu.
 */
function my_prefix_add_post_type_submenu() {
	add_submenu_page(
		'edit.php?post_type=movies',
		__( 'Movie Settings', 'my-prefix' ),
		__( 'Settings', 'my-prefix' ),
		'manage_options',
		'movie-settings',
		'my_prefix_render_movie_settings'
	);
}
add_action( 'admin_menu', 'my_prefix_add_post_type_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_movie_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Movie Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

Adding a post type to an existing menu

In the scenario where you don’t want a post type to add a top-level menu, you can register it so that it’ll show up under a parent menu instead. Let’s add a post type called “Services”, which will go under the tools menu item.

<?php
/**
 * Register the post type.
 */
function my_prefix_add_post_type() {
	register_post_type(
		'services',
		array(
			'labels'       => array(
				'name'          => __( 'Services', 'my-prefix' ),
				'singular_name' => __( 'Service', 'my-prefix' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
			'show_in_menu' => 'tools.php',
		)
	);
}
add_action( 'init', 'my_prefix_add_post_type' );
Code language: HTML, XML (xml)

When using register_post_type, you can specify the menu it should go under using the show_in_menu argument. The show_in_menu argument can be a boolean (true or false) or can be a string where you can specify the parent slug. In this case, I’m using tools.php as the parent.

Add a Services Post Type under the Tools Menu
Add a Services Post Type under the Tools Menu

You can even nest a post type under an existing post type.

<?php
/**
 * Register the post type.
 */
function my_prefix_add_post_type() {
	register_post_type(
		'movies',
		array(
			'labels'       => array(
				'name'          => __( 'Movies', 'my-prefix' ),
				'singular_name' => __( 'Movie', 'my-prefix' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
		)
	);
	register_post_type(
		'actors',
		array(
			'labels'       => array(
				'name'          => __( 'Actors', 'my-prefix' ),
				'singular_name' => __( 'Actor', 'my-prefix' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
			'show_in_menu' => 'edit.php?post_type=movies',
		)
	);
}
add_action( 'init', 'my_prefix_add_post_type' );Code language: PHP (php)

I’ve created a post type named “Movies” and placed an “Actors” post type under the movies post type item.

Post Type Menu Within a Post Type Menu
Post Type Menu Within a Post Type Menu

Adding submenus to specific admin sections

You don’t always have to use add_submenu_page or add_menu_page to add in your menus. WordPress has several built-in functions, which allow you to create submenus in a specific section. Each one of these functions takes in the same arguments, which I’ll cover below.

  1. Page Title: This will be the title of the admin panel settings.
  2. Menu Title: This will be the menu item title.
  3. Capability: Determine what level of permissions are needed in order to access the menu.
  4. Menu Slug: A unique slug that should identify your admin menu item.
  5. A Callback: A callable callback is needed in order to output the menu in the admin.
  6. A Position: Determine where and in what order your admin panel menu should appear. Setting a position of 99 would place the menu item toward the bottom.

add_dashboard_page

If you’d like your menu item to show up under the Dashboard menu item, you can use add_dashboard_page.

Dashboard Menu Items
Dashboard Menu Items

Here’s some example code for adding a dashboard page.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_dashboard_page(
		__( 'My Dashboard Page', 'my-prefix' ),
		__( 'Dashboard Page', 'my-prefix' ),
		'manage_options',
		'my-dashboard-page',
		'my_prefix_render_dashboard_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_dashboard_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Dashboard Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_posts_page

Admin menus here will show up under the “Posts” menu item when using add_posts_page.

Launch With Words Under the Posts Menu Item
Launch With Words Under the Posts Menu Item

Here’s some code that’ll add in a posts menu item.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_posts_page(
		__( 'My Posts Page', 'my-prefix' ),
		__( 'Posts Page', 'my-prefix' ),
		'manage_options',
		'my-posts-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Post Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_media_page

Admin menus here will show up under the “Media” section when using add_media_page.

Menu Item under the Media Settings Menu
Menu Item under the Media Settings Menu

Here’s code that’ll add the menu item under Media.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_media_page(
		__( 'My Media Page', 'my-prefix' ),
		__( 'Media Page', 'my-prefix' ),
		'manage_options',
		'my-media-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Media Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_pages_page

Use add_pages_page to add a menu item under the “Pages” menu.

Pages Menu Item under Pages
Pages Menu Item under Pages

Here’s some example code:

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_pages_page(
		__( 'My Pages Page', 'my-prefix' ),
		__( 'Pages Page', 'my-prefix' ),
		'manage_options',
		'my-pages-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Page Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_comments_page

Use add_comments_page to add submenu items to the “Comments” menu item.

Comment Submenu Items
Comment Submenu Items

Here’s some code demonstrating adding a comments submenu item.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_comments_page(
		__( 'My Comments Page', 'my-prefix' ),
		__( 'Comments Page', 'my-prefix' ),
		'manage_options',
		'my-comments-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Comment Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_theme_page

Use add_theme_page to place a submenu item under the “Appearance” menu item.

Submenu Item in the Appearance Settings
Submenu Item in the Appearance Settings

Here’s some code demonstrating adding a theme page.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_theme_page(
		__( 'My Theme Page', 'my-prefix' ),
		__( 'Theme Page', 'my-prefix' ),
		'manage_options',
		'my-theme-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Theme Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_plugins_page

Use add_plugins_page to add a submenu item to the “Plugins” menu item.

Plugins Page Menu Items
Plugins Page Menu Items

Here’s some code demonstrating adding a “Plugins” submenu item.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_plugins_page(
		__( 'My Plugin Page', 'my-prefix' ),
		__( 'Plugin Page', 'my-prefix' ),
		'manage_options',
		'my-plugin-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Plugin Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_users_page

Use add_users_page to add a submenu item to the “Users” menu item.

Users Submenu Item
Users Submenu Item

Here’s some code demonstrating adding a user’s submenu item.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_users_page(
		__( 'My Users Page', 'my-prefix' ),
		__( 'Users Page', 'my-prefix' ),
		'manage_options',
		'my-users-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'User Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_management_page

Use add_management_page to add an item under the “Tools” menu item.

Add a Submenu Item Under the Tools Menu
Add a Submenu Item Under the Tools Menu

Here’s some code that adds a menu item to the Tools menu.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_management_page(
		__( 'My Tools Page', 'my-prefix' ),
		__( 'Tools Page', 'my-prefix' ),
		'manage_options',
		'my-tools-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Tools Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

add_options_page

Use add_options_page to add an item to the “Settings” menu item.

Add an Options Submenu Item in the Settings Menu
Add an Options Submenu Item in the Settings Menu

Here is some code to add to the “Settings” menu item.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_options_page(
		__( 'My Plugin Page', 'my-prefix' ),
		__( 'Plugin Page', 'my-prefix' ),
		'manage_options',
		'my-options-page',
		'my_prefix_render_settings',
		10
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Plugin Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

Adding your admin menu to multiple locations

Say, for example, you have a plugin that could go under the Posts menu, but also want it under the Settings menu since most people look there first for admin settings.

The admin settings, realistically, can only have one permanent location. But you can add another location and just set up a redirect to go to the permanent location.

First, let’s add the two menu items.

<?php
/**
 * Add a submenu item.
 */
function my_prefix_add_submenu() {
	add_posts_page(
		__( 'Launch With Words', 'launch-with-words' ),
		__( 'Launch With Words', 'launch-with-words' ),
		'manage_options',
		'launch-with-words',
		'my_prefix_render_settings',
		100
	);

	add_options_page(
		__( 'Launch With Words', 'launch-with-words' ),
		__( 'Launch With Words', 'launch-with-words' ),
		'manage_options',
		'launch-with-words-options',
		'__return_empty_string',
		100
	);
}
add_action( 'admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Plugin Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

This adds a menu item named “Launch With Words” to the Posts and Settings menus. The Settings page item’s callback returns an empty string, as this is the location we’d like to redirect.

Launch With Words under Posts and Settings
Launch With Words under Posts and Settings

Finally, you’d wire up a redirect to point to the Posts menu item.

/**
 * Redirects settings page to the post settings page.
 */
function my_prefix_redirect_posts_page() {
	if ( isset( $_GET['page'] ) && 'launch-with-words-options' === $_GET['page'] ) {
		wp_safe_redirect( admin_url( 'edit.php?page=launch-with-words') );
		exit;
	}
}
add_action( 'admin_init', 'my_prefix_redirect_posts_page' );Code language: PHP (php)

Adding menus to a multisite network

To add to a multisite network admin menu, you’d use action network_admin_menu instead of admin_menu. You’d want to make use of add_menu_page or add_submenu_page.

If using add_submenu_page, you can use the following as parents:

  • index.php (Dashboard)
  • sites.php (Sites menu)
  • users.php (Users menu)
  • themes.php (Themes menu)
  • plugins.php (Plugins menu)
  • settings.php (Settings menu)

Here’s an example of adding a submenu page in multisite:

<?php

/**
 * Add a submenu item to multisite.
 */
function my_prefix_add_submenu() {
	add_submenu_page(
		'settings.php', /* can be index.php, sites.php, users.php, themes.php, plugins.php, settings.php */
		__( 'Plugin Settings', 'my-prefix' ),
		__( 'Plugin Settings', 'my-prefix' ),
		'manage_network',
		'my-prefix-settings',
		'my_prefix_render_settings'
	);
}
add_action( 'network_admin_menu', 'my_prefix_add_submenu' );

/**
 * Callback function to render the movie settings page.
 */
function my_prefix_render_settings() {
	?>
	<div class="wrap">
		<h1><?php esc_html_e( 'Plugin Settings', 'my-prefix' ); ?></h1>
		<p>Settings</p>
	</div>
	<?php
}Code language: PHP (php)

Conclusion

Within this tutorial, I demonstrated how to add top-level menu items, sub-menu items, and also how to add menus to multisite.

If you have any questions, please leave a comment below and I’ll be sure to address it. Thank you for reading.

Like this tutorial? There's more like it. Subscribe today!

Name(Required)

Ronald Huereca
By: Ronald Huereca
Published On: on June 16, 2023

Ronald Huereca founded DLX Plugins in 2022 with the goal of providing deluxe plugins available for download. Find out more about DLX Plugins, check out some tutorials, and check out our plugins.

Leave Your Valuable Feedback

Your email address will not be published. Required fields are marked *

Shopping Cart
  • Your cart is empty.
Scroll to Top