Connectors: Backport Gutenberg PR #75833 PHP integration#11056
Connectors: Backport Gutenberg PR #75833 PHP integration#11056jorgefilipecosta wants to merge 7 commits intoWordPress:trunkfrom
Conversation
|
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. |
| }, | ||
| "gutenberg": { | ||
| "ref": "23b566c72e9c4a36219ef5d6e62890f05551f6cb" | ||
| "ref": "336a47b80b566256ce5035cae56b2ab16f583dad" |
There was a problem hiding this comment.
This change is here just for testing it will not happen on this PR, it will happen during the Gutenberg package sync.
felixarntz
left a comment
There was a problem hiding this comment.
@jorgefilipecosta Thanks for preparing this!
There are of course still several things in here that need iteration, but given it's all private and we need this in Beta 2 tomorrow, I think we can proceed.
I left a few minor comments, that (other than the registry related ones) would be great to address before commit. But overall I think it's good to go in.
We'll need to iron out the whole registry bit and improve DX of registering a connector for Beta 3.
| return null; | ||
| } | ||
|
|
||
| $registry->setProviderRequestAuthentication( | ||
| $provider_id, | ||
| new ApiKeyRequestAuthentication( $key ) | ||
| ); | ||
|
|
||
| return $registry->isProviderConfigured( $provider_id ); | ||
| } catch ( \Error $e ) { | ||
| return null; |
There was a problem hiding this comment.
I think for both of the return null cases, we'll want to add some kind of messaging, at least for debugging.
could use _doing_it_wrong for the first one (because that would be doing it wrong on the developer side) and wp_trigger_error for the second one.
There was a problem hiding this comment.
Done with 31ab71c. I still need to look into it, because we most likely will need to pass here some generic translatable message instead of the code-generated error message.
src/wp-includes/connectors.php
Outdated
| * @param string $key The API key. | ||
| * @param string $provider_id The WP AI client provider ID. | ||
| */ | ||
| function _wp_connectors_set_provider_api_key( string $key, string $provider_id ): void { |
There was a problem hiding this comment.
I think this function should return bool, to have an idea whether it worked or not.
There was a problem hiding this comment.
Updated the method in 31ab71c. We might want to revisit this method if we are looking at supporting multiple auth methods. In that case, we might want something more like:
function _wp_connectors_set_provider_auth( string $provider_id, string $auth_type, array $auth_params ): void {This way we would have a general purpose util that devs can use elsewhere, too.
src/wp-includes/connectors.php
Outdated
| return array( | ||
| 'connectors_gemini_api_key' => array( | ||
| 'provider' => 'google', | ||
| 'mask' => '_wp_connectors_mask_gemini_api_key', | ||
| 'sanitize' => '_wp_connectors_sanitize_gemini_api_key', | ||
| ), | ||
| 'connectors_openai_api_key' => array( | ||
| 'provider' => 'openai', | ||
| 'mask' => '_wp_connectors_mask_openai_api_key', | ||
| 'sanitize' => '_wp_connectors_sanitize_openai_api_key', | ||
| ), | ||
| 'connectors_anthropic_api_key' => array( | ||
| 'provider' => 'anthropic', | ||
| 'mask' => '_wp_connectors_mask_anthropic_api_key', | ||
| 'sanitize' => '_wp_connectors_sanitize_anthropic_api_key', | ||
| ), | ||
| ); |
There was a problem hiding this comment.
This is fine for now (i.e. Beta 2), but as discussed earlier today we should enhance this to allow properly registering a provider with all its base information in PHP, and notably reduce the barrier of entry.
First of all, of course this will require a proper registry.
In terms of this function, we would then want to use the registry, and for the 3 ones here, they would continue to be hard-coded, but overridable by the registry. This will allow us to make updates to the provider plugins (which is more appropriate for timing, since we can't quickly ship a new Core release when some of the metadata might be worth a change), and the hard-coded Core references would only be "starting points" / "fallbacks" for when the provider plugins are not active yet.
For the AI connectors specifically, we should as much as possible rely on what the WordPress\AiClient\AiClient::defaultRegistry() already offers:
namedescription(coming in Adds optional description to providers php-ai-client#210)credentialsUrlauthenticationMethod(e.g. "api_key")
Ideally we can simply iterate through those providers and then register the connector for it based on this information. We could support a "merge" behavior, where it would still be allowed to pass in additional information for the provider that may not (yet) have a 1:1 mapping in the WordPress\AiClient provider registry.
We should be able to avoid the need to provide all these callbacks, ideally this is handled centrally in Core, based on the authenticationMethod given.
And as for React UI for the fields, there should be a built-in component that is automatically used based on the given authenticationMethod. For flexibility with more advanced processes (e.g. Jetpack might add some kind of one-button click flow for better UX), we should of course still allow using a custom render component. But for the regular AI provider connector, we need to simplify this so that a single PHP array is all that's needed.
None of this is a blocker for this PR. But wanted to capture it here.
cc @gziolo
There was a problem hiding this comment.
Cool, as noted in #11056 (comment), I plan to work on all the described changes. It seems like a viable path forward, which would make the dev experience for AI provider authors very compelling 💯
| 'connectors', | ||
| $option_name, | ||
| array( | ||
| 'type' => 'string', |
There was a problem hiding this comment.
This works for now, but is problematic and needs to be improved before stable release: Not every credential is a single string. A connector may require two fields (e.g. ID and secret, username and password, ...). We need to abstract this in a way that it's not enforcing a single option per provider usage - or at the very least, if we use a single option, it also needs to allow for more complex data, e.g. an object / associative array with multiple fields in it.
Once we have the connector registry, I think a good idea might be to have an settings field in there that allows an array and then handles these things. Or it could even be a register_settings PHP callback.
(Again, for some predefined authentication methods like "api_key" we could auto-populate this.)
cc @gziolo
There was a problem hiding this comment.
I refactored _wp_connectors_get_provider_settings(), so it generates all necessary settings for registered (hardcoded for now) providers. The current shape will allow us to iterate further while moving most of the logic to that function. I will continue working on it based on the proposed design after Beta 2.
- Change catch blocks from `\Error` to `Exception` (global namespace). - Add `_doing_it_wrong` when an unregistered provider ID is passed. - Add `wp_trigger_error` to surface exception messages in catch blocks. - Change `_wp_connectors_set_provider_api_key` to return `bool`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cks. Replace six identical per-provider mask/sanitize wrapper functions with `_wp_connectors_mask_api_key` used directly and sanitize closures built from a provider map in `_wp_connectors_get_connectors()`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… boilerplate. Rename `_wp_connectors_get_connectors` to `_wp_connectors_get_provider_settings` and dynamically assemble setting names, labels, and descriptions from a minimal provider slug/name map. Add `label` and `description` to `register_setting` calls so they appear in the REST API schema. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| mockedApiResponse.settings = { | ||
| "connectors_gemini_api_key": "", | ||
| "connectors_openai_api_key": "", | ||
| "connectors_anthropic_api_key": "", |
There was a problem hiding this comment.
I don't know if that matters that much, but we use Claude in the UI instead of Anthropic, similar to Gemini instead of Google. We could be more consistent, but it isn't a blocker to me.
| * @access private | ||
| */ | ||
| function _wp_register_default_connector_settings(): void { | ||
| if ( ! class_exists( '\WordPress\AiClient\AiClient' ) ) { |
There was a problem hiding this comment.
@jorgefilipecosta, do we need this check in WP core? I bet we don't.
There was a problem hiding this comment.
Well we don't excatly "need" but I would prefer to be defensive here, in the same way code normally checks for the inclusion of build generated functions function_exists( 'wp_connectors_wp_admin_render_page' ), AI client also seems like an external lib we had conversations in the past about some constant that makes AI client not even load etc, so I think being defensive here may be good.
|
I need to re-test the branch after all the refactoring applied based on the feedback provided, but it looks like we are good to go if it still works as expected 😅 |
Trac ticket: https://core.trac.wordpress.org/ticket/64730
Summary
Notes
Testing Instructions
Visit wp-admin/options-general.php?page=connectors-wp-admin and verify the Connectors page appears under Settings.
Verify Connectors appears between General and Writing in the Settings submenu.
Install all AI provider plugins.
Set API keys for every supported provider.
Remove the key and set it again for every supported provider.
When a incorrect API key is provided then it isn't possible to save it.
API keys are properly masked on the frontend (including REST API response).
Deactivate the AI provider plugin from the Plugins screen and activate the plugin again from the Connectors screen.
Uninstall the AI provider plugin from the Plugins screen and install the plugin again from the Connectors screen.
Revoke a key that was valid on the provider website and veify the screen does not says connected anymore.