Commit dc0a207b49 for wordpress.org
commit dc0a207b49a8d607896d56a8cec47ce4e35e2dff
Author: jorgefilipecosta <jorgefilipecosta@git.wordpress.org>
Date: Tue Oct 20 14:47:56 2026 +0000
REST API: Use `wp_prepare_json_value_for_client()` for view configs and entity fields.
Removes the private `_rest_cast_empty_objects_from_schema()` helper, so a single function prepares empty objects according to a schema. The view config and entity fields endpoints now call `wp_prepare_json_value_for_client()`, and `WP_REST_View_Config_Controller::cast_empty_objects()` delegates to it. The private helper was added in this release cycle, so it is removed without deprecation.
`wp_prepare_json_value_for_client()` also recurses into the matching `oneOf`/`anyOf` branch and into `patternProperties`, and keeps `[]` when the schema also allows an array. No view config or entity fields schema allows both an object and an array, so the existing responses are unchanged.
Developed in https://github.com/WordPress/wordpress-develop/pull/14552.
Follow-up to [64503], [64592].
Props jorgefilipecosta, oandregal.
See #66267.
Built from https://develop.svn.wordpress.org/trunk@64602
git-svn-id: http://core.svn.wordpress.org/trunk@63752 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/rest-api.php b/wp-includes/rest-api.php
index 4ec8f119f3..9998e14da7 100644
--- a/wp-includes/rest-api.php
+++ b/wp-includes/rest-api.php
@@ -3235,80 +3235,6 @@ function rest_default_additional_properties_to_false( $schema ) {
return $schema;
}
-/**
- * Recursively casts empty arrays to objects where the schema types them as objects.
- *
- * PHP cannot distinguish an empty associative array from an empty list, so
- * `json_encode()` always serializes `array()` as a JSON array (`[]`). A REST
- * schema, however, may type a value as an object, which must encode as `{}`.
- * This walks the value against its schema and casts any empty, object-typed
- * array to an object. Non-empty associative arrays already encode as objects,
- * so they are left as arrays and only recursed into to fix any nested empty
- * objects.
- *
- * Union schemas (`oneOf`/`anyOf`) are handled only for the empty-array case:
- * an empty value is cast to an object when any branch allows an object. Such
- * values are not recursed into.
- *
- * @since 7.2.0
- * @access private
- *
- * @param mixed $value The value to normalize.
- * @param array $schema The schema node describing the value.
- * @return mixed The normalized value, with empty object-typed arrays cast to objects.
- */
-function _rest_cast_empty_objects_from_schema( $value, $schema ) {
- if ( ! is_array( $value ) || ! is_array( $schema ) ) {
- return $value;
- }
-
- if ( isset( $schema['oneOf'] ) || isset( $schema['anyOf'] ) ) {
- $branches = $schema['oneOf'] ?? $schema['anyOf'];
- if ( array() === $value ) {
- foreach ( $branches as $branch ) {
- if ( is_array( $branch ) && in_array( 'object', (array) ( $branch['type'] ?? array() ), true ) ) {
- return (object) array();
- }
- }
- }
- return $value;
- }
-
- $types = (array) ( $schema['type'] ?? array() );
-
- if ( in_array( 'array', $types, true ) && isset( $schema['items'] ) ) {
- foreach ( $value as $index => $item ) {
- $value[ $index ] = _rest_cast_empty_objects_from_schema( $item, $schema['items'] );
- }
- return $value;
- }
-
- if ( in_array( 'object', $types, true ) ) {
- if ( isset( $schema['properties'] ) ) {
- foreach ( $schema['properties'] as $property => $property_schema ) {
- if ( array_key_exists( $property, $value ) ) {
- $value[ $property ] = _rest_cast_empty_objects_from_schema( $value[ $property ], $property_schema );
- }
- }
- }
- if ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) {
- foreach ( $value as $key => $item ) {
- if ( isset( $schema['properties'][ $key ] ) ) {
- continue;
- }
- $value[ $key ] = _rest_cast_empty_objects_from_schema( $item, $schema['additionalProperties'] );
- }
- }
-
- // Empty object-typed arrays must serialize as {} to match the schema.
- if ( array() === $value ) {
- return (object) array();
- }
- }
-
- return $value;
-}
-
/**
* Gets the REST API route for a post.
*
diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-entity-fields-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-entity-fields-controller.php
index dae68fff62..e7674e2a80 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-entity-fields-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-entity-fields-controller.php
@@ -156,7 +156,7 @@ class WP_REST_Entity_Fields_Controller extends WP_REST_Controller {
$field_schema = $this->get_field_schema();
$fields = array();
foreach ( wp_get_registered_entity_fields( $kind, $name ) as $field ) {
- $fields[] = _rest_cast_empty_objects_from_schema( $field, $field_schema );
+ $fields[] = wp_prepare_json_value_for_client( $field, $field_schema );
}
$script_modules = array();
diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php
index 44de983ab4..7da61b0486 100644
--- a/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php
+++ b/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php
@@ -155,10 +155,10 @@ class WP_REST_View_Config_Controller extends WP_REST_Controller {
'kind' => $kind,
'name' => $name,
'version' => WP_View_Config_Data::LATEST_VERSION,
- 'default_view' => _rest_cast_empty_objects_from_schema( $config['default_view'], $schema['properties']['default_view'] ),
- 'default_layouts' => _rest_cast_empty_objects_from_schema( $config['default_layouts'], $schema['properties']['default_layouts'] ),
- 'view_list' => _rest_cast_empty_objects_from_schema( $config['view_list'], $schema['properties']['view_list'] ),
- 'form' => _rest_cast_empty_objects_from_schema( $config['form'], $schema['properties']['form'] ),
+ 'default_view' => wp_prepare_json_value_for_client( $config['default_view'], $schema['properties']['default_view'] ),
+ 'default_layouts' => wp_prepare_json_value_for_client( $config['default_layouts'], $schema['properties']['default_layouts'] ),
+ 'view_list' => wp_prepare_json_value_for_client( $config['view_list'], $schema['properties']['view_list'] ),
+ 'form' => wp_prepare_json_value_for_client( $config['form'], $schema['properties']['form'] ),
);
return rest_ensure_response( $response );
@@ -169,16 +169,16 @@ class WP_REST_View_Config_Controller extends WP_REST_Controller {
* objects.
*
* @since 7.1.0
- * @since 7.2.0 Moved the logic to _rest_cast_empty_objects_from_schema().
+ * @since 7.2.0 Uses wp_prepare_json_value_for_client().
*
- * @see _rest_cast_empty_objects_from_schema()
+ * @see wp_prepare_json_value_for_client()
*
* @param mixed $value The value to normalize.
* @param array $schema The schema node describing the value.
* @return mixed The normalized value, with empty object-typed arrays cast to objects.
*/
protected function cast_empty_objects( $value, $schema ) {
- return _rest_cast_empty_objects_from_schema( $value, $schema );
+ return is_array( $schema ) ? wp_prepare_json_value_for_client( $value, $schema ) : $value;
}
/**
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 8378878821..20ec81a110 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-64601';
+$wp_version = '7.2-alpha-64602';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.