REST API: Add featured_media field to attachments endpoint.

Audio and video attachments can have a featured image, also known as a poster image. This functionality is now properly exposed by the `wp/v2/media` endpoint.

Props swissspidy, timothyblynjacobs, wonderboymusic, dlh, spacedmonkey.
Fixes #41692.

git-svn-id: https://develop.svn.wordpress.org/trunk@57603 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Pascal Birchler 2024-02-12 22:15:45 +00:00
parent 35feae5c75
commit 54d72c5dee
5 changed files with 149 additions and 2 deletions

View File

@ -171,6 +171,14 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
}
if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
$thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment_id );
if ( is_wp_error( $thumbnail_update ) ) {
return $thumbnail_update;
}
}
if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
$meta_update = $this->meta->update_value( $request['meta'], $attachment_id );
@ -322,6 +330,43 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
);
}
/**
* Determines the featured media based on a request param.
*
* @since 6.5.0
*
* @param int $featured_media Featured Media ID.
* @param int $post_id Post ID.
* @return bool|WP_Error Whether the post thumbnail was successfully deleted, otherwise WP_Error.
*/
protected function handle_featured_media( $featured_media, $post_id ) {
$post_type = get_post_type( $post_id );
$thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' );
// Similar check as in wp_insert_post().
if ( ! $thumbnail_support && get_post_mime_type( $post_id ) ) {
if ( wp_attachment_is( 'audio', $post_id ) ) {
$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
} elseif ( wp_attachment_is( 'video', $post_id ) ) {
$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
}
}
if ( $thumbnail_support ) {
return parent::handle_featured_media( $featured_media, $post_id );
}
return new WP_Error(
'rest_no_featured_media',
sprintf(
/* translators: %s: attachment mime type */
__( 'This site does not support post thumbnails on attachments with MIME type %s.' ),
get_post_mime_type( $post_id )
),
array( 'status' => 400 )
);
}
/**
* Updates a single attachment.
*
@ -355,6 +400,14 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
$attachment = get_post( $request['id'] );
if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
$thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment->ID );
if ( is_wp_error( $thumbnail_update ) ) {
return $thumbnail_update;
}
}
$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
if ( is_wp_error( $fields_update ) ) {

View File

@ -2377,6 +2377,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
'comments',
'revisions',
'custom-fields',
'thumbnail',
),
);

View File

@ -77,7 +77,16 @@ abstract class WP_Test_REST_Post_Type_Controller_Testcase extends WP_Test_REST_C
$this->assertSame( get_page_template_slug( $post->ID ), $data['template'] );
}
if ( post_type_supports( $post->post_type, 'thumbnail' ) ) {
if (
post_type_supports( $post->post_type, 'thumbnail' ) ||
(
'attachment' === $post->post_type &&
(
post_type_supports( 'attachment:audio', 'thumbnail' ) ||
post_type_supports( 'attachment:video', 'thumbnail' )
)
)
) {
$this->assertSame( (int) get_post_thumbnail_id( $post->ID ), $data['featured_media'] );
} else {
$this->assertArrayNotHasKey( 'featured_media', $data );

View File

@ -1067,6 +1067,77 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
$this->assertSame( $category['term_id'], $term[0]->term_id );
}
/**
* @ticket 41692
*/
public function test_create_update_post_with_featured_media() {
// Add support for thumbnails on all attachment types to avoid incorrect-usage notice.
add_post_type_support( 'attachment', 'thumbnail' );
wp_set_current_user( self::$editor_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/media' );
$request->set_file_params(
array(
'file' => array(
'file' => file_get_contents( self::$test_file ),
'name' => 'canola.jpg',
'size' => filesize( self::$test_file ),
'tmp_name' => self::$test_file,
),
)
);
$request->set_header( 'Content-MD5', md5_file( self::$test_file ) );
$file = DIR_TESTDATA . '/images/canola.jpg';
$attachment_id = self::factory()->attachment->create_object(
$file,
0,
array(
'post_mime_type' => 'image/jpeg',
'menu_order' => rand( 1, 100 ),
)
);
$request->set_param( 'featured_media', $attachment_id );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertEquals( 201, $response->get_status() );
$new_attachment = get_post( $data['id'] );
$this->assertEquals( $attachment_id, (int) get_post_thumbnail_id( $new_attachment->ID ) );
$this->assertEquals( $attachment_id, $data['featured_media'] );
$request = new WP_REST_Request( 'PUT', '/wp/v2/media/' . $new_attachment->ID );
$params = $this->set_post_data(
array(
'featured_media' => 0,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( 0, $data['featured_media'] );
$this->assertEquals( 0, (int) get_post_thumbnail_id( $new_attachment->ID ) );
$request = new WP_REST_Request( 'PUT', '/wp/v2/media/' . $new_attachment->ID );
$params = $this->set_post_data(
array(
'featured_media' => $attachment_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( $attachment_id, $data['featured_media'] );
$this->assertEquals( $attachment_id, (int) get_post_thumbnail_id( $new_attachment->ID ) );
}
public function test_update_item() {
wp_set_current_user( self::$editor_id );
$attachment_id = self::factory()->attachment->create_object(
@ -1576,7 +1647,7 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertCount( 27, $properties );
$this->assertCount( 28, $properties );
$this->assertArrayHasKey( 'author', $properties );
$this->assertArrayHasKey( 'alt_text', $properties );
$this->assertArrayHasKey( 'caption', $properties );
@ -1610,6 +1681,7 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
$this->assertArrayHasKey( 'rendered', $properties['title']['properties'] );
$this->assertArrayHasKey( 'type', $properties );
$this->assertArrayHasKey( 'missing_image_sizes', $properties );
$this->assertArrayHasKey( 'featured_media', $properties );
}
public function test_get_additional_field_registration() {

View File

@ -7315,6 +7315,11 @@ mockedApiResponse.Schema = {
"type": "integer",
"required": false
},
"featured_media": {
"description": "The ID of the featured media for the post.",
"type": "integer",
"required": false
},
"comment_status": {
"description": "Whether or not comments are open on the post.",
"type": "string",
@ -7517,6 +7522,11 @@ mockedApiResponse.Schema = {
"type": "integer",
"required": false
},
"featured_media": {
"description": "The ID of the featured media for the post.",
"type": "integer",
"required": false
},
"comment_status": {
"description": "Whether or not comments are open on the post.",
"type": "string",
@ -12693,6 +12703,7 @@ mockedApiResponse.MediaCollection = [
"rendered": "REST API Client Fixture: Attachment"
},
"author": 0,
"featured_media": 0,
"comment_status": "open",
"ping_status": "closed",
"template": "",
@ -12754,6 +12765,7 @@ mockedApiResponse.MediaModel = {
"rendered": "REST API Client Fixture: Attachment"
},
"author": 0,
"featured_media": 0,
"comment_status": "open",
"ping_status": "closed",
"template": "",