@@ -82,50 +82,114 @@ function _gutenberg_get_real_api_key( string $option_name, callable $mask_callba
8282 *
8383 * @access private
8484 *
85- * @return array<string, array{provider: string, label: string, description: string, mask: callable, sanitize: callable}> Provider settings keyed by setting name.
85+ * @return array {
86+ * Provider settings keyed by provider ID.
87+ *
88+ * @type array ...$0 {
89+ * Data for a single provider.
90+ *
91+ * @type string $name The provider's display name.
92+ * @type string $description The provider's description.
93+ * @type string|null $credentials_url URL where users can obtain API credentials.
94+ * @type array $settings {
95+ * Settings keyed by setting name.
96+ *
97+ * @type array ...$0 {
98+ * Data for a single setting.
99+ *
100+ * @type string $label The setting label.
101+ * @type string $description The setting description.
102+ * @type callable $sanitize Callback to sanitize the input value.
103+ * }
104+ * }
105+ * }
106+ * }
86107 */
87108function _gutenberg_get_provider_settings (): array {
88109 $ providers = array (
89110 'google ' => array (
90- 'name ' => 'Google ' ,
111+ 'name ' => 'Gemini ' ,
112+ 'description ' => __ ( 'Content generation, translation, and vision with Google \'s Gemini. ' , 'gutenberg ' ),
113+ 'credentials_url ' => 'https://aistudio.google.com/ ' ,
91114 ),
92115 'openai ' => array (
93- 'name ' => 'OpenAI ' ,
116+ 'name ' => 'OpenAI ' ,
117+ 'description ' => __ ( 'Text, image, and code generation with GPT and DALL-E. ' , 'gutenberg ' ),
118+ 'credentials_url ' => 'https://platform.openai.com/ ' ,
94119 ),
95120 'anthropic ' => array (
96- 'name ' => 'Anthropic ' ,
121+ 'name ' => 'Claude ' ,
122+ 'description ' => __ ( 'Writing, research, and analysis with Claude. ' , 'gutenberg ' ),
123+ 'credentials_url ' => 'https://console.anthropic.com/ ' ,
97124 ),
98125 );
99126
127+ $ registry = \WordPress \AiClient \AiClient::defaultRegistry ();
128+
129+ foreach ( $ registry ->getRegisteredProviderIds () as $ provider_id ) {
130+ $ provider_class_name = $ registry ->getProviderClassName ( $ provider_id );
131+ $ provider_metadata = $ provider_class_name ::metadata ();
132+
133+ $ auth_method = $ provider_metadata ->getAuthenticationMethod ();
134+ if ( null === $ auth_method || ! $ auth_method ->isApiKey () ) {
135+ continue ;
136+ }
137+
138+ $ registry_data = array_filter (
139+ array (
140+ 'name ' => $ provider_metadata ->getName (),
141+ 'credentials_url ' => $ provider_metadata ->getCredentialsUrl (),
142+ )
143+ );
144+
145+ if ( isset ( $ providers [ $ provider_id ] ) ) {
146+ // Merge non-empty registry data over hardcoded fallbacks.
147+ $ providers [ $ provider_id ] = array_merge ( $ providers [ $ provider_id ], $ registry_data );
148+ } else {
149+ $ providers [ $ provider_id ] = array_merge (
150+ array (
151+ 'name ' => '' ,
152+ 'description ' => '' ,
153+ 'credentials_url ' => null ,
154+ ),
155+ $ registry_data
156+ );
157+ }
158+ }
159+
100160 $ provider_settings = array ();
101161 foreach ( $ providers as $ provider => $ data ) {
102162 $ setting_name = "connectors_ai_ {$ provider }_api_key " ;
103163
104- $ provider_settings [ $ setting_name ] = array (
105- 'provider ' => $ provider ,
106- 'label ' => sprintf (
107- /* translators: %s: AI provider name. */
108- __ ( '%s API Key ' , 'gutenberg ' ),
109- $ data ['name ' ]
110- ),
111- 'description ' => sprintf (
112- /* translators: %s: AI provider name. */
113- __ ( 'API key for the %s AI provider. ' , 'gutenberg ' ),
114- $ data ['name ' ]
115- ),
116- 'mask ' => '_gutenberg_mask_api_key ' ,
117- 'sanitize ' => static function ( string $ value ) use ( $ provider ): string {
118- $ value = sanitize_text_field ( $ value );
119- if ( '' === $ value ) {
120- return $ value ;
121- }
164+ $ provider_settings [ $ provider ] = array (
165+ 'name ' => $ data ['name ' ],
166+ 'description ' => $ data ['description ' ],
167+ 'credentials_url ' => $ data ['credentials_url ' ],
168+ 'settings ' => array (
169+ $ setting_name => array (
170+ 'label ' => sprintf (
171+ /* translators: %s: AI provider name. */
172+ __ ( '%s API Key ' , 'gutenberg ' ),
173+ $ data ['name ' ]
174+ ),
175+ 'description ' => sprintf (
176+ /* translators: %s: AI provider name. */
177+ __ ( 'API key for the %s AI provider. ' , 'gutenberg ' ),
178+ $ data ['name ' ]
179+ ),
180+ 'sanitize ' => static function ( string $ value ) use ( $ provider ): string {
181+ $ value = sanitize_text_field ( $ value );
182+ if ( '' === $ value ) {
183+ return $ value ;
184+ }
122185
123- $ valid = _gutenberg_is_api_key_valid ( $ value , $ provider );
124- return true === $ valid ? $ value : '' ;
125- },
186+ $ valid = _gutenberg_is_api_key_valid ( $ value , $ provider );
187+ return true === $ valid ? $ value : '' ;
188+ },
189+ ),
190+ ),
126191 );
127192 }
128-
129193 return $ provider_settings ;
130194}
131195
@@ -169,18 +233,20 @@ function _gutenberg_validate_connector_keys_in_rest( WP_REST_Response $response,
169233 return $ response ;
170234 }
171235
172- foreach ( _gutenberg_get_provider_settings () as $ setting_name => $ config ) {
173- if ( ! in_array ( $ setting_name , $ requested , true ) ) {
174- continue ;
175- }
236+ foreach ( _gutenberg_get_provider_settings () as $ provider => $ provider_data ) {
237+ foreach ( $ provider_data ['settings ' ] as $ setting_name => $ config ) {
238+ if ( ! in_array ( $ setting_name , $ requested , true ) ) {
239+ continue ;
240+ }
176241
177- $ real_key = _gutenberg_get_real_api_key ( $ setting_name , $ config [ ' mask ' ] );
178- if ( '' === $ real_key ) {
179- continue ;
180- }
242+ $ real_key = _gutenberg_get_real_api_key ( $ setting_name , ' _gutenberg_mask_api_key ' );
243+ if ( '' === $ real_key ) {
244+ continue ;
245+ }
181246
182- if ( true !== _gutenberg_is_api_key_valid ( $ real_key , $ config ['provider ' ] ) ) {
183- $ data [ $ setting_name ] = 'invalid_key ' ;
247+ if ( true !== _gutenberg_is_api_key_valid ( $ real_key , $ provider ) ) {
248+ $ data [ $ setting_name ] = 'invalid_key ' ;
249+ }
184250 }
185251 }
186252
@@ -200,20 +266,22 @@ function _gutenberg_register_default_connector_settings(): void {
200266 return ;
201267 }
202268
203- foreach ( _gutenberg_get_provider_settings () as $ setting_name => $ config ) {
204- register_setting (
205- 'connectors ' ,
206- $ setting_name ,
207- array (
208- 'type ' => 'string ' ,
209- 'label ' => $ config ['label ' ],
210- 'description ' => $ config ['description ' ],
211- 'default ' => '' ,
212- 'show_in_rest ' => true ,
213- 'sanitize_callback ' => $ config ['sanitize ' ],
214- )
215- );
216- add_filter ( "option_ {$ setting_name }" , $ config ['mask ' ] );
269+ foreach ( _gutenberg_get_provider_settings () as $ provider_data ) {
270+ foreach ( $ provider_data ['settings ' ] as $ setting_name => $ config ) {
271+ register_setting (
272+ 'connectors ' ,
273+ $ setting_name ,
274+ array (
275+ 'type ' => 'string ' ,
276+ 'label ' => $ config ['label ' ],
277+ 'description ' => $ config ['description ' ],
278+ 'default ' => '' ,
279+ 'show_in_rest ' => true ,
280+ 'sanitize_callback ' => $ config ['sanitize ' ],
281+ )
282+ );
283+ add_filter ( "option_ {$ setting_name }" , '_gutenberg_mask_api_key ' );
284+ }
217285 }
218286}
219287remove_action ( 'init ' , '_wp_register_default_connector_settings ' );
@@ -231,16 +299,18 @@ function _gutenberg_pass_default_connector_keys_to_ai_client(): void {
231299
232300 try {
233301 $ registry = \WordPress \AiClient \AiClient::defaultRegistry ();
234- foreach ( _gutenberg_get_provider_settings () as $ setting_name => $ config ) {
235- $ api_key = _gutenberg_get_real_api_key ( $ setting_name , $ config ['mask ' ] );
236- if ( '' === $ api_key || ! $ registry ->hasProvider ( $ config ['provider ' ] ) ) {
237- continue ;
238- }
302+ foreach ( _gutenberg_get_provider_settings () as $ provider => $ provider_data ) {
303+ foreach ( $ provider_data ['settings ' ] as $ setting_name => $ config ) {
304+ $ api_key = _gutenberg_get_real_api_key ( $ setting_name , '_gutenberg_mask_api_key ' );
305+ if ( '' === $ api_key || ! $ registry ->hasProvider ( $ provider ) ) {
306+ continue ;
307+ }
239308
240- $ registry ->setProviderRequestAuthentication (
241- $ config ['provider ' ],
242- new \WordPress \AiClient \Providers \Http \DTO \ApiKeyRequestAuthentication ( $ api_key )
243- );
309+ $ registry ->setProviderRequestAuthentication (
310+ $ provider ,
311+ new \WordPress \AiClient \Providers \Http \DTO \ApiKeyRequestAuthentication ( $ api_key )
312+ );
313+ }
244314 }
245315 } catch ( Exception $ e ) {
246316 wp_trigger_error ( __FUNCTION__ , $ e ->getMessage () );
0 commit comments