PluginUtil: Add method to get active valid plugins (2nd attempt) (#50974)

* Restore changes from 48709

* Update the PluginUtil method and related unit test

* Update API endpoint, fix schemas

* Improve unit tests for API controllers
This commit is contained in:
Corey McKrill 2024-08-27 23:44:17 -07:00 committed by GitHub
parent 4dbc8aa74b
commit eb868090b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 126 additions and 25 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Ensure that active plugins shown in the System Status API endpoint actually exist

View File

@ -17,7 +17,7 @@ use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchro
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper;
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Utilities\{ OrderUtil, PluginUtil };
use Automattic\WooCommerce\Internal\Utilities\PluginInstaller;
defined( 'ABSPATH' ) || exit;
@ -1283,7 +1283,8 @@ class WC_Install {
return;
}
if ( in_array( $legacy_api_plugin, wp_get_active_and_valid_plugins(), true ) ) {
$active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins();
if ( in_array( $legacy_api_plugin, $active_valid_plugins, true ) ) {
return;
}

View File

@ -13,7 +13,7 @@ defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer as Order_DataSynchronizer;
use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil };
use Automattic\WooCommerce\Utilities\{ LoggingUtil, OrderUtil, PluginUtil };
/**
* System status controller class.
@ -373,8 +373,42 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'object',
'properties' => array(
'plugin' => array(
'description' => __( 'Plugin basename. The path to the main plugin file relative to the plugins directory.', 'woocommerce' ),
'type' => 'string',
),
'name' => array(
'description' => __( 'Name of the plugin.', 'woocommerce' ),
'type' => 'string',
),
'version' => array(
'description' => __( 'Current plugin version.', 'woocommerce' ),
'type' => 'string',
),
'version_latest' => array(
'description' => __( 'Latest available plugin version.', 'woocommerce' ),
'type' => 'string',
),
'url' => array(
'description' => __( 'Plugin URL.', 'woocommerce' ),
'type' => 'string',
),
'author_name' => array(
'description' => __( 'Plugin author name.', 'woocommerce' ),
'type' => 'string',
),
'author_url' => array(
'description' => __( 'Plugin author URL.', 'woocommerce' ),
'type' => 'string',
),
'network_activated' => array(
'description' => __( 'Whether the plugin can only be activated network-wide.', 'woocommerce' ),
'type' => 'boolean',
),
),
),
),
'inactive_plugins' => array(
'description' => __( 'Inactive plugins.', 'woocommerce' ),
@ -382,8 +416,42 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
'context' => array( 'view' ),
'readonly' => true,
'items' => array(
'type' => 'object',
'properties' => array(
'plugin' => array(
'description' => __( 'Plugin basename. The path to the main plugin file relative to the plugins directory.', 'woocommerce' ),
'type' => 'string',
),
'name' => array(
'description' => __( 'Name of the plugin.', 'woocommerce' ),
'type' => 'string',
),
'version' => array(
'description' => __( 'Current plugin version.', 'woocommerce' ),
'type' => 'string',
),
'version_latest' => array(
'description' => __( 'Latest available plugin version.', 'woocommerce' ),
'type' => 'string',
),
'url' => array(
'description' => __( 'Plugin URL.', 'woocommerce' ),
'type' => 'string',
),
'author_name' => array(
'description' => __( 'Plugin author name.', 'woocommerce' ),
'type' => 'string',
),
'author_url' => array(
'description' => __( 'Plugin author URL.', 'woocommerce' ),
'type' => 'string',
),
'network_activated' => array(
'description' => __( 'Whether the plugin can only be activated network-wide.', 'woocommerce' ),
'type' => 'boolean',
),
),
),
),
'dropins_mu_plugins' => array(
'description' => __( 'Dropins & MU plugins.', 'woocommerce' ),
@ -1044,15 +1112,10 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
return array();
}
$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ) {
$network_activated_plugins = array_keys( get_site_option( 'active_sitewide_plugins', array() ) );
$active_plugins = array_merge( $active_plugins, $network_activated_plugins );
}
$active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins();
$active_plugins_data = array();
foreach ( $active_plugins as $plugin ) {
foreach ( $active_valid_plugins as $plugin ) {
$data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$active_plugins_data[] = $this->format_plugin_data( $plugin, $data );
}

View File

@ -4,7 +4,7 @@ namespace Automattic\WooCommerce\Internal\Utilities;
use Automattic\WooCommerce\Internal\RegisterHooksInterface;
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
use Automattic\WooCommerce\Utilities\StringUtil;
use Automattic\WooCommerce\Utilities\{ PluginUtil, StringUtil };
/**
* This class allows installing a plugin programmatically.
@ -206,7 +206,14 @@ class PluginInstaller implements RegisterHooksInterface {
* @return bool True if WooCommerce is installed and active in the current blog, false otherwise.
*/
private static function woocommerce_is_active_in_current_site(): bool {
return ! empty( array_filter( wp_get_active_and_valid_plugins(), fn( $plugin ) => substr_compare( $plugin, '/woocommerce.php', -strlen( '/woocommerce.php' ) ) === 0 ) );
$active_valid_plugins = wc_get_container()->get( PluginUtil::class )->get_all_active_valid_plugins();
return ! empty(
array_filter(
$active_valid_plugins,
fn( $plugin ) => substr_compare( $plugin, '/woocommerce.php', -strlen( '/woocommerce.php' ) ) === 0
)
);
}
/**

View File

@ -78,7 +78,7 @@ class PluginUtil {
* Note that the doc block for `wp_get_active_and_valid_plugins` says it returns "Array of paths to plugin files
* relative to the plugins directory", but it actually returns absolute paths.
*
* @return string[] Array of absolute paths to plugin files.
* @return string[] Array of plugin basenames (paths relative to the plugin directory).
*/
public function get_all_active_valid_plugins() {
$local = wp_get_active_and_valid_plugins();
@ -91,8 +91,11 @@ class PluginUtil {
}
$all = array_merge( $local, $network );
$all = array_unique( $all );
$all = array_map( 'plugin_basename', $all );
sort( $all );
return array_unique( $all );
return $all;
}
/**

View File

@ -154,9 +154,8 @@ class WC_Tests_REST_System_Status_V2 extends WC_REST_Unit_Test_Case {
* @since 3.0.0
*/
public function test_get_system_status_info_active_plugins() {
$this->skip_on_php_8_1();
wp_set_current_user( self::$administrator_user );
delete_transient( 'wc_system_status_active_plugins' );
$actual_plugins = array( 'hello.php' );
update_option( 'active_plugins', $actual_plugins );
@ -165,9 +164,20 @@ class WC_Tests_REST_System_Status_V2 extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$plugins = (array) $data['active_plugins'];
$this->assertEquals( 1, count( $plugins ) );
$this->assertEquals( 'Hello Dolly', $plugins[0]['name'] );
$plugin = reset( $plugins );
$this->assertArrayHasKey( 'plugin', $plugin );
$this->assertEquals( 'hello.php', $plugin['plugin'] );
$this->assertArrayHasKey( 'name', $plugin );
$this->assertEquals( 'Hello Dolly', $plugin['name'] );
$this->assertArrayHasKey( 'version', $plugin );
$this->assertArrayHasKey( 'version_latest', $plugin );
$this->assertArrayHasKey( 'url', $plugin );
$this->assertArrayHasKey( 'author_name', $plugin );
$this->assertArrayHasKey( 'author_url', $plugin );
$this->assertArrayHasKey( 'network_activated', $plugin );
$this->assertEquals( false, $plugin['network_activated'] );
}
/**

View File

@ -183,6 +183,8 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case {
*/
public function test_get_system_status_info_active_plugins() {
wp_set_current_user( self::$administrator_user );
delete_transient( 'wc_system_status_active_plugins' );
$actual_plugins = array( 'hello.php' );
update_option( 'active_plugins', $actual_plugins );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/system_status' ) );
@ -190,9 +192,20 @@ class WC_Tests_REST_System_Status extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$plugins = (array) $data['active_plugins'];
$this->assertEquals( 1, count( $plugins ) );
$this->assertEquals( 'Hello Dolly', $plugins[0]['name'] );
$plugin = reset( $plugins );
$this->assertArrayHasKey( 'plugin', $plugin );
$this->assertEquals( 'hello.php', $plugin['plugin'] );
$this->assertArrayHasKey( 'name', $plugin );
$this->assertEquals( 'Hello Dolly', $plugin['name'] );
$this->assertArrayHasKey( 'version', $plugin );
$this->assertArrayHasKey( 'version_latest', $plugin );
$this->assertArrayHasKey( 'url', $plugin );
$this->assertArrayHasKey( 'author_name', $plugin );
$this->assertArrayHasKey( 'author_url', $plugin );
$this->assertArrayHasKey( 'network_activated', $plugin );
$this->assertEquals( false, $plugin['network_activated'] );
}
/**

View File

@ -64,12 +64,12 @@ class PluginUtilTests extends \WC_Unit_Test_Case {
if ( is_multisite() ) {
$this->assertCount( 2, $active_valid_plugins );
$this->assertContains( WP_PLUGIN_DIR . '/test3/test3.php', $active_valid_plugins );
$this->assertContains( 'test3/test3.php', $active_valid_plugins );
} else {
$this->assertCount( 1, $active_valid_plugins );
}
$this->assertContains( WP_PLUGIN_DIR . '/test1/test1.php', $active_valid_plugins );
$this->assertContains( 'test1/test1.php', $active_valid_plugins );
if ( false === $orig_local_plugins ) {
delete_option( 'active_plugins' );