wp/wp-admin/includes/plugin.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    42  * the file. This is not checked however and the file is only opened for
    42  * the file. This is not checked however and the file is only opened for
    43  * reading.
    43  * reading.
    44  *
    44  *
    45  * @since 1.5.0
    45  * @since 1.5.0
    46  * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers.
    46  * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers.
       
    47  * @since 5.8.0 Added support for `Update URI` header.
    47  *
    48  *
    48  * @param string $plugin_file Absolute path to the main plugin file.
    49  * @param string $plugin_file Absolute path to the main plugin file.
    49  * @param bool   $markup      Optional. If the returned data should have HTML markup applied.
    50  * @param bool   $markup      Optional. If the returned data should have HTML markup applied.
    50  *                            Default true.
    51  *                            Default true.
    51  * @param bool   $translate   Optional. If the returned data should be translated. Default true.
    52  * @param bool   $translate   Optional. If the returned data should be translated. Default true.
    61  *     @type string $TextDomain  Plugin textdomain.
    62  *     @type string $TextDomain  Plugin textdomain.
    62  *     @type string $DomainPath  Plugins relative directory path to .mo files.
    63  *     @type string $DomainPath  Plugins relative directory path to .mo files.
    63  *     @type bool   $Network     Whether the plugin can only be activated network-wide.
    64  *     @type bool   $Network     Whether the plugin can only be activated network-wide.
    64  *     @type string $RequiresWP  Minimum required version of WordPress.
    65  *     @type string $RequiresWP  Minimum required version of WordPress.
    65  *     @type string $RequiresPHP Minimum required version of PHP.
    66  *     @type string $RequiresPHP Minimum required version of PHP.
       
    67  *     @type string $UpdateURI   ID of the plugin for update purposes, should be a URI.
    66  * }
    68  * }
    67  */
    69  */
    68 function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
    70 function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
    69 
    71 
    70 	$default_headers = array(
    72 	$default_headers = array(
    77 		'TextDomain'  => 'Text Domain',
    79 		'TextDomain'  => 'Text Domain',
    78 		'DomainPath'  => 'Domain Path',
    80 		'DomainPath'  => 'Domain Path',
    79 		'Network'     => 'Network',
    81 		'Network'     => 'Network',
    80 		'RequiresWP'  => 'Requires at least',
    82 		'RequiresWP'  => 'Requires at least',
    81 		'RequiresPHP' => 'Requires PHP',
    83 		'RequiresPHP' => 'Requires PHP',
       
    84 		'UpdateURI'   => 'Update URI',
    82 		// Site Wide Only is deprecated in favor of Network.
    85 		// Site Wide Only is deprecated in favor of Network.
    83 		'_sitewide'   => 'Site Wide Only',
    86 		'_sitewide'   => 'Site Wide Only',
    84 	);
    87 	);
    85 
    88 
    86 	$plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
    89 	$plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
   291 	if ( ! empty( $plugin_folder ) ) {
   294 	if ( ! empty( $plugin_folder ) ) {
   292 		$plugin_root .= $plugin_folder;
   295 		$plugin_root .= $plugin_folder;
   293 	}
   296 	}
   294 
   297 
   295 	// Files in wp-content/plugins directory.
   298 	// Files in wp-content/plugins directory.
   296 	$plugins_dir  = @ opendir( $plugin_root );
   299 	$plugins_dir  = @opendir( $plugin_root );
   297 	$plugin_files = array();
   300 	$plugin_files = array();
   298 
   301 
   299 	if ( $plugins_dir ) {
   302 	if ( $plugins_dir ) {
   300 		while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
   303 		while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
   301 			if ( '.' === substr( $file, 0, 1 ) ) {
   304 			if ( '.' === substr( $file, 0, 1 ) ) {
   302 				continue;
   305 				continue;
   303 			}
   306 			}
   304 
   307 
   305 			if ( is_dir( $plugin_root . '/' . $file ) ) {
   308 			if ( is_dir( $plugin_root . '/' . $file ) ) {
   306 				$plugins_subdir = @ opendir( $plugin_root . '/' . $file );
   309 				$plugins_subdir = @opendir( $plugin_root . '/' . $file );
   307 
   310 
   308 				if ( $plugins_subdir ) {
   311 				if ( $plugins_subdir ) {
   309 					while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) {
   312 					while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) {
   310 						if ( '.' === substr( $subfile, 0, 1 ) ) {
   313 						if ( '.' === substr( $subfile, 0, 1 ) ) {
   311 							continue;
   314 							continue;
   649 	$requirements = validate_plugin_requirements( $plugin );
   652 	$requirements = validate_plugin_requirements( $plugin );
   650 	if ( is_wp_error( $requirements ) ) {
   653 	if ( is_wp_error( $requirements ) ) {
   651 		return $requirements;
   654 		return $requirements;
   652 	}
   655 	}
   653 
   656 
   654 	if ( ( $network_wide && ! isset( $current[ $plugin ] ) ) || ( ! $network_wide && ! in_array( $plugin, $current, true ) ) ) {
   657 	if ( $network_wide && ! isset( $current[ $plugin ] )
       
   658 		|| ! $network_wide && ! in_array( $plugin, $current, true )
       
   659 	) {
   655 		if ( ! empty( $redirect ) ) {
   660 		if ( ! empty( $redirect ) ) {
   656 			// We'll override this later if the plugin can be included without fatal error.
   661 			// We'll override this later if the plugin can be included without fatal error.
   657 			wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
   662 			wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) );
   658 		}
   663 		}
   659 
   664 
   660 		ob_start();
   665 		ob_start();
   661 
   666 
   662 		if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
   667 		// Load the plugin to test whether it throws any errors.
   663 			define( 'WP_SANDBOX_SCRAPING', true );
   668 		plugin_sandbox_scrape( $plugin );
   664 		}
       
   665 
       
   666 		wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
       
   667 		$_wp_plugin_file = $plugin;
       
   668 		include_once WP_PLUGIN_DIR . '/' . $plugin;
       
   669 		$plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin.
       
   670 
   669 
   671 		if ( ! $silent ) {
   670 		if ( ! $silent ) {
   672 			/**
   671 			/**
   673 			 * Fires before a plugin is activated.
   672 			 * Fires before a plugin is activated.
   674 			 *
   673 			 *
   728 
   727 
   729 		if ( ob_get_length() > 0 ) {
   728 		if ( ob_get_length() > 0 ) {
   730 			$output = ob_get_clean();
   729 			$output = ob_get_clean();
   731 			return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
   730 			return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output );
   732 		}
   731 		}
       
   732 
   733 		ob_end_clean();
   733 		ob_end_clean();
   734 	}
   734 	}
   735 
   735 
   736 	return null;
   736 	return null;
   737 }
   737 }
   762 		$plugin = plugin_basename( trim( $plugin ) );
   762 		$plugin = plugin_basename( trim( $plugin ) );
   763 		if ( ! is_plugin_active( $plugin ) ) {
   763 		if ( ! is_plugin_active( $plugin ) ) {
   764 			continue;
   764 			continue;
   765 		}
   765 		}
   766 
   766 
   767 		$network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
   767 		$network_deactivating = ( false !== $network_wide ) && is_plugin_active_for_network( $plugin );
   768 
   768 
   769 		if ( ! $silent ) {
   769 		if ( ! $silent ) {
   770 			/**
   770 			/**
   771 			 * Fires before a plugin is deactivated.
   771 			 * Fires before a plugin is deactivated.
   772 			 *
   772 			 *
   976 
   976 
   977 		$this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );
   977 		$this_plugin_dir = trailingslashit( dirname( $plugins_dir . $plugin_file ) );
   978 
   978 
   979 		// If plugin is in its own directory, recursively delete the directory.
   979 		// If plugin is in its own directory, recursively delete the directory.
   980 		// Base check on if plugin includes directory separator AND that it's not the root plugin folder.
   980 		// Base check on if plugin includes directory separator AND that it's not the root plugin folder.
   981 		if ( strpos( $plugin_file, '/' ) && $this_plugin_dir != $plugins_dir ) {
   981 		if ( strpos( $plugin_file, '/' ) && $this_plugin_dir !== $plugins_dir ) {
   982 			$deleted = $wp_filesystem->delete( $this_plugin_dir, true );
   982 			$deleted = $wp_filesystem->delete( $this_plugin_dir, true );
   983 		} else {
   983 		} else {
   984 			$deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
   984 			$deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file );
   985 		}
   985 		}
   986 
   986 
   997 		if ( ! $deleted ) {
   997 		if ( ! $deleted ) {
   998 			$errors[] = $plugin_file;
   998 			$errors[] = $plugin_file;
   999 			continue;
   999 			continue;
  1000 		}
  1000 		}
  1001 
  1001 
       
  1002 		$plugin_slug = dirname( $plugin_file );
       
  1003 
       
  1004 		if ( 'hello.php' === $plugin_file ) {
       
  1005 			$plugin_slug = 'hello-dolly';
       
  1006 		}
       
  1007 
  1002 		// Remove language files, silently.
  1008 		// Remove language files, silently.
  1003 		$plugin_slug = dirname( $plugin_file );
       
  1004 		if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
  1009 		if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) {
  1005 			$translations = $plugin_translations[ $plugin_slug ];
  1010 			$translations = $plugin_translations[ $plugin_slug ];
  1006 
  1011 
  1007 			foreach ( $translations as $translation => $data ) {
  1012 			foreach ( $translations as $translation => $data ) {
  1008 				$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
  1013 				$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
  1112  * Validates the plugin requirements for WordPress version and PHP version.
  1117  * Validates the plugin requirements for WordPress version and PHP version.
  1113  *
  1118  *
  1114  * Uses the information from `Requires at least` and `Requires PHP` headers
  1119  * Uses the information from `Requires at least` and `Requires PHP` headers
  1115  * defined in the plugin's main PHP file.
  1120  * defined in the plugin's main PHP file.
  1116  *
  1121  *
  1117  * If the headers are not present in the plugin's main PHP file,
       
  1118  * `readme.txt` is also checked as a fallback.
       
  1119  *
       
  1120  * @since 5.2.0
  1122  * @since 5.2.0
  1121  * @since 5.3.0 Added support for reading the headers from the plugin's
  1123  * @since 5.3.0 Added support for reading the headers from the plugin's
  1122  *              main PHP file, with `readme.txt` as a fallback.
  1124  *              main PHP file, with `readme.txt` as a fallback.
       
  1125  * @since 5.8.0 Removed support for using `readme.txt` as a fallback.
  1123  *
  1126  *
  1124  * @param string $plugin Path to the plugin file relative to the plugins directory.
  1127  * @param string $plugin Path to the plugin file relative to the plugins directory.
  1125  * @return true|WP_Error True if requirements are met, WP_Error on failure.
  1128  * @return true|WP_Error True if requirements are met, WP_Error on failure.
  1126  */
  1129  */
  1127 function validate_plugin_requirements( $plugin ) {
  1130 function validate_plugin_requirements( $plugin ) {
  1130 	$requirements = array(
  1133 	$requirements = array(
  1131 		'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
  1134 		'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
  1132 		'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
  1135 		'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
  1133 	);
  1136 	);
  1134 
  1137 
  1135 	$readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt';
       
  1136 
       
  1137 	if ( file_exists( $readme_file ) ) {
       
  1138 		$readme_headers = get_file_data(
       
  1139 			$readme_file,
       
  1140 			array(
       
  1141 				'requires'     => 'Requires at least',
       
  1142 				'requires_php' => 'Requires PHP',
       
  1143 			),
       
  1144 			'plugin'
       
  1145 		);
       
  1146 
       
  1147 		$requirements = array_merge( $readme_headers, $requirements );
       
  1148 	}
       
  1149 
       
  1150 	$compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
  1138 	$compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
  1151 	$compatible_php = is_php_version_compatible( $requirements['requires_php'] );
  1139 	$compatible_php = is_php_version_compatible( $requirements['requires_php'] );
  1152 
  1140 
  1153 	/* translators: %s: URL to Update PHP page. */
       
  1154 	$php_update_message = '</p><p>' . sprintf(
  1141 	$php_update_message = '</p><p>' . sprintf(
       
  1142 		/* translators: %s: URL to Update PHP page. */
  1155 		__( '<a href="%s">Learn more about updating PHP</a>.' ),
  1143 		__( '<a href="%s">Learn more about updating PHP</a>.' ),
  1156 		esc_url( wp_get_update_php_url() )
  1144 		esc_url( wp_get_update_php_url() )
  1157 	);
  1145 	);
  1158 
  1146 
  1159 	$annotation = wp_get_update_php_annotation();
  1147 	$annotation = wp_get_update_php_annotation();
  1227  * Calls the uninstall hook, if it is available.
  1215  * Calls the uninstall hook, if it is available.
  1228  *
  1216  *
  1229  * @since 2.7.0
  1217  * @since 2.7.0
  1230  *
  1218  *
  1231  * @param string $plugin Path to the plugin file relative to the plugins directory.
  1219  * @param string $plugin Path to the plugin file relative to the plugins directory.
  1232  * @return true True if a plugin's uninstall.php file has been found and included.
  1220  * @return true|void True if a plugin's uninstall.php file has been found and included.
       
  1221  *                   Void otherwise.
  1233  */
  1222  */
  1234 function uninstall_plugin( $plugin ) {
  1223 function uninstall_plugin( $plugin ) {
  1235 	$file = plugin_basename( $plugin );
  1224 	$file = plugin_basename( $plugin );
  1236 
  1225 
  1237 	$uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
  1226 	$uninstallable_plugins = (array) get_option( 'uninstall_plugins' );
  1412 	 * If the parent doesn't already have a submenu, add a link to the parent
  1401 	 * If the parent doesn't already have a submenu, add a link to the parent
  1413 	 * as the first item in the submenu. If the submenu file is the same as the
  1402 	 * as the first item in the submenu. If the submenu file is the same as the
  1414 	 * parent file someone is trying to link back to the parent manually. In
  1403 	 * parent file someone is trying to link back to the parent manually. In
  1415 	 * this case, don't automatically add a link back to avoid duplication.
  1404 	 * this case, don't automatically add a link back to avoid duplication.
  1416 	 */
  1405 	 */
  1417 	if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug != $parent_slug ) {
  1406 	if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug !== $parent_slug ) {
  1418 		foreach ( (array) $menu as $parent_menu ) {
  1407 		foreach ( (array) $menu as $parent_menu ) {
  1419 			if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) {
  1408 			if ( $parent_menu[2] === $parent_slug && current_user_can( $parent_menu[1] ) ) {
  1420 				$submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 );
  1409 				$submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 );
  1421 			}
  1410 			}
  1422 		}
  1411 		}
  1423 	}
  1412 	}
  1424 
  1413 
  1759  * @since 3.1.0
  1748  * @since 3.1.0
  1760  *
  1749  *
  1761  * @global array $menu
  1750  * @global array $menu
  1762  *
  1751  *
  1763  * @param string $menu_slug The slug of the menu.
  1752  * @param string $menu_slug The slug of the menu.
  1764  * @return array|bool The removed menu on success, false if not found.
  1753  * @return array|false The removed menu on success, false if not found.
  1765  */
  1754  */
  1766 function remove_menu_page( $menu_slug ) {
  1755 function remove_menu_page( $menu_slug ) {
  1767 	global $menu;
  1756 	global $menu;
  1768 
  1757 
  1769 	foreach ( $menu as $i => $item ) {
  1758 	foreach ( $menu as $i => $item ) {
  1770 		if ( $menu_slug == $item[2] ) {
  1759 		if ( $menu_slug === $item[2] ) {
  1771 			unset( $menu[ $i ] );
  1760 			unset( $menu[ $i ] );
  1772 			return $item;
  1761 			return $item;
  1773 		}
  1762 		}
  1774 	}
  1763 	}
  1775 
  1764 
  1783  *
  1772  *
  1784  * @global array $submenu
  1773  * @global array $submenu
  1785  *
  1774  *
  1786  * @param string $menu_slug    The slug for the parent menu.
  1775  * @param string $menu_slug    The slug for the parent menu.
  1787  * @param string $submenu_slug The slug of the submenu.
  1776  * @param string $submenu_slug The slug of the submenu.
  1788  * @return array|bool The removed submenu on success, false if not found.
  1777  * @return array|false The removed submenu on success, false if not found.
  1789  */
  1778  */
  1790 function remove_submenu_page( $menu_slug, $submenu_slug ) {
  1779 function remove_submenu_page( $menu_slug, $submenu_slug ) {
  1791 	global $submenu;
  1780 	global $submenu;
  1792 
  1781 
  1793 	if ( ! isset( $submenu[ $menu_slug ] ) ) {
  1782 	if ( ! isset( $submenu[ $menu_slug ] ) ) {
  1794 		return false;
  1783 		return false;
  1795 	}
  1784 	}
  1796 
  1785 
  1797 	foreach ( $submenu[ $menu_slug ] as $i => $item ) {
  1786 	foreach ( $submenu[ $menu_slug ] as $i => $item ) {
  1798 		if ( $submenu_slug == $item[2] ) {
  1787 		if ( $submenu_slug === $item[2] ) {
  1799 			unset( $submenu[ $menu_slug ][ $i ] );
  1788 			unset( $submenu[ $menu_slug ][ $i ] );
  1800 			return $item;
  1789 			return $item;
  1801 		}
  1790 		}
  1802 	}
  1791 	}
  1803 
  1792 
  1820 function menu_page_url( $menu_slug, $echo = true ) {
  1809 function menu_page_url( $menu_slug, $echo = true ) {
  1821 	global $_parent_pages;
  1810 	global $_parent_pages;
  1822 
  1811 
  1823 	if ( isset( $_parent_pages[ $menu_slug ] ) ) {
  1812 	if ( isset( $_parent_pages[ $menu_slug ] ) ) {
  1824 		$parent_slug = $_parent_pages[ $menu_slug ];
  1813 		$parent_slug = $_parent_pages[ $menu_slug ];
       
  1814 
  1825 		if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) {
  1815 		if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) {
  1826 			$url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
  1816 			$url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
  1827 		} else {
  1817 		} else {
  1828 			$url = admin_url( 'admin.php?page=' . $menu_slug );
  1818 			$url = admin_url( 'admin.php?page=' . $menu_slug );
  1829 		}
  1819 		}
  1868 
  1858 
  1869 	if ( ! empty( $parent ) && 'admin.php' !== $parent ) {
  1859 	if ( ! empty( $parent ) && 'admin.php' !== $parent ) {
  1870 		if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
  1860 		if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
  1871 			$parent = $_wp_real_parent_file[ $parent ];
  1861 			$parent = $_wp_real_parent_file[ $parent ];
  1872 		}
  1862 		}
       
  1863 
  1873 		return $parent;
  1864 		return $parent;
  1874 	}
  1865 	}
  1875 
  1866 
  1876 	if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) {
  1867 	if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) {
  1877 		foreach ( (array) $menu as $parent_menu ) {
  1868 		foreach ( (array) $menu as $parent_menu ) {
  1878 			if ( $parent_menu[2] == $plugin_page ) {
  1869 			if ( $parent_menu[2] === $plugin_page ) {
  1879 				$parent_file = $plugin_page;
  1870 				$parent_file = $plugin_page;
       
  1871 
  1880 				if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1872 				if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1881 					$parent_file = $_wp_real_parent_file[ $parent_file ];
  1873 					$parent_file = $_wp_real_parent_file[ $parent_file ];
  1882 				}
  1874 				}
       
  1875 
  1883 				return $parent_file;
  1876 				return $parent_file;
  1884 			}
  1877 			}
  1885 		}
  1878 		}
  1886 		if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  1879 		if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  1887 			$parent_file = $plugin_page;
  1880 			$parent_file = $plugin_page;
       
  1881 
  1888 			if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1882 			if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1889 					$parent_file = $_wp_real_parent_file[ $parent_file ];
  1883 					$parent_file = $_wp_real_parent_file[ $parent_file ];
  1890 			}
  1884 			}
       
  1885 
  1891 			return $parent_file;
  1886 			return $parent_file;
  1892 		}
  1887 		}
  1893 	}
  1888 	}
  1894 
  1889 
  1895 	if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
  1890 	if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) {
  1896 		$parent_file = $pagenow;
  1891 		$parent_file = $pagenow;
       
  1892 
  1897 		if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1893 		if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) {
  1898 			$parent_file = $_wp_real_parent_file[ $parent_file ];
  1894 			$parent_file = $_wp_real_parent_file[ $parent_file ];
  1899 		}
  1895 		}
       
  1896 
  1900 		return $parent_file;
  1897 		return $parent_file;
  1901 	}
  1898 	}
  1902 
  1899 
  1903 	foreach ( array_keys( (array) $submenu ) as $parent ) {
  1900 	foreach ( array_keys( (array) $submenu ) as $parent ) {
  1904 		foreach ( $submenu[ $parent ] as $submenu_array ) {
  1901 		foreach ( $submenu[ $parent ] as $submenu_array ) {
  1905 			if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
  1902 			if ( isset( $_wp_real_parent_file[ $parent ] ) ) {
  1906 				$parent = $_wp_real_parent_file[ $parent ];
  1903 				$parent = $_wp_real_parent_file[ $parent ];
  1907 			}
  1904 			}
  1908 			if ( ! empty( $typenow ) && ( "$pagenow?post_type=$typenow" === $submenu_array[2] ) ) {
  1905 
       
  1906 			if ( ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $submenu_array[2] ) {
  1909 				$parent_file = $parent;
  1907 				$parent_file = $parent;
  1910 				return $parent;
  1908 				return $parent;
  1911 			} elseif ( $submenu_array[2] == $pagenow && empty( $typenow ) && ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) ) ) {
  1909 			} elseif ( empty( $typenow ) && $pagenow === $submenu_array[2]
       
  1910 				&& ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) )
       
  1911 			) {
  1912 				$parent_file = $parent;
  1912 				$parent_file = $parent;
  1913 				return $parent;
  1913 				return $parent;
  1914 			} elseif ( isset( $plugin_page ) && ( $plugin_page == $submenu_array[2] ) ) {
  1914 			} elseif ( isset( $plugin_page ) && $plugin_page === $submenu_array[2] ) {
  1915 				$parent_file = $parent;
  1915 				$parent_file = $parent;
  1916 				return $parent;
  1916 				return $parent;
  1917 			}
  1917 			}
  1918 		}
  1918 		}
  1919 	}
  1919 	}
  1951 	$parent1 = $parent;
  1951 	$parent1 = $parent;
  1952 
  1952 
  1953 	if ( empty( $parent ) ) {
  1953 	if ( empty( $parent ) ) {
  1954 		foreach ( (array) $menu as $menu_array ) {
  1954 		foreach ( (array) $menu as $menu_array ) {
  1955 			if ( isset( $menu_array[3] ) ) {
  1955 			if ( isset( $menu_array[3] ) ) {
  1956 				if ( $menu_array[2] == $pagenow ) {
  1956 				if ( $menu_array[2] === $pagenow ) {
  1957 					$title = $menu_array[3];
  1957 					$title = $menu_array[3];
  1958 					return $menu_array[3];
  1958 					return $menu_array[3];
  1959 				} elseif ( isset( $plugin_page ) && ( $plugin_page == $menu_array[2] ) && ( $hook == $menu_array[5] ) ) {
  1959 				} elseif ( isset( $plugin_page ) && $plugin_page === $menu_array[2] && $hook === $menu_array[5] ) {
  1960 					$title = $menu_array[3];
  1960 					$title = $menu_array[3];
  1961 					return $menu_array[3];
  1961 					return $menu_array[3];
  1962 				}
  1962 				}
  1963 			} else {
  1963 			} else {
  1964 				$title = $menu_array[0];
  1964 				$title = $menu_array[0];
  1966 			}
  1966 			}
  1967 		}
  1967 		}
  1968 	} else {
  1968 	} else {
  1969 		foreach ( array_keys( $submenu ) as $parent ) {
  1969 		foreach ( array_keys( $submenu ) as $parent ) {
  1970 			foreach ( $submenu[ $parent ] as $submenu_array ) {
  1970 			foreach ( $submenu[ $parent ] as $submenu_array ) {
  1971 				if ( isset( $plugin_page ) &&
  1971 				if ( isset( $plugin_page )
  1972 					( $plugin_page == $submenu_array[2] ) &&
  1972 					&& $plugin_page === $submenu_array[2]
  1973 					(
  1973 					&& ( $pagenow === $parent
  1974 						( $parent == $pagenow ) ||
  1974 						|| $plugin_page === $parent
  1975 						( $parent == $plugin_page ) ||
  1975 						|| $plugin_page === $hook
  1976 						( $plugin_page == $hook ) ||
  1976 						|| 'admin.php' === $pagenow && $parent1 !== $submenu_array[2]
  1977 						( 'admin.php' === $pagenow && $parent1 != $submenu_array[2] ) ||
  1977 						|| ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $parent )
  1978 						( ! empty( $typenow ) && $parent == $pagenow . '?post_type=' . $typenow )
       
  1979 					)
       
  1980 					) {
  1978 					) {
  1981 						$title = $submenu_array[3];
  1979 						$title = $submenu_array[3];
  1982 						return $submenu_array[3];
  1980 						return $submenu_array[3];
  1983 				}
  1981 				}
  1984 
  1982 
  1985 				if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) { // Not the current page.
  1983 				if ( $submenu_array[2] !== $pagenow || isset( $_GET['page'] ) ) { // Not the current page.
  1986 					continue;
  1984 					continue;
  1987 				}
  1985 				}
  1988 
  1986 
  1989 				if ( isset( $submenu_array[3] ) ) {
  1987 				if ( isset( $submenu_array[3] ) ) {
  1990 					$title = $submenu_array[3];
  1988 					$title = $submenu_array[3];
  1995 				}
  1993 				}
  1996 			}
  1994 			}
  1997 		}
  1995 		}
  1998 		if ( empty( $title ) ) {
  1996 		if ( empty( $title ) ) {
  1999 			foreach ( $menu as $menu_array ) {
  1997 			foreach ( $menu as $menu_array ) {
  2000 				if ( isset( $plugin_page ) &&
  1998 				if ( isset( $plugin_page )
  2001 					( $plugin_page == $menu_array[2] ) &&
  1999 					&& $plugin_page === $menu_array[2]
  2002 					( 'admin.php' === $pagenow ) &&
  2000 					&& 'admin.php' === $pagenow
  2003 					( $parent1 == $menu_array[2] ) ) {
  2001 					&& $parent1 === $menu_array[2]
       
  2002 				) {
  2004 						$title = $menu_array[3];
  2003 						$title = $menu_array[3];
  2005 						return $menu_array[3];
  2004 						return $menu_array[3];
  2006 				}
  2005 				}
  2007 			}
  2006 			}
  2008 		}
  2007 		}
  2111 			return false;
  2110 			return false;
  2112 		}
  2111 		}
  2113 		if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  2112 		if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  2114 			return false;
  2113 			return false;
  2115 		}
  2114 		}
       
  2115 
  2116 		foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) {
  2116 		foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) {
  2117 			if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) {
  2117 			if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) {
  2118 				return false;
  2118 				return false;
  2119 			}
  2119 			}
  2120 			if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) {
  2120 			if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $key ][ $plugin_page ] ) ) {
  2121 				return false;
  2121 				return false;
  2122 			}
  2122 			}
  2123 		}
  2123 		}
       
  2124 
  2124 		return true;
  2125 		return true;
  2125 	}
  2126 	}
  2126 
  2127 
  2127 	if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  2128 	if ( isset( $plugin_page ) && $plugin_page === $parent && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) {
  2128 		return false;
  2129 		return false;
  2129 	}
  2130 	}
  2130 
  2131 
  2131 	if ( isset( $submenu[ $parent ] ) ) {
  2132 	if ( isset( $submenu[ $parent ] ) ) {
  2132 		foreach ( $submenu[ $parent ] as $submenu_array ) {
  2133 		foreach ( $submenu[ $parent ] as $submenu_array ) {
  2133 			if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) {
  2134 			if ( isset( $plugin_page ) && $submenu_array[2] === $plugin_page ) {
  2134 				if ( current_user_can( $submenu_array[1] ) ) {
  2135 				return current_user_can( $submenu_array[1] );
  2135 					return true;
  2136 			} elseif ( $submenu_array[2] === $pagenow ) {
  2136 				} else {
  2137 				return current_user_can( $submenu_array[1] );
  2137 					return false;
       
  2138 				}
       
  2139 			} elseif ( $submenu_array[2] == $pagenow ) {
       
  2140 				if ( current_user_can( $submenu_array[1] ) ) {
       
  2141 					return true;
       
  2142 				} else {
       
  2143 					return false;
       
  2144 				}
       
  2145 			}
  2138 			}
  2146 		}
  2139 		}
  2147 	}
  2140 	}
  2148 
  2141 
  2149 	foreach ( $menu as $menu_array ) {
  2142 	foreach ( $menu as $menu_array ) {
  2150 		if ( $menu_array[2] == $parent ) {
  2143 		if ( $menu_array[2] === $parent ) {
  2151 			if ( current_user_can( $menu_array[1] ) ) {
  2144 			return current_user_can( $menu_array[1] );
  2152 				return true;
       
  2153 			} else {
       
  2154 				return false;
       
  2155 			}
       
  2156 		}
  2145 		}
  2157 	}
  2146 	}
  2158 
  2147 
  2159 	return true;
  2148 	return true;
  2160 }
  2149 }
  2186 }
  2175 }
  2187 
  2176 
  2188 /**
  2177 /**
  2189  * Adds an array of options to the list of allowed options.
  2178  * Adds an array of options to the list of allowed options.
  2190  *
  2179  *
  2191  * @since 2.7.0
  2180  * @since 5.5.0
  2192  *
  2181  *
  2193  * @global array $allowed_options
  2182  * @global array $allowed_options
  2194  *
  2183  *
  2195  * @param array        $new_options
  2184  * @param array        $new_options
  2196  * @param string|array $options
  2185  * @param string|array $options
  2292 	if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
  2281 	if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
  2293 		define( 'WP_SANDBOX_SCRAPING', true );
  2282 		define( 'WP_SANDBOX_SCRAPING', true );
  2294 	}
  2283 	}
  2295 
  2284 
  2296 	wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
  2285 	wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
  2297 	include WP_PLUGIN_DIR . '/' . $plugin;
  2286 	include_once WP_PLUGIN_DIR . '/' . $plugin;
  2298 }
  2287 }
  2299 
  2288 
  2300 /**
  2289 /**
  2301  * Helper function for adding content to the Privacy Policy Guide.
  2290  * Helper function for adding content to the Privacy Policy Guide.
  2302  *
  2291  *
  2458 
  2447 
  2459 /**
  2448 /**
  2460  * Renders an admin notice in case some plugins have been paused due to errors.
  2449  * Renders an admin notice in case some plugins have been paused due to errors.
  2461  *
  2450  *
  2462  * @since 5.2.0
  2451  * @since 5.2.0
       
  2452  *
       
  2453  * @global string $pagenow
  2463  */
  2454  */
  2464 function paused_plugins_notice() {
  2455 function paused_plugins_notice() {
  2465 	if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
  2456 	if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
  2466 		return;
  2457 		return;
  2467 	}
  2458 	}
  2480 		__( 'You can find more details and make changes on the Plugins screen.' ),
  2471 		__( 'You can find more details and make changes on the Plugins screen.' ),
  2481 		esc_url( admin_url( 'plugins.php?plugin_status=paused' ) ),
  2472 		esc_url( admin_url( 'plugins.php?plugin_status=paused' ) ),
  2482 		__( 'Go to the Plugins screen' )
  2473 		__( 'Go to the Plugins screen' )
  2483 	);
  2474 	);
  2484 }
  2475 }
       
  2476 
       
  2477 /**
       
  2478  * Renders an admin notice when a plugin was deactivated during an update.
       
  2479  *
       
  2480  * Displays an admin notice in case a plugin has been deactivated during an
       
  2481  * upgrade due to incompatibility with the current version of WordPress.
       
  2482  *
       
  2483  * @since 5.8.0
       
  2484  * @access private
       
  2485  *
       
  2486  * @global string $pagenow
       
  2487  * @global string $wp_version
       
  2488  */
       
  2489 function deactivated_plugins_notice() {
       
  2490 	if ( 'plugins.php' === $GLOBALS['pagenow'] ) {
       
  2491 		return;
       
  2492 	}
       
  2493 
       
  2494 	if ( ! current_user_can( 'activate_plugins' ) ) {
       
  2495 		return;
       
  2496 	}
       
  2497 
       
  2498 	$blog_deactivated_plugins = get_option( 'wp_force_deactivated_plugins' );
       
  2499 	$site_deactivated_plugins = array();
       
  2500 
       
  2501 	if ( false === $blog_deactivated_plugins ) {
       
  2502 		// Option not in database, add an empty array to avoid extra DB queries on subsequent loads.
       
  2503 		update_option( 'wp_force_deactivated_plugins', array() );
       
  2504 	}
       
  2505 
       
  2506 	if ( is_multisite() ) {
       
  2507 		$site_deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins' );
       
  2508 		if ( false === $site_deactivated_plugins ) {
       
  2509 			// Option not in database, add an empty array to avoid extra DB queries on subsequent loads.
       
  2510 			update_site_option( 'wp_force_deactivated_plugins', array() );
       
  2511 		}
       
  2512 	}
       
  2513 
       
  2514 	if ( empty( $blog_deactivated_plugins ) && empty( $site_deactivated_plugins ) ) {
       
  2515 		// No deactivated plugins.
       
  2516 		return;
       
  2517 	}
       
  2518 
       
  2519 	$deactivated_plugins = array_merge( $blog_deactivated_plugins, $site_deactivated_plugins );
       
  2520 
       
  2521 	foreach ( $deactivated_plugins as $plugin ) {
       
  2522 		if ( ! empty( $plugin['version_compatible'] ) && ! empty( $plugin['version_deactivated'] ) ) {
       
  2523 			$explanation = sprintf(
       
  2524 				/* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version, 4: Compatible plugin version */
       
  2525 				__( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s, please upgrade to %1$s %4$s or later.' ),
       
  2526 				$plugin['plugin_name'],
       
  2527 				$plugin['version_deactivated'],
       
  2528 				$GLOBALS['wp_version'],
       
  2529 				$plugin['version_compatible']
       
  2530 			);
       
  2531 		} else {
       
  2532 			$explanation = sprintf(
       
  2533 				/* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version */
       
  2534 				__( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s.' ),
       
  2535 				$plugin['plugin_name'],
       
  2536 				! empty( $plugin['version_deactivated'] ) ? $plugin['version_deactivated'] : '',
       
  2537 				$GLOBALS['wp_version'],
       
  2538 				$plugin['version_compatible']
       
  2539 			);
       
  2540 		}
       
  2541 
       
  2542 		printf(
       
  2543 			'<div class="notice notice-warning"><p><strong>%s</strong><br>%s</p><p><a href="%s">%s</a></p></div>',
       
  2544 			sprintf(
       
  2545 				/* translators: %s: Name of deactivated plugin */
       
  2546 				__( '%s plugin deactivated during WordPress upgrade.' ),
       
  2547 				$plugin['plugin_name']
       
  2548 			),
       
  2549 			$explanation,
       
  2550 			esc_url( admin_url( 'plugins.php?plugin_status=inactive' ) ),
       
  2551 			__( 'Go to the Plugins screen' )
       
  2552 		);
       
  2553 	}
       
  2554 
       
  2555 	// Empty the options.
       
  2556 	update_option( 'wp_force_deactivated_plugins', array() );
       
  2557 	if ( is_multisite() ) {
       
  2558 		update_site_option( 'wp_force_deactivated_plugins', array() );
       
  2559 	}
       
  2560 }