Skip to content

Commit 868b575

Browse files
committed
Abilities API: Unify schema conventions across core abilities
Align `core/get-site-info`, `core/get-user-info`, and `core/get-environment-info` on a shared blueprint: every output property carries a Title Case `title` and a `description`, `core/get-environment-info` gains the optional `fields` input parameter the other two already accept, and `core/get-user-info` is exposed via REST. Descriptions are also tightened for programmatic consumers, and registration tests now lock the exact ordered set of property keys. Props gziolo, westonruter. Fixes #65355. git-svn-id: https://develop.svn.wordpress.org/trunk@62426 602fd350-edb4-49c9-b593-d223f7449a82
1 parent cc27792 commit 868b575

2 files changed

Lines changed: 159 additions & 49 deletions

File tree

src/wp-includes/abilities.php

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -46,35 +46,43 @@ function wp_register_core_abilities(): void {
4646
$site_info_properties = array(
4747
'name' => array(
4848
'type' => 'string',
49+
'title' => __( 'Site Title' ),
4950
'description' => __( 'The site title.' ),
5051
),
5152
'description' => array(
5253
'type' => 'string',
54+
'title' => __( 'Tagline' ),
5355
'description' => __( 'The site tagline.' ),
5456
),
5557
'url' => array(
5658
'type' => 'string',
57-
'description' => __( 'The site home URL.' ),
59+
'title' => __( 'Site Address (URL)' ),
60+
'description' => __( 'The public URL where visitors access the site. May differ from the WordPress installation URL.' ),
5861
),
5962
'wpurl' => array(
6063
'type' => 'string',
61-
'description' => __( 'The WordPress installation URL.' ),
64+
'title' => __( 'WordPress Address (URL)' ),
65+
'description' => __( 'The URL where WordPress core files are served. May differ from the public site URL.' ),
6266
),
6367
'admin_email' => array(
6468
'type' => 'string',
69+
'title' => __( 'Administration Email Address' ),
6570
'description' => __( 'The site administrator email address.' ),
6671
),
6772
'charset' => array(
6873
'type' => 'string',
74+
'title' => __( 'Site Charset' ),
6975
'description' => __( 'The site character encoding.' ),
7076
),
7177
'language' => array(
7278
'type' => 'string',
73-
'description' => __( 'The site language locale code.' ),
79+
'title' => __( 'Site Language' ),
80+
'description' => __( 'The site locale in dash form (e.g. en-US).' ),
7481
),
7582
'version' => array(
7683
'type' => 'string',
77-
'description' => __( 'The WordPress version.' ),
84+
'title' => __( 'WordPress Version' ),
85+
'description' => __( 'The WordPress core version running on this site.' ),
7886
),
7987
);
8088
$site_info_fields = array_keys( $site_info_properties );
@@ -138,7 +146,7 @@ function wp_register_core_abilities(): void {
138146
'id' => array(
139147
'type' => 'integer',
140148
'title' => __( 'User ID' ),
141-
'description' => __( 'Unique numeric identifier for the user.' ),
149+
'description' => __( 'Unique identifier for the user.' ),
142150
),
143151
'display_name' => array(
144152
'type' => 'string',
@@ -186,7 +194,7 @@ function wp_register_core_abilities(): void {
186194
'description' => array(
187195
'type' => 'string',
188196
'title' => __( 'Biographical Info' ),
189-
'description' => __( 'User-authored biography, often shown on author pages.' ),
197+
'description' => __( 'User-authored biography. May be empty.' ),
190198
),
191199
'user_url' => array(
192200
'type' => 'string',
@@ -253,58 +261,82 @@ function wp_register_core_abilities(): void {
253261
'destructive' => false,
254262
'idempotent' => true,
255263
),
256-
'show_in_rest' => false,
264+
'show_in_rest' => true,
257265
),
258266
)
259267
);
260268

269+
$environment_info_properties = array(
270+
'environment' => array(
271+
'type' => 'string',
272+
'title' => __( 'Environment Type' ),
273+
'description' => __( 'The site\'s runtime environment classification.' ),
274+
'enum' => array( 'production', 'staging', 'development', 'local' ),
275+
),
276+
'php_version' => array(
277+
'type' => 'string',
278+
'title' => __( 'PHP Version' ),
279+
'description' => __( 'The PHP runtime version executing WordPress.' ),
280+
),
281+
'db_server_info' => array(
282+
'type' => 'string',
283+
'title' => __( 'Database Server Info' ),
284+
'description' => __( 'The database server vendor and version string reported by the driver.' ),
285+
),
286+
'wp_version' => array(
287+
'type' => 'string',
288+
'title' => __( 'WordPress Version' ),
289+
'description' => __( 'The WordPress core version running on this site.' ),
290+
),
291+
);
292+
$environment_info_fields = array_keys( $environment_info_properties );
293+
261294
wp_register_ability(
262295
'core/get-environment-info',
263296
array(
264297
'label' => __( 'Get Environment Info' ),
265-
'description' => __( 'Returns core details about the site\'s runtime context for diagnostics and compatibility (environment, PHP runtime, database server info, WordPress version).' ),
298+
'description' => __( 'Returns core details about the site\'s runtime context for diagnostics and compatibility (environment, PHP runtime, database server info, WordPress version). By default returns all fields, or optionally a filtered subset.' ),
266299
'category' => $category_site,
267-
'output_schema' => array(
300+
'input_schema' => array(
268301
'type' => 'object',
269-
'required' => array( 'environment', 'php_version', 'db_server_info', 'wp_version' ),
270302
'properties' => array(
271-
'environment' => array(
272-
'type' => 'string',
273-
'description' => __( 'The site\'s runtime environment classification (can be one of these: production, staging, development, local).' ),
274-
'enum' => array( 'production', 'staging', 'development', 'local' ),
275-
),
276-
'php_version' => array(
277-
'type' => 'string',
278-
'description' => __( 'The PHP runtime version executing WordPress.' ),
279-
),
280-
'db_server_info' => array(
281-
'type' => 'string',
282-
'description' => __( 'The database server vendor and version string reported by the driver.' ),
283-
),
284-
'wp_version' => array(
285-
'type' => 'string',
286-
'description' => __( 'The WordPress core version running on this site.' ),
303+
'fields' => array(
304+
'type' => 'array',
305+
'items' => array(
306+
'type' => 'string',
307+
'enum' => $environment_info_fields,
308+
),
309+
'description' => __( 'Optional: Limit response to specific fields. If omitted, all fields are returned.' ),
287310
),
288311
),
289312
'additionalProperties' => false,
313+
'default' => array(),
314+
),
315+
'output_schema' => array(
316+
'type' => 'object',
317+
'properties' => $environment_info_properties,
318+
'additionalProperties' => false,
290319
),
291-
'execute_callback' => static function (): array {
320+
'execute_callback' => static function ( $input = array() ) use ( $environment_info_fields ): array {
292321
global $wpdb;
293322

294-
$env = wp_get_environment_type();
295-
$php_version = phpversion();
296-
$db_server_info = '';
323+
/** @var array{ fields?: string[] } $input */
324+
$input = is_array( $input ) ? $input : array();
325+
$requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $environment_info_fields;
326+
327+
$db_server_info = '';
297328
if ( method_exists( $wpdb, 'db_server_info' ) ) {
298329
$db_server_info = $wpdb->db_server_info() ?? '';
299330
}
300-
$wp_version = get_bloginfo( 'version' );
301331

302-
return array(
303-
'environment' => $env,
304-
'php_version' => $php_version,
332+
$all = array(
333+
'environment' => wp_get_environment_type(),
334+
'php_version' => phpversion(),
305335
'db_server_info' => $db_server_info,
306-
'wp_version' => $wp_version,
336+
'wp_version' => get_bloginfo( 'version' ),
307337
);
338+
339+
return array_intersect_key( $all, array_flip( $requested_fields ) );
308340
},
309341
'permission_callback' => static function (): bool {
310342
return current_user_can( 'manage_options' );

tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php

Lines changed: 92 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,18 @@ public function test_core_get_site_info_ability_is_registered(): void {
7070
$this->assertArrayHasKey( 'default', $input_schema );
7171
$this->assertSame( array(), $input_schema['default'] );
7272

73-
// Input schema should have optional fields array.
7473
$this->assertArrayHasKey( 'fields', $input_schema['properties'] );
7574
$this->assertSame( 'array', $input_schema['properties']['fields']['type'] );
76-
$this->assertContains( 'name', $input_schema['properties']['fields']['items']['enum'] );
7775

78-
// Output schema should have all fields documented.
79-
$this->assertArrayHasKey( 'name', $output_schema['properties'] );
80-
$this->assertArrayHasKey( 'url', $output_schema['properties'] );
81-
$this->assertArrayHasKey( 'version', $output_schema['properties'] );
76+
$expected_fields = array( 'name', 'description', 'url', 'wpurl', 'admin_email', 'charset', 'language', 'version' );
77+
78+
$this->assertSame( $expected_fields, $input_schema['properties']['fields']['items']['enum'] );
79+
$this->assertSame( $expected_fields, array_keys( $output_schema['properties'] ) );
80+
81+
foreach ( $expected_fields as $field ) {
82+
$this->assertArrayHasKey( 'title', $output_schema['properties'][ $field ] );
83+
$this->assertArrayHasKey( 'description', $output_schema['properties'][ $field ] );
84+
}
8285
}
8386

8487
/**
@@ -200,25 +203,23 @@ public function test_core_get_user_info_ability_is_registered(): void {
200203
$ability = wp_get_ability( 'core/get-user-info' );
201204

202205
$this->assertInstanceOf( WP_Ability::class, $ability );
206+
$this->assertTrue( $ability->get_meta_item( 'show_in_rest', false ) );
203207

204208
$input_schema = $ability->get_input_schema();
205209
$output_schema = $ability->get_output_schema();
206210

207-
// Input schema should expose an optional `fields` array with an enum of valid field names.
208211
$this->assertSame( 'object', $input_schema['type'] );
209212
$this->assertArrayHasKey( 'default', $input_schema );
210213
$this->assertSame( array(), $input_schema['default'] );
211214
$this->assertArrayHasKey( 'fields', $input_schema['properties'] );
212215
$this->assertSame( 'array', $input_schema['properties']['fields']['type'] );
213216

214-
$enum = $input_schema['properties']['fields']['items']['enum'];
215-
foreach ( array( 'id', 'display_name', 'first_name', 'last_name', 'nickname', 'description', 'user_url' ) as $field ) {
216-
$this->assertContains( $field, $enum );
217-
}
217+
$expected_fields = array( 'id', 'display_name', 'user_nicename', 'user_login', 'roles', 'locale', 'first_name', 'last_name', 'nickname', 'description', 'user_url' );
218+
219+
$this->assertSame( $expected_fields, $input_schema['properties']['fields']['items']['enum'] );
220+
$this->assertSame( $expected_fields, array_keys( $output_schema['properties'] ) );
218221

219-
// Output schema should document the original and new profile fields with title + description.
220-
foreach ( array( 'id', 'display_name', 'first_name', 'last_name', 'nickname', 'description', 'user_url' ) as $field ) {
221-
$this->assertArrayHasKey( $field, $output_schema['properties'] );
222+
foreach ( $expected_fields as $field ) {
222223
$this->assertArrayHasKey( 'title', $output_schema['properties'][ $field ] );
223224
$this->assertArrayHasKey( 'description', $output_schema['properties'][ $field ] );
224225
}
@@ -298,6 +299,83 @@ public function test_core_get_environment_info_executes(): void {
298299
$this->assertSame( $environment, $ability_data['environment'] );
299300
}
300301

302+
/**
303+
* Tests that the `core/get-environment-info` ability is registered with the expected schema.
304+
*
305+
* @ticket 65355
306+
*/
307+
public function test_core_get_environment_info_ability_is_registered(): void {
308+
$ability = wp_get_ability( 'core/get-environment-info' );
309+
310+
$this->assertInstanceOf( WP_Ability::class, $ability );
311+
$this->assertTrue( $ability->get_meta_item( 'show_in_rest', false ) );
312+
313+
$input_schema = $ability->get_input_schema();
314+
$output_schema = $ability->get_output_schema();
315+
316+
$this->assertSame( 'object', $input_schema['type'] );
317+
$this->assertArrayHasKey( 'default', $input_schema );
318+
$this->assertSame( array(), $input_schema['default'] );
319+
$this->assertArrayHasKey( 'fields', $input_schema['properties'] );
320+
$this->assertSame( 'array', $input_schema['properties']['fields']['type'] );
321+
322+
$expected_fields = array( 'environment', 'php_version', 'db_server_info', 'wp_version' );
323+
324+
$this->assertSame( $expected_fields, $input_schema['properties']['fields']['items']['enum'] );
325+
$this->assertSame( $expected_fields, array_keys( $output_schema['properties'] ) );
326+
327+
foreach ( $expected_fields as $field ) {
328+
$this->assertArrayHasKey( 'title', $output_schema['properties'][ $field ] );
329+
$this->assertArrayHasKey( 'description', $output_schema['properties'][ $field ] );
330+
}
331+
}
332+
333+
/**
334+
* Tests that the `core/get-environment-info` ability filters its output by the `fields` input parameter.
335+
*
336+
* @ticket 65355
337+
*/
338+
public function test_core_get_environment_info_filters_fields(): void {
339+
$admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
340+
wp_set_current_user( $admin_id );
341+
342+
$ability = wp_get_ability( 'core/get-environment-info' );
343+
344+
$result = $ability->execute(
345+
array(
346+
'fields' => array( 'environment', 'wp_version' ),
347+
)
348+
);
349+
350+
$this->assertIsArray( $result );
351+
$this->assertCount( 2, $result );
352+
$this->assertArrayHasKey( 'environment', $result );
353+
$this->assertArrayHasKey( 'wp_version', $result );
354+
$this->assertArrayNotHasKey( 'php_version', $result );
355+
$this->assertArrayNotHasKey( 'db_server_info', $result );
356+
}
357+
358+
/**
359+
* Tests that the `core/get-environment-info` ability rejects unknown field names via schema validation.
360+
*
361+
* @ticket 65355
362+
*/
363+
public function test_core_get_environment_info_rejects_invalid_fields(): void {
364+
$admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
365+
wp_set_current_user( $admin_id );
366+
367+
$ability = wp_get_ability( 'core/get-environment-info' );
368+
369+
$result = $ability->execute(
370+
array(
371+
'fields' => array( 'environment', 'not_a_real_field' ),
372+
)
373+
);
374+
375+
$this->assertWPError( $result );
376+
$this->assertSame( 'ability_invalid_input', $result->get_error_code() );
377+
}
378+
301379
/**
302380
* Tests that all core ability schemas only use valid JSON Schema keywords.
303381
*

0 commit comments

Comments
 (0)