Connectors: Use validate_plugin() for the connector install check#11701
Connectors: Use validate_plugin() for the connector install check#11701t-hamano wants to merge 9 commits intoWordPress:trunkfrom
Conversation
Previously, `WP_Connector_Registry::register()` silently filled in `__return_true` when no `is_active` callback was provided, which made it impossible for consumers to distinguish "no callback supplied" from "callback always returns true." Defer the check to call sites instead, so the stored connector data reflects what was actually registered. Update `_wp_register_default_connector_settings()` and `_wp_connectors_get_connector_script_module_data()` to treat a missing callback as active, matching the documented `Defaults to __return_true` semantics. See #65020. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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. |
| if ( ! isset( $connector['plugin']['is_active'] ) ) { | ||
| $connector['plugin']['is_active'] = '__return_true'; | ||
| } | ||
|
|
There was a problem hiding this comment.
Remove Defaults to __return_true. from line no 118
|
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. |
…default. Replace the raw `file_exists()` install probe in `_wp_connectors_get_connector_script_module_data()` with `validate_plugin()`, which adds path traversal protection and confirms the file is a recognised plugin rather than just any file at that path. Restores the `require_once` for `wp-admin/includes/plugin.php` that the function depends on. Also updates the `is_active` docblock in `WP_Connector_Registry::register()` to spell out that an omitted callback paired with a `file` is treated as active on the assumption that the plugin must be loaded in order to register itself, so callers do not mistake the omission for a no-op. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
See feedback from @jorgefilipecosta at https://github.com/WordPress/gutenberg/pull/77897/changes#r3183140237 and https://github.com/WordPress/gutenberg/pull/77897/changes#r3189900673 If diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php
index fbf35ad73e..4fd451b2b0 100644
--- a/src/wp-includes/class-wp-connector-registry.php
+++ b/src/wp-includes/class-wp-connector-registry.php
@@ -41,7 +41,7 @@
* },
* plugin?: array{
* file: non-empty-string,
- * is_active?: callable(): bool
+ * is_active: callable(): bool
* }
* }
*/
|
Move the missing-callback fallback from `_wp_connectors_get_connector_script_module_data()` into `WP_Connector_Registry::register()`, where the registered connector now always has `plugin.is_active` set to `__return_true` when omitted. This lets every consumer call the callback unconditionally instead of repeating an `isset()` guard, and tightens the PHPStan shape so `is_active` is no longer optional on the stored array. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ion. Follow-up to the previous commit, which moved the `__return_true` fallback back into `WP_Connector_Registry::register()`. Restore the test assertions so they once again expect `plugin.is_active` to be set to `__return_true` when a callback is omitted, matching the registered shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Based on the feedback in Gutenberg, I have updated this PR. Ultimately, this PR only leaves minor code quality improvements 😄 |
plugin.is_active in the registry`WP_Connector_Registry::register()` always initializes `$connector['plugin']` as an array and always defaults `is_active` to `__return_true`, while `file` is only set when supplied. Reflect that in the type: `plugin` is required on the stored connector and `file` is the optional key, not the other way around. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| * plugin: array{ | ||
| * file?: non-empty-string, | ||
| * is_active: callable(): bool | ||
| * } |
There was a problem hiding this comment.
I believe this is the correct type to match the current specifications. The plugins should always be an array, and the file field should be optional.
There was a problem hiding this comment.
There is a small discrepancy here, it seems. Namely, the the register() method says that $args is a Connector. But this isn't true, because for Connector the plugin key is optional and both the file and is_active keys are optional. I suggest we replace this line:
* @phpstan-param Connector $args
With the actual shape that is allowed to be passed into register() for $args.
jorgefilipecosta
left a comment
There was a problem hiding this comment.
The changes look good, thank you @t-hamano!
Why: The variable was flagged by `Generic.Formatting.MultipleStatementAlignment` because the equals sign was not aligned with the adjacent `$is_activated` and `$is_installed` assignments. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This comment was marked as off-topic.
This comment was marked as off-topic.
|
This was not committed yet. |
|
I found several PHPStan issues at rule level 10 when looking at I've fixed these in e15d155 by amending this PR. |
| * file?: non-empty-string, | ||
| * is_active: callable(): bool, |
There was a problem hiding this comment.
Updated to be consistent with Connector on WP_Connector_Registry.
| * file?: non-empty-string, | ||
| * is_active: callable(): bool, |
There was a problem hiding this comment.
Updated to be consistent with Connector on WP_Connector_Registry.
| * @phpstan-return ?array{ | ||
| * name: non-empty-string, | ||
| * description: non-empty-string, | ||
| * description: string, |
There was a problem hiding this comment.
Because the default is an empty string.
However, it would seem preferable to remain non-empty-string and to instead have the property be optional as with the other properties.
There was a problem hiding this comment.
For reference, the underlying description is nullable: https://github.com/WordPress/php-ai-client/blob/631704201d15ffeff7091ad3bc7156db74054956/src/Providers/DTO/ProviderMetadata.php#L57
| $ai_registry = AiClient::defaultRegistry(); | ||
|
|
||
| foreach ( $ai_registry->getRegisteredProviderIds() as $connector_id ) { | ||
| foreach ( array_filter( $ai_registry->getRegisteredProviderIds() ) as $connector_id ) { |
There was a problem hiding this comment.
This is because returns list<string> and not list<non-empty-string>. The array_filter() can be removed with an upstream fix: WordPress/php-ai-client#232
| 'method' => 'api_key', | ||
| ); | ||
| if ( $credentials_url ) { | ||
| $authentication['credentials_url'] = $credentials_url; |
There was a problem hiding this comment.
This is because credentials_url is either a non-empty-string or undefined. It doesn't accept null.
| 'logo_url' => $logo_url, | ||
| ); | ||
| if ( $logo_url ) { | ||
| $defaults[ $connector_id ]['logo_url'] = $logo_url; |
There was a problem hiding this comment.
Again, because the type is non-empty-string when provided, not non-empty-string|null
| if ( 'api_key' === $args['authentication']['method'] ) { | ||
| $sanitized_id = str_replace( '-', '_', $id ); | ||
|
|
||
| if ( ! isset( $args['authentication']['setting_name'] ) ) { |
There was a problem hiding this comment.
For this change and the other changes in this block, the if conditions were removed. This is because it was checking isset() for array keys which are never set on $defaults.
There was a problem hiding this comment.
(Suppress whitespace changes to make the review of the diff easier.)
|
For reference, the command I used to obtain the above PHPStan errors: composer phpstan -- --configuration=phpstan.neon.dist --level=10 src/wp-includes/class-wp-connector-registry.php src/wp-includes/connectors.php |
This PR backports the changes from Gutenberg to the core: WordPress/gutenberg#77897
Trac ticket: https://core.trac.wordpress.org/ticket/65020
Use of AI Tools
None
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.