Skip to content

Commit cb8b288

Browse files
REST API: Add tests for the sideload convert_format boolean arg.
Backport of Gutenberg PR #77565. The convert_format boolean arg on the sideload route is already present in core (it was included when client-side media processing was reintroduced), so this backport adds the test coverage from the Gutenberg PR: - test_sideload_route_declares_convert_format_boolean asserts the route schema declares convert_format as a boolean defaulting to true. - test_sideload_convert_format_false_suppresses_alt_ext_suffix verifies that passing convert_format as the string "false" (multipart/form-data semantics) coerces to PHP false, suppressing the image_editor_output_format filter so a companion file sharing the attachment basename is not given a numeric suffix.
1 parent 9fd5b2e commit cb8b288

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

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

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,4 +3805,96 @@ public function test_sideload_image_size_invalid() {
38053805

38063806
$this->assertSame( 400, $response->get_status(), 'An unknown size name should be rejected.' );
38073807
}
3808+
3809+
/**
3810+
* Tests that the sideload route declares `convert_format` as a boolean arg.
3811+
*
3812+
* Without this declaration, multipart/form-data requests deliver the value as
3813+
* a string ("false") which evaluates truthy in PHP, so the sideload handler's
3814+
* `if ( ! $request['convert_format'] )` check never fires and the
3815+
* `image_editor_output_format` filter is never suppressed - meaning the
3816+
* server still performs the format conversion the client opted out of.
3817+
*
3818+
* @ticket 64737
3819+
* @covers WP_REST_Attachments_Controller::register_routes
3820+
*/
3821+
public function test_sideload_route_declares_convert_format_boolean() {
3822+
$this->enable_client_side_media_processing();
3823+
3824+
$routes = rest_get_server()->get_routes();
3825+
$endpoint = '/wp/v2/media/(?P<id>[\d]+)/sideload';
3826+
$this->assertArrayHasKey( $endpoint, $routes, 'Sideload route should exist.' );
3827+
3828+
$args = $routes[ $endpoint ][0]['args'];
3829+
3830+
$this->assertArrayHasKey( 'convert_format', $args, 'Route should declare convert_format.' );
3831+
$this->assertSame( 'boolean', $args['convert_format']['type'], 'convert_format should be a boolean.' );
3832+
$this->assertTrue( $args['convert_format']['default'], 'convert_format should default to true.' );
3833+
}
3834+
3835+
/**
3836+
* Tests that sideloading with `convert_format=false` (sent as the string
3837+
* "false", matching multipart/form-data semantics) suppresses the
3838+
* alt-extension collision check in `wp_unique_filename()`, so a companion
3839+
* file sharing the attachment basename does not get a numeric suffix.
3840+
*
3841+
* Mirrors the HEIC companion upload flow: a JPEG derivative is created via
3842+
* the media endpoint, then the original is sideloaded under the same stem.
3843+
* Without the arg declared as boolean, "false" coerces truthy, the filter
3844+
* is never added, and the companion is bumped to `-1` while the JPEG stays
3845+
* unsuffixed. PNG stands in for HEIC because core's default
3846+
* `image_editor_output_format` only maps HEIC/HEIF to JPEG; a local filter
3847+
* adds a PNG to JPEG mapping to trigger the same alt-ext check.
3848+
*
3849+
* @ticket 64737
3850+
* @covers WP_REST_Attachments_Controller::sideload_item
3851+
* @covers WP_REST_Attachments_Controller::register_routes
3852+
* @requires function imagejpeg
3853+
*/
3854+
public function test_sideload_convert_format_false_suppresses_alt_ext_suffix() {
3855+
$this->enable_client_side_media_processing();
3856+
3857+
wp_set_current_user( self::$author_id );
3858+
3859+
// Upload a JPEG "parent" attachment the way client-side uploads do.
3860+
$request = new WP_REST_Request( 'POST', '/wp/v2/media' );
3861+
$request->set_header( 'Content-Type', 'image/jpeg' );
3862+
$request->set_header( 'Content-Disposition', 'attachment; filename=heic-companion.jpg' );
3863+
$request->set_param( 'generate_sub_sizes', false );
3864+
$request->set_body( (string) file_get_contents( self::$test_file ) );
3865+
3866+
$response = rest_get_server()->dispatch( $request );
3867+
$attachment_id = $response->get_data()['id'];
3868+
$this->assertSame( 201, $response->get_status() );
3869+
3870+
// Simulate an alt-ext conversion mapping so an alt-extension companion
3871+
// (PNG here, HEIC in production) would otherwise get a `-1` suffix.
3872+
$add_png_mapping = static function ( $formats ) {
3873+
$formats['image/png'] = 'image/jpeg';
3874+
return $formats;
3875+
};
3876+
add_filter( 'image_editor_output_format', $add_png_mapping, 5 );
3877+
3878+
// Sideload a companion sharing the same basename. Pass convert_format as
3879+
// the string "false" to match multipart/form-data request semantics.
3880+
$request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" );
3881+
$request->set_header( 'Content-Type', 'image/png' );
3882+
$request->set_header( 'Content-Disposition', 'attachment; filename=heic-companion.png' );
3883+
$request->set_param( 'image_size', 'original' );
3884+
$request->set_param( 'convert_format', 'false' );
3885+
$request->set_body( (string) file_get_contents( DIR_TESTDATA . '/images/one-blue-pixel-100x100.png' ) );
3886+
3887+
$response = rest_get_server()->dispatch( $request );
3888+
3889+
remove_filter( 'image_editor_output_format', $add_png_mapping, 5 );
3890+
3891+
$this->assertSame( 200, $response->get_status() );
3892+
3893+
$data = $response->get_data();
3894+
$this->assertSame(
3895+
'heic-companion.png',
3896+
$data['file'],
3897+
'Companion file should share the attachment basename without a numeric suffix.'
3898+
);
3899+
}
38083900
}

0 commit comments

Comments
 (0)