Make WordPress Core

Changeset 57658


Ignore:
Timestamp:
02/20/2024 07:25:38 AM (2 years ago)
Author:
costdev
Message:

Plugin Dependencies: Remove auto-deactivation and bootstrapping logic.

Automatic deactivation of dependents with unmet dependencies requires a write operation to the database. This was performed during Core's bootstrap, which risked the database and cache becoming out-of-sync on sites with heavy traffic.

No longer loading plugins that have unmet requirements has not had a final approach decided core-wide, and is still in discussion in #60491 to be handled in a future release.

The plugin_data option, used to persistently store plugin data for detecting unmet dependencies during Core's bootstrap, is no longer needed.

Follow-up to [57545], [57592], [57606], [57617].

Props dd32, azaozz, swissspidy, desrosj, afragen, pbiron, zunaid321, costdev.
Fixes #60457. See #60491, #60510, #60518.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-plugin-upgrader.php

    r57545 r57658  
    155155                // Force refresh of plugin update information.
    156156                wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
    157 
    158                 $all_plugin_data = get_option( 'plugin_data', array() );
    159                 $plugin_file     = $this->new_plugin_data['file'];
    160                 unset( $this->new_plugin_data['file'] );
    161                 $all_plugin_data[ $plugin_file ] = $this->new_plugin_data;
    162                 update_option( 'plugin_data', $all_plugin_data );
    163157
    164158                if ( $parsed_args['overwrite_package'] ) {
     
    489483                                $info = get_plugin_data( $file, false, false );
    490484                                if ( ! empty( $info['Name'] ) ) {
    491                                         $basename = basename( $file );
    492                                         $dirname  = basename( dirname( $file ) );
    493 
    494                                         if ( '.' === $dirname ) {
    495                                                 $plugin_file = $basename;
    496                                         } else {
    497                                                 $plugin_file = "$dirname/$basename";
    498                                         }
    499                                         $this->new_plugin_data         = ( $info );
    500                                         $this->new_plugin_data['file'] = $plugin_file;
     485                                        $this->new_plugin_data = $info;
    501486                                        break;
    502487                                }
  • trunk/src/wp-admin/includes/plugin-install.php

    r57545 r57658  
    928928        // Determine the status of plugin dependencies.
    929929        $installed_plugins                   = get_plugins();
    930         $active_plugins                      = get_option( 'active_plugins' );
     930        $active_plugins                      = get_option( 'active_plugins', array() );
    931931        $plugin_dependencies_count           = count( $requires_plugins );
    932932        $installed_plugin_dependencies_count = 0;
  • trunk/src/wp-admin/includes/plugin.php

    r57644 r57658  
    334334        }
    335335
    336         $new_plugin_data = array();
    337336        foreach ( $plugin_files as $plugin_file ) {
    338337                if ( ! is_readable( "$plugin_root/$plugin_file" ) ) {
     
    347346                }
    348347
    349                 $new_plugin_file = str_replace(
    350                         trailingslashit( WP_PLUGIN_DIR ),
    351                         '',
    352                         "$plugin_root/$plugin_file"
    353                 );
    354 
    355                 $new_plugin_data[ $new_plugin_file ]           = $plugin_data;
    356348                $wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data;
    357349        }
     
    361353        $cache_plugins[ $plugin_folder ] = $wp_plugins;
    362354        wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
    363 
    364         if ( ! wp_installing() ) {
    365                 update_option( 'plugin_data', $new_plugin_data );
    366         }
    367355
    368356        return $wp_plugins;
     
    976964
    977965        $plugin_translations = wp_get_installed_translations( 'plugins' );
    978         $all_plugin_data     = get_option( 'plugin_data', array() );
    979966
    980967        $errors = array();
     
    10211008                        continue;
    10221009                }
    1023                 unset( $all_plugin_data[ $plugin_file ] );
    10241010
    10251011                $plugin_slug = dirname( $plugin_file );
     
    10701056                return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
    10711057        }
    1072         update_option( 'plugin_data', $all_plugin_data );
    10731058
    10741059        return true;
     
    12151200        }
    12161201
     1202        WP_Plugin_Dependencies::initialize();
     1203
    12171204        if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) {
    12181205                $dependencies       = WP_Plugin_Dependencies::get_dependencies( $plugin );
  • trunk/src/wp-admin/plugin-install.php

    r57545 r57658  
    136136require_once ABSPATH . 'wp-admin/admin-header.php';
    137137
     138WP_Plugin_Dependencies::initialize();
    138139WP_Plugin_Dependencies::display_admin_notice_for_unmet_dependencies();
    139 WP_Plugin_Dependencies::display_admin_notice_for_deactivated_dependents();
    140140WP_Plugin_Dependencies::display_admin_notice_for_circular_dependencies();
    141141?>
  • trunk/src/wp-admin/plugins.php

    r57586 r57658  
    4040
    4141wp_enqueue_script( 'updates' );
     42
     43WP_Plugin_Dependencies::initialize();
    4244
    4345if ( $action ) {
     
    742744
    743745<?php WP_Plugin_Dependencies::display_admin_notice_for_unmet_dependencies(); ?>
    744 <?php WP_Plugin_Dependencies::display_admin_notice_for_deactivated_dependents(); ?>
    745746<?php WP_Plugin_Dependencies::display_admin_notice_for_circular_dependencies(); ?>
    746747<div class="wrap">
  • trunk/src/wp-includes/class-wp-plugin-dependencies.php

    r57617 r57658  
    106106
    107107        /**
    108          * Initializes by fetching plugin header and plugin API data,
    109          * and deactivating dependents with unmet dependencies.
     108         * Whether Plugin Dependencies have been initialized.
     109         *
     110         * @since 6.5.0
     111         *
     112         * @var bool
     113         */
     114        protected static $initialized = false;
     115
     116        /**
     117         * Initializes by fetching plugin header and plugin API data.
    110118         *
    111119         * @since 6.5.0
    112120         */
    113121        public static function initialize() {
    114                 self::read_dependencies_from_plugin_headers();
    115                 self::get_dependency_api_data();
    116                 self::deactivate_dependents_with_unmet_dependencies();
     122                if ( false === self::$initialized ) {
     123                        self::read_dependencies_from_plugin_headers();
     124                        self::get_dependency_api_data();
     125                        self::$initialized = true;
     126                }
    117127        }
    118128
     
    126136         */
    127137        public static function has_dependents( $plugin_file ) {
    128                 return in_array( self::convert_to_slug( $plugin_file ), self::$dependency_slugs, true );
     138                return in_array( self::convert_to_slug( $plugin_file ), (array) self::$dependency_slugs, true );
    129139        }
    130140
     
    173183                $dependents = array();
    174184
    175                 foreach ( self::$dependencies as $dependent => $dependencies ) {
     185                foreach ( (array) self::$dependencies as $dependent => $dependencies ) {
    176186                        if ( in_array( $slug, $dependencies, true ) ) {
    177187                                $dependents[] = $dependent;
     
    370380
    371381        /**
    372          * Displays an admin notice if dependencies have been deactivated.
    373          *
    374          * @since 6.5.0
    375          */
    376         public static function display_admin_notice_for_deactivated_dependents() {
    377                 /*
    378                  * Plugin deactivated if dependencies not met.
    379                  * Transient on a 10 second timeout.
    380                  */
    381                 $deactivate_requires = get_site_transient( 'wp_plugin_dependencies_deactivated_plugins' );
    382                 if ( ! empty( $deactivate_requires ) ) {
    383                         $deactivated_plugins = '';
    384                         foreach ( $deactivate_requires as $deactivated ) {
    385                                 $deactivated_plugins .= '<li>' . esc_html( self::$plugins[ $deactivated ]['Name'] ) . '</li>';
    386                         }
    387                         wp_admin_notice(
    388                                 sprintf(
    389                                         /* translators: 1: plugin names */
    390                                         __( 'The following plugin(s) have been deactivated due to uninstalled or inactive dependencies: %s' ),
    391                                         "<ul>$deactivated_plugins</ul>"
    392                                 ),
    393                                 array(
    394                                         'type'        => 'error',
    395                                         'dismissible' => true,
    396                                 )
    397                         );
    398                 }
    399         }
    400 
    401         /**
    402382         * Displays an admin notice if circular dependencies are installed.
    403383         *
     
    544524                }
    545525
    546                 $all_plugin_data = get_option( 'plugin_data', array() );
    547 
    548                 if ( empty( $all_plugin_data ) ) {
    549                         require_once ABSPATH . '/wp-admin/includes/plugin.php';
    550                         $all_plugin_data = get_plugins();
    551                 }
    552 
    553                 self::$plugins = $all_plugin_data;
     526                require_once ABSPATH . '/wp-admin/includes/plugin.php';
     527                self::$plugins = get_plugins();
    554528
    555529                return self::$plugins;
     
    622596
    623597        /**
    624          * Gets plugin filepaths for active plugins that depend on the dependency.
    625          *
    626          * Recurses for each dependent that is also a dependency.
    627          *
    628          * @param string $plugin_file The dependency's filepath, relative to the plugin directory.
    629          * @return string[] An array of active dependent plugin filepaths, relative to the plugin directory.
    630          */
    631         protected static function get_active_dependents_in_dependency_tree( $plugin_file ) {
    632                 $all_dependents = array();
    633                 $dependents     = self::get_dependents( self::convert_to_slug( $plugin_file ) );
    634 
    635                 if ( empty( $dependents ) ) {
    636                         return $all_dependents;
    637                 }
    638 
    639                 require_once ABSPATH . '/wp-admin/includes/plugin.php';
    640                 foreach ( $dependents as $dependent ) {
    641                         if ( is_plugin_active( $dependent ) ) {
    642                                 $all_dependents[] = $dependent;
    643                                 $all_dependents   = array_merge(
    644                                         $all_dependents,
    645                                         self::get_active_dependents_in_dependency_tree( $dependent )
    646                                 );
    647                         }
    648                 }
    649 
    650                 return $all_dependents;
    651         }
    652 
    653         /**
    654          * Deactivates dependent plugins with unmet dependencies.
    655          *
    656          * @since 6.5.0
    657          */
    658         protected static function deactivate_dependents_with_unmet_dependencies() {
    659                 $dependents_to_deactivate = array();
    660                 $circular_dependencies    = array_reduce(
    661                         self::get_circular_dependencies(),
    662                         function ( $all_circular, $circular_pair ) {
    663                                 return array_merge( $all_circular, $circular_pair );
    664                         },
    665                         array()
    666                 );
    667 
    668                 require_once ABSPATH . '/wp-admin/includes/plugin.php';
    669                 foreach ( self::$dependencies as $dependent => $dependencies ) {
    670                         // Skip dependents that are no longer installed or aren't active.
    671                         if ( ! array_key_exists( $dependent, self::$plugins ) || is_plugin_inactive( $dependent ) ) {
    672                                 continue;
    673                         }
    674 
    675                         // Skip plugins within a circular dependency tree or plugins that have no unmet dependencies.
    676                         if ( in_array( $dependent, $circular_dependencies, true ) || ! self::has_unmet_dependencies( $dependent ) ) {
    677                                 continue;
    678                         }
    679 
    680                         $dependents_to_deactivate[] = $dependent;
    681 
    682                         // Also add any plugins that rely on any of this plugin's dependents.
    683                         $dependents_to_deactivate = array_merge(
    684                                 $dependents_to_deactivate,
    685                                 self::get_active_dependents_in_dependency_tree( $dependent )
    686                         );
    687                 }
    688 
    689                 // Bail early if there are no dependents to deactivate.
    690                 if ( empty( $dependents_to_deactivate ) ) {
    691                         return;
    692                 }
    693 
    694                 $dependents_to_deactivate = array_unique( $dependents_to_deactivate );
    695 
    696                 deactivate_plugins( $dependents_to_deactivate );
    697                 set_site_transient( 'wp_plugin_dependencies_deactivated_plugins', $dependents_to_deactivate, 10 );
    698         }
    699 
    700         /**
    701598         * Gets the filepath of installed dependencies.
    702599         * If a dependency is not installed, the filepath defaults to false.
     
    709606                if ( is_array( self::$dependency_filepaths ) ) {
    710607                        return self::$dependency_filepaths;
     608                }
     609
     610                if ( null === self::$dependency_slugs ) {
     611                        return array();
    711612                }
    712613
     
    847748                }
    848749
     750                if ( null === self::$dependencies ) {
     751                        return array();
     752                }
     753
    849754                self::$circular_dependencies_slugs = array();
    850755
  • trunk/src/wp-settings.php

    r57628 r57658  
    389389require ABSPATH . WPINC . '/interactivity-api/class-wp-interactivity-api-directives-processor.php';
    390390require ABSPATH . WPINC . '/interactivity-api/interactivity-api.php';
     391require ABSPATH . WPINC . '/class-wp-plugin-dependencies.php';
    391392
    392393wp_script_modules()->add_hooks();
     
    419420
    420421$GLOBALS['wp_plugin_paths'] = array();
    421 
    422 // Load and initialize WP_Plugin_Dependencies.
    423 require_once ABSPATH . WPINC . '/class-wp-plugin-dependencies.php';
    424 if ( ! defined( 'WP_RUN_CORE_TESTS' ) ) {
    425         WP_Plugin_Dependencies::initialize();
    426 }
    427422
    428423// Load must-use plugins.
     
    500495
    501496// Load active plugins.
    502 $all_plugin_data    = get_option( 'plugin_data', array() );
    503 $failed_plugins     = array();
    504 $plugins_dir_strlen = strlen( trailingslashit( WP_PLUGIN_DIR ) );
    505497foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
    506         $plugin_file = substr( $plugin, $plugins_dir_strlen );
    507 
    508         /*
    509          * Skip any plugins that have not been added to the 'plugin_data' option yet.
    510          *
    511          * Some plugin files may be added locally and activated, but will not yet be
    512          * added to the 'plugin_data' option. This causes the 'active_plugins' option
    513          * and the 'plugin_data' option to be temporarily out of sync until the next
    514          * call to `get_plugins()`.
    515          */
    516         if ( isset( $all_plugin_data[ $plugin_file ] ) ) {
    517                 $plugin_headers = $all_plugin_data[ $plugin_file ];
    518                 $errors         = array();
    519                 $requirements   = array(
    520                         'requires'     => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
    521                         'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
    522                 );
    523                 $compatible_wp  = is_wp_version_compatible( $requirements['requires'] );
    524                 $compatible_php = is_php_version_compatible( $requirements['requires_php'] );
    525 
    526                 $php_update_message = '</p><p>' . sprintf(
    527                         /* translators: %s: URL to Update PHP page. */
    528                         __( '<a href="%s">Learn more about updating PHP</a>.' ),
    529                         esc_url( wp_get_update_php_url() )
    530                 );
    531 
    532                 $annotation = wp_get_update_php_annotation();
    533 
    534                 if ( $annotation ) {
    535                         $php_update_message .= '</p><p><em>' . $annotation . '</em>';
    536                 }
    537 
    538                 if ( ! $compatible_wp && ! $compatible_php ) {
    539                         $errors[] = sprintf(
    540                                 /* translators: 1: Current WordPress version, 2: Current PHP version, 3: Plugin name, 4: Required WordPress version, 5: Required PHP version. */
    541                                 _x( '<strong>Error:</strong> 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' ),
    542                                 get_bloginfo( 'version' ),
    543                                 PHP_VERSION,
    544                                 $plugin_headers['Name'],
    545                                 $requirements['requires'],
    546                                 $requirements['requires_php']
    547                         ) . $php_update_message;
    548                 } elseif ( ! $compatible_php ) {
    549                         $errors[] = sprintf(
    550                                 /* translators: 1: Current PHP version, 2: Plugin name, 3: Required PHP version. */
    551                                 _x( '<strong>Error:</strong> Current PHP version (%1$s) does not meet minimum requirements for %2$s. The plugin requires PHP %3$s.', 'plugin' ),
    552                                 PHP_VERSION,
    553                                 $plugin_headers['Name'],
    554                                 $requirements['requires_php']
    555                         ) . $php_update_message;
    556                 } elseif ( ! $compatible_wp ) {
    557                         $errors[] = sprintf(
    558                                 /* translators: 1: Current WordPress version, 2: Plugin name, 3: Required WordPress version. */
    559                                 _x( '<strong>Error:</strong> Current WordPress version (%1$s) does not meet minimum requirements for %2$s. The plugin requires WordPress %3$s.', 'plugin' ),
    560                                 get_bloginfo( 'version' ),
    561                                 $plugin_headers['Name'],
    562                                 $requirements['requires']
    563                         );
    564                 }
    565 
    566                 if ( ! empty( $errors ) ) {
    567                         $failed_plugins[ $plugin_file ] = '';
    568                         foreach ( $errors as $error ) {
    569                                 $failed_plugins[ $plugin_file ] .= wp_get_admin_notice(
    570                                         $error,
    571                                         array(
    572                                                 'type'        => 'error',
    573                                                 'dismissible' => true,
    574                                         )
    575                                 );
    576                         }
    577                         continue;
    578                 }
    579         }
    580 
    581498        wp_register_plugin_realpath( $plugin );
    582499
     
    596513unset( $plugin, $_wp_plugin_file );
    597514
    598 if ( ! empty( $failed_plugins ) ) {
    599         add_action(
    600                 'admin_notices',
    601                 function () use ( $failed_plugins ) {
    602                         global $pagenow;
    603 
    604                         if ( 'index.php' === $pagenow || 'plugins.php' === $pagenow ) {
    605                                 echo implode( '', $failed_plugins );
    606                         }
    607                 }
    608         );
    609 }
    610 unset( $failed_plugins );
    611 
    612515// Load pluggable functions.
    613516require ABSPATH . WPINC . '/pluggable.php';
  • trunk/tests/phpunit/tests/admin/plugin-dependencies/base.php

    r57545 r57658  
    3333                'circular_dependencies_pairs' => null,
    3434                'circular_dependencies_slugs' => null,
     35                'initialized'                 => false,
    3536        );
    3637
     
    6364         * Resets all static properties to a default value after each test.
    6465         */
    65         public function set_up() {
    66                 parent::set_up();
    67 
     66        public function tear_down() {
    6867                foreach ( self::$static_properties as $name => $default_value ) {
    6968                        $this->set_property_value( $name, $default_value );
    7069                }
     70
     71                parent::tear_down();
    7172        }
    7273
  • trunk/tests/phpunit/tests/admin/plugin-dependencies/getDependencyFilepath.php

    r57545 r57658  
    1717 */
    1818class Tests_Admin_WPPluginDependencies_GetDependencyFilepath extends WP_PluginDependencies_UnitTestCase {
     19
     20        /**
     21         * Tests that false is returned if Plugin Dependencies has not been initialized.
     22         *
     23         * @ticket 60457
     24         */
     25        public function test_should_return_false_before_initialization() {
     26                // Ensure Plugin Dependencies has not been initialized.
     27                $this->assertFalse(
     28                        $this->get_property_value( 'initialized' ),
     29                        'Plugin Dependencies has been initialized.'
     30                );
     31
     32                $this->assertSame(
     33                        self::$static_properties['dependency_slugs'],
     34                        $this->get_property_value( 'dependency_slugs' ),
     35                        '"dependency_slugs" was not set to its default value.'
     36                );
     37
     38                $this->assertFalse(
     39                        self::$instance->get_dependency_filepath( 'dependency' ),
     40                        'false was not returned before initialization.'
     41                );
     42        }
    1943
    2044        /**
  • trunk/tests/phpunit/tests/admin/plugin-dependencies/hasCircularDependency.php

    r57545 r57658  
    1717 */
    1818class Tests_Admin_WPPluginDependencies_HasCircularDependency extends WP_PluginDependencies_UnitTestCase {
     19
     20        /**
     21         * Tests that false is returned if Plugin Dependencies has not been initialized.
     22         *
     23         * @ticket 60457
     24         */
     25        public function test_should_return_false_before_initialization() {
     26                $this->set_property_value(
     27                        'plugins',
     28                        array(
     29                                'dependent/dependent.php'   => array(
     30                                        'Name'            => 'Dependent',
     31                                        'RequiresPlugins' => 'dependency',
     32                                ),
     33                                'dependency/dependency.php' => array(
     34                                        'Name'            => 'Dependency',
     35                                        'RequiresPlugins' => 'dependent',
     36                                ),
     37                        )
     38                );
     39
     40                // Ensure Plugin Dependencies has not been initialized.
     41                $this->assertFalse(
     42                        $this->get_property_value( 'initialized' ),
     43                        'Plugin Dependencies has been initialized.'
     44                );
     45
     46                $this->assertSame(
     47                        self::$static_properties['circular_dependencies_slugs'],
     48                        $this->get_property_value( 'circular_dependencies_slugs' ),
     49                        '"circular_dependencies_slugs" was not set to its default value.'
     50                );
     51
     52                $this->assertFalse(
     53                        self::$instance->has_circular_dependency( 'dependency' ),
     54                        'false was not returned before initialization.'
     55                );
     56        }
    1957
    2058        /**
  • trunk/tests/phpunit/tests/admin/plugin-dependencies/initialize.php

    r57545 r57658  
    1515 */
    1616class Tests_Admin_WPPluginDependencies_Initialize extends WP_PluginDependencies_UnitTestCase {
     17
     18        /**
     19         * Tests that initialization runs only once.
     20         *
     21         * @ticket 60457
     22         *
     23         * @dataProvider data_static_properties_set_during_initialization
     24         *
     25         * @param string $property_name The name of the property to check.
     26         */
     27        public function test_should_only_initialize_once( $property_name ) {
     28                $this->assertFalse(
     29                        $this->get_property_value( 'initialized' ),
     30                        'Plugin Dependencies has already been initialized.'
     31                );
     32
     33                self::$instance->initialize();
     34
     35                $this->assertTrue(
     36                        $this->get_property_value( 'initialized' ),
     37                        '"initialized" was not set to true during initialization.'
     38                );
     39
     40                $default_value = self::$static_properties[ $property_name ];
     41
     42                $this->assertNotSame(
     43                        $default_value,
     44                        $this->get_property_value( $property_name ),
     45                        "\"{$property_name}\" was not set during initialization."
     46                );
     47
     48                // Reset it to its default.
     49                $this->set_property_value( $property_name, self::$static_properties[ $property_name ] );
     50
     51                self::$instance->initialize();
     52
     53                $this->assertSame(
     54                        $default_value,
     55                        $this->get_property_value( $property_name ),
     56                        "\"{$property_name}\" was set during the second initialization attempt."
     57                );
     58        }
     59
     60        /**
     61         * Data provider.
     62         *
     63         * @return array[]
     64         */
     65        public function data_static_properties_set_during_initialization() {
     66                /*
     67                 * This does not include 'dependency_api_data' as it is only set
     68                 * on certain pages. This is tested later.
     69                 */
     70                return self::text_array_to_dataprovider(
     71                        array(
     72                                'plugins',
     73                                'dependencies',
     74                                'dependency_slugs',
     75                                'dependent_slugs',
     76                        )
     77                );
     78        }
    1779
    1880        /**
     
    239301                $this->assertSame( $expected_slugs, $this->get_property_value( 'dependent_slugs' ) );
    240302        }
    241 
    242         /**
    243          * Tests that dependents with unmet dependencies are deactivated.
    244          *
    245          * @ticket 22316
    246          *
    247          * @covers WP_Plugin_Dependencies::deactivate_dependents_with_unmet_dependencies
    248          * @covers WP_Plugin_Dependencies::has_unmet_dependencies
    249          * @covers WP_Plugin_Dependencies::get_active_dependents_in_dependency_tree
    250          *
    251          * @dataProvider data_should_only_deactivate_dependents_with_unmet_dependencies
    252          *
    253          * @param array $active_plugins An array of active plugin paths.
    254          * @param array $plugins        An array of installed plugins.
    255          * @param array $expected       The expected value of 'active_plugins' after initialization.
    256          */
    257         public function test_should_deactivate_dependents_with_uninstalled_dependencies( $active_plugins, $plugins, $expected ) {
    258                 update_option( 'active_plugins', $active_plugins );
    259 
    260                 $this->set_property_value( 'plugins', $plugins );
    261                 self::$instance::initialize();
    262 
    263                 $this->assertSame( $expected, array_values( get_option( 'active_plugins', array() ) ) );
    264         }
    265 
    266         /**
    267          * Data provider.
    268          *
    269          * @return array[]
    270          */
    271         public function data_should_only_deactivate_dependents_with_unmet_dependencies() {
    272                 return array(
    273                         'a dependent with an uninstalled dependency' => array(
    274                                 'active_plugins' => array( 'dependent/dependent.php' ),
    275                                 'plugins'        => array(
    276                                         'dependent/dependent.php' => array( 'RequiresPlugins' => 'dependency' ),
    277                                 ),
    278                                 'expected'       => array(),
    279                         ),
    280                         'a dependent with an inactive dependency'    => array(
    281                                 'active_plugins' => array( 'dependent/dependent.php' ),
    282                                 'plugins'        => array(
    283                                         'dependent/dependent.php'   => array( 'RequiresPlugins' => 'dependency' ),
    284                                         'dependency/dependency.php' => array( 'RequiresPlugins' => '' ),
    285                                 ),
    286                                 'expected'       => array(),
    287                         ),
    288                         'a dependent with two dependencies, one uninstalled, one inactive' => array(
    289                                 'active_plugins' => array( 'dependent/dependent.php' ),
    290                                 'plugins'        => array(
    291                                         'dependent/dependent.php'     => array( 'RequiresPlugins' => 'dependency, dependency2' ),
    292                                         'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ),
    293                                 ),
    294                                 'expected'       => array(),
    295                         ),
    296                         'a dependent with a dependency that is installed and active' => array(
    297                                 'active_plugins' => array( 'dependent/dependent.php', 'dependency/dependency.php' ),
    298                                 'plugins'        => array(
    299                                         'dependent/dependent.php'   => array( 'RequiresPlugins' => 'dependency' ),
    300                                         'dependency/dependency.php' => array( 'RequiresPlugins' => '' ),
    301                                 ),
    302                                 'expected'       => array( 'dependent/dependent.php', 'dependency/dependency.php' ),
    303                         ),
    304                         'one dependent with two dependencies that are installed and active' => array(
    305                                 'active_plugins' => array(
    306                                         'dependent/dependent.php',
    307                                         'dependency/dependency.php',
    308                                         'dependency2/dependency2.php',
    309                                 ),
    310                                 'plugins'        => array(
    311                                         'dependent/dependent.php'     => array( 'RequiresPlugins' => 'dependency, dependency2' ),
    312                                         'dependency/dependency.php'   => array( 'RequiresPlugins' => '' ),
    313                                         'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ),
    314                                 ),
    315                                 'expected'       => array(
    316                                         'dependent/dependent.php',
    317                                         'dependency/dependency.php',
    318                                         'dependency2/dependency2.php',
    319                                 ),
    320                         ),
    321                         'two dependents, one with an uninstalled dependency, and one with an active dependency' => array(
    322                                 'active_plugins' => array(
    323                                         'dependent/dependent.php',
    324                                         'dependent2/dependent2.php',
    325                                         'dependency2/dependency2.php',
    326                                 ),
    327                                 'plugins'        => array(
    328                                         'dependent/dependent.php'     => array( 'RequiresPlugins' => 'dependency' ),
    329                                         'dependent2/dependent2.php'   => array( 'RequiresPlugins' => 'dependency2' ),
    330                                         'dependency2/dependency2.php' => array( 'RequiresPlugins' => '' ),
    331                                 ),
    332                                 'expected'       => array( 'dependent2/dependent2.php', 'dependency2/dependency2.php' ),
    333                         ),
    334                 );
    335         }
    336303}
Note: See TracChangeset for help on using the changeset viewer.