Make WordPress Core


Ignore:
Timestamp:
03/30/2026 02:25:32 PM (7 months ago)
Author:
jorgefilipecosta
Message:

Connectors: Fix and generalize the API for custom connector types.

Validate setting_name, constant_name, and env_var_name in connector
registration — reject invalid values with _doing_it_wrong() instead of
silently falling back.
Change the auto-generated setting_name pattern from
connectors_ai_{$id}_api_key to connectors_{$type}_{$id}_api_key so it
works for any connector type. Built-in AI providers infer their names using
the existing connectors_ai_{$id}_api_key convention, preserving backward
compatibility.
Add constant_name and env_var_name as optional authentication fields,
allowing connectors to declare explicit PHP constant and environment
variable names for API key lookup. AI providers auto-generate these using
the {CONSTANT_CASE_ID}_API_KEY convention.
Refactor _wp_connectors_get_api_key_source() to accept explicit
env_var_name and constant_name parameters instead of deriving them from
the provider ID. Environment variable and constant checks are skipped when
not provided.
Generalize REST dispatch, settings registration, and script module data to
work with all connector types, not just ai_provider. Settings
registration skips already-registered settings. Non-AI connectors determine
isConnected based on key source.
Replace isInstalled with pluginFile in script module data output to fix
plugin entity ID resolution on the frontend.
Update PHPDoc to reflect current behavior — widen type from literal
'ai_provider' to non-empty-string, document new authentication fields,
and use Anthropic examples throughout.

Props gziolo, jorgefilipecosta.
Fixes #64957.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/connectors/wpConnectorRegistry.php

    r62067 r62180  
    3333
    3434                self::$default_args = array(
    35                         'name'           => 'Test Provider',
    36                         'description'    => 'A test AI provider.',
    37                         'type'           => 'ai_provider',
     35                        'name'           => 'Test Connector',
     36                        'description'    => 'A test connector.',
     37                        'type'           => 'test_type',
    3838                        'authentication' => array(
    3939                                'method'          => 'api_key',
    … …  
    5050
    5151                $this->assertIsArray( $result );
    52                 $this->assertSame( 'Test Provider', $result['name'] );
    53                 $this->assertSame( 'A test AI provider.', $result['description'] );
    54                 $this->assertSame( 'ai_provider', $result['type'] );
     52                $this->assertSame( 'Test Connector', $result['name'] );
     53                $this->assertSame( 'A test connector.', $result['description'] );
     54                $this->assertSame( 'test_type', $result['type'] );
    5555                $this->assertSame( 'api_key', $result['authentication']['method'] );
    5656                $this->assertSame( 'https://example.com/keys', $result['authentication']['credentials_url'] );
    57                 $this->assertSame( 'connectors_ai_test_provider_api_key', $result['authentication']['setting_name'] );
     57                $this->assertSame( 'connectors_test_type_test_provider_api_key', $result['authentication']['setting_name'] );
    5858        }
    5959
    … …  
    6464                $result = $this->registry->register( 'myai', self::$default_args );
    6565
    66                 $this->assertSame( 'connectors_ai_myai_api_key', $result['authentication']['setting_name'] );
     66                $this->assertSame( 'connectors_test_type_myai_api_key', $result['authentication']['setting_name'] );
    6767        }
    6868
    … …  
    7373                $result = $this->registry->register( 'my-ai', self::$default_args );
    7474
    75                 $this->assertSame( 'connectors_ai_my_ai_api_key', $result['authentication']['setting_name'] );
     75                $this->assertSame( 'connectors_test_type_my_ai_api_key', $result['authentication']['setting_name'] );
     76        }
     77
     78        /**
     79         * @ticket 64957
     80         */
     81        public function test_register_generates_setting_name_using_type_and_id() {
     82                $args         = self::$default_args;
     83                $args['type'] = 'email_delivery';
     84
     85                $result = $this->registry->register( 'sendgrid', $args );
     86
     87                $this->assertSame( 'connectors_email_delivery_sendgrid_api_key', $result['authentication']['setting_name'] );
     88        }
     89
     90        /**
     91         * @ticket 64957
     92         */
     93        public function test_register_uses_custom_setting_name_when_provided() {
     94                $args                                   = self::$default_args;
     95                $args['authentication']['setting_name'] = 'wordpress_api_key';
     96
     97                $result = $this->registry->register( 'custom-setting', $args );
     98
     99                $this->assertSame( 'wordpress_api_key', $result['authentication']['setting_name'] );
     100        }
     101
     102        /**
     103         * @ticket 64957
     104         */
     105        public function test_register_rejects_empty_setting_name() {
     106                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     107
     108                $args                                   = self::$default_args;
     109                $args['authentication']['setting_name'] = '';
     110
     111                $result = $this->registry->register( 'empty-setting', $args );
     112
     113                $this->assertNull( $result );
     114        }
     115
     116        /**
     117         * @ticket 64957
     118         */
     119        public function test_register_rejects_non_string_setting_name() {
     120                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     121
     122                $args                                   = self::$default_args;
     123                $args['authentication']['setting_name'] = 123;
     124
     125                $result = $this->registry->register( 'non-string-setting', $args );
     126
     127                $this->assertNull( $result );
     128        }
     129
     130        /**
     131         * @ticket 64957
     132         */
     133        public function test_register_stores_constant_name_when_provided() {
     134                $args                                    = self::$default_args;
     135                $args['authentication']['constant_name'] = 'MY_PROVIDER_API_KEY';
     136
     137                $result = $this->registry->register( 'my-provider', $args );
     138
     139                $this->assertSame( 'MY_PROVIDER_API_KEY', $result['authentication']['constant_name'] );
     140        }
     141
     142        /**
     143         * @ticket 64957
     144         */
     145        public function test_register_omits_constant_name_when_not_provided() {
     146                $result = $this->registry->register( 'no-const', self::$default_args );
     147
     148                $this->assertArrayNotHasKey( 'constant_name', $result['authentication'] );
     149        }
     150
     151        /**
     152         * @ticket 64957
     153         */
     154        public function test_register_rejects_empty_constant_name() {
     155                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     156
     157                $args                                    = self::$default_args;
     158                $args['authentication']['constant_name'] = '';
     159
     160                $result = $this->registry->register( 'empty-const', $args );
     161
     162                $this->assertNull( $result );
     163        }
     164
     165        /**
     166         * @ticket 64957
     167         */
     168        public function test_register_rejects_non_string_constant_name() {
     169                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     170
     171                $args                                    = self::$default_args;
     172                $args['authentication']['constant_name'] = 123;
     173
     174                $result = $this->registry->register( 'bad-const', $args );
     175
     176                $this->assertNull( $result );
     177        }
     178
     179        /**
     180         * @ticket 64957
     181         */
     182        public function test_register_stores_env_var_name_when_provided() {
     183                $args                                   = self::$default_args;
     184                $args['authentication']['env_var_name'] = 'MY_PROVIDER_API_KEY';
     185
     186                $result = $this->registry->register( 'my-provider', $args );
     187
     188                $this->assertSame( 'MY_PROVIDER_API_KEY', $result['authentication']['env_var_name'] );
     189        }
     190
     191        /**
     192         * @ticket 64957
     193         */
     194        public function test_register_omits_env_var_name_when_not_provided() {
     195                $result = $this->registry->register( 'no-env', self::$default_args );
     196
     197                $this->assertArrayNotHasKey( 'env_var_name', $result['authentication'] );
     198        }
     199
     200        /**
     201         * @ticket 64957
     202         */
     203        public function test_register_rejects_empty_env_var_name() {
     204                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     205
     206                $args                                   = self::$default_args;
     207                $args['authentication']['env_var_name'] = '';
     208
     209                $result = $this->registry->register( 'empty-env', $args );
     210
     211                $this->assertNull( $result );
     212        }
     213
     214        /**
     215         * @ticket 64957
     216         */
     217        public function test_register_rejects_non_string_env_var_name() {
     218                $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     219
     220                $args                                   = self::$default_args;
     221                $args['authentication']['env_var_name'] = 123;
     222
     223                $result = $this->registry->register( 'bad-env', $args );
     224
     225                $this->assertNull( $result );
    76226        }
    77227
    … …  
    81231        public function test_register_no_setting_name_for_none_auth() {
    82232                $args   = array(
    83                         'name'           => 'No Auth Provider',
    84                         'type'           => 'ai_provider',
     233                        'name'           => 'No Auth Connector',
     234                        'type'           => 'test_type',
    85235                        'authentication' => array( 'method' => 'none' ),
    86236                );
    … …  
    97247                $args = array(
    98248                        'name'           => 'Minimal',
    99                         'type'           => 'ai_provider',
     249                        'type'           => 'test_type',
    100250                        'authentication' => array( 'method' => 'none' ),
    101251                );
    … …  
    309459
    310460                $this->assertIsArray( $result );
    311                 $this->assertSame( 'Test Provider', $result['name'] );
     461                $this->assertSame( 'Test Connector', $result['name'] );
    312462        }
    313463
    … …  
    356506
    357507                $this->assertIsArray( $result );
    358                 $this->assertSame( 'Test Provider', $result['name'] );
     508                $this->assertSame( 'Test Connector', $result['name'] );
    359509                $this->assertFalse( $this->registry->is_registered( 'to-remove' ) );
    360510        }
    … …  
    405555                add_filter( 'wp_supports_ai', '__return_false' );
    406556
    407                 $this->registry->register( 'first', self::$default_args );
     557                $args         = self::$default_args;
     558                $args['type'] = 'ai_provider';
     559                $this->registry->register( 'first', $args );
    408560
    409561                $all = $this->registry->get_all_registered();
Note: See TracChangeset for help on using the changeset viewer.