diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 18a5f80c94dbd..d7643360efeeb 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -40,7 +40,7 @@ * env_var_name?: non-empty-string * }, * plugin?: array{ - * slug: non-empty-string + * file: non-empty-string * } * } */ @@ -109,7 +109,8 @@ final class WP_Connector_Registry { * @type array $plugin { * Optional. Plugin data for install/activate UI. * - * @type string $slug The WordPress.org plugin slug. + * @type string $file The plugin's main file path relative to the plugins + * directory (e.g. 'akismet/akismet.php' or 'hello.php'). * } * } * @return array|null The registered connector data on success, null on failure. @@ -242,8 +243,8 @@ public function register( string $id, array $args ): ?array { } } - if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) ) { - $connector['plugin'] = $args['plugin']; + if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) && ! empty( $args['plugin']['file'] ) ) { + $connector['plugin'] = array( 'file' => $args['plugin']['file'] ); } $this->registered_connectors[ $id ] = $connector; diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 06683ccaaa25c..68c8b4c1570d0 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -58,7 +58,8 @@ function wp_is_connector_registered( string $id ): bool { * @type array $plugin { * Optional. Plugin data for install/activate UI. * - * @type string $slug The WordPress.org plugin slug. + * @type string $file The plugin's main file path relative to the plugins + * directory (e.g. 'akismet/akismet.php' or 'hello.php'). * } * } * @phpstan-return ?array{ @@ -74,7 +75,7 @@ function wp_is_connector_registered( string $id ): bool { * env_var_name?: non-empty-string * }, * plugin?: array{ - * slug: non-empty-string + * file: non-empty-string * } * } */ @@ -118,7 +119,8 @@ function wp_get_connector( string $id ): ?array { * @type array $plugin { * Optional. Plugin data for install/activate UI. * - * @type string $slug The WordPress.org plugin slug. + * @type string $file The plugin's main file path relative to the plugins + * directory (e.g. 'akismet/akismet.php' or 'hello.php'). * } * } * } @@ -135,7 +137,7 @@ function wp_get_connector( string $id ): ?array { * env_var_name?: non-empty-string * }, * plugin?: array{ - * slug: non-empty-string + * file: non-empty-string * } * }> */ @@ -256,7 +258,7 @@ function _wp_connectors_register_default_ai_providers( WP_Connector_Registry $re 'description' => __( 'Text generation with Claude.' ), 'type' => 'ai_provider', 'plugin' => array( - 'slug' => 'ai-provider-for-anthropic', + 'file' => 'ai-provider-for-anthropic/plugin.php', ), 'authentication' => array( 'method' => 'api_key', @@ -268,7 +270,7 @@ function _wp_connectors_register_default_ai_providers( WP_Connector_Registry $re 'description' => __( 'Text and image generation with Gemini and Imagen.' ), 'type' => 'ai_provider', 'plugin' => array( - 'slug' => 'ai-provider-for-google', + 'file' => 'ai-provider-for-google/plugin.php', ), 'authentication' => array( 'method' => 'api_key', @@ -280,7 +282,7 @@ function _wp_connectors_register_default_ai_providers( WP_Connector_Registry $re 'description' => __( 'Text and image generation with GPT and Dall-E.' ), 'type' => 'ai_provider', 'plugin' => array( - 'slug' => 'ai-provider-for-openai', + 'file' => 'ai-provider-for-openai/plugin.php', ), 'authentication' => array( 'method' => 'api_key', @@ -636,15 +638,9 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void { function _wp_connectors_get_connector_script_module_data( array $data ): array { $registry = AiClient::defaultRegistry(); - // Build a slug-to-file map for plugin installation status. - if ( ! function_exists( 'get_plugins' ) ) { + if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } - $plugin_files_by_slug = array(); - foreach ( array_keys( get_plugins() ) as $plugin_file ) { - $slug = str_contains( $plugin_file, '/' ) ? dirname( $plugin_file ) : str_replace( '.php', '', $plugin_file ); - $plugin_files_by_slug[ $slug ] = $plugin_file; - } $connectors = array(); foreach ( wp_get_connectors() as $connector_id => $connector_data ) { @@ -676,18 +672,14 @@ function _wp_connectors_get_connector_script_module_data( array $data ): array { 'authentication' => $auth_out, ); - if ( ! empty( $connector_data['plugin']['slug'] ) ) { - $plugin_slug = $connector_data['plugin']['slug']; - $plugin_file = $plugin_files_by_slug[ $plugin_slug ] ?? null; - - $is_installed = null !== $plugin_file; - $is_activated = $is_installed && is_plugin_active( $plugin_file ); + 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 ); $connector_out['plugin'] = array( - 'slug' => $plugin_slug, - 'pluginFile' => $is_installed - ? ( str_ends_with( $plugin_file, '.php' ) ? substr( $plugin_file, 0, -4 ) : $plugin_file ) - : null, + 'file' => $file, + 'isInstalled' => $is_installed, 'isActivated' => $is_activated, ); } diff --git a/tests/phpunit/tests/connectors/wpConnectorRegistry.php b/tests/phpunit/tests/connectors/wpConnectorRegistry.php index cab030d930dcd..d1a46dc0981fe 100644 --- a/tests/phpunit/tests/connectors/wpConnectorRegistry.php +++ b/tests/phpunit/tests/connectors/wpConnectorRegistry.php @@ -294,12 +294,12 @@ public function test_register_omits_logo_url_when_empty() { */ public function test_register_includes_plugin_data() { $args = self::$default_args; - $args['plugin'] = array( 'slug' => 'my-plugin' ); + $args['plugin'] = array( 'file' => 'my-plugin/my-plugin.php' ); $result = $this->registry->register( 'with-plugin', $args ); $this->assertArrayHasKey( 'plugin', $result ); - $this->assertSame( array( 'slug' => 'my-plugin' ), $result['plugin'] ); + $this->assertSame( array( 'file' => 'my-plugin/my-plugin.php' ), $result['plugin'] ); } /**