Skip to content

Commit 0025a49

Browse files
committed
REST API: Ensure empty meta is returned as an object in view context
1 parent 4d3b0b9 commit 0025a49

4 files changed

Lines changed: 111 additions & 3 deletions

File tree

src/wp-includes/rest-api/endpoints/class-wp-rest-blocks-controller.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,15 @@ public function filter_response_by_context( $data, $context ) {
5858
unset( $data['content']['rendered'] );
5959

6060
// Add the core wp_pattern_sync_status meta as top level property to the response.
61-
$data['wp_pattern_sync_status'] = $data['meta']['wp_pattern_sync_status'] ?? '';
62-
unset( $data['meta']['wp_pattern_sync_status'] );
61+
$meta = (array) $data['meta'];
62+
$data['wp_pattern_sync_status'] = $meta['wp_pattern_sync_status'] ?? '';
63+
64+
if ( is_object( $data['meta'] ) ) {
65+
unset( $data['meta']->wp_pattern_sync_status );
66+
} else {
67+
unset( $data['meta']['wp_pattern_sync_status'] );
68+
}
69+
6370
return $data;
6471
}
6572

src/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ public function register_field() {
7474
*
7575
* @param int $object_id Object ID to fetch meta for.
7676
* @param WP_REST_Request $request Full details about the request.
77-
* @return array Array containing the meta values keyed by name.
77+
* @return array|object Array containing the meta values keyed by name,
78+
* or an empty object if to ensure JSON object encoding.
7879
*/
7980
public function get_value( $object_id, $request ) {
8081
$fields = $this->get_registered_fields();
@@ -105,6 +106,11 @@ public function get_value( $object_id, $request ) {
105106
$response[ $name ] = $value;
106107
}
107108

109+
// Use stdClass so that JSON result is {} and not [].
110+
if ( empty( $response ) ) {
111+
return (object) array();
112+
}
113+
108114
return $response;
109115
}
110116

@@ -582,6 +588,10 @@ public static function prepare_value( $value, $request, $args ) {
582588
* @return array|false The meta array, if valid, false otherwise.
583589
*/
584590
public function check_meta_is_array( $value, $request, $param ) {
591+
if ( is_object( $value ) ) {
592+
$value = (array) $value;
593+
}
594+
585595
if ( ! is_array( $value ) ) {
586596
return false;
587597
}

tests/phpunit/tests/rest-api/rest-blocks-controller.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,39 @@ public function test_wp_patterns_sync_status_post_meta() {
255255
$this->assertArrayHasKey( 'wp_pattern_sync_status', $data );
256256
$this->assertArrayNotHasKey( 'wp_pattern_sync_status', $data['meta'] );
257257
}
258+
259+
/**
260+
* Tests that check_meta_is_array correctly handles object types.
261+
*
262+
* @ticket 54484
263+
*/
264+
public function test_check_meta_is_array_accepts_object() {
265+
wp_set_current_user( self::$user_ids['editor'] );
266+
267+
// Implement all abstract methods required by WP_REST_Meta_Fields.
268+
$meta_fields = new class( 'post' ) extends WP_REST_Meta_Fields {
269+
protected function get_meta_type() {
270+
return 'post';
271+
}
272+
273+
protected function get_rest_field_type() {
274+
return 'post';
275+
}
276+
};
277+
278+
// Simulate an object parsed from JSON (stdClass).
279+
$object_value = new stdClass();
280+
$object_value->test_key = 'test_value';
281+
282+
// Execute the method from the patch.
283+
$result = $meta_fields->check_meta_is_array( $object_value, new WP_REST_Request(), 'meta' );
284+
285+
// Verify: The object should be converted to an array to pass validation.
286+
$this->assertIsArray( $result, 'The object should be converted to an array to pass validation.' );
287+
$this->assertArrayHasKey( 'test_key', $result );
288+
$this->assertSame( 'test_value', $result['test_key'] );
289+
290+
// Verify: Values that are neither object nor array (e.g., string) should still return false.
291+
$this->assertFalse( $meta_fields->check_meta_is_array( 'not-an-array', new WP_REST_Request(), 'meta' ) );
292+
}
258293
}

tests/phpunit/tests/rest-api/rest-post-meta-fields.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,4 +4014,60 @@ public static function data_scalar_default_values() {
40144014
'string default' => array( 'string', 'string', 'string2' ),
40154015
);
40164016
}
4017+
4018+
/**
4019+
* Tests that the Meta fields handle an empty object (stdClass) correctly.
4020+
*
4021+
* This verifies the compatibility of filter_response_by_context with object types
4022+
* when meta is cast to an object (e.g., in specific PHP versions or filter modifications).
4023+
*
4024+
* @ticket 54484
4025+
*/
4026+
public function test_filter_response_by_context_with_empty_object_meta() {
4027+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) );
4028+
4029+
register_post_meta(
4030+
'post',
4031+
'test_object_compat_meta',
4032+
array(
4033+
'single' => true,
4034+
'type' => 'string',
4035+
'show_in_rest' => true,
4036+
)
4037+
);
4038+
4039+
add_filter(
4040+
'rest_prepare_post',
4041+
function ( $response ) {
4042+
$data = $response->get_data();
4043+
// Inject an empty object for meta to test type compatibility
4044+
$data['meta'] = new stdClass();
4045+
$response->set_data( $data );
4046+
return $response;
4047+
},
4048+
10
4049+
);
4050+
4051+
$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . self::$post_id );
4052+
$response = rest_get_server()->dispatch( $request );
4053+
$data = $response->get_data();
4054+
4055+
$this->assertArrayHasKey( 'meta', $data );
4056+
4057+
// Use a more robust check for both array and object types
4058+
$meta_data = $data['meta'];
4059+
4060+
if ( is_object( $meta_data ) ) {
4061+
$this->assertFalse(
4062+
property_exists( $meta_data, 'test_object_compat_meta' ),
4063+
'Failed asserting that the meta object does not have the property "test_object_compat_meta".'
4064+
);
4065+
} else {
4066+
$this->assertArrayNotHasKey(
4067+
'test_object_compat_meta',
4068+
$meta_data,
4069+
'Failed asserting that the meta array does not have the key "test_object_compat_meta".'
4070+
);
4071+
}
4072+
}
40174073
}

0 commit comments

Comments
 (0)