Recently, 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 />"; }