diff --git a/src/wp-admin/includes/menu.php b/src/wp-admin/includes/menu.php index 3cf4a5fdd6c17..9e7f84250f2f6 100644 --- a/src/wp-admin/includes/menu.php +++ b/src/wp-admin/includes/menu.php @@ -368,7 +368,17 @@ function sort_menu( $a, $b ) { } unset( $last_menu_key ); -if ( ! user_can_access_admin_page() ) { +if ( ! admin_page_exists() ) { + + /** + * Fires when access to an admin page which does not exist. + * + * @since 7.0 + */ + do_action( 'admin_page_not_found' ); + + wp_die( __( 'The requested page does not exist.' ), 404 ); +} elseif ( ! user_can_access_admin_page() ) { /** * Fires when access to an admin page is denied. diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php index de1468352b3d9..8e3b7505c2821 100644 --- a/src/wp-admin/includes/plugin.php +++ b/src/wp-admin/includes/plugin.php @@ -2130,6 +2130,35 @@ function get_plugin_page_hook( $plugin_page, $parent_page ) { } } +/** + * Checks if admin page exists, if the user would have the required capabilities. + * + * @since 7.0.0 + * + * @global string $admin_page_parent The parent slug of the current admin page. + * @global string $plugin_page The plugin page slug being loaded. + * @global array $_registered_pages Array of all registered admin page hooks. + * + * @return bool True if the admin page exists, false otherwise. + */ +function admin_page_exists() { + global $admin_page_parent, $plugin_page, $_registered_pages; + + if ( ! isset( $admin_page_parent ) ) { + $admin_page_parent = get_admin_page_parent(); + } + + if ( isset( $plugin_page ) ) { + $hookname = get_plugin_page_hookname( $plugin_page, $admin_page_parent ); + + if ( ! isset( $_registered_pages[ $hookname ] ) ) { + return false; + } + } + + return true; +} + /** * Gets the hook name for the administrative page of a plugin. * @@ -2175,14 +2204,15 @@ function get_plugin_page_hookname( $plugin_page, $parent_page ) { * @global array $_wp_submenu_nopriv * @global string $plugin_page * @global array $_registered_pages + * @global string $admin_page_parent * * @return bool True if the current user can access the admin page, false otherwise. */ function user_can_access_admin_page() { global $pagenow, $menu, $submenu, $_wp_menu_nopriv, $_wp_submenu_nopriv, - $plugin_page, $_registered_pages; + $plugin_page, $_registered_pages, $admin_page_parent; - $parent = get_admin_page_parent(); + $parent = isset( $admin_page_parent ) ? $admin_page_parent : get_admin_page_parent(); if ( ! isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $parent ][ $pagenow ] ) ) { return false; @@ -2195,6 +2225,10 @@ function user_can_access_admin_page() { $hookname = get_plugin_page_hookname( $plugin_page, $parent ); + if ( ! admin_page_exists() ) { + return false; + } + if ( ! isset( $_registered_pages[ $hookname ] ) ) { return false; }