Skip to content

Commit 555bb8a

Browse files
gzioloclaude
andcommitted
Connectors: Add wp_connectors_settings filter for extensibility.
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>
1 parent 5f0ac6f commit 555bb8a

File tree

2 files changed

+175
-2
lines changed

2 files changed

+175
-2
lines changed

src/wp-includes/connectors.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,26 @@ function _wp_connectors_get_connector_settings(): array {
202202

203203
ksort( $connectors );
204204

205-
// Add setting_name for connectors that use API key authentication.
205+
/**
206+
* Filters the registered connector settings.
207+
*
208+
* Allows plugins to add, modify, or remove connectors displayed
209+
* on the Connectors screen. Runs after built-in and AI Client
210+
* registry providers are collected, but before `setting_name` is
211+
* generated for API-key connectors.
212+
*
213+
* @since 7.0.0
214+
*
215+
* @param array $connectors Connector settings keyed by connector ID.
216+
* Each entry is an array with keys: name, description,
217+
* type, authentication (with method, and optionally
218+
* credentials_url), and optionally plugin.
219+
*/
220+
$connectors = apply_filters( 'wp_connectors_settings', $connectors );
221+
222+
// Add setting_name for AI provider connectors that use API key authentication.
206223
foreach ( $connectors as $connector_id => $connector ) {
207-
if ( 'api_key' === $connector['authentication']['method'] ) {
224+
if ( 'ai_provider' === $connector['type'] && 'api_key' === $connector['authentication']['method'] ) {
208225
$connectors[ $connector_id ]['authentication']['setting_name'] = "connectors_ai_{$connector_id}_api_key";
209226
}
210227
}

tests/phpunit/tests/connectors/wpConnectorsGetConnectorSettings.php

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,160 @@ public function test_includes_registered_provider_from_registry() {
115115
$this->assertNull( $mock['authentication']['credentials_url'] );
116116
$this->assertSame( 'connectors_ai_mock_connectors_test_api_key', $mock['authentication']['setting_name'] );
117117
}
118+
119+
/**
120+
* @ticket 64730
121+
*/
122+
public function test_filter_can_add_new_connector() {
123+
add_filter(
124+
'wp_connectors_settings',
125+
static function ( $connectors ) {
126+
$connectors['my_email_service'] = array(
127+
'name' => 'My Email Service',
128+
'description' => 'Send transactional emails.',
129+
'type' => 'email_service',
130+
'authentication' => array( 'method' => 'none' ),
131+
);
132+
return $connectors;
133+
}
134+
);
135+
136+
$connectors = _wp_connectors_get_connector_settings();
137+
138+
$this->assertArrayHasKey( 'my_email_service', $connectors );
139+
$this->assertSame( 'My Email Service', $connectors['my_email_service']['name'] );
140+
$this->assertSame( 'email_service', $connectors['my_email_service']['type'] );
141+
$this->assertSame( 'none', $connectors['my_email_service']['authentication']['method'] );
142+
143+
remove_all_filters( 'wp_connectors_settings' );
144+
}
145+
146+
/**
147+
* @ticket 64730
148+
*/
149+
public function test_filter_can_modify_existing_connector() {
150+
add_filter(
151+
'wp_connectors_settings',
152+
static function ( $connectors ) {
153+
$connectors['google']['description'] = 'Custom description for Google.';
154+
return $connectors;
155+
}
156+
);
157+
158+
$connectors = _wp_connectors_get_connector_settings();
159+
160+
$this->assertSame( 'Custom description for Google.', $connectors['google']['description'] );
161+
162+
remove_all_filters( 'wp_connectors_settings' );
163+
}
164+
165+
/**
166+
* @ticket 64730
167+
*/
168+
public function test_filter_can_remove_connector() {
169+
add_filter(
170+
'wp_connectors_settings',
171+
static function ( $connectors ) {
172+
unset( $connectors['openai'] );
173+
return $connectors;
174+
}
175+
);
176+
177+
$connectors = _wp_connectors_get_connector_settings();
178+
179+
$this->assertArrayNotHasKey( 'openai', $connectors );
180+
// Other connectors remain.
181+
$this->assertArrayHasKey( 'google', $connectors );
182+
$this->assertArrayHasKey( 'anthropic', $connectors );
183+
184+
remove_all_filters( 'wp_connectors_settings' );
185+
}
186+
187+
/**
188+
* @ticket 64730
189+
*/
190+
public function test_filter_added_api_key_connector_gets_setting_name() {
191+
add_filter(
192+
'wp_connectors_settings',
193+
static function ( $connectors ) {
194+
$connectors['custom_ai'] = array(
195+
'name' => 'Custom AI',
196+
'description' => 'A custom AI provider.',
197+
'type' => 'ai_provider',
198+
'authentication' => array(
199+
'method' => 'api_key',
200+
'credentials_url' => 'https://example.com/keys',
201+
),
202+
);
203+
return $connectors;
204+
}
205+
);
206+
207+
$connectors = _wp_connectors_get_connector_settings();
208+
209+
$this->assertArrayHasKey( 'custom_ai', $connectors );
210+
$this->assertSame(
211+
'connectors_ai_custom_ai_api_key',
212+
$connectors['custom_ai']['authentication']['setting_name'],
213+
'Connectors added via the filter with api_key auth should receive a setting_name automatically.'
214+
);
215+
216+
remove_all_filters( 'wp_connectors_settings' );
217+
}
218+
219+
/**
220+
* @ticket 64730
221+
*/
222+
public function test_filter_added_non_ai_api_key_connector_does_not_get_setting_name() {
223+
add_filter(
224+
'wp_connectors_settings',
225+
static function ( $connectors ) {
226+
$connectors['my_crm'] = array(
227+
'name' => 'My CRM',
228+
'description' => 'CRM integration.',
229+
'type' => 'crm',
230+
'authentication' => array(
231+
'method' => 'api_key',
232+
'credentials_url' => 'https://example.com/crm-keys',
233+
),
234+
);
235+
return $connectors;
236+
}
237+
);
238+
239+
$connectors = _wp_connectors_get_connector_settings();
240+
241+
$this->assertArrayHasKey( 'my_crm', $connectors );
242+
$this->assertArrayNotHasKey(
243+
'setting_name',
244+
$connectors['my_crm']['authentication'],
245+
'Non-AI connectors should not receive an auto-generated setting_name.'
246+
);
247+
248+
remove_all_filters( 'wp_connectors_settings' );
249+
}
250+
251+
/**
252+
* @ticket 64730
253+
*/
254+
public function test_filter_receives_all_default_connectors() {
255+
$received = null;
256+
257+
add_filter(
258+
'wp_connectors_settings',
259+
static function ( $connectors ) use ( &$received ) {
260+
$received = $connectors;
261+
return $connectors;
262+
}
263+
);
264+
265+
_wp_connectors_get_connector_settings();
266+
267+
$this->assertArrayHasKey( 'google', $received );
268+
$this->assertArrayHasKey( 'openai', $received );
269+
$this->assertArrayHasKey( 'anthropic', $received );
270+
$this->assertArrayHasKey( 'mock_connectors_test', $received );
271+
272+
remove_all_filters( 'wp_connectors_settings' );
273+
}
118274
}

0 commit comments

Comments
 (0)