Connectors: Dynamically register providers from WP AI Client registry#11080
Connectors: Dynamically register providers from WP AI Client registry#11080gziolo wants to merge 13 commits intoWordPress:trunkfrom
Conversation
|
@felixarntz, there are still some things to address, but it's close to ready to include all basic metadata that we could expose to the client to automatically expose their cards for registered plugins that implement AI providers. We would always show 3 featured AI providers by default, but their metadata would be replaced as soon as the corresponding plugin gets installed. For all other AI providers, they would show up on the Connectors screen only after they get installed, solely based on the metadata used during registration. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3d53c9c to
e625773
Compare
|
I synced changes from WordPress/gutenberg#76014 based on the feedback provided there. To land these changes, we will have to sync the JS changes applied in the Gutenberg plugin, too. |
e625773 to
b78d7dd
Compare
jorgefilipecosta
left a comment
There was a problem hiding this comment.
Awesome work here things tested well for me.
In order to test with the JS/TS changes I applied the following patch:
diff --git a/package.json b/package.json
index acbe679d2f..1ada94f47c 100644
--- a/package.json
+++ b/package.json
@@ -6,9 +6,9 @@
"type": "svn",
"url": "https://develop.svn.wordpress.org/trunk"
},
"gutenberg": {
- "ref": "022d8dd3d461f91b15c1f0410649d3ebb027207f"
+ "ref": "853d89e66761c1bc60c2fae1c239261fc8c3b9cf"
},
"engines": {
"node": ">=20.10.0",
"npm": ">=10.2.3"
Left just some minor comments which can be considered before the merge.
tests/phpunit/tests/connectors/wpConnectorsGetProviderSettings.php
Outdated
Show resolved
Hide resolved
Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…#76014) * Connectors: Dynamically register providers from WP AI Client registry Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Expose provider settings to the script module Pass provider data (name, description, credentials URL, setting keys) to the `connectors-wp-admin` script module via the `script_module_data` filter, making it available as inline JSON for the frontend to consume. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Register connectors dynamically from server-provided data Replace hardcoded per-provider connector components with a single dynamic loop that reads provider data from the script module data JSON tag. Known providers retain their SVG logos via a client-side map; third-party providers from the registry render without a logo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Use ucwords fallback for empty provider name When a third-party provider from the AI Client registry has no name, fall back to ucwords( $provider_id ) for a reasonable display label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add authentication_method to provider data structure Expose authentication_method ('api_key' or 'none') in provider settings instead of silently filtering out non-API-key providers. This makes the public-facing interfaces extensible for future authentication methods while still only implementing api_key support for now. - Include all registered providers regardless of auth method - Conditionally generate settings sub-array only for api_key providers - Expose authenticationMethod in script module data for the frontend - Skip non-api_key providers in the frontend registration loop - Rename ProviderConnector to ApiKeyProviderConnector for clarity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add type field to distinguish AI providers from other connectors Add a 'type' field ('ai_provider') to the provider data structure so credentials are only passed to the WP AI Client for AI providers. The frontend also filters by type, only rendering connectors for AI providers. This separates AI providers from future non-AI connectors and makes the intent of the API explicit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Group authentication fields into sub-object and eliminate settings duplication Restructure provider data so credentials_url, setting_name, and method live together in an authentication sub-object rather than as flat top-level fields. Remove the redundant settings array from _gutenberg_get_provider_settings() and move register_setting logic (label, description, sanitize) into the consumer function. Update all PHP consumers to read from authentication directly. On the frontend, change ProviderAuthentication to a discriminated union type for type-safe access after narrowing on method. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename _gutenberg_get_provider_settings to _gutenberg_get_connector_settings Use the domain term "connector" consistently with the rest of the codebase (settings group, option names, script module filter). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Clarify authentication docblock for none method Document that credentials_url and setting_name are only present when method is 'api_key' and absent when method is 'none'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use URL hostname for help label instead of regex stripping Replace manual regex URL stripping with new URL().hostname for a cleaner, more robust extraction of the domain name used as the help link label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use type-based namespace for connector names Derive the connector name namespace from data.type instead of hardcoding 'core/'. Sanitize both parts to only allow letters, numbers, and hyphens. This produces names like 'ai-provider/google'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename ApiKeyProviderConnector and derive helpLabel internally Rename ApiKeyProviderConnector to ApiKeyConnector and move helpLabel derivation from the registration loop into the component itself, since it already receives helpUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Rename _gutenberg_is_api_key_valid to _gutenberg_is_ai_api_key_valid The function is AI-provider-specific, so the name should reflect that. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Move sanitize helper outside the loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Pass plugin data from server instead of deriving slug client-side Hardcode plugin slugs for the three featured AI providers in PHP within a `plugin` sub-object and pass them to the client via script module data. When no plugin data is provided (e.g. dynamically registered providers), the install/activate UI is skipped and the connector assumes the plugin is already active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add backport changelog entry for Core PR #11080 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add remove_filter for Core script module data function Ensures the Gutenberg version overrides the equivalent Core function (_wp_connectors_get_connector_script_module_data), consistent with the pattern used by the other connector functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Felix Arntz <flixos90@gmail.com> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: raftaar1191 <raftaar1191@git.wordpress.org> Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: felixarntz <flixos90@git.wordpress.org>
…#76014) * Connectors: Dynamically register providers from WP AI Client registry Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Expose provider settings to the script module Pass provider data (name, description, credentials URL, setting keys) to the `connectors-wp-admin` script module via the `script_module_data` filter, making it available as inline JSON for the frontend to consume. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Register connectors dynamically from server-provided data Replace hardcoded per-provider connector components with a single dynamic loop that reads provider data from the script module data JSON tag. Known providers retain their SVG logos via a client-side map; third-party providers from the registry render without a logo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Use ucwords fallback for empty provider name When a third-party provider from the AI Client registry has no name, fall back to ucwords( $provider_id ) for a reasonable display label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add authentication_method to provider data structure Expose authentication_method ('api_key' or 'none') in provider settings instead of silently filtering out non-API-key providers. This makes the public-facing interfaces extensible for future authentication methods while still only implementing api_key support for now. - Include all registered providers regardless of auth method - Conditionally generate settings sub-array only for api_key providers - Expose authenticationMethod in script module data for the frontend - Skip non-api_key providers in the frontend registration loop - Rename ProviderConnector to ApiKeyProviderConnector for clarity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add type field to distinguish AI providers from other connectors Add a 'type' field ('ai_provider') to the provider data structure so credentials are only passed to the WP AI Client for AI providers. The frontend also filters by type, only rendering connectors for AI providers. This separates AI providers from future non-AI connectors and makes the intent of the API explicit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Group authentication fields into sub-object and eliminate settings duplication Restructure provider data so credentials_url, setting_name, and method live together in an authentication sub-object rather than as flat top-level fields. Remove the redundant settings array from _gutenberg_get_provider_settings() and move register_setting logic (label, description, sanitize) into the consumer function. Update all PHP consumers to read from authentication directly. On the frontend, change ProviderAuthentication to a discriminated union type for type-safe access after narrowing on method. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename _gutenberg_get_provider_settings to _gutenberg_get_connector_settings Use the domain term "connector" consistently with the rest of the codebase (settings group, option names, script module filter). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Clarify authentication docblock for none method Document that credentials_url and setting_name are only present when method is 'api_key' and absent when method is 'none'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use URL hostname for help label instead of regex stripping Replace manual regex URL stripping with new URL().hostname for a cleaner, more robust extraction of the domain name used as the help link label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use type-based namespace for connector names Derive the connector name namespace from data.type instead of hardcoding 'core/'. Sanitize both parts to only allow letters, numbers, and hyphens. This produces names like 'ai-provider/google'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename ApiKeyProviderConnector and derive helpLabel internally Rename ApiKeyProviderConnector to ApiKeyConnector and move helpLabel derivation from the registration loop into the component itself, since it already receives helpUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Rename _gutenberg_is_api_key_valid to _gutenberg_is_ai_api_key_valid The function is AI-provider-specific, so the name should reflect that. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Move sanitize helper outside the loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Pass plugin data from server instead of deriving slug client-side Hardcode plugin slugs for the three featured AI providers in PHP within a `plugin` sub-object and pass them to the client via script module data. When no plugin data is provided (e.g. dynamically registered providers), the install/activate UI is skipped and the connector assumes the plugin is already active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add backport changelog entry for Core PR #11080 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add remove_filter for Core script module data function Ensures the Gutenberg version overrides the equivalent Core function (_wp_connectors_get_connector_script_module_data), consistent with the pattern used by the other connector functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Felix Arntz <flixos90@gmail.com> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: raftaar1191 <raftaar1191@git.wordpress.org> Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: felixarntz <flixos90@git.wordpress.org>
Expand `_wp_connectors_get_provider_settings()` to fetch registered providers from the AI Client registry alongside the hardcoded featured providers. Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url`, and nested `settings`. Filter out providers that don't use API key authentication. Update all consumer functions and tests accordingly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…callback. Filter out empty registry values before merging so hardcoded fallbacks (e.g. credentials_url, description) are preserved when the registry doesn't provide them. Replace per-setting $config['mask'] references with direct '_wp_connectors_mask_api_key' calls since the callback is always the same. Make REST settings test resilient to dynamically registered connector providers by querying get_registered_settings(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and expose to script module. Polyfills WordPress/gutenberg#76014: - Rename _wp_connectors_get_provider_settings() to _wp_connectors_get_connector_settings() with a restructured return format: type field, authentication sub-object (method, credentials_url, setting_name) replacing the nested settings array. - Include all registered providers regardless of auth method (api_key or none) instead of filtering out non-API-key providers. - Move label, description, and sanitize logic into consumer functions. - Add ucwords() fallback for providers with no name. - Add _wp_connectors_get_connector_script_module_data() to expose connector data to the connectors-wp-admin script module. - Update all consumer functions and tests to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getDescription() is now part of the provider metadata API contract, so the defensive method_exists() guard is no longer needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rovider names. - Add plugin sub-object with WordPress.org slugs to featured connector definitions for install/activate UI support. - Expose plugin data in script module output for the frontend. - Rename _wp_connectors_is_api_key_valid to _wp_connectors_is_ai_api_key_valid to reflect AI-provider scope. - Update provider names and descriptions to match Gutenberg PR #76014. - Add type check for 'ai_provider' in REST validation function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Renames Tests_Connectors_WpConnectorsGetProviderSettings to Tests_Connectors_WpConnectorsGetConnectorSettings and the file from wpConnectorsGetProviderSettings.php to wpConnectorsGetConnectorSettings.php to match the renamed _wp_connectors_get_connector_settings() function. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
a5a5d22 to
3d72894
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…om fixtures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rity 20. This ensures plugins registering AI providers at default priority have completed before connector settings are built from the registry. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@jorgefilipecosta, I synced all the changes from the Gutenberg plugin merged with WordPress/gutenberg#76014, and addressed all your feedback.
|
|
@ellatrix, would it be possible to sync Gutenberg plugin changes (WordPress/gutenberg@3763f32) as part of this PR? They are necessary so these changes continue to work. |
… re-init. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Yes, but if you can, I'd do an update up until (and excluding) the commit you need that includes a log of all changes that were made in Gutenberg. Then you could update the sha as part of this PR that just bumps it by one commit. We currently don't have a good process for this because it's all new. How would we have done it for packages? Cc @desrosj because I know you really like to have the changelog in the commit message. |
…WordPress#76014) * Connectors: Dynamically register providers from WP AI Client registry Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Expose provider settings to the script module Pass provider data (name, description, credentials URL, setting keys) to the `connectors-wp-admin` script module via the `script_module_data` filter, making it available as inline JSON for the frontend to consume. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Register connectors dynamically from server-provided data Replace hardcoded per-provider connector components with a single dynamic loop that reads provider data from the script module data JSON tag. Known providers retain their SVG logos via a client-side map; third-party providers from the registry render without a logo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Use ucwords fallback for empty provider name When a third-party provider from the AI Client registry has no name, fall back to ucwords( $provider_id ) for a reasonable display label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add authentication_method to provider data structure Expose authentication_method ('api_key' or 'none') in provider settings instead of silently filtering out non-API-key providers. This makes the public-facing interfaces extensible for future authentication methods while still only implementing api_key support for now. - Include all registered providers regardless of auth method - Conditionally generate settings sub-array only for api_key providers - Expose authenticationMethod in script module data for the frontend - Skip non-api_key providers in the frontend registration loop - Rename ProviderConnector to ApiKeyProviderConnector for clarity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add type field to distinguish AI providers from other connectors Add a 'type' field ('ai_provider') to the provider data structure so credentials are only passed to the WP AI Client for AI providers. The frontend also filters by type, only rendering connectors for AI providers. This separates AI providers from future non-AI connectors and makes the intent of the API explicit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Group authentication fields into sub-object and eliminate settings duplication Restructure provider data so credentials_url, setting_name, and method live together in an authentication sub-object rather than as flat top-level fields. Remove the redundant settings array from _gutenberg_get_provider_settings() and move register_setting logic (label, description, sanitize) into the consumer function. Update all PHP consumers to read from authentication directly. On the frontend, change ProviderAuthentication to a discriminated union type for type-safe access after narrowing on method. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename _gutenberg_get_provider_settings to _gutenberg_get_connector_settings Use the domain term "connector" consistently with the rest of the codebase (settings group, option names, script module filter). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Clarify authentication docblock for none method Document that credentials_url and setting_name are only present when method is 'api_key' and absent when method is 'none'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use URL hostname for help label instead of regex stripping Replace manual regex URL stripping with new URL().hostname for a cleaner, more robust extraction of the domain name used as the help link label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use type-based namespace for connector names Derive the connector name namespace from data.type instead of hardcoding 'core/'. Sanitize both parts to only allow letters, numbers, and hyphens. This produces names like 'ai-provider/google'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename ApiKeyProviderConnector and derive helpLabel internally Rename ApiKeyProviderConnector to ApiKeyConnector and move helpLabel derivation from the registration loop into the component itself, since it already receives helpUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Rename _gutenberg_is_api_key_valid to _gutenberg_is_ai_api_key_valid The function is AI-provider-specific, so the name should reflect that. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Move sanitize helper outside the loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Pass plugin data from server instead of deriving slug client-side Hardcode plugin slugs for the three featured AI providers in PHP within a `plugin` sub-object and pass them to the client via script module data. When no plugin data is provided (e.g. dynamically registered providers), the install/activate UI is skipped and the connector assumes the plugin is already active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add backport changelog entry for Core PR WordPress#11080 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add remove_filter for Core script module data function Ensures the Gutenberg version overrides the equivalent Core function (_wp_connectors_get_connector_script_module_data), consistent with the pattern used by the other connector functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Felix Arntz <flixos90@gmail.com> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: raftaar1191 <raftaar1191@git.wordpress.org> Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: felixarntz <flixos90@git.wordpress.org>
… (#76014) * Connectors: Dynamically register providers from WP AI Client registry Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Expose provider settings to the script module Pass provider data (name, description, credentials URL, setting keys) to the `connectors-wp-admin` script module via the `script_module_data` filter, making it available as inline JSON for the frontend to consume. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Register connectors dynamically from server-provided data Replace hardcoded per-provider connector components with a single dynamic loop that reads provider data from the script module data JSON tag. Known providers retain their SVG logos via a client-side map; third-party providers from the registry render without a logo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Use ucwords fallback for empty provider name When a third-party provider from the AI Client registry has no name, fall back to ucwords( $provider_id ) for a reasonable display label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add authentication_method to provider data structure Expose authentication_method ('api_key' or 'none') in provider settings instead of silently filtering out non-API-key providers. This makes the public-facing interfaces extensible for future authentication methods while still only implementing api_key support for now. - Include all registered providers regardless of auth method - Conditionally generate settings sub-array only for api_key providers - Expose authenticationMethod in script module data for the frontend - Skip non-api_key providers in the frontend registration loop - Rename ProviderConnector to ApiKeyProviderConnector for clarity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add type field to distinguish AI providers from other connectors Add a 'type' field ('ai_provider') to the provider data structure so credentials are only passed to the WP AI Client for AI providers. The frontend also filters by type, only rendering connectors for AI providers. This separates AI providers from future non-AI connectors and makes the intent of the API explicit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Group authentication fields into sub-object and eliminate settings duplication Restructure provider data so credentials_url, setting_name, and method live together in an authentication sub-object rather than as flat top-level fields. Remove the redundant settings array from _gutenberg_get_provider_settings() and move register_setting logic (label, description, sanitize) into the consumer function. Update all PHP consumers to read from authentication directly. On the frontend, change ProviderAuthentication to a discriminated union type for type-safe access after narrowing on method. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename _gutenberg_get_provider_settings to _gutenberg_get_connector_settings Use the domain term "connector" consistently with the rest of the codebase (settings group, option names, script module filter). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Clarify authentication docblock for none method Document that credentials_url and setting_name are only present when method is 'api_key' and absent when method is 'none'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use URL hostname for help label instead of regex stripping Replace manual regex URL stripping with new URL().hostname for a cleaner, more robust extraction of the domain name used as the help link label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use type-based namespace for connector names Derive the connector name namespace from data.type instead of hardcoding 'core/'. Sanitize both parts to only allow letters, numbers, and hyphens. This produces names like 'ai-provider/google'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename ApiKeyProviderConnector and derive helpLabel internally Rename ApiKeyProviderConnector to ApiKeyConnector and move helpLabel derivation from the registration loop into the component itself, since it already receives helpUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Rename _gutenberg_is_api_key_valid to _gutenberg_is_ai_api_key_valid The function is AI-provider-specific, so the name should reflect that. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Move sanitize helper outside the loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Pass plugin data from server instead of deriving slug client-side Hardcode plugin slugs for the three featured AI providers in PHP within a `plugin` sub-object and pass them to the client via script module data. When no plugin data is provided (e.g. dynamically registered providers), the install/activate UI is skipped and the connector assumes the plugin is already active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add backport changelog entry for Core PR #11080 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add remove_filter for Core script module data function Ensures the Gutenberg version overrides the equivalent Core function (_wp_connectors_get_connector_script_module_data), consistent with the pattern used by the other connector functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Felix Arntz <flixos90@gmail.com> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: raftaar1191 <raftaar1191@git.wordpress.org> Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: felixarntz <flixos90@git.wordpress.org> Source: WordPress/gutenberg@7f7f2ea
… (#76014) * Connectors: Dynamically register providers from WP AI Client registry Polyfills WordPress/wordpress-develop#11080 for the Gutenberg plugin: - Expand `_gutenberg_get_provider_settings()` to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude). - Restructure the return value to be keyed by provider ID with `name`, `description`, `credentials_url` at the top level and `settings` as a nested array. - Filter out providers whose authentication method is not `api_key`. - Update all consumer functions to use the new structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Expose provider settings to the script module Pass provider data (name, description, credentials URL, setting keys) to the `connectors-wp-admin` script module via the `script_module_data` filter, making it available as inline JSON for the frontend to consume. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Register connectors dynamically from server-provided data Replace hardcoded per-provider connector components with a single dynamic loop that reads provider data from the script module data JSON tag. Known providers retain their SVG logos via a client-side map; third-party providers from the registry render without a logo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Use ucwords fallback for empty provider name When a third-party provider from the AI Client registry has no name, fall back to ucwords( $provider_id ) for a reasonable display label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add authentication_method to provider data structure Expose authentication_method ('api_key' or 'none') in provider settings instead of silently filtering out non-API-key providers. This makes the public-facing interfaces extensible for future authentication methods while still only implementing api_key support for now. - Include all registered providers regardless of auth method - Conditionally generate settings sub-array only for api_key providers - Expose authenticationMethod in script module data for the frontend - Skip non-api_key providers in the frontend registration loop - Rename ProviderConnector to ApiKeyProviderConnector for clarity Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add type field to distinguish AI providers from other connectors Add a 'type' field ('ai_provider') to the provider data structure so credentials are only passed to the WP AI Client for AI providers. The frontend also filters by type, only rendering connectors for AI providers. This separates AI providers from future non-AI connectors and makes the intent of the API explicit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Group authentication fields into sub-object and eliminate settings duplication Restructure provider data so credentials_url, setting_name, and method live together in an authentication sub-object rather than as flat top-level fields. Remove the redundant settings array from _gutenberg_get_provider_settings() and move register_setting logic (label, description, sanitize) into the consumer function. Update all PHP consumers to read from authentication directly. On the frontend, change ProviderAuthentication to a discriminated union type for type-safe access after narrowing on method. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename _gutenberg_get_provider_settings to _gutenberg_get_connector_settings Use the domain term "connector" consistently with the rest of the codebase (settings group, option names, script module filter). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Clarify authentication docblock for none method Document that credentials_url and setting_name are only present when method is 'api_key' and absent when method is 'none'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use URL hostname for help label instead of regex stripping Replace manual regex URL stripping with new URL().hostname for a cleaner, more robust extraction of the domain name used as the help link label. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Use type-based namespace for connector names Derive the connector name namespace from data.type instead of hardcoding 'core/'. Sanitize both parts to only allow letters, numbers, and hyphens. This produces names like 'ai-provider/google'. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Rename ApiKeyProviderConnector and derive helpLabel internally Rename ApiKeyProviderConnector to ApiKeyConnector and move helpLabel derivation from the registration loop into the component itself, since it already receives helpUrl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Update lib/experimental/connectors/default-connectors.php Co-authored-by: Felix Arntz <flixos90@gmail.com> * Connectors: Rename _gutenberg_is_api_key_valid to _gutenberg_is_ai_api_key_valid The function is AI-provider-specific, so the name should reflect that. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Move sanitize helper outside the loop Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Pass plugin data from server instead of deriving slug client-side Hardcode plugin slugs for the three featured AI providers in PHP within a `plugin` sub-object and pass them to the client via script module data. When no plugin data is provided (e.g. dynamically registered providers), the install/activate UI is skipped and the connector assumes the plugin is already active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add backport changelog entry for Core PR #11080 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Connectors: Add remove_filter for Core script module data function Ensures the Gutenberg version overrides the equivalent Core function (_wp_connectors_get_connector_script_module_data), consistent with the pattern used by the other connector functions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Felix Arntz <flixos90@gmail.com> Co-authored-by: gziolo <gziolo@git.wordpress.org> Co-authored-by: raftaar1191 <raftaar1191@git.wordpress.org> Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: felixarntz <flixos90@git.wordpress.org> Source: WordPress/gutenberg@3763f32
| * @return bool|null True if valid, false if invalid, null if unable to determine. | ||
| */ | ||
| function _wp_connectors_is_api_key_valid( string $key, string $provider_id ): ?bool { | ||
| function _wp_connectors_is_ai_api_key_valid( string $key, string $provider_id ): ?bool { |
There was a problem hiding this comment.
Just curious: are we expecting other type of _wp_connectors_* API keys? we're going to need to handle?
There was a problem hiding this comment.
not yet - or at least there is not generally applicable way to validate API keys. This function only exists because for AI provider API keys specifically, we can validate them by using the PHP AI Client SDK abstraction.
@gziolo @jorgefilipecosta I'm catching up - did the rest of the feedback from the initial WordPress/gutenberg#75833 make it in too? Particularly on my mind is the unencrypted API key storage. |
felixarntz
left a comment
There was a problem hiding this comment.
Thanks @gziolo for bringing this over here, and all the iterations.
LGTM, except for a few notes. Once you've address these, I think this is good to commit. I'm preemptively approving.
| $providers = array( | ||
| function _wp_connectors_get_connector_settings(): array { | ||
| $connectors = array( | ||
| 'google' => array( |
There was a problem hiding this comment.
Can we sort these alphabetically? Just to be neutral. should be Anthropic, Google, OpenAI
| } | ||
| return $provider_settings; | ||
|
|
||
| return $connectors; |
There was a problem hiding this comment.
Related to the above: We should probably sort alphabetically by key here too, so that any registered providers are also integrated properly into the list.
Alternatively, if we want to keep the primary / "official" ones first, we could keep them first, and only sort any additional ones to be alphabetically listed after that.
There was a problem hiding this comment.
+1 to sorting all, and not just the unofficial ones.
| } | ||
| foreach ( _wp_connectors_get_connector_settings() as $connector_id => $connector_data ) { | ||
| $auth = $connector_data['authentication']; | ||
| if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { |
There was a problem hiding this comment.
The sanitize_callback and the description below are also only correct for AI providers. So I think here we need to add the check for ai_provider type too.
Probably makes sense anyway, because we only really support these at the moment - prevents future errors by accident.

Trac ticket: https://core.trac.wordpress.org/ticket/64730
Follow-up for #11056.
Synced from WordPress/gutenberg#76014.
Summary
_wp_connectors_get_provider_settings()to dynamically fetch registered providers from the AI Client registry, in addition to the three hardcoded featured providers (Gemini, OpenAI, Claude).name,description,credentials_urlat the top level andsettingsas a nested array.api_key._wp_connectors_validate_keys_in_rest,_wp_register_default_connector_settings,_wp_connectors_pass_default_keys_to_ai_client) to use the new structure.Test plan
npm run test:php -- --group connectorspasses (14 tests, 64 assertions).AiClient::defaultRegistry()->registerProvider()with API key auth appears in the settings.🤖 Generated with Claude Code