Make WordPress Core

Opened 4 years ago

Last modified 5 weeks ago

#54484 assigned defect (bug)

REST API returns (empty) array for Meta but Schema has type object

Reported by: dtrunk90's profile dtrunk90 Owned by: flixos90's profile flixos90
Milestone: 7.1 Priority: normal
Severity: normal Version: 4.7
Component: REST API Keywords: has-patch changes-requested
Focuses: Cc:

Description

When checking http://localhost/wp-json/wp/v2/posts (fresh setup) the meta field is an empty array:

[{"id":1,...,"meta":[],...}]

But the schema (localhost/wp-json/wp/v2/posts?_method=OPTIONS) has type definition object:

{
   ...,
   "schema":{
      "$schema":"http:\/\/json-schema.org\/draft-04\/schema#",
      "title":"post",
      "type":"object",
      "properties":{
         ...,
         "meta":{
            "description":"Metafelder.",
            "type":"object",
            "context":[
               "view",
               "edit"
            ],
            "properties":[
               
            ]
         },
         ...
      },
      ...
   },
   ...
}

Either the schema is wrong and should be array or REST API should not return an empty array

I'm downloading the schema from my local WordPress instance in order to create POJOs and using those with Springs WebClient which results in the following error:

Error: JSON decoding error: Cannot deserialize value of type `com.acme.api.wp.Meta` from Array value (token `JsonToken.START_ARRAY`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `com.acme.api.wp.Meta` from Array value (token `JsonToken.START_ARRAY`)
 at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.acme.api.wp.Posts["meta"])

Manually changing type from object to array fixes it. But I'm not sure if the schema is wrong or the REST API is returning invalid data.

Change History (14)

#1 @dtrunk90
4 years ago

Still the case for current dev version (5.9)

And it's the same for menu, menu-items and I guess many others which contains a meta "object".

Last edited 4 years ago by dtrunk90 (previous) (diff)

#2 @dtrunk90
4 years ago

  • Summary changed from REST API returns (empty) array for Post Meta but Schema has type object to REST API returns (empty) array for Meta but Schema has type object

#3 @flixos90
13 months ago

  • Milestone changed from Awaiting Review to 6.9
  • Owner set to flixos90
  • Status changed from new to assigned
  • Version changed from 5.8.2 to 4.7

I realize I am finding this ticket very late, but thank you for raising this @dtrunk90!

The type of meta is object, so that's all correct. But the problem is that an empty array in PHP becomes [] when JSON-encoded, it doesn't make a difference whether it's supposed to be a regular (indexed) array ([] in JS/JSON) or an associative array ({} in JS/JSON). So this is certainly a bug.

The workaround is to either use JSON_FORCE_OBJECT when JSON-encoding the data, or transform the empty array to an empty object (e.g. via new stdClass()).

I think the latter fix is what's needed here, since it has to be determined for each specific possibly empty array individually, based on the JSON schema of the data. I'm going to take a closer look at this.

This has been a bug ever since the REST API was introduced, therefore setting the version to 4.7.

This ticket was mentioned in PR #8712 on WordPress/wordpress-develop by @sukhendu2002.


12 months ago
#4

  • Keywords has-patch added

This PR addresses an inconsistency in the WordPress REST API where an empty meta field was returned as [] (empty array), while the API schema specifies it should be {} (empty object). This primarily affects clients consuming the API in the default 'view' context.

The WP_REST_Posts_Controller::prepare_item_for_response() method now checks the request context. It only converts an empty meta array ([]) to an empty object ({}) if $request['context'] === 'view'. For the 'edit' context, it remains [].
The WP_REST_Blocks_Controller::filter_response_by_context() method has been updated to safely access the wp_pattern_sync_status key/property regardless of whether $data['meta'] is an array or an object.

Trac ticket:

This ticket was mentioned in Slack in #core by welcher. View the logs.


6 months ago

#6 @welcher
6 months ago

  • Keywords changes-requested added

This was reviewed in the 6.9 Bug Scrub today. The associated PR has some changes requested.

#7 @wildworks
6 months ago

  • Milestone changed from 6.9 to 7.0

Since the RC1 release is coming soon, I'm punting this ticket to 7.0.

#9 @vishalkakadiya
2 months ago

@wildworks @welcher @flixos90 I have raised a fresh new PR for this, can someone from you review that? Thanks!

https://github.com/WordPress/wordpress-develop/pull/10889

@vishalkakadiya commented on PR #10889:


2 months ago
#10

@westonruter Thank you for reviewing the PR. I have addressed the feedback now.

This ticket was mentioned in Slack in #core-test by nikunj8866. View the logs.


7 weeks ago

#12 @sajib1223
7 weeks ago

Patch Testing Report

Patch Tested: https://github.com/WordPress/wordpress-develop/pull/10889

Environment

  • WordPress: 7.0-beta1-61709-src
  • PHP: 8.2.29
  • Server: nginx/1.29.5
  • Database: mysqli (Server: 8.4.8 / Client: mysqlnd 8.2.29)
  • Browser: Firefox 148.0
  • OS: Windows 10/11
  • Theme: Twenty Twenty-Five 1.4
  • MU Plugins:
  • test-trac-54484.php
  • Plugins:
  • Test Reports 1.2.1

Steps taken

  1. Applied the PR diff on trunk using gh pr diff 10889 | git apply
  2. Created an MU plugin that registers a custom post type book with show_in_rest => true and custom-fields support, but no registered meta fields
  3. Created a sample book post (ID 7) via WP-CLI
  4. Tested http://localhost:8889/wp-json/wp/v2/books/7?_fields=meta with patch — returned {"meta":{}} (empty object)
  5. Reverted the patch using git checkout
  6. Tested the same URL without patch — returned {"meta":[]} (empty array, the bug)
  7. Re-applied the patch and ran PHPUnit tests: WP_Test_REST_Post_Meta_Fields (151 tests, 581 assertions),

WP_Test_REST_Posts_Controller (278 tests, 2627 assertions), REST_Blocks (17 tests, 26 assertions) — all passing

  1. ✅ Patch is solving the problem

Expected result

  • Empty meta field should return {} (JSON object) instead of [] (JSON array), matching the REST API schema type definition of object

Additional Notes

  • Default posts/pages have Gutenberg's footnotes meta registered, so their meta is never truly empty. A custom post type with no registered meta is needed to reproduce the bug.
  • The patch also correctly handles the wp_pattern_sync_status meta in the blocks controller for both array and object

types.

Support Content

MU Plugin used for testing (mu-plugins/test-trac-54484.php):

<?php
add_action( 'init', function () {
    register_post_type(
        'book',
        array(
            'label'        => 'Books',
            'public'       => true,
            'show_in_rest' => true,
            'rest_base'    => 'books',
            'supports'     => array( 'title', 'editor', 'custom-fields' ),
        )
    );
});

This ticket was mentioned in Slack in #core by audrasjb. View the logs.


5 weeks ago

#14 @audrasjb
5 weeks ago

  • Milestone changed from 7.0 to 7.1

As per today's 7.0 pre-RC1 bug scrub:
It's a bit late for this to ship before RC1.
I'm moving it to 7.1, but @flixos90 as ticket owner, if you feel this can ship before RC1 tomorrow, you can of course move it back to 7.0.

Note: See TracTickets for help on using tickets.