Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions src/wp-includes/class-wp-connector-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
* env_var_name?: non-empty-string
* },
* plugin?: array{
* file: non-empty-string
* file: non-empty-string,
* is_active?: callable(): bool
* }
* }
*/
Expand Down Expand Up @@ -109,8 +110,12 @@ final class WP_Connector_Registry {
* @type array $plugin {
* Optional. Plugin data for install/activate UI.
*
* @type string $file The plugin's main file path relative to the plugins
* directory (e.g. 'my-plugin/my-plugin.php' or 'hello.php').
* @type string $file Optional. The plugin's main file path relative to the
* plugins directory (e.g. 'my-plugin/my-plugin.php' or
* 'hello.php').
* @type callable $is_active Optional callback to determine whether the plugin
* is active. Receives no arguments and must return bool.
* Defaults to `__return_true`.
* }
* }
* @return array|null The registered connector data on success, null on failure.
Expand Down Expand Up @@ -243,8 +248,30 @@ public function register( string $id, array $args ): ?array {
}
}

if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) && ! empty( $args['plugin']['file'] ) ) {
$connector['plugin'] = array( 'file' => $args['plugin']['file'] );
$connector['plugin'] = array();

if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) ) {
if ( ! empty( $args['plugin']['file'] ) ) {
$connector['plugin']['file'] = $args['plugin']['file'];
}

if ( isset( $args['plugin']['is_active'] ) ) {
if ( ! is_callable( $args['plugin']['is_active'] ) ) {
_doing_it_wrong(
__METHOD__,
/* translators: %s: Connector ID. */
sprintf( __( 'Connector "%s" plugin is_active must be callable.' ), esc_html( $id ) ),
'7.0.0'
);
return null;
}

$connector['plugin']['is_active'] = $args['plugin']['is_active'];
}
}

if ( ! isset( $connector['plugin']['is_active'] ) ) {
$connector['plugin']['is_active'] = '__return_true';
}

$this->registered_connectors[ $id ] = $connector;
Expand Down
19 changes: 13 additions & 6 deletions src/wp-includes/connectors.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,17 @@ function _wp_connectors_register_default_ai_providers( WP_Connector_Registry $re
}
}
}

if ( ! isset( $args['plugin']['is_active'] ) ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That one is very important 👍🏻

$args['plugin']['is_active'] = static function () use ( $ai_registry, $id ): bool {
try {
return $ai_registry->hasProvider( $id );
} catch ( Exception $e ) {
return false;
}
};
}

$registry->register( $id, $args );
}
}
Expand Down Expand Up @@ -638,10 +649,6 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void {
function _wp_connectors_get_connector_script_module_data( array $data ): array {
$registry = AiClient::defaultRegistry();

if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

$connectors = array();
foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
$auth = $connector_data['authentication'];
Expand Down Expand Up @@ -674,8 +681,8 @@ function _wp_connectors_get_connector_script_module_data( array $data ): array {

if ( ! empty( $connector_data['plugin']['file'] ) ) {
$file = $connector_data['plugin']['file'];
$is_installed = file_exists( wp_normalize_path( WP_PLUGIN_DIR . '/' . $file ) );
$is_activated = $is_installed && is_plugin_active( $file );
$is_activated = (bool) call_user_func( $connector_data['plugin']['is_active'] );
$is_installed = $is_activated || file_exists( wp_normalize_path( WP_PLUGIN_DIR . '/' . $file ) );

$connector_out['plugin'] = array(
'file' => $file,
Expand Down
56 changes: 53 additions & 3 deletions tests/phpunit/tests/connectors/wpConnectorRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,66 @@ public function test_register_includes_plugin_data() {
$result = $this->registry->register( 'with-plugin', $args );

$this->assertArrayHasKey( 'plugin', $result );
$this->assertSame( array( 'file' => 'my-plugin/my-plugin.php' ), $result['plugin'] );
$this->assertSame( 'my-plugin/my-plugin.php', $result['plugin']['file'] );
}

/**
* @ticket 65020
*/
public function test_register_stores_plugin_is_active_callback() {
$args = self::$default_args;
$args['plugin'] = array(
'file' => 'my-plugin/my-plugin.php',
'is_active' => '__return_true',
);

$result = $this->registry->register( 'with-callback', $args );

$this->assertIsArray( $result );
$this->assertArrayHasKey( 'is_active', $result['plugin'] );
$this->assertIsCallable( $result['plugin']['is_active'] );
}

/**
* @ticket 65020
*/
public function test_register_rejects_non_callable_plugin_is_active() {
$this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );

$args = self::$default_args;
$args['plugin'] = array(
'file' => 'my-plugin/my-plugin.php',
'is_active' => 'not_a_real_function_name',
);

$result = $this->registry->register( 'bad-callback', $args );

$this->assertNull( $result );
}

/**
* @ticket 65020
*/
public function test_register_defaults_plugin_is_active_to_return_true() {
$args = self::$default_args;
$args['plugin'] = array( 'file' => 'my-plugin/my-plugin.php' );

$result = $this->registry->register( 'default-callback', $args );

$this->assertIsArray( $result );
$this->assertArrayHasKey( 'is_active', $result['plugin'] );
$this->assertSame( '__return_true', $result['plugin']['is_active'] );
}

/**
* @ticket 64791
*/
public function test_register_omits_plugin_when_not_provided() {
public function test_register_defaults_plugin_when_not_provided() {
$result = $this->registry->register( 'no-plugin', self::$default_args );

$this->assertArrayNotHasKey( 'plugin', $result );
$this->assertArrayHasKey( 'plugin', $result );
$this->assertArrayNotHasKey( 'file', $result['plugin'] );
$this->assertSame( '__return_true', $result['plugin']['is_active'] );
}

/**
Expand Down
Loading