How to Get URLs for WordPress Admin Menu Items

Get WordPress admin menu item URL'sRecently, we were working on a project in which we needed a reliable way to get URL’s for WordPress admin menu items (Dashboard, Posts, Plugins, Tools, etc). Despite our best searching efforts, we simply could not find an answer – seemingly no existing function to accomplish this task. So we ended up digging into menu-header.php, the file that generates WordPress admin menu, and creating a function of our own.

get_admin_menu_item_url() retrieves a URL based on an admin menu item’s associated “file”:

/**
 * Get the URL of an admin menu item
 *
 * @param   string $menu_item_file admin menu item file
 *          - can be obtained via array key #2 for any item in the global $menu or $submenu array
 * @param   boolean $submenu_as_parent
 * 
 * @return  string URL of admin menu item, NULL if the menu item file can't be found in $menu or $submenu 
 */
function get_admin_menu_item_url( $menu_item_file, $submenu_as_parent = true ) {
	global $menu, $submenu, $self, $parent_file, $submenu_file, $plugin_page, $typenow;

	$admin_is_parent = false;
	$item = '';
	$submenu_item = '';
	$url = '';

	// 1. Check if top-level menu item
	foreach( $menu as $key => $menu_item ) {
		if ( array_keys( $menu_item, $menu_item_file, true ) ) {
			$item = $menu[ $key ];
		}

		if ( $submenu_as_parent && ! empty( $submenu_item ) ) {
			$menu_hook = get_plugin_page_hook( $submenu_item[2], $item[2] );
			$menu_file = $submenu_item[2];

			if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
				$menu_file = substr( $menu_file, 0, $pos );
			if ( ! empty( $menu_hook ) || ( ( 'index.php' != $submenu_item[2] ) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! file_exists( ABSPATH . "/wp-admin/$menu_file" ) ) ) {
				$admin_is_parent = true;
				$url = 'admin.php?page=' . $submenu_item[2];
			} else {
				$url = $submenu_item[2];
			}
		}

		elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) {
			$menu_hook = get_plugin_page_hook( $item[2], 'admin.php' );
			$menu_file = $item[2];

			if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
				$menu_file = substr( $menu_file, 0, $pos );
			if ( ! empty( $menu_hook ) || ( ( 'index.php' != $item[2] ) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! file_exists( ABSPATH . "/wp-admin/$menu_file" ) ) ) {
				$admin_is_parent = true;
				$url = 'admin.php?page=' . $item[2];
			} else {
				$url = $item[2];
			}
		}
	}

	// 2. Check if sub-level menu item
	if ( ! $item ) {
		$sub_item = '';
		foreach( $submenu as $top_file => $submenu_items ) {

			// Reindex $submenu_items
			$submenu_items = array_values( $submenu_items );

			foreach( $submenu_items as $key => $submenu_item ) {
				if ( array_keys( $submenu_item, $menu_item_file ) ) {
					$sub_item = $submenu_items[ $key ];
					break;
				}
			}					

			if ( ! empty( $sub_item ) )
				break;
		}

		// Get top-level parent item
		foreach( $menu as $key => $menu_item ) {
			if ( array_keys( $menu_item, $top_file, true ) ) {
				$item = $menu[ $key ];
				break;
			}
		}

		// If the $menu_item_file parameter doesn't match any menu item, return false
		if ( ! $sub_item )
			return false;

		// Get URL
		$menu_file = $item[2];

		if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
			$menu_file = substr( $menu_file, 0, $pos );

		// Handle current for post_type=post|page|foo pages, which won't match $self.
		$self_type = ! empty( $typenow ) ? $self . '?post_type=' . $typenow : 'nothing';
		$menu_hook = get_plugin_page_hook( $sub_item[2], $item[2] );

		$sub_file = $sub_item[2];
		if ( false !== ( $pos = strpos( $sub_file, '?' ) ) )
			$sub_file = substr($sub_file, 0, $pos);

		if ( ! empty( $menu_hook ) || ( ( 'index.php' != $sub_item[2] ) && file_exists( WP_PLUGIN_DIR . "/$sub_file" ) && ! file_exists( ABSPATH . "/wp-admin/$sub_file" ) ) ) {
			// If admin.php is the current page or if the parent exists as a file in the plugins or admin dir
			if ( ( ! $admin_is_parent && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! is_dir( WP_PLUGIN_DIR . "/{$item[2]}" ) ) || file_exists( $menu_file ) )
				$url = add_query_arg( array( 'page' => $sub_item[2] ), $item[2] );
			else
				$url = add_query_arg( array( 'page' => $sub_item[2] ), 'admin.php' );
		} else {
			$url = $sub_item[2];
		}
	}

	return esc_url( $url );

}

 Usage

To use get_admin_menu_item_url(), you first need to figure out the “file” that corresponds to the menu item you’re interested in. This file name can be found by accessing items in the global $menu and $submenu arrays – which hold the top- and sub-level admin menu items. Each of these items is an array with the following key/value pairs:

0 – name
1 – capability
2 – file
3 – class
4 – id
5 – icon source

What we’re interested in is the file, which is the unique identifier that will allow us to retrieve the menu item’s URL. So when all is said and done, your code might look like this:

global $menu;

foreach ( $menu as $item ) {

	// Get name of menu item
	$name = $item[0];

	// Get dashboard item file
	$file = $item[2];

	// Get URL for item
	$url = get_admin_menu_item_url( $file );

	echo "$name: $url<br />";

}

 

Leave a Comment

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

%d bloggers like this: