Skip to content

Commit 92333d1

Browse files
committed
Enhancement: Add support for filtering attachments by multiple media types.
This update introduces a new `media_types` parameter to the WP REST Attachments Controller, allowing users to filter attachment queries by an array of media types. Additionally, the existing `media_type` parameter remains functional, ensuring backward compatibility. `post_mime_type` already supports multiple mime types.
1 parent 70d0050 commit 92333d1

File tree

2 files changed

+156
-2
lines changed

2 files changed

+156
-2
lines changed

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,18 @@ protected function prepare_items_query( $prepared_args = array(), $request = nul
8888
$query_args['post_mime_type'] = $media_types[ $request['media_type'] ];
8989
}
9090

91+
if ( empty( $query_args['post_mime_type'] ) && ! empty( $request['media_types'] ) && is_array( $request['media_types'] ) ) {
92+
$mime_types_query = array();
93+
94+
foreach ( $request['media_types'] as $media_type ) {
95+
if ( isset( $media_types[ $media_type ] ) ) {
96+
$mime_types_query[] = $media_type;
97+
}
98+
}
99+
100+
$query_args['post_mime_type'] = $mime_types_query;
101+
}
102+
91103
if ( ! empty( $request['mime_type'] ) ) {
92104
$parts = explode( '/', $request['mime_type'] );
93105
if ( isset( $media_types[ $parts[0] ] ) && in_array( $request['mime_type'], $media_types[ $parts[0] ], true ) ) {
@@ -1278,20 +1290,31 @@ public static function get_filename_from_disposition( $disposition_header ) {
12781290
* Retrieves the query params for collections of attachments.
12791291
*
12801292
* @since 4.7.0
1293+
* @since 6.6.0 Adds the `media_types` parameter to filter by multiple media types.
12811294
*
12821295
* @return array Query parameters for the attachment collection as an array.
12831296
*/
12841297
public function get_collection_params() {
12851298
$params = parent::get_collection_params();
12861299
$params['status']['default'] = 'inherit';
12871300
$params['status']['items']['enum'] = array( 'inherit', 'private', 'trash' );
1288-
$media_types = $this->get_media_types();
1301+
$media_types = array_keys( $this->get_media_types() );
12891302

12901303
$params['media_type'] = array(
12911304
'default' => null,
12921305
'description' => __( 'Limit result set to attachments of a particular media type.' ),
12931306
'type' => 'string',
1294-
'enum' => array_keys( $media_types ),
1307+
'enum' => $media_types,
1308+
);
1309+
1310+
$params['media_types'] = array(
1311+
'default' => null,
1312+
'description' => __( 'Limit result set to an array of media types.' ),
1313+
'type' => 'array',
1314+
'items' => array(
1315+
'type' => 'string',
1316+
'enum' => $media_types,
1317+
),
12951318
);
12961319

12971320
$params['mime_type'] = array(

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

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
3737
*/
3838
private static $test_svg_file;
3939

40+
/**
41+
* @var string The path to the test video.
42+
*/
43+
private static $test_video_file;
44+
45+
/**
46+
* @var string The path to the test audio.
47+
*/
48+
private static $test_audio_file;
49+
50+
4051
/**
4152
* @var array The recorded posts query clauses.
4253
*/
@@ -85,6 +96,12 @@ public static function wpTearDownAfterClass() {
8596
if ( file_exists( self::$test_avif_file ) ) {
8697
unlink( self::$test_avif_file );
8798
}
99+
if ( file_exists( self::$test_video_file ) ) {
100+
unlink( self::$test_video_file );
101+
}
102+
if ( file_exists( self::$test_audio_file ) ) {
103+
unlink( self::$test_audio_file );
104+
}
88105

89106
self::delete_user( self::$editor_id );
90107
self::delete_user( self::$author_id );
@@ -126,6 +143,18 @@ public function set_up() {
126143
copy( $test_svg_file, self::$test_svg_file );
127144
}
128145

146+
$test_video_file = DIR_TESTDATA . '/uploads/small-video.mp4';
147+
self::$test_video_file = get_temp_dir() . 'small-video.mp4';
148+
if ( ! file_exists( self::$test_video_file ) ) {
149+
copy( $test_video_file, self::$test_video_file );
150+
}
151+
152+
$test_audio_file = DIR_TESTDATA . '/uploads/small-audio.mp3';
153+
self::$test_audio_file = get_temp_dir() . 'small-audio.mp3';
154+
if ( ! file_exists( self::$test_audio_file ) ) {
155+
copy( $test_audio_file, self::$test_audio_file );
156+
}
157+
129158
add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
130159
add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
131160
}
@@ -242,6 +271,7 @@ public function test_registered_query_params() {
242271
'exclude',
243272
'include',
244273
'media_type',
274+
'media_types',
245275
'mime_type',
246276
'modified_after',
247277
'modified_before',
@@ -2640,4 +2670,105 @@ public function test_upload_svg_image() {
26402670

26412671
$this->assertTrue( $result );
26422672
}
2673+
2674+
/**
2675+
* @ticket ??????
2676+
*/
2677+
public function test_get_items_with_media_types() {
2678+
$video_id = self::factory()->attachment->create_object(
2679+
self::$test_video_file,
2680+
0,
2681+
array(
2682+
'post_mime_type' => 'video/mp4',
2683+
'post_excerpt' => 'A sample caption',
2684+
)
2685+
);
2686+
2687+
$audio_id = self::factory()->attachment->create_object(
2688+
self::$test_audio_file,
2689+
0,
2690+
array(
2691+
'post_mime_type' => 'audio/mpeg',
2692+
'post_excerpt' => 'A sample caption',
2693+
)
2694+
);
2695+
2696+
$image_id = self::factory()->attachment->create_object(
2697+
self::$test_file,
2698+
0,
2699+
array(
2700+
'post_mime_type' => 'image/jpeg',
2701+
'post_excerpt' => 'A sample caption',
2702+
)
2703+
);
2704+
2705+
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
2706+
$request->set_param( 'media_types', array( 'audio', 'video' ) );
2707+
$response = rest_get_server()->dispatch( $request );
2708+
$this->assertCount( 2, $response->get_data() );
2709+
$this->assertContains( $video_id, wp_list_pluck( $response->get_data(), 'id' ), 'Video ID not found in response for [audio, video]' );
2710+
$this->assertContains( $audio_id, wp_list_pluck( $response->get_data(), 'id' ), 'Audio ID not found in response for [audio, video]' );
2711+
2712+
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
2713+
$request->set_param( 'media_types', array( 'image' ) );
2714+
$response = rest_get_server()->dispatch( $request );
2715+
$this->assertCount( 1, $response->get_data() );
2716+
$this->assertContains( $image_id, wp_list_pluck( $response->get_data(), 'id' ), 'Image ID not found in response for [image]' );
2717+
2718+
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
2719+
$request->set_param( 'media_types', array( 'image', 'audio' ) );
2720+
$response = rest_get_server()->dispatch( $request );
2721+
$this->assertCount( 2, $response->get_data() );
2722+
$this->assertContains( $image_id, wp_list_pluck( $response->get_data(), 'id' ), 'Image ID not found in response for [image, audio]' );
2723+
$this->assertContains( $audio_id, wp_list_pluck( $response->get_data(), 'id' ), 'Audio ID not found in response for [image, audio]' );
2724+
2725+
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
2726+
$request->set_param( 'media_types', array( 'image', 'video', 'audio' ) );
2727+
$response = rest_get_server()->dispatch( $request );
2728+
$this->assertCount( 3, $response->get_data() );
2729+
$this->assertContains( $image_id, wp_list_pluck( $response->get_data(), 'id' ), 'Image ID not found in response for [image, video, audio]' );
2730+
$this->assertContains( $video_id, wp_list_pluck( $response->get_data(), 'id' ), 'Video ID not found in response for [image, video, audio]' );
2731+
$this->assertContains( $audio_id, wp_list_pluck( $response->get_data(), 'id' ), 'Audio ID not found in response for [image, video, audio]' );
2732+
}
2733+
2734+
/**
2735+
* Test that the `media_type` parameter overrides the `media_types` parameter.
2736+
*
2737+
* @ticket ??????
2738+
*/
2739+
public function test_get_items_with_media_type_and_media_types() {
2740+
self::factory()->attachment->create_object(
2741+
self::$test_video_file,
2742+
0,
2743+
array(
2744+
'post_mime_type' => 'video/mp4',
2745+
'post_excerpt' => 'A sample caption',
2746+
)
2747+
);
2748+
2749+
self::factory()->attachment->create_object(
2750+
self::$test_audio_file,
2751+
0,
2752+
array(
2753+
'post_mime_type' => 'audio/mpeg',
2754+
'post_excerpt' => 'A sample caption',
2755+
)
2756+
);
2757+
2758+
$image_id = self::factory()->attachment->create_object(
2759+
self::$test_file,
2760+
0,
2761+
array(
2762+
'post_mime_type' => 'image/jpeg',
2763+
'post_excerpt' => 'A sample caption',
2764+
)
2765+
);
2766+
2767+
$request = new WP_REST_Request( 'GET', '/wp/v2/media' );
2768+
$request->set_param( 'media_types', array( 'audio', 'video' ) );
2769+
$request->set_param( 'media_type', 'image' );
2770+
$response = rest_get_server()->dispatch( $request );
2771+
$this->assertCount( 1, $response->get_data() );
2772+
$this->assertContains( $image_id, wp_list_pluck( $response->get_data(), 'id' ), 'Image ID not found in response' );
2773+
}
26432774
}

0 commit comments

Comments
 (0)