This includes a `WP_AI_SUPPORT` constant and a `wp_supports_ai` filter. When false, - `_wp_connectors_get_provider_settings()` will return an empty array (short-circuiting the other functionality). - `WP_AI_Client_Prompt_Builder()` will short-circuit the construction with a `WP_Error()`. `wp_ai_client_prompt()` will still return an instance, to allow for fluidity to remain intact. Priority: `WP_AI_SUPPORT` > `add_filter( 'wp_supports_ai', ...) > (default: true)` Follow-up to [61943], [61749], [61943]. Props justlevine, westonruter, gziolo, flixos90, romainmrhenry, ahortin, chrismcelroyseo, SergeyBiryukov. See #64706. Built from https://develop.svn.wordpress.org/trunk@62067 git-svn-id: http://core.svn.wordpress.org/trunk@61349 1a063a9b-81f0-0310-95a4-ce76da25c4cd
660 lines
20 KiB
PHP
660 lines
20 KiB
PHP
<?php
|
|
/**
|
|
* Connectors API.
|
|
*
|
|
* @package WordPress
|
|
* @subpackage Connectors
|
|
* @since 7.0.0
|
|
*/
|
|
|
|
use WordPress\AiClient\AiClient;
|
|
use WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication;
|
|
|
|
/**
|
|
* Checks if a connector is registered.
|
|
*
|
|
* @since 7.0.0
|
|
*
|
|
* @see WP_Connector_Registry::is_registered()
|
|
*
|
|
* @param string $id The connector identifier.
|
|
* @return bool True if the connector is registered, false otherwise.
|
|
*/
|
|
function wp_is_connector_registered( string $id ): bool {
|
|
$registry = WP_Connector_Registry::get_instance();
|
|
if ( null === $registry ) {
|
|
return false;
|
|
}
|
|
|
|
return $registry->is_registered( $id );
|
|
}
|
|
|
|
/**
|
|
* Retrieves a registered connector.
|
|
*
|
|
* @since 7.0.0
|
|
*
|
|
* @see WP_Connector_Registry::get_registered()
|
|
*
|
|
* @param string $id The connector identifier.
|
|
* @return array|null {
|
|
* Connector data, or null if not registered.
|
|
*
|
|
* @type string $name The connector's display name.
|
|
* @type string $description The connector's description.
|
|
* @type string $logo_url Optional. URL to the connector's logo image.
|
|
* @type string $type The connector type. Currently, only 'ai_provider' is supported.
|
|
* @type array $authentication {
|
|
* Authentication configuration. When method is 'api_key', includes
|
|
* credentials_url and setting_name. When 'none', only method is present.
|
|
*
|
|
* @type string $method The authentication method: 'api_key' or 'none'.
|
|
* @type string $credentials_url Optional. URL where users can obtain API credentials.
|
|
* @type string $setting_name Optional. The setting name for the API key.
|
|
* }
|
|
* @type array $plugin {
|
|
* Optional. Plugin data for install/activate UI.
|
|
*
|
|
* @type string $slug The WordPress.org plugin slug.
|
|
* }
|
|
* }
|
|
* @phpstan-return ?array{
|
|
* name: non-empty-string,
|
|
* description: non-empty-string,
|
|
* logo_url?: non-empty-string,
|
|
* type: 'ai_provider',
|
|
* authentication: array{
|
|
* method: 'api_key'|'none',
|
|
* credentials_url?: non-empty-string,
|
|
* setting_name?: non-empty-string
|
|
* },
|
|
* plugin?: array{
|
|
* slug: non-empty-string
|
|
* }
|
|
* }
|
|
*/
|
|
function wp_get_connector( string $id ): ?array {
|
|
$registry = WP_Connector_Registry::get_instance();
|
|
if ( null === $registry ) {
|
|
return null;
|
|
}
|
|
|
|
return $registry->get_registered( $id );
|
|
}
|
|
|
|
/**
|
|
* Retrieves all registered connectors.
|
|
*
|
|
* @since 7.0.0
|
|
*
|
|
* @see WP_Connector_Registry::get_all_registered()
|
|
*
|
|
* @return array {
|
|
* Connector settings keyed by connector ID.
|
|
*
|
|
* @type array ...$0 {
|
|
* Data for a single connector.
|
|
*
|
|
* @type string $name The connector's display name.
|
|
* @type string $description The connector's description.
|
|
* @type string $logo_url Optional. URL to the connector's logo image.
|
|
* @type string $type The connector type. Currently, only 'ai_provider' is supported.
|
|
* @type array $authentication {
|
|
* Authentication configuration. When method is 'api_key', includes
|
|
* credentials_url and setting_name. When 'none', only method is present.
|
|
*
|
|
* @type string $method The authentication method: 'api_key' or 'none'.
|
|
* @type string $credentials_url Optional. URL where users can obtain API credentials.
|
|
* @type string $setting_name Optional. The setting name for the API key.
|
|
* }
|
|
* @type array $plugin {
|
|
* Optional. Plugin data for install/activate UI.
|
|
*
|
|
* @type string $slug The WordPress.org plugin slug.
|
|
* }
|
|
* }
|
|
* }
|
|
* @phpstan-return array<string, array{
|
|
* name: non-empty-string,
|
|
* description: non-empty-string,
|
|
* logo_url?: non-empty-string,
|
|
* type: 'ai_provider',
|
|
* authentication: array{
|
|
* method: 'api_key'|'none',
|
|
* credentials_url?: non-empty-string,
|
|
* setting_name?: non-empty-string
|
|
* },
|
|
* plugin?: array{
|
|
* slug: non-empty-string
|
|
* }
|
|
* }>
|
|
*/
|
|
function wp_get_connectors(): array {
|
|
$registry = WP_Connector_Registry::get_instance();
|
|
if ( null === $registry ) {
|
|
return array();
|
|
}
|
|
|
|
return $registry->get_all_registered();
|
|
}
|
|
|
|
/**
|
|
* Resolves an AI provider logo file path to a URL.
|
|
*
|
|
* Converts an absolute file path to a plugin URL. The path must reside within
|
|
* the plugins or must-use plugins directory.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param string $path Absolute path to the logo file.
|
|
* @return string|null The URL to the logo file, or null if the path is invalid.
|
|
*/
|
|
function _wp_connectors_resolve_ai_provider_logo_url( string $path ): ?string {
|
|
if ( ! $path ) {
|
|
return null;
|
|
}
|
|
|
|
$path = wp_normalize_path( $path );
|
|
|
|
if ( ! file_exists( $path ) ) {
|
|
return null;
|
|
}
|
|
|
|
$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );
|
|
if ( str_starts_with( $path, $mu_plugin_dir . '/' ) ) {
|
|
return plugins_url( substr( $path, strlen( $mu_plugin_dir ) ), WPMU_PLUGIN_DIR . '/.' );
|
|
}
|
|
|
|
$plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
|
|
if ( str_starts_with( $path, $plugin_dir . '/' ) ) {
|
|
return plugins_url( substr( $path, strlen( $plugin_dir ) ) );
|
|
}
|
|
|
|
_doing_it_wrong(
|
|
__FUNCTION__,
|
|
__( 'Provider logo path must be located within the plugins or must-use plugins directory.' ),
|
|
'7.0.0'
|
|
);
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Initializes the connector registry with default connectors and fires the registration action.
|
|
*
|
|
* Creates the registry instance, registers built-in connectors (which cannot be unhooked),
|
|
* and then fires the `wp_connectors_init` action for plugins to register their own connectors.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*/
|
|
function _wp_connectors_init(): void {
|
|
$registry = new WP_Connector_Registry();
|
|
WP_Connector_Registry::set_instance( $registry );
|
|
|
|
// Only register default AI providers if AI support is enabled.
|
|
if ( wp_supports_ai() ) {
|
|
_wp_connectors_register_default_ai_providers( $registry );
|
|
}
|
|
|
|
/**
|
|
* Fires when the connector registry is ready for plugins to register connectors.
|
|
*
|
|
* Built-in connectors and any AI providers auto-discovered from the WP AI Client
|
|
* registry have already been registered at this point and cannot be unhooked.
|
|
*
|
|
* AI provider plugins that register with the WP AI Client do not need to use
|
|
* this action — their connectors are created automatically. This action is
|
|
* primarily for registering non-AI-provider connectors or overriding metadata
|
|
* on existing connectors.
|
|
*
|
|
* Use `$registry->register()` within this action to add new connectors.
|
|
* To override an existing connector, unregister it first, then re-register
|
|
* with updated data.
|
|
*
|
|
* Example — overriding metadata on an auto-discovered connector:
|
|
*
|
|
* add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) {
|
|
* if ( $registry->is_registered( 'openai' ) ) {
|
|
* $connector = $registry->unregister( 'openai' );
|
|
* $connector['description'] = __( 'Custom description for OpenAI.', 'my-plugin' );
|
|
* $registry->register( 'openai', $connector );
|
|
* }
|
|
* } );
|
|
*
|
|
* @since 7.0.0
|
|
*
|
|
* @param WP_Connector_Registry $registry Connector registry instance.
|
|
*/
|
|
do_action( 'wp_connectors_init', $registry );
|
|
}
|
|
|
|
/**
|
|
* Registers connectors for the built-in AI providers.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param WP_Connector_Registry $registry The connector registry instance.
|
|
*/
|
|
function _wp_connectors_register_default_ai_providers( WP_Connector_Registry $registry ): void {
|
|
// Built-in connectors.
|
|
$defaults = array(
|
|
'anthropic' => array(
|
|
'name' => 'Anthropic',
|
|
'description' => __( 'Text generation with Claude.' ),
|
|
'type' => 'ai_provider',
|
|
'plugin' => array(
|
|
'slug' => 'ai-provider-for-anthropic',
|
|
),
|
|
'authentication' => array(
|
|
'method' => 'api_key',
|
|
'credentials_url' => 'https://platform.claude.com/settings/keys',
|
|
),
|
|
),
|
|
'google' => array(
|
|
'name' => 'Google',
|
|
'description' => __( 'Text and image generation with Gemini and Imagen.' ),
|
|
'type' => 'ai_provider',
|
|
'plugin' => array(
|
|
'slug' => 'ai-provider-for-google',
|
|
),
|
|
'authentication' => array(
|
|
'method' => 'api_key',
|
|
'credentials_url' => 'https://aistudio.google.com/api-keys',
|
|
),
|
|
),
|
|
'openai' => array(
|
|
'name' => 'OpenAI',
|
|
'description' => __( 'Text and image generation with GPT and Dall-E.' ),
|
|
'type' => 'ai_provider',
|
|
'plugin' => array(
|
|
'slug' => 'ai-provider-for-openai',
|
|
),
|
|
'authentication' => array(
|
|
'method' => 'api_key',
|
|
'credentials_url' => 'https://platform.openai.com/api-keys',
|
|
),
|
|
),
|
|
);
|
|
|
|
// Merge AI Client registry data on top of defaults.
|
|
// Registry values (from provider plugins) take precedence over hardcoded fallbacks.
|
|
$ai_registry = AiClient::defaultRegistry();
|
|
|
|
foreach ( $ai_registry->getRegisteredProviderIds() as $connector_id ) {
|
|
$provider_class_name = $ai_registry->getProviderClassName( $connector_id );
|
|
$provider_metadata = $provider_class_name::metadata();
|
|
|
|
$auth_method = $provider_metadata->getAuthenticationMethod();
|
|
$is_api_key = null !== $auth_method && $auth_method->isApiKey();
|
|
|
|
if ( $is_api_key ) {
|
|
$credentials_url = $provider_metadata->getCredentialsUrl();
|
|
$authentication = array(
|
|
'method' => 'api_key',
|
|
'credentials_url' => $credentials_url ? $credentials_url : null,
|
|
);
|
|
} else {
|
|
$authentication = array( 'method' => 'none' );
|
|
}
|
|
|
|
$name = $provider_metadata->getName();
|
|
$description = $provider_metadata->getDescription();
|
|
$logo_url = $provider_metadata->getLogoPath()
|
|
? _wp_connectors_resolve_ai_provider_logo_url( $provider_metadata->getLogoPath() )
|
|
: null;
|
|
|
|
if ( isset( $defaults[ $connector_id ] ) ) {
|
|
// Override fields with non-empty registry values.
|
|
if ( $name ) {
|
|
$defaults[ $connector_id ]['name'] = $name;
|
|
}
|
|
if ( $description ) {
|
|
$defaults[ $connector_id ]['description'] = $description;
|
|
}
|
|
if ( $logo_url ) {
|
|
$defaults[ $connector_id ]['logo_url'] = $logo_url;
|
|
}
|
|
// Always update auth method; keep existing credentials_url as fallback.
|
|
$defaults[ $connector_id ]['authentication']['method'] = $authentication['method'];
|
|
if ( ! empty( $authentication['credentials_url'] ) ) {
|
|
$defaults[ $connector_id ]['authentication']['credentials_url'] = $authentication['credentials_url'];
|
|
}
|
|
} else {
|
|
$defaults[ $connector_id ] = array(
|
|
'name' => $name ? $name : ucwords( $connector_id ),
|
|
'description' => $description ? $description : '',
|
|
'type' => 'ai_provider',
|
|
'authentication' => $authentication,
|
|
'logo_url' => $logo_url,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Register all default connectors directly on the registry.
|
|
foreach ( $defaults as $id => $args ) {
|
|
$registry->register( $id, $args );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Masks an API key, showing only the last 4 characters.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param string $key The API key to mask.
|
|
* @return string The masked key, e.g. "************fj39".
|
|
*/
|
|
function _wp_connectors_mask_api_key( string $key ): string {
|
|
if ( strlen( $key ) <= 4 ) {
|
|
return $key;
|
|
}
|
|
|
|
return str_repeat( "\u{2022}", min( strlen( $key ) - 4, 16 ) ) . substr( $key, -4 );
|
|
}
|
|
|
|
/**
|
|
* Determines the source of an API key for a given provider.
|
|
*
|
|
* Checks in order: environment variable, PHP constant, database.
|
|
* Uses the same naming convention as the WP AI Client ProviderRegistry.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param string $provider_id The provider ID (e.g., 'openai', 'anthropic', 'google').
|
|
* @param string $setting_name The option name for the API key (e.g., 'connectors_ai_openai_api_key').
|
|
* @return string The key source: 'env', 'constant', 'database', or 'none'.
|
|
*/
|
|
function _wp_connectors_get_api_key_source( string $provider_id, string $setting_name ): string {
|
|
// Convert provider ID to CONSTANT_CASE for env var name.
|
|
// e.g., 'openai' -> 'OPENAI', 'anthropic' -> 'ANTHROPIC'.
|
|
$constant_case_id = strtoupper(
|
|
preg_replace( '/([a-z])([A-Z])/', '$1_$2', str_replace( '-', '_', $provider_id ) )
|
|
);
|
|
$env_var_name = "{$constant_case_id}_API_KEY";
|
|
|
|
// Check environment variable first.
|
|
$env_value = getenv( $env_var_name );
|
|
if ( false !== $env_value && '' !== $env_value ) {
|
|
return 'env';
|
|
}
|
|
|
|
// Check PHP constant.
|
|
if ( defined( $env_var_name ) ) {
|
|
$const_value = constant( $env_var_name );
|
|
if ( is_string( $const_value ) && '' !== $const_value ) {
|
|
return 'constant';
|
|
}
|
|
}
|
|
|
|
// Check database.
|
|
$db_value = get_option( $setting_name, '' );
|
|
if ( '' !== $db_value ) {
|
|
return 'database';
|
|
}
|
|
|
|
return 'none';
|
|
}
|
|
|
|
/**
|
|
* Checks whether an API key is valid for a given provider.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param string $key The API key to check.
|
|
* @param string $provider_id The WP AI client provider ID.
|
|
* @return bool|null True if valid, false if invalid, null if unable to determine.
|
|
*/
|
|
function _wp_connectors_is_ai_api_key_valid( string $key, string $provider_id ): ?bool {
|
|
try {
|
|
$registry = AiClient::defaultRegistry();
|
|
|
|
if ( ! $registry->hasProvider( $provider_id ) ) {
|
|
_doing_it_wrong(
|
|
__FUNCTION__,
|
|
sprintf(
|
|
/* translators: %s: AI provider ID. */
|
|
__( 'The provider "%s" is not registered in the AI client registry.' ),
|
|
$provider_id
|
|
),
|
|
'7.0.0'
|
|
);
|
|
return null;
|
|
}
|
|
|
|
$registry->setProviderRequestAuthentication(
|
|
$provider_id,
|
|
new ApiKeyRequestAuthentication( $key )
|
|
);
|
|
|
|
return $registry->isProviderConfigured( $provider_id );
|
|
} catch ( Exception $e ) {
|
|
wp_trigger_error( __FUNCTION__, $e->getMessage() );
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Masks and validates connector API keys in REST responses.
|
|
*
|
|
* On every `/wp/v2/settings` response, masks connector API key values so raw
|
|
* keys are never exposed via the REST API.
|
|
*
|
|
* On POST or PUT requests, validates each updated key against the provider
|
|
* before masking. If validation fails, the key is reverted to an empty string.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param WP_REST_Response $response The response object.
|
|
* @param WP_REST_Server $server The server instance.
|
|
* @param WP_REST_Request $request The request object.
|
|
* @return WP_REST_Response The modified response with masked/validated keys.
|
|
*/
|
|
function _wp_connectors_rest_settings_dispatch( WP_REST_Response $response, WP_REST_Server $server, WP_REST_Request $request ): WP_REST_Response {
|
|
if ( '/wp/v2/settings' !== $request->get_route() ) {
|
|
return $response;
|
|
}
|
|
|
|
$data = $response->get_data();
|
|
if ( ! is_array( $data ) ) {
|
|
return $response;
|
|
}
|
|
|
|
$is_update = 'POST' === $request->get_method() || 'PUT' === $request->get_method();
|
|
|
|
foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
|
|
$auth = $connector_data['authentication'];
|
|
if ( 'ai_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$setting_name = $auth['setting_name'];
|
|
if ( ! array_key_exists( $setting_name, $data ) ) {
|
|
continue;
|
|
}
|
|
|
|
$value = $data[ $setting_name ];
|
|
|
|
// On update, validate the key before masking.
|
|
if ( $is_update && is_string( $value ) && '' !== $value ) {
|
|
if ( true !== _wp_connectors_is_ai_api_key_valid( $value, $connector_id ) ) {
|
|
update_option( $setting_name, '' );
|
|
$data[ $setting_name ] = '';
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Mask the key in the response.
|
|
if ( is_string( $value ) && '' !== $value ) {
|
|
$data[ $setting_name ] = _wp_connectors_mask_api_key( $value );
|
|
}
|
|
}
|
|
|
|
$response->set_data( $data );
|
|
return $response;
|
|
}
|
|
add_filter( 'rest_post_dispatch', '_wp_connectors_rest_settings_dispatch', 10, 3 );
|
|
|
|
/**
|
|
* Registers default connector settings.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*/
|
|
function _wp_register_default_connector_settings(): void {
|
|
$ai_registry = AiClient::defaultRegistry();
|
|
|
|
foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
|
|
$auth = $connector_data['authentication'];
|
|
if ( 'ai_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Skip registering the setting if the provider is not in the registry.
|
|
if ( ! $ai_registry->hasProvider( $connector_id ) ) {
|
|
continue;
|
|
}
|
|
|
|
register_setting(
|
|
'connectors',
|
|
$auth['setting_name'],
|
|
array(
|
|
'type' => 'string',
|
|
'label' => sprintf(
|
|
/* translators: %s: AI provider name. */
|
|
__( '%s API Key' ),
|
|
$connector_data['name']
|
|
),
|
|
'description' => sprintf(
|
|
/* translators: %s: AI provider name. */
|
|
__( 'API key for the %s AI provider.' ),
|
|
$connector_data['name']
|
|
),
|
|
'default' => '',
|
|
'show_in_rest' => true,
|
|
'sanitize_callback' => 'sanitize_text_field',
|
|
)
|
|
);
|
|
}
|
|
}
|
|
add_action( 'init', '_wp_register_default_connector_settings', 20 );
|
|
|
|
/**
|
|
* Passes stored connector API keys to the WP AI client.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*/
|
|
function _wp_connectors_pass_default_keys_to_ai_client(): void {
|
|
try {
|
|
$ai_registry = AiClient::defaultRegistry();
|
|
foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
|
|
if ( 'ai_provider' !== $connector_data['type'] ) {
|
|
continue;
|
|
}
|
|
|
|
$auth = $connector_data['authentication'];
|
|
if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( ! $ai_registry->hasProvider( $connector_id ) ) {
|
|
continue;
|
|
}
|
|
|
|
// Skip if the key is already provided via env var or constant.
|
|
$key_source = _wp_connectors_get_api_key_source( $connector_id, $auth['setting_name'] );
|
|
if ( 'env' === $key_source || 'constant' === $key_source ) {
|
|
continue;
|
|
}
|
|
|
|
$api_key = get_option( $auth['setting_name'], '' );
|
|
if ( '' === $api_key ) {
|
|
continue;
|
|
}
|
|
|
|
$ai_registry->setProviderRequestAuthentication(
|
|
$connector_id,
|
|
new ApiKeyRequestAuthentication( $api_key )
|
|
);
|
|
}
|
|
} catch ( Exception $e ) {
|
|
wp_trigger_error( __FUNCTION__, $e->getMessage() );
|
|
}
|
|
}
|
|
add_action( 'init', '_wp_connectors_pass_default_keys_to_ai_client', 20 );
|
|
|
|
/**
|
|
* Exposes connector settings to the connectors-wp-admin script module.
|
|
*
|
|
* @since 7.0.0
|
|
* @access private
|
|
*
|
|
* @param array<string, mixed> $data Existing script module data.
|
|
* @return array<string, mixed> Script module data with connectors added.
|
|
*/
|
|
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' ) ) {
|
|
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 ) {
|
|
$auth = $connector_data['authentication'];
|
|
$auth_out = array( 'method' => $auth['method'] );
|
|
|
|
if ( 'api_key' === $auth['method'] ) {
|
|
$auth_out['settingName'] = $auth['setting_name'] ?? '';
|
|
$auth_out['credentialsUrl'] = $auth['credentials_url'] ?? null;
|
|
$auth_out['keySource'] = _wp_connectors_get_api_key_source( $connector_id, $auth['setting_name'] ?? '' );
|
|
try {
|
|
$auth_out['isConnected'] = $registry->hasProvider( $connector_id ) && $registry->isProviderConfigured( $connector_id );
|
|
} catch ( Exception $e ) {
|
|
$auth_out['isConnected'] = false;
|
|
}
|
|
}
|
|
|
|
$connector_out = array(
|
|
'name' => $connector_data['name'],
|
|
'description' => $connector_data['description'],
|
|
'logoUrl' => ! empty( $connector_data['logo_url'] ) ? $connector_data['logo_url'] : null,
|
|
'type' => $connector_data['type'],
|
|
'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 );
|
|
|
|
$connector_out['plugin'] = array(
|
|
'slug' => $plugin_slug,
|
|
'isInstalled' => $is_installed,
|
|
'isActivated' => $is_activated,
|
|
);
|
|
}
|
|
|
|
$connectors[ $connector_id ] = $connector_out;
|
|
}
|
|
ksort( $connectors );
|
|
$data['connectors'] = $connectors;
|
|
return $data;
|
|
}
|
|
add_filter( 'script_module_data_options-connectors-wp-admin', '_wp_connectors_get_connector_script_module_data' );
|