From 99f0358a80069b71a65a440b0e4d75dae347b375 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Mar 2026 17:58:53 +0100 Subject: [PATCH 1/9] Connectors: Remove redundant helper and inline sorting where needed. Removes the private `_wp_connectors_get_connector_settings()` wrapper, which only called `wp_get_connectors()` and applied `ksort()`. Callers now use `wp_get_connectors()` directly, and the alphabetical sort is applied in `_wp_connectors_get_connector_script_module_data()` just before the data is passed to JavaScript, which is the only place where ordering matters. Expands the `@return` PHPDoc on `wp_get_connectors()` with the full array shape that was previously documented on the removed helper. Updates tests accordingly: renames `wpConnectorsGetConnectorSettings` to `wpGetConnectors` targeting `wp_get_connectors()` directly. Props gziolo. Fixes #64791. Co-Authored-By: Claude Sonnet 4.6 --- src/wp-includes/connectors.php | 67 ++++++++----------- ...nectorSettings.php => wpGetConnectors.php} | 28 +++----- 2 files changed, 35 insertions(+), 60 deletions(-) rename tests/phpunit/tests/connectors/{wpConnectorsGetConnectorSettings.php => wpGetConnectors.php} (84%) diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 60f97839dabb6..8a96f3d9aabe4 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -55,7 +55,28 @@ function wp_get_connector( string $id ): ?array { * * @see WP_Connector_Registry::get_all_registered() * - * @return array[] An array of registered connectors keyed by connector ID. + * @return array { + * Connector settings keyed by connector ID. + * + * @type array ...$0 { + * Data for a single connector. + * + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin Optional. Plugin data for install/activate UI. + * @type string $slug The WordPress.org plugin slug. + * } + * @type array $authentication { + * Authentication configuration. When method is 'api_key', includes + * credentials_url and setting_name. When 'none', only method is present. + * + * @type string $method The authentication method: 'api_key' or 'none'. + * @type string|null $credentials_url Optional. URL where users can obtain API credentials. + * @type string $setting_name Optional. The setting name for the API key. + * } + * } + * } */ function wp_get_connectors(): array { $registry = WP_Connector_Registry::get_instance(); @@ -324,41 +345,6 @@ function _wp_connectors_get_real_api_key( string $option_name, callable $mask_ca return (string) $value; } -/** - * Gets the registered connector settings. - * - * @since 7.0.0 - * @access private - * - * @return array { - * Connector settings keyed by connector ID. - * - * @type array ...$0 { - * Data for a single connector. - * - * @type string $name The connector's display name. - * @type string $description The connector's description. - * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin Optional. Plugin data for install/activate UI. - * @type string $slug The WordPress.org plugin slug. - * } - * @type array $authentication { - * Authentication configuration. When method is 'api_key', includes - * credentials_url and setting_name. When 'none', only method is present. - * - * @type string $method The authentication method: 'api_key' or 'none'. - * @type string|null $credentials_url Optional. URL where users can obtain API credentials. - * @type string $setting_name Optional. The setting name for the API key. - * } - * } - * } - */ -function _wp_connectors_get_connector_settings(): array { - $connectors = wp_get_connectors(); - ksort( $connectors ); - return $connectors; -} - /** * Validates connector API keys in the REST response when explicitly requested. * @@ -396,7 +382,7 @@ function _wp_connectors_validate_keys_in_rest( WP_REST_Response $response, WP_RE return $response; } - foreach ( _wp_connectors_get_connector_settings() as $connector_id => $connector_data ) { + foreach ( wp_get_connectors() as $connector_id => $connector_data ) { $auth = $connector_data['authentication']; if ( 'ai_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { continue; @@ -431,7 +417,7 @@ function _wp_connectors_validate_keys_in_rest( WP_REST_Response $response, WP_RE function _wp_register_default_connector_settings(): void { $ai_registry = AiClient::defaultRegistry(); - foreach ( _wp_connectors_get_connector_settings() as $connector_id => $connector_data ) { + foreach ( wp_get_connectors() as $connector_id => $connector_data ) { $auth = $connector_data['authentication']; if ( 'ai_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { continue; @@ -485,7 +471,7 @@ function _wp_register_default_connector_settings(): void { function _wp_connectors_pass_default_keys_to_ai_client(): void { try { $ai_registry = AiClient::defaultRegistry(); - foreach ( _wp_connectors_get_connector_settings() as $connector_id => $connector_data ) { + foreach ( wp_get_connectors() as $connector_id => $connector_data ) { if ( 'ai_provider' !== $connector_data['type'] ) { continue; } @@ -526,7 +512,7 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void { */ function _wp_connectors_get_connector_script_module_data( array $data ): array { $connectors = array(); - foreach ( _wp_connectors_get_connector_settings() as $connector_id => $connector_data ) { + foreach ( wp_get_connectors() as $connector_id => $connector_data ) { $auth = $connector_data['authentication']; $auth_out = array( 'method' => $auth['method'] ); @@ -548,6 +534,7 @@ function _wp_connectors_get_connector_script_module_data( array $data ): array { $connectors[ $connector_id ] = $connector_out; } + ksort( $connectors ); $data['connectors'] = $connectors; return $data; } diff --git a/tests/phpunit/tests/connectors/wpConnectorsGetConnectorSettings.php b/tests/phpunit/tests/connectors/wpGetConnectors.php similarity index 84% rename from tests/phpunit/tests/connectors/wpConnectorsGetConnectorSettings.php rename to tests/phpunit/tests/connectors/wpGetConnectors.php index 2a7ce199fa777..8faa2791a26f6 100644 --- a/tests/phpunit/tests/connectors/wpConnectorsGetConnectorSettings.php +++ b/tests/phpunit/tests/connectors/wpGetConnectors.php @@ -3,12 +3,12 @@ require_once dirname( __DIR__, 2 ) . '/includes/wp-ai-client-mock-provider-trait.php'; /** - * Tests for _wp_connectors_get_connector_settings(). + * Tests for wp_get_connectors(). * * @group connectors - * @covers ::_wp_connectors_get_connector_settings + * @covers ::wp_get_connectors */ -class Tests_Connectors_WpConnectorsGetConnectorSettings extends WP_UnitTestCase { +class Tests_Connectors_WpGetConnectors extends WP_UnitTestCase { use WP_AI_Client_Mock_Provider_Trait; @@ -32,7 +32,7 @@ public static function tear_down_after_class() { * @ticket 64730 */ public function test_returns_expected_connector_keys() { - $connectors = _wp_connectors_get_connector_settings(); + $connectors = wp_get_connectors(); $this->assertArrayHasKey( 'google', $connectors ); $this->assertArrayHasKey( 'openai', $connectors ); @@ -45,7 +45,7 @@ public function test_returns_expected_connector_keys() { * @ticket 64730 */ public function test_each_connector_has_required_fields() { - $connectors = _wp_connectors_get_connector_settings(); + $connectors = wp_get_connectors(); $this->assertNotEmpty( $connectors, 'Connector settings should not be empty.' ); @@ -68,7 +68,7 @@ public function test_each_connector_has_required_fields() { * @ticket 64730 */ public function test_api_key_connectors_have_setting_name_and_credentials_url() { - $connectors = _wp_connectors_get_connector_settings(); + $connectors = wp_get_connectors(); $api_key_count = 0; foreach ( $connectors as $connector_id => $connector_data ) { @@ -94,7 +94,7 @@ public function test_api_key_connectors_have_setting_name_and_credentials_url() * @ticket 64730 */ public function test_featured_provider_names_match_expected() { - $connectors = _wp_connectors_get_connector_settings(); + $connectors = wp_get_connectors(); $this->assertSame( 'Google', $connectors['google']['name'] ); $this->assertSame( 'OpenAI', $connectors['openai']['name'] ); @@ -105,7 +105,7 @@ public function test_featured_provider_names_match_expected() { * @ticket 64730 */ public function test_includes_registered_provider_from_registry() { - $connectors = _wp_connectors_get_connector_settings(); + $connectors = wp_get_connectors(); $mock = $connectors['mock_connectors_test']; $this->assertSame( 'Mock Connectors Test', $mock['name'] ); @@ -115,16 +115,4 @@ public function test_includes_registered_provider_from_registry() { $this->assertNull( $mock['authentication']['credentials_url'] ); $this->assertSame( 'connectors_ai_mock_connectors_test_api_key', $mock['authentication']['setting_name'] ); } - - /** - * @ticket 64730 - */ - public function test_connectors_are_sorted_alphabetically() { - $connectors = _wp_connectors_get_connector_settings(); - $keys = array_keys( $connectors ); - $sorted = $keys; - sort( $sorted ); - - $this->assertSame( $sorted, $keys, 'Connectors should be sorted alphabetically by ID.' ); - } } From 2ce88c496c6c5e73198b8174ae07d1882a2fa4f6 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Mar 2026 18:05:48 +0100 Subject: [PATCH 2/9] Connectors: Align PHPDoc between wp_get_connectors() and get_all_registered(). Expands the terse `@return array` on `WP_Connector_Registry::get_all_registered()` to the full WordPress-style array shape, matching `wp_get_connectors()`. Adds `@phpstan-import-type Connector from WP_Connector_Registry` and `@phpstan-return array` to `wp_get_connectors()`, matching the PHPStan annotation already present on the class method. Co-Authored-By: Claude Sonnet 4.6 --- .../class-wp-connector-registry.php | 23 ++++++++++++++++++- src/wp-includes/connectors.php | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 75a6b8ef0c993..6e0fee199dfb5 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -206,7 +206,28 @@ public function unregister( string $id ): ?array { * * @see wp_get_connectors() * - * @return array The array of registered connectors keyed by connector ID. + * @return array { + * Connector settings keyed by connector ID. + * + * @type array ...$0 { + * Data for a single connector. + * + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin Optional. Plugin data for install/activate UI. + * @type string $slug The WordPress.org plugin slug. + * } + * @type array $authentication { + * Authentication configuration. When method is 'api_key', includes + * credentials_url and setting_name. When 'none', only method is present. + * + * @type string $method The authentication method: 'api_key' or 'none'. + * @type string|null $credentials_url Optional. URL where users can obtain API credentials. + * @type string $setting_name Optional. The setting name for the API key. + * } + * } + * } * @phpstan-return array */ public function get_all_registered(): array { diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 8a96f3d9aabe4..b8b37a1dedc1a 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -55,6 +55,8 @@ function wp_get_connector( string $id ): ?array { * * @see WP_Connector_Registry::get_all_registered() * + * @phpstan-import-type Connector from WP_Connector_Registry + * * @return array { * Connector settings keyed by connector ID. * @@ -77,6 +79,7 @@ function wp_get_connector( string $id ): ?array { * } * } * } + * @phpstan-return array */ function wp_get_connectors(): array { $registry = WP_Connector_Registry::get_instance(); From 0a77bad95c92444f7ff372886f57ffb521cf58cc Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Mar 2026 18:13:17 +0100 Subject: [PATCH 3/9] Connectors: Add missing logo_url field to PHPDoc array shape. The `logo_url?: string|null` field present in the PHPStan `Connector` type was absent from the WordPress-style `@return` array shape on both `wp_get_connectors()` and `WP_Connector_Registry::get_all_registered()`. Adds it after `description` to match the PHPStan field order, and adjusts column alignment across all sibling `@type` entries. Props gziolo. Fixes #64791. Co-Authored-By: Claude Sonnet 4.6 --- src/wp-includes/class-wp-connector-registry.php | 9 +++++---- src/wp-includes/connectors.php | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 6e0fee199dfb5..9512e2cfedf8f 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -212,10 +212,11 @@ public function unregister( string $id ): ?array { * @type array ...$0 { * Data for a single connector. * - * @type string $name The connector's display name. - * @type string $description The connector's description. - * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin Optional. Plugin data for install/activate UI. + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string|null $logo_url Optional. URL to the connector's logo image. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin Optional. Plugin data for install/activate UI. * @type string $slug The WordPress.org plugin slug. * } * @type array $authentication { diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index b8b37a1dedc1a..b3c7a5f5cbc8d 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -63,10 +63,11 @@ function wp_get_connector( string $id ): ?array { * @type array ...$0 { * Data for a single connector. * - * @type string $name The connector's display name. - * @type string $description The connector's description. - * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin Optional. Plugin data for install/activate UI. + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string|null $logo_url Optional. URL to the connector's logo image. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin Optional. Plugin data for install/activate UI. * @type string $slug The WordPress.org plugin slug. * } * @type array $authentication { From b4c814bcb58c446c1867aeb3c03fd1f70e2e8f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 11 Mar 2026 19:00:50 +0100 Subject: [PATCH 4/9] Update src/wp-includes/connectors.php Co-authored-by: Weston Ruter --- src/wp-includes/connectors.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index b3c7a5f5cbc8d..49ad728b0e90d 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -512,7 +512,8 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void { * @access private * * @param array $data Existing script module data. - * @return array Script module data with connectors added. + * @param array $data Existing script module data. + * @return array Script module data with connectors added. */ function _wp_connectors_get_connector_script_module_data( array $data ): array { $connectors = array(); From 5f9f22b2fa16519d448525b5a990966074b91fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 11 Mar 2026 19:01:37 +0100 Subject: [PATCH 5/9] Apply suggestions from code review Co-authored-by: Weston Ruter --- .../class-wp-connector-registry.php | 2 +- src/wp-includes/connectors.php | 33 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 9512e2cfedf8f..3fe9ff9877888 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -214,7 +214,7 @@ public function unregister( string $id ): ?array { * * @type string $name The connector's display name. * @type string $description The connector's description. - * @type string|null $logo_url Optional. URL to the connector's logo image. + * @type string|null $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. * @type array $plugin Optional. Plugin data for install/activate UI. * @type string $slug The WordPress.org plugin slug. diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 49ad728b0e90d..6e8f350318037 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -38,6 +38,20 @@ function wp_is_connector_registered( string $id ): bool { * * @param string $id The connector identifier. * @return array|null The registered connector data, or null if not registered. + * @phpstan-return ?array{ + * name: string, + * description: string, + * logo_url?: string|null, + * type: string, + * authentication: array{ + * method: string, + * credentials_url?: string|null, + * setting_name?: string + * }, + * plugin?: array{ + * slug: string + * } + * } */ function wp_get_connector( string $id ): ?array { $registry = WP_Connector_Registry::get_instance(); @@ -55,8 +69,6 @@ function wp_get_connector( string $id ): ?array { * * @see WP_Connector_Registry::get_all_registered() * - * @phpstan-import-type Connector from WP_Connector_Registry - * * @return array { * Connector settings keyed by connector ID. * @@ -65,7 +77,7 @@ function wp_get_connector( string $id ): ?array { * * @type string $name The connector's display name. * @type string $description The connector's description. - * @type string|null $logo_url Optional. URL to the connector's logo image. + * @type string|null $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. * @type array $plugin Optional. Plugin data for install/activate UI. * @type string $slug The WordPress.org plugin slug. @@ -80,7 +92,20 @@ function wp_get_connector( string $id ): ?array { * } * } * } - * @phpstan-return array + * @phpstan-return array */ function wp_get_connectors(): array { $registry = WP_Connector_Registry::get_instance(); From b7d6b2a56ddad3377d7a9860bf6f19d7ff254b08 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Mar 2026 19:04:40 +0100 Subject: [PATCH 6/9] Connectors: Address review feedback on PHPDoc and test improvements. Removes the duplicate untyped `@param array` tag from `_wp_connectors_get_connector_script_module_data()` left over after applying the `@param array` suggestion. In `wpGetConnectors.php`, adds `void` return types to all test methods for PHPStan level 8 compliance, and uses `?? null` when accessing optional array keys (`setting_name`, `credentials_url`) so PHPStan does not complain about potentially missing offsets. Props gziolo, westonruter. Fixes #64791. Co-Authored-By: Claude Sonnet 4.6 --- src/wp-includes/connectors.php | 1 - .../tests/connectors/wpGetConnectors.php | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 6e8f350318037..7f89610e2da92 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -536,7 +536,6 @@ function _wp_connectors_pass_default_keys_to_ai_client(): void { * @since 7.0.0 * @access private * - * @param array $data Existing script module data. * @param array $data Existing script module data. * @return array Script module data with connectors added. */ diff --git a/tests/phpunit/tests/connectors/wpGetConnectors.php b/tests/phpunit/tests/connectors/wpGetConnectors.php index 8faa2791a26f6..81a7d2cc635a6 100644 --- a/tests/phpunit/tests/connectors/wpGetConnectors.php +++ b/tests/phpunit/tests/connectors/wpGetConnectors.php @@ -15,7 +15,7 @@ class Tests_Connectors_WpGetConnectors extends WP_UnitTestCase { /** * Registers the mock provider once before any tests in this class run. */ - public static function set_up_before_class() { + public static function set_up_before_class(): void { parent::set_up_before_class(); self::register_mock_connectors_provider(); } @@ -23,7 +23,7 @@ public static function set_up_before_class() { /** * Unregisters the mock provider setting added by `init`. */ - public static function tear_down_after_class() { + public static function tear_down_after_class(): void { self::unregister_mock_connector_setting(); parent::tear_down_after_class(); } @@ -31,7 +31,7 @@ public static function tear_down_after_class() { /** * @ticket 64730 */ - public function test_returns_expected_connector_keys() { + public function test_returns_expected_connector_keys(): void { $connectors = wp_get_connectors(); $this->assertArrayHasKey( 'google', $connectors ); @@ -44,7 +44,7 @@ public function test_returns_expected_connector_keys() { /** * @ticket 64730 */ - public function test_each_connector_has_required_fields() { + public function test_each_connector_has_required_fields(): void { $connectors = wp_get_connectors(); $this->assertNotEmpty( $connectors, 'Connector settings should not be empty.' ); @@ -67,7 +67,7 @@ public function test_each_connector_has_required_fields() { /** * @ticket 64730 */ - public function test_api_key_connectors_have_setting_name_and_credentials_url() { + public function test_api_key_connectors_have_setting_name_and_credentials_url(): void { $connectors = wp_get_connectors(); $api_key_count = 0; @@ -81,7 +81,7 @@ public function test_api_key_connectors_have_setting_name_and_credentials_url() $this->assertArrayHasKey( 'setting_name', $connector_data['authentication'], "Connector '{$connector_id}' authentication is missing 'setting_name'." ); $this->assertSame( "connectors_ai_{$connector_id}_api_key", - $connector_data['authentication']['setting_name'], + $connector_data['authentication']['setting_name'] ?? null, "Connector '{$connector_id}' setting_name does not match expected format." ); $this->assertArrayHasKey( 'credentials_url', $connector_data['authentication'], "Connector '{$connector_id}' authentication is missing 'credentials_url'." ); @@ -93,7 +93,7 @@ public function test_api_key_connectors_have_setting_name_and_credentials_url() /** * @ticket 64730 */ - public function test_featured_provider_names_match_expected() { + public function test_featured_provider_names_match_expected(): void { $connectors = wp_get_connectors(); $this->assertSame( 'Google', $connectors['google']['name'] ); @@ -104,7 +104,7 @@ public function test_featured_provider_names_match_expected() { /** * @ticket 64730 */ - public function test_includes_registered_provider_from_registry() { + public function test_includes_registered_provider_from_registry(): void { $connectors = wp_get_connectors(); $mock = $connectors['mock_connectors_test']; @@ -112,7 +112,7 @@ public function test_includes_registered_provider_from_registry() { $this->assertSame( '', $mock['description'] ); $this->assertSame( 'ai_provider', $mock['type'] ); $this->assertSame( 'api_key', $mock['authentication']['method'] ); - $this->assertNull( $mock['authentication']['credentials_url'] ); - $this->assertSame( 'connectors_ai_mock_connectors_test_api_key', $mock['authentication']['setting_name'] ); + $this->assertNull( $mock['authentication']['credentials_url'] ?? null ); + $this->assertSame( 'connectors_ai_mock_connectors_test_api_key', $mock['authentication']['setting_name'] ?? null ); } } From 223064ef8a59be75fccbd9f7fcf9f65df62a0c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Wed, 11 Mar 2026 21:22:15 +0100 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: Weston Ruter --- .../class-wp-connector-registry.php | 4 +++- src/wp-includes/connectors.php | 22 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 3fe9ff9877888..e5ebba73556ba 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -216,7 +216,9 @@ public function unregister( string $id ): ?array { * @type string $description The connector's description. * @type string|null $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin Optional. Plugin data for install/activate UI. + * @type array $plugin { + * Optional. Plugin data for install/activate UI. + * * @type string $slug The WordPress.org plugin slug. * } * @type array $authentication { diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 7f89610e2da92..321b90c785ed9 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -39,17 +39,17 @@ function wp_is_connector_registered( string $id ): bool { * @param string $id The connector identifier. * @return array|null The registered connector data, or null if not registered. * @phpstan-return ?array{ - * name: string, - * description: string, - * logo_url?: string|null, - * type: string, + * name: non-empty-string, + * description: non-empty-string, + * logo_url?: non-empty-string|null, + * type: 'ai_provider', * authentication: array{ - * method: string, - * credentials_url?: string|null, - * setting_name?: string + * method: 'api_key'|'none', + * credentials_url?: non-empty-string|null, + * setting_name?: non-empty-string * }, * plugin?: array{ - * slug: string + * slug: non-empty-string * } * } */ @@ -79,8 +79,10 @@ function wp_get_connector( string $id ): ?array { * @type string $description The connector's description. * @type string|null $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin Optional. Plugin data for install/activate UI. - * @type string $slug The WordPress.org plugin slug. + * @type array $plugin { + * Optional. Plugin data for install/activate UI. + * + * @type string $slug The WordPress.org plugin slug. * } * @type array $authentication { * Authentication configuration. When method is 'api_key', includes From b20bf879cb6440cc77524766ea31f728e65a55d6 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Wed, 11 Mar 2026 21:47:42 +0100 Subject: [PATCH 8/9] Connectors: Improve PHPDoc and PHPStan types for connector data shape. - Expand @return shape for wp_get_connector() to match wp_get_connectors() - Use non-empty-string and literal types in @phpstan-return annotations - Remove |null from optional fields (logo_url, credentials_url); store them only when non-empty, consistent with the existing logo_url pattern - Fix PHPDoc alignment across modified blocks - Update test to reflect credentials_url being truly optional Co-Authored-By: Claude Sonnet 4.6 --- .../class-wp-connector-registry.php | 32 ++++++------ src/wp-includes/connectors.php | 52 +++++++++++++------ .../tests/connectors/wpGetConnectors.php | 1 - 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index e5ebba73556ba..58815ec10a85c 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -18,11 +18,11 @@ * @phpstan-type Connector array{ * name: string, * description: string, - * logo_url?: string|null, + * logo_url?: string, * type: string, * authentication: array{ * method: string, - * credentials_url?: string|null, + * credentials_url?: string, * setting_name?: string * }, * plugin?: array{ @@ -62,13 +62,13 @@ final class WP_Connector_Registry { * * @type string $name Required. The connector's display name. * @type string $description Optional. The connector's description. Default empty string. - * @type string|null $logo_url Optional. URL to the connector's logo image. Default null. + * @type string $logo_url Optional. URL to the connector's logo image. * @type string $type Required. The connector type. Currently, only 'ai_provider' is supported. * @type array $authentication { * Required. Authentication configuration. * - * @type string $method Required. The authentication method: 'api_key' or 'none'. - * @type string|null $credentials_url Optional. URL where users can obtain API credentials. + * @type string $method Required. The authentication method: 'api_key' or 'none'. + * @type string $credentials_url Optional. URL where users can obtain API credentials. * } * @type array $plugin { * Optional. Plugin data for install/activate UI. @@ -158,8 +158,10 @@ public function register( string $id, array $args ): ?array { } if ( 'api_key' === $args['authentication']['method'] ) { - $connector['authentication']['credentials_url'] = $args['authentication']['credentials_url'] ?? null; - $connector['authentication']['setting_name'] = "connectors_ai_{$id}_api_key"; + if ( ! empty( $args['authentication']['credentials_url'] ) && is_string( $args['authentication']['credentials_url'] ) ) { + $connector['authentication']['credentials_url'] = $args['authentication']['credentials_url']; + } + $connector['authentication']['setting_name'] = "connectors_ai_{$id}_api_key"; } if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) ) { @@ -212,11 +214,11 @@ public function unregister( string $id ): ?array { * @type array ...$0 { * Data for a single connector. * - * @type string $name The connector's display name. - * @type string $description The connector's description. - * @type string|null $logo_url Optional. URL to the connector's logo image. - * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin { + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string $logo_url Optional. URL to the connector's logo image. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin { * Optional. Plugin data for install/activate UI. * * @type string $slug The WordPress.org plugin slug. @@ -225,9 +227,9 @@ public function unregister( string $id ): ?array { * Authentication configuration. When method is 'api_key', includes * credentials_url and setting_name. When 'none', only method is present. * - * @type string $method The authentication method: 'api_key' or 'none'. - * @type string|null $credentials_url Optional. URL where users can obtain API credentials. - * @type string $setting_name Optional. The setting name for the API key. + * @type string $method The authentication method: 'api_key' or 'none'. + * @type string $credentials_url Optional. URL where users can obtain API credentials. + * @type string $setting_name Optional. The setting name for the API key. * } * } * } diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index 321b90c785ed9..de3c68d9428ef 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -37,15 +37,35 @@ function wp_is_connector_registered( string $id ): bool { * @see WP_Connector_Registry::get_registered() * * @param string $id The connector identifier. - * @return array|null The registered connector data, or null if not registered. + * @return array|null { + * Connector data, or null if not registered. + * + * @type string $name The connector's display name. + * @type string $description The connector's description. + * @type string $logo_url Optional. URL to the connector's logo image. + * @type string $type The connector type. Currently, only 'ai_provider' is supported. + * @type array $plugin { + * Optional. Plugin data for install/activate UI. + * + * @type string $slug The WordPress.org plugin slug. + * } + * @type array $authentication { + * Authentication configuration. When method is 'api_key', includes + * credentials_url and setting_name. When 'none', only method is present. + * + * @type string $method The authentication method: 'api_key' or 'none'. + * @type string $credentials_url Optional. URL where users can obtain API credentials. + * @type string $setting_name Optional. The setting name for the API key. + * } + * } * @phpstan-return ?array{ * name: non-empty-string, * description: non-empty-string, - * logo_url?: non-empty-string|null, + * logo_url?: non-empty-string, * type: 'ai_provider', * authentication: array{ * method: 'api_key'|'none', - * credentials_url?: non-empty-string|null, + * credentials_url?: non-empty-string, * setting_name?: non-empty-string * }, * plugin?: array{ @@ -77,35 +97,35 @@ function wp_get_connector( string $id ): ?array { * * @type string $name The connector's display name. * @type string $description The connector's description. - * @type string|null $logo_url Optional. URL to the connector's logo image. + * @type string $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. * @type array $plugin { * Optional. Plugin data for install/activate UI. * * @type string $slug The WordPress.org plugin slug. * } - * @type array $authentication { + * @type array $authentication { * Authentication configuration. When method is 'api_key', includes * credentials_url and setting_name. When 'none', only method is present. * - * @type string $method The authentication method: 'api_key' or 'none'. - * @type string|null $credentials_url Optional. URL where users can obtain API credentials. - * @type string $setting_name Optional. The setting name for the API key. + * @type string $method The authentication method: 'api_key' or 'none'. + * @type string $credentials_url Optional. URL where users can obtain API credentials. + * @type string $setting_name Optional. The setting name for the API key. * } * } * } * @phpstan-return array */ diff --git a/tests/phpunit/tests/connectors/wpGetConnectors.php b/tests/phpunit/tests/connectors/wpGetConnectors.php index 81a7d2cc635a6..8cb7a5c5d2d90 100644 --- a/tests/phpunit/tests/connectors/wpGetConnectors.php +++ b/tests/phpunit/tests/connectors/wpGetConnectors.php @@ -84,7 +84,6 @@ public function test_api_key_connectors_have_setting_name_and_credentials_url(): $connector_data['authentication']['setting_name'] ?? null, "Connector '{$connector_id}' setting_name does not match expected format." ); - $this->assertArrayHasKey( 'credentials_url', $connector_data['authentication'], "Connector '{$connector_id}' authentication is missing 'credentials_url'." ); } $this->assertGreaterThan( 0, $api_key_count, 'At least one connector should use api_key authentication.' ); From f22aae659b955a442094dff09485a6a89e6cef23 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 12 Mar 2026 07:00:29 +0100 Subject: [PATCH 9/9] Connectors: Refine PHPDoc consistency across connector shape documentation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Simplify get_all_registered() @return to a one-liner, keeping @phpstan-return for static analysis — avoids maintaining a duplicate expanded shape on an internal method marked "do not use directly" - Order $authentication before $plugin consistently across all PHPDoc blocks, matching the actual construction order in register() - Fix @return array|null typo on get_all_registered() which never returns null Co-Authored-By: Claude Sonnet 4.6 --- .../class-wp-connector-registry.php | 27 ++----------------- src/wp-includes/connectors.php | 20 +++++++------- 2 files changed, 12 insertions(+), 35 deletions(-) diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php index 58815ec10a85c..a1cd1ab1252ba 100644 --- a/src/wp-includes/class-wp-connector-registry.php +++ b/src/wp-includes/class-wp-connector-registry.php @@ -70,7 +70,7 @@ final class WP_Connector_Registry { * @type string $method Required. The authentication method: 'api_key' or 'none'. * @type string $credentials_url Optional. URL where users can obtain API credentials. * } - * @type array $plugin { + * @type array $plugin { * Optional. Plugin data for install/activate UI. * * @type string $slug The WordPress.org plugin slug. @@ -208,31 +208,8 @@ public function unregister( string $id ): ?array { * * @see wp_get_connectors() * - * @return array { - * Connector settings keyed by connector ID. + * @return array Connector settings keyed by connector ID. * - * @type array ...$0 { - * Data for a single connector. - * - * @type string $name The connector's display name. - * @type string $description The connector's description. - * @type string $logo_url Optional. URL to the connector's logo image. - * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin { - * Optional. Plugin data for install/activate UI. - * - * @type string $slug The WordPress.org plugin slug. - * } - * @type array $authentication { - * Authentication configuration. When method is 'api_key', includes - * credentials_url and setting_name. When 'none', only method is present. - * - * @type string $method The authentication method: 'api_key' or 'none'. - * @type string $credentials_url Optional. URL where users can obtain API credentials. - * @type string $setting_name Optional. The setting name for the API key. - * } - * } - * } * @phpstan-return array */ public function get_all_registered(): array { diff --git a/src/wp-includes/connectors.php b/src/wp-includes/connectors.php index de3c68d9428ef..b8b9004354652 100644 --- a/src/wp-includes/connectors.php +++ b/src/wp-includes/connectors.php @@ -44,11 +44,6 @@ function wp_is_connector_registered( string $id ): bool { * @type string $description The connector's description. * @type string $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin { - * Optional. Plugin data for install/activate UI. - * - * @type string $slug The WordPress.org plugin slug. - * } * @type array $authentication { * Authentication configuration. When method is 'api_key', includes * credentials_url and setting_name. When 'none', only method is present. @@ -57,6 +52,11 @@ function wp_is_connector_registered( string $id ): bool { * @type string $credentials_url Optional. URL where users can obtain API credentials. * @type string $setting_name Optional. The setting name for the API key. * } + * @type array $plugin { + * Optional. Plugin data for install/activate UI. + * + * @type string $slug The WordPress.org plugin slug. + * } * } * @phpstan-return ?array{ * name: non-empty-string, @@ -99,11 +99,6 @@ function wp_get_connector( string $id ): ?array { * @type string $description The connector's description. * @type string $logo_url Optional. URL to the connector's logo image. * @type string $type The connector type. Currently, only 'ai_provider' is supported. - * @type array $plugin { - * Optional. Plugin data for install/activate UI. - * - * @type string $slug The WordPress.org plugin slug. - * } * @type array $authentication { * Authentication configuration. When method is 'api_key', includes * credentials_url and setting_name. When 'none', only method is present. @@ -112,6 +107,11 @@ function wp_get_connector( string $id ): ?array { * @type string $credentials_url Optional. URL where users can obtain API credentials. * @type string $setting_name Optional. The setting name for the API key. * } + * @type array $plugin { + * Optional. Plugin data for install/activate UI. + * + * @type string $slug The WordPress.org plugin slug. + * } * } * } * @phpstan-return array