Skip to content

Commit 00738dc

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 93c823b commit 00738dc

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
@@ -3804,4 +3804,96 @@ public function test_sideload_image_size_invalid() {
38043804

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

0 commit comments

Comments
 (0)