diff -r 34716fd837a4 -r be944660c56a wp/wp-admin/includes/plugin.php --- a/wp/wp-admin/includes/plugin.php Tue Dec 15 15:52:01 2020 +0100 +++ b/wp/wp-admin/includes/plugin.php Wed Sep 21 18:19:35 2022 +0200 @@ -44,6 +44,7 @@ * * @since 1.5.0 * @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers. + * @since 5.8.0 Added support for `Update URI` header. * * @param string $plugin_file Absolute path to the main plugin file. * @param bool $markup Optional. If the returned data should have HTML markup applied. @@ -63,6 +64,7 @@ * @type bool $Network Whether the plugin can only be activated network-wide. * @type string $RequiresWP Minimum required version of WordPress. * @type string $RequiresPHP Minimum required version of PHP. + * @type string $UpdateURI ID of the plugin for update purposes, should be a URI. * } */ function get_plugin_data( $plugin_file, $markup = true, $translate = true ) { @@ -79,6 +81,7 @@ 'Network' => 'Network', 'RequiresWP' => 'Requires at least', 'RequiresPHP' => 'Requires PHP', + 'UpdateURI' => 'Update URI', // Site Wide Only is deprecated in favor of Network. '_sitewide' => 'Site Wide Only', ); @@ -293,7 +296,7 @@ } // Files in wp-content/plugins directory. - $plugins_dir = @ opendir( $plugin_root ); + $plugins_dir = @opendir( $plugin_root ); $plugin_files = array(); if ( $plugins_dir ) { @@ -303,7 +306,7 @@ } if ( is_dir( $plugin_root . '/' . $file ) ) { - $plugins_subdir = @ opendir( $plugin_root . '/' . $file ); + $plugins_subdir = @opendir( $plugin_root . '/' . $file ); if ( $plugins_subdir ) { while ( ( $subfile = readdir( $plugins_subdir ) ) !== false ) { @@ -651,7 +654,9 @@ return $requirements; } - if ( ( $network_wide && ! isset( $current[ $plugin ] ) ) || ( ! $network_wide && ! in_array( $plugin, $current, true ) ) ) { + if ( $network_wide && ! isset( $current[ $plugin ] ) + || ! $network_wide && ! in_array( $plugin, $current, true ) + ) { if ( ! empty( $redirect ) ) { // We'll override this later if the plugin can be included without fatal error. wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) ); @@ -659,14 +664,8 @@ ob_start(); - if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) { - define( 'WP_SANDBOX_SCRAPING', true ); - } - - wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin ); - $_wp_plugin_file = $plugin; - include_once WP_PLUGIN_DIR . '/' . $plugin; - $plugin = $_wp_plugin_file; // Avoid stomping of the $plugin variable in a plugin. + // Load the plugin to test whether it throws any errors. + plugin_sandbox_scrape( $plugin ); if ( ! $silent ) { /** @@ -730,6 +729,7 @@ $output = ob_get_clean(); return new WP_Error( 'unexpected_output', __( 'The plugin generated unexpected output.' ), $output ); } + ob_end_clean(); } @@ -764,7 +764,7 @@ continue; } - $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin ); + $network_deactivating = ( false !== $network_wide ) && is_plugin_active_for_network( $plugin ); if ( ! $silent ) { /** @@ -978,7 +978,7 @@ // If plugin is in its own directory, recursively delete the directory. // Base check on if plugin includes directory separator AND that it's not the root plugin folder. - if ( strpos( $plugin_file, '/' ) && $this_plugin_dir != $plugins_dir ) { + if ( strpos( $plugin_file, '/' ) && $this_plugin_dir !== $plugins_dir ) { $deleted = $wp_filesystem->delete( $this_plugin_dir, true ); } else { $deleted = $wp_filesystem->delete( $plugins_dir . $plugin_file ); @@ -999,8 +999,13 @@ continue; } + $plugin_slug = dirname( $plugin_file ); + + if ( 'hello.php' === $plugin_file ) { + $plugin_slug = 'hello-dolly'; + } + // Remove language files, silently. - $plugin_slug = dirname( $plugin_file ); if ( '.' !== $plugin_slug && ! empty( $plugin_translations[ $plugin_slug ] ) ) { $translations = $plugin_translations[ $plugin_slug ]; @@ -1114,12 +1119,10 @@ * Uses the information from `Requires at least` and `Requires PHP` headers * defined in the plugin's main PHP file. * - * If the headers are not present in the plugin's main PHP file, - * `readme.txt` is also checked as a fallback. - * * @since 5.2.0 * @since 5.3.0 Added support for reading the headers from the plugin's * main PHP file, with `readme.txt` as a fallback. + * @since 5.8.0 Removed support for using `readme.txt` as a fallback. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @return true|WP_Error True if requirements are met, WP_Error on failure. @@ -1132,26 +1135,11 @@ 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '', ); - $readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt'; - - if ( file_exists( $readme_file ) ) { - $readme_headers = get_file_data( - $readme_file, - array( - 'requires' => 'Requires at least', - 'requires_php' => 'Requires PHP', - ), - 'plugin' - ); - - $requirements = array_merge( $readme_headers, $requirements ); - } - $compatible_wp = is_wp_version_compatible( $requirements['requires'] ); $compatible_php = is_php_version_compatible( $requirements['requires_php'] ); - /* translators: %s: URL to Update PHP page. */ $php_update_message = '
' . sprintf( + /* translators: %s: URL to Update PHP page. */ __( 'Learn more about updating PHP.' ), esc_url( wp_get_update_php_url() ) ); @@ -1229,7 +1217,8 @@ * @since 2.7.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. - * @return true True if a plugin's uninstall.php file has been found and included. + * @return true|void True if a plugin's uninstall.php file has been found and included. + * Void otherwise. */ function uninstall_plugin( $plugin ) { $file = plugin_basename( $plugin ); @@ -1414,9 +1403,9 @@ * parent file someone is trying to link back to the parent manually. In * this case, don't automatically add a link back to avoid duplication. */ - if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug != $parent_slug ) { + if ( ! isset( $submenu[ $parent_slug ] ) && $menu_slug !== $parent_slug ) { foreach ( (array) $menu as $parent_menu ) { - if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) ) { + if ( $parent_menu[2] === $parent_slug && current_user_can( $parent_menu[1] ) ) { $submenu[ $parent_slug ][] = array_slice( $parent_menu, 0, 4 ); } } @@ -1761,13 +1750,13 @@ * @global array $menu * * @param string $menu_slug The slug of the menu. - * @return array|bool The removed menu on success, false if not found. + * @return array|false The removed menu on success, false if not found. */ function remove_menu_page( $menu_slug ) { global $menu; foreach ( $menu as $i => $item ) { - if ( $menu_slug == $item[2] ) { + if ( $menu_slug === $item[2] ) { unset( $menu[ $i ] ); return $item; } @@ -1785,7 +1774,7 @@ * * @param string $menu_slug The slug for the parent menu. * @param string $submenu_slug The slug of the submenu. - * @return array|bool The removed submenu on success, false if not found. + * @return array|false The removed submenu on success, false if not found. */ function remove_submenu_page( $menu_slug, $submenu_slug ) { global $submenu; @@ -1795,7 +1784,7 @@ } foreach ( $submenu[ $menu_slug ] as $i => $item ) { - if ( $submenu_slug == $item[2] ) { + if ( $submenu_slug === $item[2] ) { unset( $submenu[ $menu_slug ][ $i ] ); return $item; } @@ -1822,6 +1811,7 @@ if ( isset( $_parent_pages[ $menu_slug ] ) ) { $parent_slug = $_parent_pages[ $menu_slug ]; + if ( $parent_slug && ! isset( $_parent_pages[ $parent_slug ] ) ) { $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) ); } else { @@ -1870,33 +1860,40 @@ if ( isset( $_wp_real_parent_file[ $parent ] ) ) { $parent = $_wp_real_parent_file[ $parent ]; } + return $parent; } if ( 'admin.php' === $pagenow && isset( $plugin_page ) ) { foreach ( (array) $menu as $parent_menu ) { - if ( $parent_menu[2] == $plugin_page ) { + if ( $parent_menu[2] === $plugin_page ) { $parent_file = $plugin_page; + if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } + return $parent_file; } } if ( isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { $parent_file = $plugin_page; + if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } + return $parent_file; } } if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[ $pagenow ][ $plugin_page ] ) ) { $parent_file = $pagenow; + if ( isset( $_wp_real_parent_file[ $parent_file ] ) ) { $parent_file = $_wp_real_parent_file[ $parent_file ]; } + return $parent_file; } @@ -1905,13 +1902,16 @@ if ( isset( $_wp_real_parent_file[ $parent ] ) ) { $parent = $_wp_real_parent_file[ $parent ]; } - if ( ! empty( $typenow ) && ( "$pagenow?post_type=$typenow" === $submenu_array[2] ) ) { + + if ( ! empty( $typenow ) && "$pagenow?post_type=$typenow" === $submenu_array[2] ) { $parent_file = $parent; return $parent; - } elseif ( $submenu_array[2] == $pagenow && empty( $typenow ) && ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) ) ) { + } elseif ( empty( $typenow ) && $pagenow === $submenu_array[2] + && ( empty( $parent_file ) || false === strpos( $parent_file, '?' ) ) + ) { $parent_file = $parent; return $parent; - } elseif ( isset( $plugin_page ) && ( $plugin_page == $submenu_array[2] ) ) { + } elseif ( isset( $plugin_page ) && $plugin_page === $submenu_array[2] ) { $parent_file = $parent; return $parent; } @@ -1953,10 +1953,10 @@ if ( empty( $parent ) ) { foreach ( (array) $menu as $menu_array ) { if ( isset( $menu_array[3] ) ) { - if ( $menu_array[2] == $pagenow ) { + if ( $menu_array[2] === $pagenow ) { $title = $menu_array[3]; return $menu_array[3]; - } elseif ( isset( $plugin_page ) && ( $plugin_page == $menu_array[2] ) && ( $hook == $menu_array[5] ) ) { + } elseif ( isset( $plugin_page ) && $plugin_page === $menu_array[2] && $hook === $menu_array[5] ) { $title = $menu_array[3]; return $menu_array[3]; } @@ -1968,21 +1968,19 @@ } else { foreach ( array_keys( $submenu ) as $parent ) { foreach ( $submenu[ $parent ] as $submenu_array ) { - if ( isset( $plugin_page ) && - ( $plugin_page == $submenu_array[2] ) && - ( - ( $parent == $pagenow ) || - ( $parent == $plugin_page ) || - ( $plugin_page == $hook ) || - ( 'admin.php' === $pagenow && $parent1 != $submenu_array[2] ) || - ( ! empty( $typenow ) && $parent == $pagenow . '?post_type=' . $typenow ) - ) + 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 ( $submenu_array[2] !== $pagenow || isset( $_GET['page'] ) ) { // Not the current page. continue; } @@ -1997,10 +1995,11 @@ } if ( empty( $title ) ) { foreach ( $menu as $menu_array ) { - if ( isset( $plugin_page ) && - ( $plugin_page == $menu_array[2] ) && - ( 'admin.php' === $pagenow ) && - ( $parent1 == $menu_array[2] ) ) { + if ( isset( $plugin_page ) + && $plugin_page === $menu_array[2] + && 'admin.php' === $pagenow + && $parent1 === $menu_array[2] + ) { $title = $menu_array[3]; return $menu_array[3]; } @@ -2113,6 +2112,7 @@ if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { return false; } + foreach ( array_keys( $_wp_submenu_nopriv ) as $key ) { if ( isset( $_wp_submenu_nopriv[ $key ][ $pagenow ] ) ) { return false; @@ -2121,38 +2121,27 @@ return false; } } + return true; } - if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { + if ( isset( $plugin_page ) && $plugin_page === $parent && isset( $_wp_menu_nopriv[ $plugin_page ] ) ) { return false; } if ( isset( $submenu[ $parent ] ) ) { foreach ( $submenu[ $parent ] as $submenu_array ) { - if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) { - if ( current_user_can( $submenu_array[1] ) ) { - return true; - } else { - return false; - } - } elseif ( $submenu_array[2] == $pagenow ) { - if ( current_user_can( $submenu_array[1] ) ) { - return true; - } else { - return false; - } + 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 ) { - if ( current_user_can( $menu_array[1] ) ) { - return true; - } else { - return false; - } + if ( $menu_array[2] === $parent ) { + return current_user_can( $menu_array[1] ); } } @@ -2188,7 +2177,7 @@ /** * Adds an array of options to the list of allowed options. * - * @since 2.7.0 + * @since 5.5.0 * * @global array $allowed_options * @@ -2294,7 +2283,7 @@ } wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin ); - include WP_PLUGIN_DIR . '/' . $plugin; + include_once WP_PLUGIN_DIR . '/' . $plugin; } /** @@ -2460,6 +2449,8 @@ * Renders an admin notice in case some plugins have been paused due to errors. * * @since 5.2.0 + * + * @global string $pagenow */ function paused_plugins_notice() { if ( 'plugins.php' === $GLOBALS['pagenow'] ) { @@ -2482,3 +2473,88 @@ __( 'Go to the Plugins screen' ) ); } + +/** + * Renders an admin notice when a plugin was deactivated during an update. + * + * Displays an admin notice in case a plugin has been deactivated during an + * upgrade due to incompatibility with the current version of WordPress. + * + * @since 5.8.0 + * @access private + * + * @global string $pagenow + * @global string $wp_version + */ +function deactivated_plugins_notice() { + if ( 'plugins.php' === $GLOBALS['pagenow'] ) { + return; + } + + if ( ! current_user_can( 'activate_plugins' ) ) { + return; + } + + $blog_deactivated_plugins = get_option( 'wp_force_deactivated_plugins' ); + $site_deactivated_plugins = array(); + + if ( false === $blog_deactivated_plugins ) { + // Option not in database, add an empty array to avoid extra DB queries on subsequent loads. + update_option( 'wp_force_deactivated_plugins', array() ); + } + + if ( is_multisite() ) { + $site_deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins' ); + if ( false === $site_deactivated_plugins ) { + // Option not in database, add an empty array to avoid extra DB queries on subsequent loads. + update_site_option( 'wp_force_deactivated_plugins', array() ); + } + } + + if ( empty( $blog_deactivated_plugins ) && empty( $site_deactivated_plugins ) ) { + // No deactivated plugins. + return; + } + + $deactivated_plugins = array_merge( $blog_deactivated_plugins, $site_deactivated_plugins ); + + foreach ( $deactivated_plugins as $plugin ) { + if ( ! empty( $plugin['version_compatible'] ) && ! empty( $plugin['version_deactivated'] ) ) { + $explanation = sprintf( + /* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version, 4: Compatible plugin version */ + __( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s, please upgrade to %1$s %4$s or later.' ), + $plugin['plugin_name'], + $plugin['version_deactivated'], + $GLOBALS['wp_version'], + $plugin['version_compatible'] + ); + } else { + $explanation = sprintf( + /* translators: 1: Name of deactivated plugin, 2: Plugin version deactivated, 3: Current WP version */ + __( '%1$s %2$s was deactivated due to incompatibility with WordPress %3$s.' ), + $plugin['plugin_name'], + ! empty( $plugin['version_deactivated'] ) ? $plugin['version_deactivated'] : '', + $GLOBALS['wp_version'], + $plugin['version_compatible'] + ); + } + + printf( + '
%s
%s