Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public function register_routes() {
* prepares for WP_Query.
*
* @since 4.7.0
* @since 6.9.0 Extends the `media_type` and `mime_type` request arguments to support array values.
*
* @param array $prepared_args Optional. Array of prepared arguments. Default empty array.
* @param WP_REST_Request $request Optional. Request to prepare items for.
Expand All @@ -82,19 +83,30 @@ protected function prepare_items_query( $prepared_args = array(), $request = nul
$query_args['post_status'] = 'inherit';
}

$media_types = $this->get_media_types();
$all_mime_types = array();
$media_types = $this->get_media_types();

if ( ! empty( $request['media_type'] ) && isset( $media_types[ $request['media_type'] ] ) ) {
$query_args['post_mime_type'] = $media_types[ $request['media_type'] ];
if ( ! empty( $request['media_type'] ) && is_array( $request['media_type'] ) ) {
foreach ( $request['media_type'] as $type ) {
if ( isset( $media_types[ $type ] ) ) {
$all_mime_types = array_merge( $all_mime_types, $media_types[ $type ] );
}
}
}

if ( ! empty( $request['mime_type'] ) ) {
$parts = explode( '/', $request['mime_type'] );
if ( isset( $media_types[ $parts[0] ] ) && in_array( $request['mime_type'], $media_types[ $parts[0] ], true ) ) {
$query_args['post_mime_type'] = $request['mime_type'];
if ( ! empty( $request['mime_type'] ) && is_array( $request['mime_type'] ) ) {
foreach ( $request['mime_type'] as $mime_type ) {
$parts = explode( '/', $mime_type );
if ( isset( $media_types[ $parts[0] ] ) && in_array( $mime_type, $media_types[ $parts[0] ], true ) ) {
$all_mime_types[] = $mime_type;
}
}
}

if ( ! empty( $all_mime_types ) ) {
$query_args['post_mime_type'] = array_values( array_unique( $all_mime_types ) );
}

// Filter query clauses to include filenames.
if ( isset( $query_args['s'] ) ) {
add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
Expand Down Expand Up @@ -1342,26 +1354,33 @@ public static function get_filename_from_disposition( $disposition_header ) {
* Retrieves the query params for collections of attachments.
*
* @since 4.7.0
* @since 6.9.0 Extends the `media_type` and `mime_type` request arguments to support array values.
*
* @return array Query parameters for the attachment collection as an array.
*/
public function get_collection_params() {
$params = parent::get_collection_params();
$params['status']['default'] = 'inherit';
$params['status']['items']['enum'] = array( 'inherit', 'private', 'trash' );
$media_types = $this->get_media_types();
$media_types = array_keys( $this->get_media_types() );

$params['media_type'] = array(
'default' => null,
'description' => __( 'Limit result set to attachments of a particular media type.' ),
'type' => 'string',
'enum' => array_keys( $media_types ),
'description' => __( 'Limit result set to attachments of a particular media type or media types.' ),
'type' => 'array',
'items' => array(
'type' => 'string',
'enum' => $media_types,
),
);

$params['mime_type'] = array(
'default' => null,
'description' => __( 'Limit result set to attachments of a particular MIME type.' ),
'type' => 'string',
'description' => __( 'Limit result set to attachments of a particular MIME type or MIME types.' ),
'type' => 'array',
'items' => array(
'type' => 'string',
),
);

return $params;
Expand Down
272 changes: 271 additions & 1 deletion tests/phpunit/tests/rest-api/rest-attachments-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
*/
private static $test_svg_file;

/**
* @var string The path to the test video.
*/
private static $test_video_file;

/**
* @var string The path to the test audio.
*/
private static $test_audio_file;

/**
* @var string The path to the test RTF file.
*/
private static $test_rtf_file;

/**
* @var array The recorded posts query clauses.
*/
Expand Down Expand Up @@ -85,6 +100,15 @@ public static function wpTearDownAfterClass() {
if ( file_exists( self::$test_avif_file ) ) {
unlink( self::$test_avif_file );
}
if ( file_exists( self::$test_video_file ) ) {
unlink( self::$test_video_file );
}
if ( file_exists( self::$test_audio_file ) ) {
unlink( self::$test_audio_file );
}
if ( file_exists( self::$test_rtf_file ) ) {
unlink( self::$test_rtf_file );
}

self::delete_user( self::$editor_id );
self::delete_user( self::$author_id );
Expand Down Expand Up @@ -126,6 +150,24 @@ public function set_up() {
copy( $test_svg_file, self::$test_svg_file );
}

$test_video_file = DIR_TESTDATA . '/uploads/small-video.mp4';
self::$test_video_file = get_temp_dir() . 'small-video.mp4';
if ( ! file_exists( self::$test_video_file ) ) {
copy( $test_video_file, self::$test_video_file );
}

$test_audio_file = DIR_TESTDATA . '/uploads/small-audio.mp3';
self::$test_audio_file = get_temp_dir() . 'small-audio.mp3';
if ( ! file_exists( self::$test_audio_file ) ) {
copy( $test_audio_file, self::$test_audio_file );
}

$test_rtf_file = DIR_TESTDATA . '/uploads/test.rtf';
self::$test_rtf_file = get_temp_dir() . 'test.rtf';
if ( ! file_exists( self::$test_rtf_file ) ) {
copy( $test_rtf_file, self::$test_rtf_file );
}

add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
}
Expand Down Expand Up @@ -267,7 +309,7 @@ public function test_registered_query_params() {
'audio',
'text',
);
$this->assertSameSets( $media_types, $data['endpoints'][0]['args']['media_type']['enum'] );
$this->assertSameSets( $media_types, $data['endpoints'][0]['args']['media_type']['items']['enum'] );
}

public function test_registered_get_item_params() {
Expand Down Expand Up @@ -418,6 +460,233 @@ public function test_get_items_media_type() {
$this->assertSame( $id1, $data[0]['id'] );
}

/**
* Test multiple media types support with various input formats.
*
* @ticket 63668
*/
public function test_get_items_multiple_media_types() {
$image_id = self::factory()->attachment->create_object(
self::$test_file,
0,
array(
'post_mime_type' => 'image/jpeg',
)
);

$video_id = self::factory()->attachment->create_object(
self::$test_video_file,
0,
array(
'post_mime_type' => 'video/mp4',
)
);

$audio_id = self::factory()->attachment->create_object(
self::$test_audio_file,
0,
array(
'post_mime_type' => 'audio/mpeg',
)
);

$request = new WP_REST_Request( 'GET', '/wp/v2/media' );

// Test single media type.
$request->set_param( 'media_type', 'image' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 1, $data, 'Response count for single media type is not 1' );
$this->assertSame( $image_id, $data[0]['id'], 'Image ID not found in response for single media type' );

// Test multiple media types with comma-separated string.
$request->set_param( 'media_type', 'image,video' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 2, $data, 'Response count for multiple media types with comma-separated string is not 2' );
$ids = wp_list_pluck( $data, 'id' );
$this->assertContains( $image_id, $ids, 'Image ID not found in response for multiple media types with comma-separated string' );
$this->assertContains( $video_id, $ids, 'Video ID not found in response for multiple media types with comma-separated string' );
$this->assertNotContains( $audio_id, $ids, 'Audio ID found in response for multiple media types with comma-separated string' );

// Test multiple media types with array format.
$request->set_param( 'media_type', array( 'image', 'video', 'audio' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 3, $data, 'Response count for multiple media types with array format is not 3' );
$ids = wp_list_pluck( $data, 'id' );
$this->assertContains( $image_id, $ids, 'Image ID not found in response for multiple media types with array format' );
$this->assertContains( $video_id, $ids, 'Video ID not found in response for multiple media types with array format' );
$this->assertContains( $audio_id, $ids, 'Audio ID not found in response for multiple media types with array format' );

// Test invalid media type mixed with valid ones.
$request->set_param( 'media_type', 'image,invalid,video' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
}

/**
* Test multiple MIME types support and combination with media types.
*
* @ticket 63668
*/
public function test_get_items_multiple_mime_types_and_combination() {
$jpeg_id = self::factory()->attachment->create_object(
self::$test_file,
0,
array(
'post_mime_type' => 'image/jpeg',
)
);

$png_id = self::factory()->attachment->create_object(
self::$test_file2,
0,
array(
'post_mime_type' => 'image/png',
)
);

$mp4_id = self::factory()->attachment->create_object(
self::$test_video_file,
0,
array(
'post_mime_type' => 'video/mp4',
)
);

$request = new WP_REST_Request( 'GET', '/wp/v2/media' );

// Test single MIME type
$request->set_param( 'mime_type', 'image/jpeg' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 1, $data, 'Response count for single MIME type is not 1' );
$this->assertSame( $jpeg_id, $data[0]['id'], 'JPEG ID not found in response for single MIME type' );

// Test multiple MIME types with comma-separated string.
$request->set_param( 'mime_type', 'image/jpeg,image/png' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 2, $data, 'Response count for multiple MIME types with comma-separated string is not 2' );
$ids = wp_list_pluck( $data, 'id' );
$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response for multiple MIME types with comma-separated string' );
$this->assertContains( $png_id, $ids, 'PNG ID not found in response for multiple MIME types with comma-separated string' );

// Test multiple MIME types with array format.
$request->set_param( 'mime_type', array( 'image/jpeg', 'video/mp4' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertCount( 2, $data, 'Response count for multiple MIME types with array format is not 2' );
$ids = wp_list_pluck( $data, 'id' );

$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response for multiple MIME types with array format' );
$this->assertContains( $mp4_id, $ids, 'MP4 ID not found in response for multiple MIME types with array format' );
}

/**
* Test combination of media type and mime type parameters.
*
* @ticket 63668
*/
public function test_get_items_with_media_type_and_media_types() {
$audio_id = self::factory()->attachment->create_object(
self::$test_audio_file,
0,
array(
'post_mime_type' => 'audio/mpeg',
'post_excerpt' => 'A sample caption',
)
);

$jpeg_id = self::factory()->attachment->create_object(
self::$test_file,
0,
array(
'post_mime_type' => 'image/jpeg',
'post_excerpt' => 'A sample caption',
)
);

$png_id = self::factory()->attachment->create_object(
self::$test_file2,
0,
array(
'post_mime_type' => 'image/png',
)
);

$video_id = self::factory()->attachment->create_object(
self::$test_video_file,
0,
array(
'post_mime_type' => 'video/mp4',
)
);

$rtf_id = self::factory()->attachment->create_object(
self::$test_rtf_file,
0,
array(
'post_mime_type' => 'application/rtf',
)
);

// Test combination of single media type and single mime type parameters.
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
$request->set_param( 'media_type', 'image' );
$request->set_param( 'mime_type', 'audio/mpeg' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$ids = wp_list_pluck( $data, 'id' );

$this->assertCount( 3, $data, 'Response count for combination of single media type and single mime type parameters is not 3' );
$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response' );
$this->assertContains( $png_id, $ids, 'PNG ID not found in response' );
$this->assertContains( $audio_id, $ids, 'Audio ID found in response' );

// Test combination of single media type and multiple mime type parameters.
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
$request->set_param( 'media_type', 'audio' );
$request->set_param( 'mime_type', array( 'image/jpeg', 'image/png' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$ids = wp_list_pluck( $data, 'id' );

$this->assertCount( 3, $data, 'Response count for combination of single media type and multiple mime type parameters is not 3' );
$this->assertContains( $audio_id, $ids, 'Audio ID not found in response' );
$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response' );
$this->assertContains( $png_id, $ids, 'PNG ID not found in response' );

// Test combination of multiple media types and single mime type parameters.
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
$request->set_param( 'media_type', 'audio,video' );
$request->set_param( 'mime_type', array( 'image/jpeg' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$ids = wp_list_pluck( $data, 'id' );

$this->assertCount( 3, $data, 'Response count for combination of multiple media type and multiple mime type parameters is not 3' );
$this->assertContains( $audio_id, $ids, 'Audio ID not found in response' );
$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response' );
$this->assertContains( $video_id, $ids, 'Video ID not found in response' );

// Test combination of multiple media types and multiple mime type parameters.
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
$request->set_param( 'media_type', 'audio,video' );
$request->set_param( 'mime_type', array( 'image/jpeg', 'image/png', 'application/rtf' ) );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$ids = wp_list_pluck( $data, 'id' );

$this->assertCount( 5, $data, 'Response count for combination of multiple media type and multiple mime type parameters is not 3' );
$this->assertContains( $audio_id, $ids, 'Audio ID not found in response' );
$this->assertContains( $jpeg_id, $ids, 'JPEG ID not found in response' );
$this->assertContains( $video_id, $ids, 'Video ID not found in response' );
$this->assertContains( $png_id, $ids, 'PNG ID not found in response' );
$this->assertContains( $rtf_id, $ids, 'RTF ID not found in response' );
}

public function test_get_items_mime_type() {
$id1 = self::factory()->attachment->create_object(
self::$test_file,
Expand Down Expand Up @@ -2685,6 +2954,7 @@ public function test_upload_svg_image() {

/**
* Tests that the attachment fields caption, description, and title, post and alt_text are updated correctly.
*
* @ticket 64035
* @requires function imagejpeg
*/
Expand Down
Loading
Loading