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.