diff --git a/src/wp-admin/includes/class-plugin-upgrader.php b/src/wp-admin/includes/class-plugin-upgrader.php index 97343fcf9d..091cfebc18 100644 --- a/src/wp-admin/includes/class-plugin-upgrader.php +++ b/src/wp-admin/includes/class-plugin-upgrader.php @@ -155,12 +155,6 @@ class Plugin_Upgrader extends WP_Upgrader { // Force refresh of plugin update information. wp_clean_plugins_cache( $parsed_args['clear_update_cache'] ); - $all_plugin_data = get_option( 'plugin_data', array() ); - $plugin_file = $this->new_plugin_data['file']; - unset( $this->new_plugin_data['file'] ); - $all_plugin_data[ $plugin_file ] = $this->new_plugin_data; - update_option( 'plugin_data', $all_plugin_data ); - if ( $parsed_args['overwrite_package'] ) { /** * Fires when the upgrader has successfully overwritten a currently installed @@ -488,16 +482,7 @@ class Plugin_Upgrader extends WP_Upgrader { foreach ( $files as $file ) { $info = get_plugin_data( $file, false, false ); if ( ! empty( $info['Name'] ) ) { - $basename = basename( $file ); - $dirname = basename( dirname( $file ) ); - - if ( '.' === $dirname ) { - $plugin_file = $basename; - } else { - $plugin_file = "$dirname/$basename"; - } - $this->new_plugin_data = ( $info ); - $this->new_plugin_data['file'] = $plugin_file; + $this->new_plugin_data = $info; break; } } diff --git a/src/wp-admin/includes/plugin-install.php b/src/wp-admin/includes/plugin-install.php index 2de2aabbc3..2399ffc807 100644 --- a/src/wp-admin/includes/plugin-install.php +++ b/src/wp-admin/includes/plugin-install.php @@ -927,7 +927,7 @@ function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible // Determine the status of plugin dependencies. $installed_plugins = get_plugins(); - $active_plugins = get_option( 'active_plugins' ); + $active_plugins = get_option( 'active_plugins', array() ); $plugin_dependencies_count = count( $requires_plugins ); $installed_plugin_dependencies_count = 0; $active_plugin_dependencies_count = 0; diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php index fa3fa09f09..680f4a7728 100644 --- a/src/wp-admin/includes/plugin.php +++ b/src/wp-admin/includes/plugin.php @@ -333,7 +333,6 @@ function get_plugins( $plugin_folder = '' ) { return $wp_plugins; } - $new_plugin_data = array(); foreach ( $plugin_files as $plugin_file ) { if ( ! is_readable( "$plugin_root/$plugin_file" ) ) { continue; @@ -346,13 +345,6 @@ function get_plugins( $plugin_folder = '' ) { continue; } - $new_plugin_file = str_replace( - trailingslashit( WP_PLUGIN_DIR ), - '', - "$plugin_root/$plugin_file" - ); - - $new_plugin_data[ $new_plugin_file ] = $plugin_data; $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data; } @@ -361,10 +353,6 @@ function get_plugins( $plugin_folder = '' ) { $cache_plugins[ $plugin_folder ] = $wp_plugins; wp_cache_set( 'plugins', $cache_plugins, 'plugins' ); - if ( ! wp_installing() ) { - update_option( 'plugin_data', $new_plugin_data ); - } - return $wp_plugins; } @@ -975,7 +963,6 @@ function delete_plugins( $plugins, $deprecated = '' ) { $plugins_dir = trailingslashit( $plugins_dir ); $plugin_translations = wp_get_installed_translations( 'plugins' ); - $all_plugin_data = get_option( 'plugin_data', array() ); $errors = array(); @@ -1020,7 +1007,6 @@ function delete_plugins( $plugins, $deprecated = '' ) { $errors[] = $plugin_file; continue; } - unset( $all_plugin_data[ $plugin_file ] ); $plugin_slug = dirname( $plugin_file ); @@ -1069,7 +1055,6 @@ function delete_plugins( $plugins, $deprecated = '' ) { return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) ); } - update_option( 'plugin_data', $all_plugin_data ); return true; } @@ -1214,6 +1199,8 @@ function validate_plugin_requirements( $plugin ) { ); } + WP_Plugin_Dependencies::initialize(); + if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) { $dependencies = WP_Plugin_Dependencies::get_dependencies( $plugin ); $unmet_dependencies = array(); diff --git a/src/wp-admin/plugin-install.php b/src/wp-admin/plugin-install.php index a8beb8249b..5c8be143bf 100644 --- a/src/wp-admin/plugin-install.php +++ b/src/wp-admin/plugin-install.php @@ -135,8 +135,8 @@ get_current_screen()->set_screen_reader_content( */ require_once ABSPATH . 'wp-admin/admin-header.php'; +WP_Plugin_Dependencies::initialize(); WP_Plugin_Dependencies::display_admin_notice_for_unmet_dependencies(); -WP_Plugin_Dependencies::display_admin_notice_for_deactivated_dependents(); WP_Plugin_Dependencies::display_admin_notice_for_circular_dependencies(); ?>
' . sprintf( - /* translators: %s: URL to Update PHP page. */ - __( 'Learn more about updating PHP.' ), - esc_url( wp_get_update_php_url() ) - ); - - $annotation = wp_get_update_php_annotation(); - - if ( $annotation ) { - $php_update_message .= '
' . $annotation . ''; - } - - if ( ! $compatible_wp && ! $compatible_php ) { - $errors[] = sprintf( - /* translators: 1: Current WordPress version, 2: Current PHP version, 3: Plugin name, 4: Required WordPress version, 5: Required PHP version. */ - _x( 'Error: Current versions of WordPress (%1$s) and PHP (%2$s) do not meet minimum requirements for %3$s. The plugin requires WordPress %4$s and PHP %5$s.', 'plugin' ), - get_bloginfo( 'version' ), - PHP_VERSION, - $plugin_headers['Name'], - $requirements['requires'], - $requirements['requires_php'] - ) . $php_update_message; - } elseif ( ! $compatible_php ) { - $errors[] = sprintf( - /* translators: 1: Current PHP version, 2: Plugin name, 3: Required PHP version. */ - _x( 'Error: Current PHP version (%1$s) does not meet minimum requirements for %2$s. The plugin requires PHP %3$s.', 'plugin' ), - PHP_VERSION, - $plugin_headers['Name'], - $requirements['requires_php'] - ) . $php_update_message; - } elseif ( ! $compatible_wp ) { - $errors[] = sprintf( - /* translators: 1: Current WordPress version, 2: Plugin name, 3: Required WordPress version. */ - _x( 'Error: Current WordPress version (%1$s) does not meet minimum requirements for %2$s. The plugin requires WordPress %3$s.', 'plugin' ), - get_bloginfo( 'version' ), - $plugin_headers['Name'], - $requirements['requires'] - ); - } - - if ( ! empty( $errors ) ) { - $failed_plugins[ $plugin_file ] = ''; - foreach ( $errors as $error ) { - $failed_plugins[ $plugin_file ] .= wp_get_admin_notice( - $error, - array( - 'type' => 'error', - 'dismissible' => true, - ) - ); - } - continue; - } - } - wp_register_plugin_realpath( $plugin ); $_wp_plugin_file = $plugin; @@ -595,20 +512,6 @@ foreach ( wp_get_active_and_valid_plugins() as $plugin ) { } unset( $plugin, $_wp_plugin_file ); -if ( ! empty( $failed_plugins ) ) { - add_action( - 'admin_notices', - function () use ( $failed_plugins ) { - global $pagenow; - - if ( 'index.php' === $pagenow || 'plugins.php' === $pagenow ) { - echo implode( '', $failed_plugins ); - } - } - ); -} -unset( $failed_plugins ); - // Load pluggable functions. require ABSPATH . WPINC . '/pluggable.php'; require ABSPATH . WPINC . '/pluggable-deprecated.php'; diff --git a/tests/phpunit/tests/admin/plugin-dependencies/base.php b/tests/phpunit/tests/admin/plugin-dependencies/base.php index a35ed6f096..a827b4b1e7 100644 --- a/tests/phpunit/tests/admin/plugin-dependencies/base.php +++ b/tests/phpunit/tests/admin/plugin-dependencies/base.php @@ -32,6 +32,7 @@ abstract class WP_PluginDependencies_UnitTestCase extends WP_UnitTestCase { 'dependency_filepaths' => null, 'circular_dependencies_pairs' => null, 'circular_dependencies_slugs' => null, + 'initialized' => false, ); /** @@ -62,12 +63,12 @@ abstract class WP_PluginDependencies_UnitTestCase extends WP_UnitTestCase { /** * Resets all static properties to a default value after each test. */ - public function set_up() { - parent::set_up(); - + public function tear_down() { foreach ( self::$static_properties as $name => $default_value ) { $this->set_property_value( $name, $default_value ); } + + parent::tear_down(); } /** diff --git a/tests/phpunit/tests/admin/plugin-dependencies/getDependencyFilepath.php b/tests/phpunit/tests/admin/plugin-dependencies/getDependencyFilepath.php index 473609f0fb..04b4948e63 100644 --- a/tests/phpunit/tests/admin/plugin-dependencies/getDependencyFilepath.php +++ b/tests/phpunit/tests/admin/plugin-dependencies/getDependencyFilepath.php @@ -17,6 +17,30 @@ require_once __DIR__ . '/base.php'; */ class Tests_Admin_WPPluginDependencies_GetDependencyFilepath extends WP_PluginDependencies_UnitTestCase { + /** + * Tests that false is returned if Plugin Dependencies has not been initialized. + * + * @ticket 60457 + */ + public function test_should_return_false_before_initialization() { + // Ensure Plugin Dependencies has not been initialized. + $this->assertFalse( + $this->get_property_value( 'initialized' ), + 'Plugin Dependencies has been initialized.' + ); + + $this->assertSame( + self::$static_properties['dependency_slugs'], + $this->get_property_value( 'dependency_slugs' ), + '"dependency_slugs" was not set to its default value.' + ); + + $this->assertFalse( + self::$instance->get_dependency_filepath( 'dependency' ), + 'false was not returned before initialization.' + ); + } + /** * Tests that the expected dependency filepaths are retrieved for installed dependencies. * diff --git a/tests/phpunit/tests/admin/plugin-dependencies/hasCircularDependency.php b/tests/phpunit/tests/admin/plugin-dependencies/hasCircularDependency.php index 7e86303c5f..10d00d96b7 100644 --- a/tests/phpunit/tests/admin/plugin-dependencies/hasCircularDependency.php +++ b/tests/phpunit/tests/admin/plugin-dependencies/hasCircularDependency.php @@ -17,6 +17,44 @@ require_once __DIR__ . '/base.php'; */ class Tests_Admin_WPPluginDependencies_HasCircularDependency extends WP_PluginDependencies_UnitTestCase { + /** + * Tests that false is returned if Plugin Dependencies has not been initialized. + * + * @ticket 60457 + */ + public function test_should_return_false_before_initialization() { + $this->set_property_value( + 'plugins', + array( + 'dependent/dependent.php' => array( + 'Name' => 'Dependent', + 'RequiresPlugins' => 'dependency', + ), + 'dependency/dependency.php' => array( + 'Name' => 'Dependency', + 'RequiresPlugins' => 'dependent', + ), + ) + ); + + // Ensure Plugin Dependencies has not been initialized. + $this->assertFalse( + $this->get_property_value( 'initialized' ), + 'Plugin Dependencies has been initialized.' + ); + + $this->assertSame( + self::$static_properties['circular_dependencies_slugs'], + $this->get_property_value( 'circular_dependencies_slugs' ), + '"circular_dependencies_slugs" was not set to its default value.' + ); + + $this->assertFalse( + self::$instance->has_circular_dependency( 'dependency' ), + 'false was not returned before initialization.' + ); + } + /** * Tests that a plugin with a circular dependency will return true. * diff --git a/tests/phpunit/tests/admin/plugin-dependencies/initialize.php b/tests/phpunit/tests/admin/plugin-dependencies/initialize.php index fe15cd2188..375e30c4bd 100644 --- a/tests/phpunit/tests/admin/plugin-dependencies/initialize.php +++ b/tests/phpunit/tests/admin/plugin-dependencies/initialize.php @@ -15,6 +15,68 @@ require_once __DIR__ . '/base.php'; */ class Tests_Admin_WPPluginDependencies_Initialize extends WP_PluginDependencies_UnitTestCase { + /** + * Tests that initialization runs only once. + * + * @ticket 60457 + * + * @dataProvider data_static_properties_set_during_initialization + * + * @param string $property_name The name of the property to check. + */ + public function test_should_only_initialize_once( $property_name ) { + $this->assertFalse( + $this->get_property_value( 'initialized' ), + 'Plugin Dependencies has already been initialized.' + ); + + self::$instance->initialize(); + + $this->assertTrue( + $this->get_property_value( 'initialized' ), + '"initialized" was not set to true during initialization.' + ); + + $default_value = self::$static_properties[ $property_name ]; + + $this->assertNotSame( + $default_value, + $this->get_property_value( $property_name ), + "\"{$property_name}\" was not set during initialization." + ); + + // Reset it to its default. + $this->set_property_value( $property_name, self::$static_properties[ $property_name ] ); + + self::$instance->initialize(); + + $this->assertSame( + $default_value, + $this->get_property_value( $property_name ), + "\"{$property_name}\" was set during the second initialization attempt." + ); + } + + /** + * Data provider. + * + * @return array[] + */ + public function data_static_properties_set_during_initialization() { + /* + * This does not include 'dependency_api_data' as it is only set + * on certain pages. This is tested later. + */ + return self::text_array_to_dataprovider( + array( + 'plugins', + 'dependencies', + 'dependency_slugs', + 'dependent_slugs', + ) + ); + } + /** * Tests that `$dependency_api_data` is set on certain screens. * @@ -238,99 +300,4 @@ class Tests_Admin_WPPluginDependencies_Initialize extends WP_PluginDependencies_ self::$instance->initialize(); $this->assertSame( $expected_slugs, $this->get_property_value( 'dependent_slugs' ) ); } - - /** - * Tests that dependents with unmet dependencies are deactivated. - * - * @ticket 22316 - * - * @covers WP_Plugin_Dependencies::deactivate_dependents_with_unmet_dependencies - * @covers WP_Plugin_Dependencies::has_unmet_dependencies - * @covers WP_Plugin_Dependencies::get_active_dependents_in_dependency_tree - * - * @dataProvider data_should_only_deactivate_dependents_with_unmet_dependencies - * - * @param array $active_plugins An array of active plugin paths. - * @param array $plugins An array of installed plugins. - * @param array $expected The expected value of 'active_plugins' after initialization. - */ - public function test_should_deactivate_dependents_with_uninstalled_dependencies( $active_plugins, $plugins, $expected ) { - update_option( 'active_plugins', $active_plugins ); - - $this->set_property_value( 'plugins', $plugins ); - self::$instance::initialize(); - - $this->assertSame( $expected, array_values( get_option( 'active_plugins', array() ) ) ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_should_only_deactivate_dependents_with_unmet_dependencies() { - return array( - 'a dependent with an uninstalled dependency' => array( - 'active_plugins' => array( 'dependent/dependent.php' ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency' ), - ), - 'expected' => array(), - ), - 'a dependent with an inactive dependency' => array( - 'active_plugins' => array( 'dependent/dependent.php' ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency' ), - 'dependency/dependency.php' => array( 'RequiresPlugins' => '' ), - ), - 'expected' => array(), - ), - 'a dependent with two dependencies, one uninstalled, one inactive' => array( - 'active_plugins' => array( 'dependent/dependent.php' ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency, dependency2' ), - 'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ), - ), - 'expected' => array(), - ), - 'a dependent with a dependency that is installed and active' => array( - 'active_plugins' => array( 'dependent/dependent.php', 'dependency/dependency.php' ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency' ), - 'dependency/dependency.php' => array( 'RequiresPlugins' => '' ), - ), - 'expected' => array( 'dependent/dependent.php', 'dependency/dependency.php' ), - ), - 'one dependent with two dependencies that are installed and active' => array( - 'active_plugins' => array( - 'dependent/dependent.php', - 'dependency/dependency.php', - 'dependency2/dependency2.php', - ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency, dependency2' ), - 'dependency/dependency.php' => array( 'RequiresPlugins' => '' ), - 'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ), - ), - 'expected' => array( - 'dependent/dependent.php', - 'dependency/dependency.php', - 'dependency2/dependency2.php', - ), - ), - 'two dependents, one with an uninstalled dependency, and one with an active dependency' => array( - 'active_plugins' => array( - 'dependent/dependent.php', - 'dependent2/dependent2.php', - 'dependency2/dependency2.php', - ), - 'plugins' => array( - 'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency' ), - 'dependent2/dependent2.php' => array( 'RequiresPlugins' => 'dependency2' ), - 'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ), - ), - 'expected' => array( 'dependent2/dependent2.php', 'dependency2/dependency2.php' ), - ), - ); - } }