From 06746a654a1e877d2140e61f02dc8b2b61fdc5b2 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 12 Nov 2025 16:52:51 +0000 Subject: [PATCH 1/5] Fix: Core abilities schemas. --- src/wp-includes/abilities.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/abilities.php b/src/wp-includes/abilities.php index c71eeb158a304..9fedd77996328 100644 --- a/src/wp-includes/abilities.php +++ b/src/wp-includes/abilities.php @@ -100,7 +100,8 @@ function wp_register_core_abilities(): void { ), ), 'additionalProperties' => false, - 'default' => array(), + // Casting to object so when it is serilized to JSON it shows as {} instead of []. + 'default' => (object) array(), ), 'output_schema' => array( 'type' => 'object', @@ -220,7 +221,6 @@ function wp_register_core_abilities(): void { 'db_server_info' => array( 'type' => 'string', 'description' => __( 'The database server vendor and version string reported by the driver.' ), - 'examples' => array( '8.0.34', '10.11.6-MariaDB' ), ), 'wp_version' => array( 'type' => 'string', From 3051a7d87495f84877260269caa8d4fa859bddbe Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 12 Nov 2025 17:29:58 +0000 Subject: [PATCH 2/5] update test case --- tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php index c89d6daf32cd6..2783874300e3b 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php @@ -68,7 +68,7 @@ public function test_core_get_site_info_ability_is_registered(): void { $this->assertSame( 'object', $input_schema['type'] ); $this->assertArrayHasKey( 'default', $input_schema ); - $this->assertSame( array(), $input_schema['default'] ); + $this->assertEquals( (object) array(), $input_schema['default'] ); // Input schema should have optional fields array. $this->assertArrayHasKey( 'fields', $input_schema['properties'] ); From d4447808e6853050b2673c578571843ac7f2cdcd Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 13 Nov 2025 10:41:02 +0000 Subject: [PATCH 3/5] apply feedback --- src/wp-includes/abilities.php | 3 +-- ...class-wp-rest-abilities-v1-list-controller.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/abilities.php b/src/wp-includes/abilities.php index 9fedd77996328..0320df3b9f38a 100644 --- a/src/wp-includes/abilities.php +++ b/src/wp-includes/abilities.php @@ -100,8 +100,7 @@ function wp_register_core_abilities(): void { ), ), 'additionalProperties' => false, - // Casting to object so when it is serilized to JSON it shows as {} instead of []. - 'default' => (object) array(), + 'default' => array(), ), 'output_schema' => array( 'type' => 'object', diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php index 4f59d908de2c5..3783bbd808229 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php @@ -214,6 +214,21 @@ public function prepare_item_for_response( $ability, $request ) { 'meta' => $ability->get_meta(), ); + // Convert top-level defaults to an object when its type is object and + // they are an empty array so they get serialized as {} instead of []. + if ( isset( $data['input_schema']['type'] ) && 'object' === $data['input_schema']['type'] && isset( $data['input_schema']['default'] ) ) { + $default = $data['input_schema']['default']; + if ( is_array( $default ) && empty( $default ) ) { + $data['input_schema']['default'] = (object) $default; + } + } + if ( isset( $data['output_schema']['type'] ) && 'object' === $data['output_schema']['type'] && isset( $data['output_schema']['default'] ) ) { + $default = $data['output_schema']['default']; + if ( is_array( $default ) && empty( $default ) ) { + $data['output_schema']['default'] = (object) $default; + } + } + $context = $request['context'] ?? 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); From ff06657e94d8dce33e172307b9b656c61cd9b608 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 13 Nov 2025 10:45:12 +0000 Subject: [PATCH 4/5] revert test change --- tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php b/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php index 2783874300e3b..c89d6daf32cd6 100644 --- a/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php +++ b/tests/phpunit/tests/abilities-api/wpRegisterCoreAbilities.php @@ -68,7 +68,7 @@ public function test_core_get_site_info_ability_is_registered(): void { $this->assertSame( 'object', $input_schema['type'] ); $this->assertArrayHasKey( 'default', $input_schema ); - $this->assertEquals( (object) array(), $input_schema['default'] ); + $this->assertSame( array(), $input_schema['default'] ); // Input schema should have optional fields array. $this->assertArrayHasKey( 'fields', $input_schema['properties'] ); From 38dcadfc863d7e3fcf96f7c28f0d5e6c8a8ab441 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 13 Nov 2025 14:56:47 +0000 Subject: [PATCH 5/5] extract helper function for normalization --- ...s-wp-rest-abilities-v1-list-controller.php | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php index 3783bbd808229..6dfc54003863e 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php @@ -194,6 +194,27 @@ public function get_item_permissions_check( $request ) { return current_user_can( 'read' ); } + /** + * Normalizes schema empty object defaults. + * + * Converts empty array defaults to objects when the schema type is 'object' + * to ensure proper JSON serialization as {} instead of []. + * + * @since 6.9.0 + * + * @param array $schema The schema array. + * @return array The normalized schema. + */ + private function normalize_schema_empty_object_defaults( array $schema ): array { + if ( isset( $schema['type'] ) && 'object' === $schema['type'] && isset( $schema['default'] ) ) { + $default = $schema['default']; + if ( is_array( $default ) && empty( $default ) ) { + $schema['default'] = (object) $default; + } + } + return $schema; + } + /** * Prepares an ability for response. * @@ -209,26 +230,11 @@ public function prepare_item_for_response( $ability, $request ) { 'label' => $ability->get_label(), 'description' => $ability->get_description(), 'category' => $ability->get_category(), - 'input_schema' => $ability->get_input_schema(), - 'output_schema' => $ability->get_output_schema(), + 'input_schema' => $this->normalize_schema_empty_object_defaults( $ability->get_input_schema() ), + 'output_schema' => $this->normalize_schema_empty_object_defaults( $ability->get_output_schema() ), 'meta' => $ability->get_meta(), ); - // Convert top-level defaults to an object when its type is object and - // they are an empty array so they get serialized as {} instead of []. - if ( isset( $data['input_schema']['type'] ) && 'object' === $data['input_schema']['type'] && isset( $data['input_schema']['default'] ) ) { - $default = $data['input_schema']['default']; - if ( is_array( $default ) && empty( $default ) ) { - $data['input_schema']['default'] = (object) $default; - } - } - if ( isset( $data['output_schema']['type'] ) && 'object' === $data['output_schema']['type'] && isset( $data['output_schema']['default'] ) ) { - $default = $data['output_schema']['default']; - if ( is_array( $default ) && empty( $default ) ) { - $data['output_schema']['default'] = (object) $default; - } - } - $context = $request['context'] ?? 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context );