11<?php
22/**
3- * Connectors API.
3+ * Connectors API: core functions for registering and managing connectors.
4+ *
5+ * The Connectors API provides a unified framework for registering and managing
6+ * external service integrations within WordPress. A "connector" represents a
7+ * connection to an external service — currently focused on AI providers — with
8+ * standardized metadata, authentication configuration, and plugin association.
9+ *
10+ * ## Overview
11+ *
12+ * The Connectors API enables developers to:
13+ *
14+ * - Register AI provider connectors with standardized interfaces.
15+ * - Define authentication methods and credential sources.
16+ * - Associate connectors with WordPress.org plugins for install/activate UI.
17+ * - Expose connector settings through the REST API with automatic key masking.
18+ *
19+ * ## AI Provider Plugins
20+ *
21+ * AI provider plugins that register with the WP AI Client's `ProviderRegistry`
22+ * get automatic connector integration — no explicit connector registration is
23+ * needed. The system discovers providers from the WP AI Client registry and
24+ * creates connectors with the correct name, description, logo, authentication
25+ * method, and setting name derived from the provider's configuration.
26+ *
27+ * The authentication method (`api_key` or `none`) is determined by the provider's
28+ * metadata in the WP AI Client. For `api_key` providers, a `setting_name` is
29+ * automatically generated following the same naming convention used for environment
30+ * variables and PHP constants (e.g., provider `openai` maps to `OPENAI_API_KEY`
31+ * for env/constant lookup).
32+ *
33+ * @see WordPress\AiClient\Providers\ProviderRegistry
34+ *
35+ * ## Admin UI Integration
36+ *
37+ * Registered `ai_provider` connectors appear on the Settings → Connectors
38+ * admin screen. The screen renders each connector as a card using the
39+ * registry data:
40+ *
41+ * - `name`, `description`, and `logo_url` are displayed on the card.
42+ * - `plugin.slug` enables install/activate controls — the screen checks
43+ * whether the plugin is installed and active, and shows the appropriate
44+ * action button.
45+ * - `authentication.credentials_url` is rendered as a link directing users
46+ * to the provider's site to obtain API credentials.
47+ * - For `api_key` connectors, the screen shows the current key source
48+ * (environment variable, PHP constant, or database) and connection status.
49+ *
50+ * On the backend, `api_key` connectors also receive automatic settings
51+ * registration via the Settings API (`show_in_rest`), API key masking in
52+ * REST API responses, and key validation against the provider on update.
53+ *
54+ * Connectors with other authentication methods or types are registered in the PHP
55+ * registry and exposed via the script module data, but require a client-side
56+ * JavaScript registration for custom frontend UI. Support for additional
57+ * authentication methods and connector types is planned for future releases.
58+ *
59+ * ## Custom Connectors
60+ *
61+ * The `wp_connectors_init` action hook allows plugins to override metadata on
62+ * existing connectors. AI provider connectors are auto-discovered from the WP
63+ * AI Client registry and should not be manually registered here.
64+ *
65+ * Example — overriding the description of an auto-discovered connector:
66+ *
67+ * add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) {
68+ * if ( $registry->is_registered( 'openai' ) ) {
69+ * $connector = $registry->unregister( 'openai' );
70+ * $connector['description'] = __( 'Custom description for OpenAI.', 'my-plugin' );
71+ * $registry->register( 'openai', $connector );
72+ * }
73+ * } );
74+ *
75+ * Non-AI-provider connector types are not yet fully supported. The PHP registry
76+ * accepts any connector type, but only `ai_provider` connectors with `api_key`
77+ * authentication receive automatic admin UI. Support for additional connector
78+ * types with dedicated frontend integration is planned for future releases.
79+ * When available, this action will be the primary hook for registering those
80+ * new connector types.
81+ *
82+ * ## Initialization Lifecycle
83+ *
84+ * During `init`, the system:
85+ *
86+ * 1. Creates the `WP_Connector_Registry` singleton.
87+ * 2. Registers built-in connectors (Anthropic, Google, OpenAI) with hardcoded defaults.
88+ * 3. Auto-discovers providers from the WP AI Client registry and merges their
89+ * metadata (name, description, logo, authentication) on top of defaults,
90+ * with registry values taking precedence.
91+ * 4. Fires the `wp_connectors_init` action so plugins can override metadata
92+ * on existing connectors or register additional connectors.
93+ * 5. Registers settings and passes stored API keys to the WP AI Client.
94+ *
95+ * ## Authentication
96+ *
97+ * Connectors support two authentication methods:
98+ *
99+ * - `api_key`: Requires an API key, which can be provided via environment variable,
100+ * PHP constant, or the database (checked in that order).
101+ * - `none`: No authentication required.
102+ *
103+ * API keys stored in the database are automatically masked in REST API responses
104+ * and validated against the provider on update.
4105 *
5106 * @package WordPress
6107 * @subpackage Connectors
13114/**
14115 * Checks if a connector is registered.
15116 *
117+ * Example:
118+ *
119+ * if ( wp_is_connector_registered( 'openai' ) ) {
120+ * // The OpenAI connector is available.
121+ * }
122+ *
16123 * @since 7.0.0
17124 *
18125 * @see WP_Connector_Registry::is_registered()
126+ * @see wp_get_connector()
127+ * @see wp_get_connectors()
19128 *
20129 * @param string $id The connector identifier.
21130 * @return bool True if the connector is registered, false otherwise.
@@ -32,9 +141,18 @@ function wp_is_connector_registered( string $id ): bool {
32141/**
33142 * Retrieves a registered connector.
34143 *
144+ * Example:
145+ *
146+ * $connector = wp_get_connector( 'openai' );
147+ * if ( $connector ) {
148+ * echo $connector['name']; // 'OpenAI'
149+ * }
150+ *
35151 * @since 7.0.0
36152 *
37153 * @see WP_Connector_Registry::get_registered()
154+ * @see wp_is_connector_registered()
155+ * @see wp_get_connectors()
38156 *
39157 * @param string $id The connector identifier.
40158 * @return array|null {
@@ -85,9 +203,18 @@ function wp_get_connector( string $id ): ?array {
85203/**
86204 * Retrieves all registered connectors.
87205 *
206+ * Example:
207+ *
208+ * $connectors = wp_get_connectors();
209+ * foreach ( $connectors as $id => $connector ) {
210+ * printf( '%s: %s', $connector['name'], $connector['description'] );
211+ * }
212+ *
88213 * @since 7.0.0
89214 *
90215 * @see WP_Connector_Registry::get_all_registered()
216+ * @see wp_is_connector_registered()
217+ * @see wp_get_connector()
91218 *
92219 * @return array {
93220 * Connector settings keyed by connector ID.
@@ -183,8 +310,21 @@ function _wp_connectors_resolve_ai_provider_logo_url( string $path ): ?string {
183310/**
184311 * Initializes the connector registry with default connectors and fires the registration action.
185312 *
186- * Creates the registry instance, registers built-in connectors (which cannot be unhooked),
187- * and then fires the `wp_connectors_init` action for plugins to register their own connectors.
313+ * This function orchestrates the full connector initialization sequence:
314+ *
315+ * 1. Creates the `WP_Connector_Registry` singleton instance.
316+ * 2. Defines built-in connectors (Anthropic, Google, OpenAI) with hardcoded defaults
317+ * including name, description, type, plugin slug, and authentication configuration.
318+ * 3. Merges metadata from the WP AI Client provider registry on top of defaults.
319+ * Registry values (from provider plugins) take precedence over hardcoded fallbacks
320+ * for name, description, logo URL, and authentication method.
321+ * 4. Registers all connectors (built-in and AI Client-discovered) on the registry.
322+ * 5. Fires the `wp_connectors_init` action for plugins to override metadata
323+ * on existing connectors or register additional connectors.
324+ *
325+ * Built-in connectors are registered before the action fires and cannot be unhooked.
326+ * Plugins should use the `wp_connectors_init` action to override metadata or
327+ * register new connectors via `$registry->register()`.
188328 *
189329 * @since 7.0.0
190330 * @access private
@@ -294,24 +434,26 @@ function _wp_connectors_init(): void {
294434 /**
295435 * Fires when the connector registry is ready for plugins to register connectors.
296436 *
297- * Default connectors have already been registered at this point and cannot be
298- * unhooked. Use `$registry->register()` within this action to add new connectors.
437+ * Built-in connectors and any AI providers auto-discovered from the WP AI Client
438+ * registry have already been registered at this point and cannot be unhooked.
439+ *
440+ * AI provider plugins that register with the WP AI Client do not need to use
441+ * this action — their connectors are created automatically. This action is
442+ * primarily for registering non-AI-provider connectors or overriding metadata
443+ * on existing connectors.
444+ *
445+ * Use `$registry->register()` within this action to add new connectors.
446+ * To override an existing connector, unregister it first, then re-register
447+ * with updated data.
299448 *
300- * Example usage :
449+ * Example — overriding metadata on an auto-discovered connector :
301450 *
302451 * add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) {
303- * $registry->register(
304- * 'my_custom_ai',
305- * array(
306- * 'name' => __( 'My Custom AI', 'my-plugin' ),
307- * 'description' => __( 'Custom AI provider integration.', 'my-plugin' ),
308- * 'type' => 'ai_provider',
309- * 'authentication' => array(
310- * 'method' => 'api_key',
311- * 'credentials_url' => 'https://example.com/api-keys',
312- * ),
313- * )
314- * );
452+ * if ( $registry->is_registered( 'openai' ) ) {
453+ * $connector = $registry->unregister( 'openai' );
454+ * $connector['description'] = __( 'Custom description for OpenAI.', 'my-plugin' );
455+ * $registry->register( 'openai', $connector );
456+ * }
315457 * } );
316458 *
317459 * @since 7.0.0
@@ -486,6 +628,11 @@ function _wp_connectors_rest_settings_dispatch( WP_REST_Response $response, WP_R
486628/**
487629 * Registers default connector settings.
488630 *
631+ * Only registers settings for `ai_provider` connectors with `api_key`
632+ * authentication whose provider is present in the WP AI Client registry.
633+ * Each setting is registered with `show_in_rest` enabled, making it
634+ * accessible through the `/wp/v2/settings` REST endpoint.
635+ *
489636 * @since 7.0.0
490637 * @access private
491638 */
@@ -573,13 +720,27 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void {
573720add_action ( 'init ' , '_wp_connectors_pass_default_keys_to_ai_client ' , 20 );
574721
575722/**
576- * Exposes connector settings to the connectors-wp-admin script module.
723+ * Provides connector data to the Settings → Connectors admin screen.
724+ *
725+ * This function is the bridge between the PHP connector registry and the
726+ * frontend admin UI. It transforms each registered connector into the data
727+ * structure consumed by the `options-connectors-wp-admin` script module,
728+ * enriching registry data with runtime state:
729+ *
730+ * - Plugin install/activate status (via `get_plugins()` and `is_plugin_active()`).
731+ * - API key source detection (`env`, `constant`, `database`, or `none`).
732+ * - Connection status for `api_key` connectors (via the WP AI Client registry).
733+ *
734+ * Hooked to the `script_module_data_options-connectors-wp-admin` filter.
577735 *
578736 * @since 7.0.0
579737 * @access private
580738 *
739+ * @see _wp_connectors_get_api_key_source()
740+ *
581741 * @param array<string, mixed> $data Existing script module data.
582- * @return array<string, mixed> Script module data with connectors added.
742+ * @return array<string, mixed> Script module data with a `connectors` key added,
743+ * keyed by connector ID and sorted alphabetically.
583744 */
584745function _wp_connectors_get_connector_script_module_data ( array $ data ): array {
585746 $ registry = AiClient::defaultRegistry ();
0 commit comments