diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index 6f12e48ee41f2..b6301f9a2a345 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -1679,6 +1679,7 @@ protected function parse_search_order( &$q ) { * Converts the given orderby alias (if allowed) to a properly-prefixed value. * * @since 4.0.0 + * @since 6.9.0 Extends allowed_keys to support ordering by `post_mime_type`. * * @global wpdb $wpdb WordPress database abstraction object. * @@ -1695,6 +1696,7 @@ protected function parse_orderby( $orderby ) { 'post_date', 'post_title', 'post_modified', + 'post_mime_type', 'post_parent', 'post_type', 'name', @@ -1748,6 +1750,7 @@ protected function parse_orderby( $orderby ) { case 'post_author': case 'post_date': case 'post_title': + case 'post_mime_type': case 'post_modified': case 'post_parent': case 'post_type': diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 1bc0a539a02b4..8f269481e4a78 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -70,6 +70,7 @@ public function register_routes() { * prepares for WP_Query. * * @since 4.7.0 + * @since 6.9.0 Extends the `orderby` request argument to support `mime_type`. * * @param array $prepared_args Optional. Array of prepared arguments. Default empty array. * @param WP_REST_Request $request Optional. Request to prepare items for. @@ -100,6 +101,17 @@ protected function prepare_items_query( $prepared_args = array(), $request = nul add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' ); } + // Map to proper WP_Query orderby param. + if ( isset( $query_args['orderby'], $request['orderby'] ) ) { + $orderby_mappings = array( + 'mime_type' => 'post_mime_type', + ); + + if ( isset( $orderby_mappings[ $request['orderby'] ] ) ) { + $query_args['orderby'] = $orderby_mappings[ $request['orderby'] ]; + } + } + return $query_args; } @@ -1342,6 +1354,7 @@ 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 `orderby` request argument to support `mime_type`. * * @return array Query parameters for the attachment collection as an array. */ @@ -1364,6 +1377,8 @@ public function get_collection_params() { 'type' => 'string', ); + $params['orderby']['enum'][] = 'mime_type'; + return $params; } diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index fb8f1de983fd1..34c731fe13d75 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -2827,4 +2827,69 @@ public function test_edit_image_vertical_flip_only() { // The controller converts the integer values to booleans: 0 !== (int) 1 = true. $this->assertSame( array( true, false ), WP_Image_Editor_Mock::$spy['flip'][0], 'Vertical flip of the image is not identical.' ); } + + /** + * Test that the `orderby` parameter works with the `mime_type` parameter. + * + * @ticket 64073 + */ + public function test_get_items_orderby_mime_type() { + $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', + 'post_excerpt' => 'A sample caption', + ) + ); + + $avif_id = self::factory()->attachment->create_object( + self::$test_avif_file, + 0, + array( + 'post_mime_type' => 'video/avif', + 'post_excerpt' => 'A sample caption', + ) + ); + + $svg_id = self::factory()->attachment->create_object( + self::$test_svg_file, + 0, + array( + 'post_mime_type' => 'image/svg+xml', + 'post_excerpt' => 'A sample caption', + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/media' ); + $request->set_param( '_fields', 'id,mime_type' ); + + // Check ordering. Default ORDER is DESC. + $request->set_param( 'orderby', 'mime_type' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertCount( 4, $data, 'Response count for orderby DESC mime_type is not 4' ); + // Check that ordering is working by verifying the mime types are in order + $mime_types = array_column( $data, 'mime_type' ); + $expected_desc = array( 'video/avif', 'image/svg+xml', 'image/png', 'image/jpeg' ); + $this->assertSame( $expected_desc, $mime_types, 'MIME types not in expected DESC order' ); + + // ASC order. + $request->set_param( 'order', 'asc' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $mime_types = array_column( $data, 'mime_type' ); + $expected_asc = array( 'image/jpeg', 'image/png', 'image/svg+xml', 'video/avif' ); + $this->assertSame( $expected_asc, $mime_types, 'MIME types not in expected ASC order' ); + } } diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 19405f0567924..37ee541c25c17 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -2903,7 +2903,8 @@ mockedApiResponse.Schema = { "relevance", "slug", "include_slugs", - "title" + "title", + "mime_type" ], "required": false },