Skip to content

Commit 462e96d

Browse files
committed
Abilities API: Normalize inputs in core information abilities
Support object inputs and comma- or whitespace-separated field lists during direct execution. Preserve empty-selection defaults and validation of field names. Add regression tests. Props gziolo, jorgefilipecosta. Fixes #66370. git-svn-id: https://develop.svn.wordpress.org/trunk@64729 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 67850a9 commit 462e96d

2 files changed

Lines changed: 95 additions & 8 deletions

File tree

‎src/wp-includes/abilities.php‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,11 @@ function wp_register_core_abilities(): void {
136136
'additionalProperties' => false,
137137
),
138138
'execute_callback' => static function ( $input = array() ) use ( $site_info_fields ): array {
139-
$input = is_array( $input ) ? $input : array();
140-
$requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $site_info_fields;
139+
$input = rest_sanitize_object( $input );
140+
$requested_fields = rest_sanitize_array( $input['fields'] ?? array() );
141+
if ( empty( $requested_fields ) ) {
142+
$requested_fields = $site_info_fields;
143+
}
141144

142145
$result = array();
143146
foreach ( $requested_fields as $field ) {
@@ -251,9 +254,12 @@ function wp_register_core_abilities(): void {
251254
'additionalProperties' => false,
252255
),
253256
'execute_callback' => static function ( $input = array() ) use ( $user_info_fields ): array {
254-
$input = is_array( $input ) ? $input : array();
255-
$requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $user_info_fields;
256-
$current_user = wp_get_current_user();
257+
$input = rest_sanitize_object( $input );
258+
$requested_fields = rest_sanitize_array( $input['fields'] ?? array() );
259+
if ( empty( $requested_fields ) ) {
260+
$requested_fields = $user_info_fields;
261+
}
262+
$current_user = wp_get_current_user();
257263

258264
$all = array(
259265
'id' => $current_user->ID,
@@ -340,9 +346,12 @@ function wp_register_core_abilities(): void {
340346
'execute_callback' => static function ( $input = array() ) use ( $environment_info_fields ): array {
341347
global $wpdb;
342348

343-
/** @var array{ fields?: string[] } $input */
344-
$input = is_array( $input ) ? $input : array();
345-
$requested_fields = ! empty( $input['fields'] ) ? $input['fields'] : $environment_info_fields;
349+
$input = rest_sanitize_object( $input );
350+
/** @var array{ fields?: string[]|string } $input */
351+
$requested_fields = rest_sanitize_array( $input['fields'] ?? array() );
352+
if ( empty( $requested_fields ) ) {
353+
$requested_fields = $environment_info_fields;
354+
}
346355

347356
$db_server_info = '';
348357
if ( method_exists( $wpdb, 'db_server_info' ) ) {

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

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,84 @@ public function test_core_get_environment_info_rejects_invalid_fields(): void {
454454
$this->assertSame( 'ability_invalid_input', $result->get_error_code() );
455455
}
456456

457+
/**
458+
* Tests field selection through direct execution, without REST input coercion.
459+
*
460+
* @ticket 66370
461+
*
462+
* @dataProvider data_core_ability_field_lists
463+
*
464+
* @param string $ability_name Ability name.
465+
* @param array|stdClass $input Ability input.
466+
* @param array|null $expected_fields Expected fields, or null for invalid input.
467+
*/
468+
public function test_core_ability_field_lists( string $ability_name, $input, ?array $expected_fields ): void {
469+
$admin_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
470+
$user = wp_set_current_user( $admin_id );
471+
$user->add_cap( 'view_site_health_checks' );
472+
473+
$ability = wp_get_ability( $ability_name );
474+
$result = $ability->execute( $input );
475+
476+
if ( null === $expected_fields ) {
477+
$this->assertWPError( $result );
478+
$this->assertSame( 'ability_invalid_input', $result->get_error_code() );
479+
return;
480+
}
481+
482+
$expected = $ability->execute();
483+
$this->assertIsArray( $expected );
484+
if ( ! empty( $expected_fields ) ) {
485+
$expected = array_intersect_key( $expected, array_flip( $expected_fields ) );
486+
}
487+
488+
$this->assertSameSetsWithIndex( $expected, $result );
489+
}
490+
491+
/**
492+
* Provides array and string field selections for the core information abilities.
493+
*
494+
* @return array
495+
*/
496+
public static function data_core_ability_field_lists(): array {
497+
$abilities = array(
498+
'core/get-site-info' => array( 'name', 'url' ),
499+
'core/get-user-info' => array( 'id', 'display_name' ),
500+
'core/get-environment-info' => array( 'environment', 'php_version' ),
501+
);
502+
$datasets = array();
503+
504+
foreach ( $abilities as $ability_name => $fields ) {
505+
$cases = array(
506+
'array' => array( $fields, $fields ),
507+
'csv' => array( implode( ',', $fields ), $fields ),
508+
'reversed array' => array( array_reverse( $fields ), $fields ),
509+
'reversed csv' => array( implode( ',', array_reverse( $fields ) ), $fields ),
510+
'whitespace' => array( implode( " \t\n", $fields ), $fields ),
511+
'duplicates' => array( ', ' . implode( ',, ', $fields ) . ',' . $fields[0] . ',', $fields ),
512+
'empty array' => array( array(), array() ),
513+
'empty string' => array( '', array() ),
514+
'only separators' => array( " , \t\n,, ", array() ),
515+
'invalid csv' => array( $fields[0] . ',not_a_real_field', null ),
516+
'invalid array' => array( array( $fields[0], 'not_a_real_field' ), null ),
517+
);
518+
519+
foreach ( $cases as $case => $values ) {
520+
$input = array( 'fields' => $values[0] );
521+
522+
$datasets[ $ability_name . ': ' . $case ] = array( $ability_name, $input, $values[1] );
523+
}
524+
525+
$datasets[ $ability_name . ': object input' ] = array(
526+
$ability_name,
527+
(object) array( 'fields' => $fields ),
528+
$fields,
529+
);
530+
}
531+
532+
return $datasets;
533+
}
534+
457535
/**
458536
* Tests that all core ability schemas only use valid JSON Schema keywords.
459537
*

0 commit comments

Comments
 (0)