foreach ( array_keys( (array) $submenu ) as $parent_page ) {
foreach ( $submenu[ $parent_page ] as $submenu_array ) {
if ( isset( $_wp_real_parent_file[ $parent_page ] ) ) {
$parent_page = $_wp_real_parent_file[ $parent_page ];
if ( ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $submenu_array[2] ) {
$parent_file = $parent_page;
} elseif ( empty( $typenow ) && $pagenow === $submenu_array[2]
&& ( empty( $parent_file ) || ! str_contains( $parent_file, '?' ) )
$parent_file = $parent_page;
} elseif ( isset( $plugin_page ) && $plugin_page === $submenu_array[2] ) {
$parent_file = $parent_page;
if ( empty( $parent_file ) ) {
* Gets the title of the current admin page.
* @global string $title The title of the current screen.
* @global string $pagenow The filename of the current screen.
* @global string $typenow The post type of the current screen.
* @global string $plugin_page
* @return string The title of the current admin page.
function get_admin_page_title() {
global $title, $menu, $submenu, $pagenow, $typenow, $plugin_page;
if ( ! empty( $title ) ) {
$hook = get_plugin_page_hook( $plugin_page, $pagenow );
$parent = get_admin_page_parent();
if ( empty( $parent ) ) {
foreach ( (array) $menu as $menu_array ) {
if ( isset( $menu_array[3] ) ) {
if ( $menu_array[2] === $pagenow ) {
} elseif ( isset( $plugin_page ) && $plugin_page === $menu_array[2] && $hook === $menu_array[5] ) {
foreach ( array_keys( $submenu ) as $parent ) {
foreach ( $submenu[ $parent ] as $submenu_array ) {
if ( isset( $plugin_page )
&& $plugin_page === $submenu_array[2]
&& ( $pagenow === $parent
|| $plugin_page === $parent
|| $plugin_page === $hook
|| 'admin.php' === $pagenow && $parent1 !== $submenu_array[2]
|| ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $parent )
$title = $submenu_array[3];
return $submenu_array[3];
if ( $submenu_array[2] !== $pagenow || isset( $_GET['page'] ) ) { // Not the current page.
if ( isset( $submenu_array[3] ) ) {
$title = $submenu_array[3];
return $submenu_array[3];
$title = $submenu_array[0];
foreach ( $menu as $menu_array ) {
if ( isset( $plugin_page )
&& $plugin_page === $menu_array[2]
&& 'admin.php' === $pagenow
&& $parent1 === $menu_array[2]
* Gets the hook attached to the administrative page of a plugin.
* @param string $plugin_page The slug name of the plugin page.
* @param string $parent_page The slug name for the parent menu (or the file name of a standard
* @return string|null Hook attached to the plugin page, null otherwise.
function get_plugin_page_hook( $plugin_page, $parent_page ) {
$hook = get_plugin_page_hookname( $plugin_page, $parent_page );
if ( has_action( $hook ) ) {
* Gets the hook name for the administrative page of a plugin.
* @global array $admin_page_hooks
* @param string $plugin_page The slug name of the plugin page.
* @param string $parent_page The slug name for the parent menu (or the file name of a standard
* @return string Hook name for the plugin page.
function get_plugin_page_hookname( $plugin_page, $parent_page ) {
global $admin_page_hooks;
$parent = get_admin_page_parent( $parent_page );
if ( empty( $parent_page ) || 'admin.php' === $parent_page || isset( $admin_page_hooks[ $plugin_page ] ) ) {
if ( isset( $admin_page_hooks[ $plugin_page ] ) ) {
} elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
$page_type = $admin_page_hooks[ $parent ];
} elseif ( isset( $admin_page_hooks[ $parent ] ) ) {
$page_type = $admin_page_hooks[ $parent ];
$plugin_name = preg_replace( '!\.php!', '', $plugin_page );
return $page_type . '_page_' . $plugin_name;
* Determines whether the current user can access the current admin page.
* @global string $pagenow The filename of the current screen.
* @global array $_wp_menu_nopriv
* @global array $_wp_submenu_nopriv
* @global string $plugin_page
* @global array $_registered_pages
* @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;
$parent = get_admin_page_parent();
if ( ! isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $parent ][ $pagenow ] ) ) {
if ( isset( $plugin_page ) ) {
if ( isset( $_wp_submenu_nopriv[ $parent ][ $plugin_page ] ) ) {
$hookname = get_plugin_page_hookname( $plugin_page, $parent );
if ( ! isset( $_registered_pages[ $hookname ] ) ) {
if ( empty( $parent ) ) {
if ( isset( $_wp_menu_nopriv[ $pagenow ] ) ) {
if ( isset( $_wp_submenu_nopriv[ $pagenow ][ $pagenow ] ) ) {
if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) {
if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) {
if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) {
if ( isset( $plugin_page ) && $plugin_page === $parent && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
if ( isset( $submenu[ $parent ] ) ) {
foreach ( $submenu[ $parent ] as $submenu_array ) {
if ( isset( $plugin_page ) && $submenu_array[2] === $plugin_page ) {
return current_user_can( $submenu_array[1] );
} elseif ( $submenu_array[2] === $pagenow ) {
return current_user_can( $submenu_array[1] );
foreach ( $menu as $menu_array ) {
if ( $menu_array[2] === $parent ) {
return current_user_can( $menu_array[1] );
/* Allowed list functions */
* Refreshes the value of the allowed options list available via the 'allowed_options' hook.
* See the {@see 'allowed_options'} filter.
* @since 5.5.0 `$new_whitelist_options` was renamed to `$new_allowed_options`.
* Please consider writing more inclusive code.
* @global array $new_allowed_options
function option_update_filter( $options ) {
global $new_allowed_options;
if ( is_array( $new_allowed_options ) ) {
$options = add_allowed_options( $new_allowed_options, $options );
* Adds an array of options to the list of allowed options.
* @global array $allowed_options
* @param array $new_options
* @param string|array $options
function add_allowed_options( $new_options, $options = '' ) {
$allowed_options = $options;
foreach ( $new_options as $page => $keys ) {
foreach ( $keys as $key ) {
if ( ! isset( $allowed_options[ $page ] ) || ! is_array( $allowed_options[ $page ] ) ) {
$allowed_options[ $page ] = array();
$allowed_options[ $page ][] = $key;
$pos = array_search( $key, $allowed_options[ $page ], true );
$allowed_options[ $page ][] = $key;
* Removes a list of options from the allowed options list.
* @global array $allowed_options
* @param array $del_options
* @param string|array $options
function remove_allowed_options( $del_options, $options = '' ) {
$allowed_options = $options;
foreach ( $del_options as $page => $keys ) {
foreach ( $keys as $key ) {
if ( isset( $allowed_options[ $page ] ) && is_array( $allowed_options[ $page ] ) ) {
$pos = array_search( $key, $allowed_options[ $page ], true );
unset( $allowed_options[ $page ][ $pos ] );
* Outputs nonce, action, and option_page fields for a settings page.
* @param string $option_group A settings group name. This should match the group name
* used in register_setting().
function settings_fields( $option_group ) {
echo "<input type='hidden' name='option_page' value='" . esc_attr( $option_group ) . "' />";
echo '<input type="hidden" name="action" value="update" />';
wp_nonce_field( "$option_group-options" );
* Clears the plugins cache used by get_plugins() and by default, the plugin updates cache.
* @param bool $clear_update_cache Whether to clear the plugin updates cache. Default true.
function wp_clean_plugins_cache( $clear_update_cache = true ) {
if ( $clear_update_cache ) {
delete_site_transient( 'update_plugins' );
wp_cache_delete( 'plugins', 'plugins' );
* Loads a given plugin attempt to generate errors.
* @since 4.4.0 Function was moved into the `wp-admin/includes/plugin.php` file.
* @param string $plugin Path to the plugin file relative to the plugins directory.
function plugin_sandbox_scrape( $plugin ) {
if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
define( 'WP_SANDBOX_SCRAPING', true );
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
include_once WP_PLUGIN_DIR . '/' . $plugin;
* Declares a helper function for adding content to the Privacy Policy Guide.
* Plugins and themes should suggest text for inclusion in the site's privacy policy.
* The suggested text should contain information about any functionality that affects user privacy,
* and will be shown on the Privacy Policy Guide screen.
* A plugin or theme can use this function multiple times as long as it will help to better present
* the suggested policy content. For example modular plugins such as WooCommerse or Jetpack
* can add or remove suggested content depending on the modules/extensions that are enabled.
* For more information see the Plugin Handbook:
* https://developer.wordpress.org/plugins/privacy/suggesting-text-for-the-site-privacy-policy/.
* The HTML contents of the `$policy_text` supports use of a specialized `.privacy-policy-tutorial`
* CSS class which can be used to provide supplemental information. Any content contained within
* HTML elements that have the `.privacy-policy-tutorial` CSS class applied will be omitted
* from the clipboard when the section content is copied.
* Intended for use with the `'admin_init'` action.
* @param string $plugin_name The name of the plugin or theme that is suggesting content
* for the site's privacy policy.
* @param string $policy_text The suggested content for inclusion in the policy.
function wp_add_privacy_policy_content( $plugin_name, $policy_text ) {
/* translators: %s: admin_init */
__( 'The suggested privacy policy content should be added only in wp-admin by using the %s (or later) action.' ),
'<code>admin_init</code>'
} elseif ( ! doing_action( 'admin_init' ) && ! did_action( 'admin_init' ) ) {
/* translators: %s: admin_init */
__( 'The suggested privacy policy content should be added by using the %s (or later) action. Please see the inline documentation.' ),
'<code>admin_init</code>'
if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php';
WP_Privacy_Policy_Content::add( $plugin_name, $policy_text );
* Determines whether a plugin is technically active but was paused while
* For more information on this and similar theme functions, check out
* the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
* Conditional Tags} article in the Theme Developer Handbook.
* @global WP_Paused_Extensions_Storage $_paused_plugins
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return bool True, if in the list of paused plugins. False, if not in the list.
function is_plugin_paused( $plugin ) {
if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
if ( ! is_plugin_active( $plugin ) ) {
list( $plugin ) = explode( '/', $plugin );
return array_key_exists( $plugin, $GLOBALS['_paused_plugins'] );
* Gets the error that was recorded for a paused plugin.
* @global WP_Paused_Extensions_Storage $_paused_plugins
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return array|false Array of error information as returned by `error_get_last()`,
* or false if none was recorded.
function wp_get_plugin_error( $plugin ) {
if ( ! isset( $GLOBALS['_paused_plugins'] ) ) {
list( $plugin ) = explode( '/', $plugin );
if ( ! array_key_exists( $plugin, $GLOBALS['_paused_plugins'] ) ) {
return $GLOBALS['_paused_plugins'][ $plugin ];