Changeset 62194 for branches/7.0/src/wp-includes/connectors.php
- Timestamp:
- 04/01/2026 04:37:48 PM (4 months ago)
- Location:
- branches/7.0
- Files:
-
- 2 edited
-
. (modified) (1 prop)
-
src/wp-includes/connectors.php (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/7.0
-
branches/7.0/src/wp-includes/connectors.php
r62067 r62194 44 44 * @type string $description The connector's description. 45 45 * @type string $logo_url Optional. URL to the connector's logo image. 46 * @type string $type The connector type . Currently, only 'ai_provider' is supported.46 * @type string $type The connector type, e.g. 'ai_provider'. 47 47 * @type array $authentication { 48 48 * Authentication configuration. When method is 'api_key', includes 49 * credentials_url and setting_name. When 'none', only method is present. 49 * credentials_url, setting_name, and optionally constant_name and 50 * env_var_name. When 'none', only method is present. 50 51 * 51 52 * @type string $method The authentication method: 'api_key' or 'none'. 52 53 * @type string $credentials_url Optional. URL where users can obtain API credentials. 53 54 * @type string $setting_name Optional. The setting name for the API key. 55 * @type string $constant_name Optional. PHP constant name for the API key. 56 * @type string $env_var_name Optional. Environment variable name for the API key. 54 57 * } 55 58 * @type array $plugin { … … 63 66 * description: non-empty-string, 64 67 * logo_url?: non-empty-string, 65 * type: 'ai_provider',68 * type: non-empty-string, 66 69 * authentication: array{ 67 70 * method: 'api_key'|'none', 68 71 * credentials_url?: non-empty-string, 69 * setting_name?: non-empty-string 72 * setting_name?: non-empty-string, 73 * constant_name?: non-empty-string, 74 * env_var_name?: non-empty-string 70 75 * }, 71 76 * plugin?: array{ … … 99 104 * @type string $description The connector's description. 100 105 * @type string $logo_url Optional. URL to the connector's logo image. 101 * @type string $type The connector type . Currently, only 'ai_provider' is supported.106 * @type string $type The connector type, e.g. 'ai_provider'. 102 107 * @type array $authentication { 103 108 * Authentication configuration. When method is 'api_key', includes 104 * credentials_url and setting_name. When 'none', only method is present. 109 * credentials_url, setting_name, and optionally constant_name and 110 * env_var_name. When 'none', only method is present. 105 111 * 106 112 * @type string $method The authentication method: 'api_key' or 'none'. 107 113 * @type string $credentials_url Optional. URL where users can obtain API credentials. 108 114 * @type string $setting_name Optional. The setting name for the API key. 115 * @type string $constant_name Optional. PHP constant name for the API key. 116 * @type string $env_var_name Optional. Environment variable name for the API key. 109 117 * } 110 118 * @type array $plugin { … … 119 127 * description: non-empty-string, 120 128 * logo_url?: non-empty-string, 121 * type: 'ai_provider',129 * type: non-empty-string, 122 130 * authentication: array{ 123 131 * method: 'api_key'|'none', 124 132 * credentials_url?: non-empty-string, 125 * setting_name?: non-empty-string 133 * setting_name?: non-empty-string, 134 * constant_name?: non-empty-string, 135 * env_var_name?: non-empty-string 126 136 * }, 127 137 * plugin?: array{ … … 217 227 * 218 228 * add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) { 219 * if ( $registry->is_registered( ' openai' ) ) {220 * $connector = $registry->unregister( ' openai' );221 * $connector['description'] = __( 'Custom description for OpenAI.', 'my-plugin' );222 * $registry->register( ' openai', $connector );229 * if ( $registry->is_registered( 'anthropic' ) ) { 230 * $connector = $registry->unregister( 'anthropic' ); 231 * $connector['description'] = __( 'Custom description for Anthropic.', 'my-plugin' ); 232 * $registry->register( 'anthropic', $connector ); 223 233 * } 224 234 * } ); … … 336 346 // Register all default connectors directly on the registry. 337 347 foreach ( $defaults as $id => $args ) { 348 if ( 'api_key' === $args['authentication']['method'] ) { 349 $sanitized_id = str_replace( '-', '_', $id ); 350 351 if ( ! isset( $args['authentication']['setting_name'] ) ) { 352 $args['authentication']['setting_name'] = "connectors_ai_{$sanitized_id}_api_key"; 353 } 354 355 // All AI providers use the {CONSTANT_CASE_ID}_API_KEY naming convention. 356 if ( ! isset( $args['authentication']['constant_name'] ) || ! isset( $args['authentication']['env_var_name'] ) ) { 357 $constant_case_key = strtoupper( preg_replace( '/([a-z])([A-Z])/', '$1_$2', $sanitized_id ) ) . '_API_KEY'; 358 359 if ( ! isset( $args['authentication']['constant_name'] ) ) { 360 $args['authentication']['constant_name'] = $constant_case_key; 361 } 362 363 if ( ! isset( $args['authentication']['env_var_name'] ) ) { 364 $args['authentication']['env_var_name'] = $constant_case_key; 365 } 366 } 367 } 338 368 $registry->register( $id, $args ); 339 369 } … … 358 388 359 389 /** 360 * Determines the source of an API key for a given provider.390 * Determines the source of an API key for a given connector. 361 391 * 362 392 * Checks in order: environment variable, PHP constant, database. 363 * Uses the same naming convention as the WP AI Client ProviderRegistry. 364 * 365 * @since 7.0.0 366 * @access private 367 * 368 * @param string $provider_id The provider ID (e.g., 'openai', 'anthropic', 'google'). 369 * @param string $setting_name The option name for the API key (e.g., 'connectors_ai_openai_api_key'). 393 * Environment variable and constant are only checked when their 394 * respective names are provided. 395 * 396 * @since 7.0.0 397 * @access private 398 * 399 * @param string $setting_name The option name for the API key (e.g., 'connectors_spam_filtering_akismet_api_key'). 400 * @param string $env_var_name Optional. Environment variable name to check (e.g., 'AKISMET_API_KEY'). 401 * @param string $constant_name Optional. PHP constant name to check (e.g., 'AKISMET_API_KEY'). 370 402 * @return string The key source: 'env', 'constant', 'database', or 'none'. 371 403 */ 372 function _wp_connectors_get_api_key_source( string $provider_id, string $setting_name ): string { 373 // Convert provider ID to CONSTANT_CASE for env var name. 374 // e.g., 'openai' -> 'OPENAI', 'anthropic' -> 'ANTHROPIC'. 375 $constant_case_id = strtoupper( 376 preg_replace( '/([a-z])([A-Z])/', '$1_$2', str_replace( '-', '_', $provider_id ) ) 377 ); 378 $env_var_name = "{$constant_case_id}_API_KEY"; 379 404 function _wp_connectors_get_api_key_source( string $setting_name, string $env_var_name = '', string $constant_name = '' ): string { 380 405 // Check environment variable first. 381 $env_value = getenv( $env_var_name ); 382 if ( false !== $env_value && '' !== $env_value ) { 383 return 'env'; 406 if ( '' !== $env_var_name ) { 407 $env_value = getenv( $env_var_name ); 408 if ( false !== $env_value && '' !== $env_value ) { 409 return 'env'; 410 } 384 411 } 385 412 386 413 // Check PHP constant. 387 if ( defined( $env_var_name ) ) {388 $const_value = constant( $ env_var_name );414 if ( '' !== $constant_name && defined( $constant_name ) ) { 415 $const_value = constant( $constant_name ); 389 416 if ( is_string( $const_value ) && '' !== $const_value ) { 390 417 return 'constant'; … … 471 498 foreach ( wp_get_connectors() as $connector_id => $connector_data ) { 472 499 $auth = $connector_data['authentication']; 473 if ( 'a i_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) {500 if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { 474 501 continue; 475 502 } … … 482 509 $value = $data[ $setting_name ]; 483 510 484 // On update, validate the key before masking. 485 if ( $is_update && is_string( $value ) && '' !== $value ) { 511 // On update, validate AI provider keys before masking. 512 // Non-AI connectors accept keys as-is; the service plugin handles its own validation. 513 if ( $is_update && is_string( $value ) && '' !== $value && 'ai_provider' === $connector_data['type'] ) { 486 514 if ( true !== _wp_connectors_is_ai_api_key_valid( $value, $connector_id ) ) { 487 515 update_option( $setting_name, '' ); … … 509 537 */ 510 538 function _wp_register_default_connector_settings(): void { 511 $ai_registry = AiClient::defaultRegistry(); 539 $ai_registry = AiClient::defaultRegistry(); 540 $registered_settings = get_registered_settings(); 512 541 513 542 foreach ( wp_get_connectors() as $connector_id => $connector_data ) { 514 543 $auth = $connector_data['authentication']; 515 if ( 'a i_provider' !== $connector_data['type'] || 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) {544 if ( 'api_key' !== $auth['method'] || empty( $auth['setting_name'] ) ) { 516 545 continue; 517 546 } 518 547 519 // Skip registering the setting if the provider is not in the registry. 520 if ( ! $ai_registry->hasProvider( $connector_id ) ) { 548 // Skip if the setting is already registered (e.g. by an owning plugin). 549 if ( isset( $registered_settings[ $auth['setting_name'] ] ) ) { 550 continue; 551 } 552 553 // For AI providers, skip if the provider is not in the AI Client registry. 554 if ( 'ai_provider' === $connector_data['type'] && ! $ai_registry->hasProvider( $connector_id ) ) { 521 555 continue; 522 556 } … … 528 562 'type' => 'string', 529 563 'label' => sprintf( 530 /* translators: %s: AI provider name. */564 /* translators: %s: Connector name. */ 531 565 __( '%s API Key' ), 532 566 $connector_data['name'] 533 567 ), 534 568 'description' => sprintf( 535 /* translators: %s: AI provider name. */536 __( 'API key for the %s AI provider.' ),569 /* translators: %s: Connector name. */ 570 __( 'API key for the %s connector.' ), 537 571 $connector_data['name'] 538 572 ), … … 570 604 571 605 // Skip if the key is already provided via env var or constant. 572 $key_source = _wp_connectors_get_api_key_source( $ connector_id, $auth['setting_name']);606 $key_source = _wp_connectors_get_api_key_source( $auth['setting_name'], $auth['env_var_name'] ?? '', $auth['constant_name'] ?? '' ); 573 607 if ( 'env' === $key_source || 'constant' === $key_source ) { 574 608 continue; … … 621 655 $auth_out['settingName'] = $auth['setting_name'] ?? ''; 622 656 $auth_out['credentialsUrl'] = $auth['credentials_url'] ?? null; 623 $auth_out['keySource'] = _wp_connectors_get_api_key_source( $connector_id, $auth['setting_name'] ?? '' ); 624 try { 625 $auth_out['isConnected'] = $registry->hasProvider( $connector_id ) && $registry->isProviderConfigured( $connector_id ); 626 } catch ( Exception $e ) { 627 $auth_out['isConnected'] = false; 657 $key_source = _wp_connectors_get_api_key_source( $auth['setting_name'] ?? '', $auth['env_var_name'] ?? '', $auth['constant_name'] ?? '' ); 658 $auth_out['keySource'] = $key_source; 659 660 if ( 'ai_provider' === $connector_data['type'] ) { 661 try { 662 $auth_out['isConnected'] = $registry->hasProvider( $connector_id ) && $registry->isProviderConfigured( $connector_id ); 663 } catch ( Exception $e ) { 664 $auth_out['isConnected'] = false; 665 } 666 } else { 667 $auth_out['isConnected'] = 'none' !== $key_source; 628 668 } 629 669 } … … 646 686 $connector_out['plugin'] = array( 647 687 'slug' => $plugin_slug, 648 'isInstalled' => $is_installed, 688 'pluginFile' => $is_installed 689 ? ( str_ends_with( $plugin_file, '.php' ) ? substr( $plugin_file, 0, -4 ) : $plugin_file ) 690 : null, 649 691 'isActivated' => $is_activated, 650 692 );
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)