Skip to content

Connectors: Add wp_connectors_settings filter for extensibility#11175

Open
gziolo wants to merge 7 commits intoWordPress:trunkfrom
gziolo:add/connectors-settings-filter
Open

Connectors: Add wp_connectors_settings filter for extensibility#11175
gziolo wants to merge 7 commits intoWordPress:trunkfrom
gziolo:add/connectors-settings-filter

Conversation

@gziolo
Copy link
Member

@gziolo gziolo commented Mar 5, 2026

Trac ticket: https://core.trac.wordpress.org/ticket/64791

Summary

  • Adds a wp_connectors_settings filter in _wp_connectors_get_connector_settings() so plugins can add, modify, or remove connectors displayed on the Connectors screen.
  • The filter runs after built-in and AI Client registry providers are collected but before setting_name is auto-generated — so connectors added via the filter with type => 'ai_provider' and method => 'api_key' automatically get their setting_name populated.
  • Tightens setting_name generation to require type === 'ai_provider', preventing non-AI connectors from receiving an incorrect connectors_ai_* setting name.

Use cases

  1. Add a third-party AI provider with API key auth
  2. Add a non-AI connector (email, analytics, storage)
  3. Add a no-auth provider (local/on-device AI)
  4. Add a connector with plugin slug for install/activate UI
  5. Modify description, name, or credentials URL of a built-in provider
  6. Modify auth method (e.g., proxy plugin switches api_key to none)
  7. Remove a provider (enterprise policy, avoid duplicates)
  8. Filter conditionally by role, multisite, license, or feature flag
  9. Reorder connectors (filter runs after ksort)

Follows from the discussion in WordPress/gutenberg#76014 (comment).

Test plan

  • npm run test:php -- --group connectors passes (20 tests, 98 assertions)
  • Verify filter can add a new non-AI connector and it appears in the Connectors screen data
  • Verify filter can remove a built-in connector
  • Verify filter-added AI provider with api_key auth gets setting_name auto-generated
  • Verify filter-added non-AI connector with api_key auth does not get setting_name

🤖 Generated with Claude Code

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props gziolo, flixos90, mukesh27.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@gziolo gziolo changed the title Connectors: Add wp_connectors_settings filter for extensibility Connectors: Add wp_connectors_settings filter for extensibility Mar 5, 2026
@gziolo gziolo requested a review from felixarntz March 5, 2026 11:03
@gziolo gziolo self-assigned this Mar 5, 2026
@gziolo gziolo requested a review from jorgefilipecosta March 5, 2026 11:03
@gziolo gziolo force-pushed the add/connectors-settings-filter branch from 55f0e81 to 555bb8a Compare March 5, 2026 11:04
@gziolo gziolo requested a review from Jameswlepage March 5, 2026 12:29
@github-actions
Copy link

github-actions bot commented Mar 5, 2026

Test using WordPress Playground

The 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

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@gziolo
Copy link
Member Author

gziolo commented Mar 5, 2026

It's something I still feel comfortable shipping in WordPress 7.0 if we can agree that it would be a valuable addition. Nearly the same structure gets passed to the client as the filter wp_connectors_settings receives, so it's fine to seal it as a contract.

gziolo and others added 2 commits March 5, 2026 13:49
Introduce a `wp_connectors_settings` filter in
`_wp_connectors_get_connector_settings()` so plugins can add, modify,
or remove connectors on the Connectors screen. The filter runs after
built-in and AI Client registry providers are collected but before
`setting_name` is auto-generated for API-key connectors.

Also tighten the `setting_name` generation to only apply when
`type === 'ai_provider'`, preventing non-AI connectors from receiving
an incorrect `connectors_ai_*` setting name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…leanup.

Use structured PHPDoc for the `$connectors` param in `apply_filters()` to
mirror the function's return documentation. In tests, use closure references
for filter removal before assertions to prevent leaking to other tests.

Follow-up to [555bb8a].

See #64791.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gziolo gziolo force-pushed the add/connectors-settings-filter branch 2 times, most recently from c8f329a to e0a086e Compare March 5, 2026 15:23
…ng keys.

Skip `register_setting` in `_wp_register_default_connector_settings()`
when the AI provider is not in the registry, preventing REST-exposed
settings that silently reject values. Reorder the `hasProvider` check
in `_wp_connectors_pass_default_keys_to_ai_client()` to run before
reading the option. Update the REST settings test to reflect that
connector settings are only registered when their provider is active.

Follow-up to [555bb8a], [bd6c4c8].

See #64791.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gziolo gziolo force-pushed the add/connectors-settings-filter branch from e0a086e to bd4090d Compare March 5, 2026 16:30
Copy link
Member

@felixarntz felixarntz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gziolo As for the purpose of the PR so far, this looks solid.

However, I wonder, is this how we want to handle the external registration of connectors? This is a pretty big decision we shouldn't take lightly.

So far, this has all been locked down, and it's all private code. While I agree we need to allow registering connectors in 7.0 already, I'm not sure a filter is the way to go. Filters for registration can be a bad pattern for DX, especially with nested structured data like here. A declarative API, like wp_register_connector would be much more intuitive to use.

Alternatively, I think something that would work well with the current state of the code here would be a pattern where we have a registry class instance, and we expose it to an action.

In other words:

  • Introduce WP_Connector_Registry class
  • Move the 3 hard-coded connectors in there
  • Have a method on it register_connector that receives the data for a single connector
  • Create an instance of the class in _wp_connectors_get_connector_settings(), then run an action (NOT filter) where you pass that instance; action could be called e.g. wp_connectors_init or something like that
  • Have a method on the class get_registered_connectors, to call at the end of _wp_connectors_get_connector_settings()

This would lead to better DX and encapsulate registration nicely, without creating any timing concerns because all registration would be forced to happen in the action hook. And it's a single class, nothing too complicated to add even with the little time we have.

WDYT?

gziolo and others added 2 commits March 6, 2026 11:08
… generation.

Addresses review feedback to filter the final, fully populated value.
The filter now receives connectors with `setting_name` already set
for API-key connectors, and runs as the last step before returning.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gziolo
Copy link
Member Author

gziolo commented Mar 6, 2026

@felixarntz Thanks for the thoughtful review! I agree that a registry class with an action hook would be the better pattern here — it's consistent with how Core handles registration elsewhere (register_block_type, register_post_type, wp_register_ability, etc.) and avoids the pitfalls of filters with nested structured data.

I also realized that we already have a way to filter what reaches the frontend via the script_module_data_options-connectors-wp-admin filter, which reduces the need for a filter on the registration side as currently proposed in this PR.

I'm going to explore your proposed approach with WP_Connector_Registry + a wp_connectors_init action. Will update the PR once I have something to show.

gziolo and others added 2 commits March 6, 2026 11:39
…d registration.

Introduces `WP_Connector_Registry` class with `register()`, `unregister()`,
`is_registered()`, `get_registered()`, and `get_all_registered()` methods.

Adds public API functions: `wp_register_connector()`, `wp_unregister_connector()`,
`wp_has_connector()`, `wp_get_connector()`, `wp_get_connectors()`.

Connectors must be registered on the `wp_connectors_init` action hook.
Default connectors (Anthropic, Google, OpenAI) and AI Client registry
providers are registered via `_wp_register_default_connectors()`.

Removes the `wp_connectors_settings` filter in favor of the registry pattern,
consistent with `WP_Abilities_Registry` and other Core registration APIs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d defaults.

Merges AI Client registry values on top of hardcoded defaults before
registering, so provider plugin data takes precedence while hardcoded
values serve as fallbacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gziolo
Copy link
Member Author

gziolo commented Mar 6, 2026

@felixarntz, I quickly prototyped the idea you outlined. Does it align with what you had in mind?

Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestions for attaining PHPStan rule level 8 in src/wp-includes/class-wp-connector-registry.php along with leveraging some other features in PHP 7.4.

* @since 7.0.0
* @var self|null
*/
private static $instance = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static $instance = null;
private static ?WP_Connector_Registry $instance = null;

* @since 7.0.0
* @var array[]
*/
private $registered_connectors = array();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private $registered_connectors = array();
private array $registered_connectors = array();

* name, description, type, authentication, and optionally plugin.
*
* @since 7.0.0
* @var array[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @var array[]
* @var array<string, array>
* @phpstan-var array<string, Connector>

* The singleton instance of the registry.
*
* @since 7.0.0
* @var self|null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @var self|null

);

if ( 'api_key' === $args['authentication']['method'] ) {
$connector['authentication']['credentials_url'] = isset( $args['authentication']['credentials_url'] ) ? $args['authentication']['credentials_url'] : null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$connector['authentication']['credentials_url'] = isset( $args['authentication']['credentials_url'] ) ? $args['authentication']['credentials_url'] : null;
$connector['authentication']['credentials_url'] = $args['authentication']['credentials_url'] ?? null;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants