Make WordPress Core

Opened 5 months ago

Last modified 3 weeks ago

#65251 new defect (bug)

Response from media library API query includes an empty array rather than an empty object

Reported by: frankieandshadow Owned by:
Priority: normal Milestone: Awaiting Review
Component: REST API Version: 6.9.4
Severity: normal Keywords:
Cc: Focuses:

Description

In the response to a media library query over the REST API, I am seeing that $wpimage->media_details->sizes is an empty array when there are no sizes, rather than an empty object (as a non-empty instance is an object). This discrepancy is inconsistent and breaks my recipient code. It's characteristic of json_encode being used on a keyed PHP array, when it can't tell the difference between keys and numeric indexes when empty.

I asked claude.ai to locate the bug to make it easy for you to fix. It agreed with my diagnosis and said:

File: wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

Method: prepare_item_for_response()

The bug: when wp_get_attachment_metadata() returns metadata with an empty sizes array (image too small for sub-sizes), the method populates $data['media_details'] from that metadata but never explicitly sets $data['media_details']['sizes'] to new stdClass. The else { $data['media_details']['sizes'] = new stdClass; } branch is only reached when $metadata itself is empty/falsy. The result is that sizes is either absent or an empty PHP array [] in the JSON output, rather than {}.

Prior art: reference Trac #51393, which addressed a related inconsistency but didn't fix this code path.

Your fix suggestion: initialise $data['media_details']['sizes'] to new stdClass (or cast with (object)) before the loop that populates it, so the empty case is covered unconditionally.

Change History (2)

#2 @therssoftware
3 weeks ago

Thanks for the ticket!

Testing this against WordPress trunk reveals that $data['media_details']['sizes'] is already initialized as new stdClass() when empty, which correctly encodes to {} in JSON (matching the schema type: "object").

Looking at WP_REST_Attachments_Controller::prepare_item_for_response():

if ( empty( $data['media_details'] ) ) {
    $data['media_details'] = new stdClass();
} elseif ( ! empty( $data['media_details']['sizes'] ) ) {
    // ...
} else {
    $data['media_details']['sizes'] = new stdClass();
}
  1. When $metadata is empty/falsy, if ( empty( $data['media_details'] ) ) is entered and sets $data['media_details'] = new stdClass().
  2. When $metadata contains an empty sizes array (e.g. for small images without sub-sizes), ! empty( $data['media_details']['sizes'] ) evaluates to false, so execution falls directly into the else branch and sets $data['media_details']['sizes'] = new stdClass().
  3. In JSON, new stdClass() encodes to {} (never []).

This behavior was also discussed and verified in #51393.

I have submitted ​PR #13685 with unit tests verifying that both media_details.sizes and media_details consistently return {} when empty to ensure there are no regressions.

Note: See TracTickets for help on using tickets.