Skip to content

Commit ea3620e

Browse files
committed
Media: Skip the edit root link when links are not requested.
A response limited with `_fields` carries no `_links` member unless the request asks for `_links` or `_embedded`, because the posts controller builds no links at all in that case. The edit root link was added outside that check and keyed off the response field, so `_fields=id,edit_root` came back with a `_links` member holding this one link alone, and `_fields=id,_links` came back without it while every other link was there. The link is now gated on the same check the parent controller uses for its own links, and reads the edit root itself rather than the prepared field, so asking for links no longer depends on asking for the field. Follows WordPress/gutenberg#81803. The plugin also treats a bare `_embed` parameter as a request for links. Core does not: `get_fields_for_response()` drops `_embedded` from a `_fields` list that omits it, and core's own links stay out of that response too. See #65987.
1 parent 9ffc69c commit ea3620e

2 files changed

Lines changed: 79 additions & 10 deletions

File tree

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

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,17 +1691,23 @@ public function prepare_item_for_response( $item, $request ) {
16911691
}
16921692

16931693
/*
1694-
* Let clients fetch the edit root in the same request with `_embed`,
1695-
* the way `featured_media` is paired with its own link. Added here rather than in
1696-
* `prepare_links()` because that method cannot see the request, and this belongs
1697-
* in the `edit` context only, alongside the field itself.
1694+
* Embeddable link to the edit root, like `featured_media`. Added here rather than
1695+
* in `prepare_links()`, which cannot see the request, and gated like the parent
1696+
* controller's own links so a `_fields` request is not handed a stray `_links`.
16981697
*/
1699-
if ( ! empty( $data['edit_root'] ) ) {
1700-
$response->add_link(
1701-
'https://api.w.org/edit-root',
1702-
rest_url( rest_get_route_for_post( $data['edit_root'] ) ),
1703-
array( 'embeddable' => true )
1704-
);
1698+
if (
1699+
'edit' === $request['context'] &&
1700+
( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) )
1701+
) {
1702+
$edit_root_id = wp_get_edit_root_attachment_id( $post->ID );
1703+
1704+
if ( $edit_root_id !== (int) $post->ID ) {
1705+
$response->add_link(
1706+
'https://api.w.org/edit-root',
1707+
rest_url( rest_get_route_for_post( $edit_root_id ) ),
1708+
array( 'embeddable' => true )
1709+
);
1710+
}
17051711
}
17061712

17071713
/**

‎tests/phpunit/tests/rest-api/rest-attachments-controller.php‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6485,6 +6485,69 @@ public function test_edit_root_can_be_requested_on_its_own() {
64856485
$this->assertSame( $attachment, $data['edit_root'] );
64866486
}
64876487

6488+
/**
6489+
* Core leaves `_links` out of a response limited with `_fields` by not building
6490+
* its own links at all, so this link must not be the one thing that puts the
6491+
* member back.
6492+
*
6493+
* @ticket 65987
6494+
* @requires function imagejpeg
6495+
*/
6496+
public function test_field_limited_request_omits_the_edit_root_link() {
6497+
wp_set_current_user( self::$superadmin_id );
6498+
$attachment = self::factory()->attachment->create_upload_object( self::$test_file );
6499+
6500+
$edited = $this->edit_image_and_get_new_id( $attachment );
6501+
6502+
$request = new WP_REST_Request( 'GET', "/wp/v2/media/{$edited}" );
6503+
$request->set_param( 'context', 'edit' );
6504+
$request->set_param( '_fields', 'id' );
6505+
$links = rest_do_request( $request )->get_links();
6506+
6507+
$this->assertArrayNotHasKey( 'https://api.w.org/edit-root', $links );
6508+
}
6509+
6510+
/**
6511+
* Asking for the field is not asking for links.
6512+
*
6513+
* @ticket 65987
6514+
* @requires function imagejpeg
6515+
*/
6516+
public function test_requesting_the_edit_root_field_without_links_omits_the_link() {
6517+
wp_set_current_user( self::$superadmin_id );
6518+
$attachment = self::factory()->attachment->create_upload_object( self::$test_file );
6519+
6520+
$edited = $this->edit_image_and_get_new_id( $attachment );
6521+
6522+
$request = new WP_REST_Request( 'GET', "/wp/v2/media/{$edited}" );
6523+
$request->set_param( 'context', 'edit' );
6524+
$request->set_param( '_fields', 'id,edit_root' );
6525+
$links = rest_do_request( $request )->get_links();
6526+
6527+
$this->assertArrayNotHasKey( 'https://api.w.org/edit-root', $links );
6528+
}
6529+
6530+
/**
6531+
* A request that limits the fields but asks for links gets every link, this one
6532+
* included, whether or not it asked for the field.
6533+
*
6534+
* @ticket 65987
6535+
* @requires function imagejpeg
6536+
*/
6537+
public function test_field_limited_request_keeps_the_edit_root_link_when_links_are_requested() {
6538+
wp_set_current_user( self::$superadmin_id );
6539+
$attachment = self::factory()->attachment->create_upload_object( self::$test_file );
6540+
6541+
$edited = $this->edit_image_and_get_new_id( $attachment );
6542+
6543+
$request = new WP_REST_Request( 'GET', "/wp/v2/media/{$edited}" );
6544+
$request->set_param( 'context', 'edit' );
6545+
$request->set_param( '_fields', 'id,_links' );
6546+
$links = rest_do_request( $request )->get_links();
6547+
6548+
$this->assertArrayHasKey( 'https://api.w.org/edit-root', $links );
6549+
}
6550+
64886551
/**
64896552
* An attachment recorded as its own edit root is a broken record, not a chain,
64906553
* so it reports no edit root.

0 commit comments

Comments
 (0)