diff --git a/Gruntfile.js b/Gruntfile.js
index 9a35f61e79496..c925a4f567227 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -659,9 +659,7 @@ module.exports = function(grunt) {
src: [
'**/*',
'!**/*.map',
- // Skip non-minified VIPS files — they are ~16MB of inlined WASM
- // with no debugging value over the minified versions.
- '!vips/!(*.min).js',
+ '!vips/**',
],
dest: WORKING_DIR + 'wp-includes/js/dist/script-modules/',
} ],
diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php
index a1c2e4d93df87..4b6d9de25fa11 100644
--- a/src/wp-includes/default-filters.php
+++ b/src/wp-includes/default-filters.php
@@ -678,13 +678,6 @@
add_action( 'plugins_loaded', '_wp_add_additional_image_sizes', 0 );
add_filter( 'plupload_default_settings', 'wp_show_heic_upload_error' );
-// Client-side media processing.
-add_action( 'admin_init', 'wp_set_client_side_media_processing_flag' );
-// Cross-origin isolation for client-side media processing.
-add_action( 'load-post.php', 'wp_set_up_cross_origin_isolation' );
-add_action( 'load-post-new.php', 'wp_set_up_cross_origin_isolation' );
-add_action( 'load-site-editor.php', 'wp_set_up_cross_origin_isolation' );
-add_action( 'load-widgets.php', 'wp_set_up_cross_origin_isolation' );
// Nav menu.
add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
add_filter( 'nav_menu_css_class', 'wp_nav_menu_remove_menu_item_has_children_class', 10, 4 );
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php
index bc887bafd1197..5fb6b5d894d9b 100644
--- a/src/wp-includes/media-template.php
+++ b/src/wp-includes/media-template.php
@@ -156,12 +156,6 @@ class="wp-video-shortcode {{ classes.join( ' ' ) }}"
function wp_print_media_templates() {
$class = 'media-modal wp-core-ui';
- $is_cross_origin_isolation_enabled = wp_is_client_side_media_processing_enabled();
-
- if ( $is_cross_origin_isolation_enabled ) {
- ob_start();
- }
-
$alt_text_description = sprintf(
/* translators: 1: Link to tutorial, 2: Additional link attributes, 3: Accessibility text. */
__( 'Learn how to describe the purpose of the image%3$s. Leave empty if the image is purely decorative.' ),
@@ -1588,42 +1582,4 @@ function wp_print_media_templates() {
* @since 3.5.0
*/
do_action( 'print_media_templates' );
-
- if ( $is_cross_origin_isolation_enabled ) {
- $html = (string) ob_get_clean();
-
- /*
- * The media templates are inside ',
- ),
- 'cross-origin audio' => array(
- '',
- ),
- 'cross-origin video' => array(
- '',
- ),
- 'cross-origin link stylesheet' => array(
- '',
- ),
- 'cross-origin source inside video' => array(
- '',
- ),
- );
- }
-
- /**
- * Verifies that certain elements do not get crossorigin="anonymous" added.
- *
- * Images are excluded because under Document-Isolation-Policy:
- * isolate-and-credentialless, the browser handles cross-origin images
- * in credentialless mode without needing explicit CORS headers.
- *
- * @ticket 64766
- *
- * @runInSeparateProcess
- * @preserveGlobalState disabled
- *
- * @dataProvider data_elements_that_should_not_get_crossorigin
- *
- * @param string $html HTML input to process.
- */
- public function test_output_buffer_does_not_add_crossorigin( $html ) {
- $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
-
- ob_start();
-
- wp_start_cross_origin_isolation_output_buffer();
- echo $html;
-
- ob_end_flush();
- $output = ob_get_clean();
-
- $this->assertStringNotContainsString( 'crossorigin="anonymous"', $output );
- }
-
- /**
- * Data provider for elements that should not receive crossorigin="anonymous".
- *
- * @return array[]
- */
- public function data_elements_that_should_not_get_crossorigin() {
- return array(
- 'cross-origin img' => array(
- '
',
- ),
- 'cross-origin img with srcset' => array(
- '
',
- ),
- 'link with cross-origin imagesrcset only' => array(
- '',
- ),
- 'relative URL script' => array(
- '',
- ),
- );
- }
-
- /**
- * Same-origin URLs should not get crossorigin="anonymous".
- *
- * Uses site_url() at runtime since the test domain varies by CI config.
- *
- * @ticket 64766
- *
- * @runInSeparateProcess
- * @preserveGlobalState disabled
- */
- public function test_output_buffer_does_not_add_crossorigin_to_same_origin() {
- $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
-
- ob_start();
-
- wp_start_cross_origin_isolation_output_buffer();
- echo '';
-
- ob_end_flush();
- $output = ob_get_clean();
-
- $this->assertStringNotContainsString( 'crossorigin="anonymous"', $output );
- }
-
- /**
- * Elements that already have a crossorigin attribute should not be modified.
- *
- * @ticket 64766
- *
- * @runInSeparateProcess
- * @preserveGlobalState disabled
- */
- public function test_output_buffer_does_not_override_existing_crossorigin() {
- $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
-
- ob_start();
-
- wp_start_cross_origin_isolation_output_buffer();
- echo '';
-
- ob_end_flush();
- $output = ob_get_clean();
-
- $this->assertStringContainsString( 'crossorigin="use-credentials"', $output, 'Existing crossorigin attribute should not be overridden.' );
- $this->assertStringNotContainsString( 'crossorigin="anonymous"', $output );
- }
-
- /**
- * Multiple tags in the same output should each be handled correctly.
- *
- * @ticket 64766
- *
- * @runInSeparateProcess
- * @preserveGlobalState disabled
- */
- public function test_output_buffer_handles_mixed_tags() {
- $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36';
-
- ob_start();
-
- wp_start_cross_origin_isolation_output_buffer();
- echo '
';
- echo '';
- echo '';
-
- ob_end_flush();
- $output = ob_get_clean();
-
- // IMG should NOT have crossorigin.
- $this->assertStringContainsString( '
', $output, 'IMG should not be modified.' );
-
- // Script and audio should have crossorigin.
- $this->assertSame( 2, substr_count( $output, 'crossorigin="anonymous"' ), 'Script and audio should both get crossorigin, but not img.' );
- }
-}
diff --git a/tests/phpunit/tests/media/wpGetChromiumMajorVersion.php b/tests/phpunit/tests/media/wpGetChromiumMajorVersion.php
deleted file mode 100644
index 7249d9b91b665..0000000000000
--- a/tests/phpunit/tests/media/wpGetChromiumMajorVersion.php
+++ /dev/null
@@ -1,69 +0,0 @@
-original_user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : null;
- }
-
- public function tear_down() {
- if ( null === $this->original_user_agent ) {
- unset( $_SERVER['HTTP_USER_AGENT'] );
- } else {
- $_SERVER['HTTP_USER_AGENT'] = $this->original_user_agent;
- }
- parent::tear_down();
- }
-
- /**
- * @ticket 64766
- */
- public function test_returns_null_when_no_user_agent() {
- unset( $_SERVER['HTTP_USER_AGENT'] );
- $this->assertNull( wp_get_chromium_major_version() );
- }
-
- /**
- * @ticket 64766
- *
- * @dataProvider data_user_agents
- *
- * @param string $user_agent The user agent string.
- * @param int|null $expected The expected Chromium major version, or null.
- */
- public function test_returns_expected_version( $user_agent, $expected ) {
- $_SERVER['HTTP_USER_AGENT'] = $user_agent;
- $this->assertSame( $expected, wp_get_chromium_major_version() );
- }
-
- /**
- * Data provider for test_returns_expected_version.
- *
- * @return array[]
- */
- public function data_user_agents() {
- return array(
- 'empty user agent' => array( '', null ),
- 'Firefox' => array( 'Mozilla/5.0 (Windows NT 10.0; rv:128.0) Gecko/20100101 Firefox/128.0', null ),
- 'Safari' => array( 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15', null ),
- 'Chrome 137' => array( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', 137 ),
- 'Edge 137' => array( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0', 137 ),
- 'Opera (Chrome 136)' => array( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 OPR/122.0.0.0', 136 ),
- 'Chrome 100' => array( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36', 100 ),
- );
- }
-}
diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php
index 79e9d23cf9dd3..c8746931ed30a 100644
--- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php
+++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php
@@ -194,18 +194,6 @@ public function tear_down() {
parent::tear_down();
}
- /**
- * Enables client-side media processing and reinitializes the REST server
- * so that the sideload and finalize routes are registered.
- */
- private function enable_client_side_media_processing(): void {
- add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
-
- global $wp_rest_server;
- $wp_rest_server = new Spy_REST_Server();
- do_action( 'rest_api_init', $wp_rest_server );
- }
-
public function test_register_routes() {
$routes = rest_get_server()->get_routes();
$this->assertArrayHasKey( '/wp/v2/media', $routes );
@@ -2941,43 +2929,6 @@ public function test_upload_unsupported_image_type_with_filter() {
$this->assertSame( 201, $response->get_status() );
}
- /**
- * Test that unsupported image type check is skipped when not generating sub-sizes.
- *
- * When the client handles image processing (generate_sub_sizes is false),
- * the server should not check image editor support.
- *
- * Tests the permissions check directly with file params set, since the core
- * check uses get_file_params() which is only populated for multipart uploads.
- *
- * @ticket 64836
- */
- public function test_upload_unsupported_image_type_skipped_when_not_generating_sub_sizes() {
- wp_set_current_user( self::$author_id );
-
- add_filter( 'wp_image_editors', '__return_empty_array' );
-
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_file_params(
- array(
- 'file' => array(
- 'name' => 'avif-lossy.avif',
- 'type' => 'image/avif',
- 'tmp_name' => self::$test_avif_file,
- 'error' => 0,
- 'size' => filesize( self::$test_avif_file ),
- ),
- )
- );
- $request->set_param( 'generate_sub_sizes', false );
-
- $controller = new WP_REST_Attachments_Controller( 'attachment' );
- $result = $controller->create_item_permissions_check( $request );
-
- // Should pass because generate_sub_sizes is false (client handles processing).
- $this->assertTrue( $result );
- }
-
/**
* Test that unsupported image type check is enforced when generating sub-sizes.
*
@@ -3240,305 +3191,4 @@ static function ( $data ) use ( &$captured_data ) {
// Verify that the data is an array (not an object).
$this->assertIsArray( $captured_data, 'Data passed to wp_insert_attachment should be an array' );
}
-
- /**
- * Tests sideloading a scaled image for an existing attachment.
- *
- * @ticket 64737
- * @requires function imagejpeg
- */
- public function test_sideload_scaled_image() {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // First, create an attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $data = $response->get_data();
- $attachment_id = $data['id'];
-
- $this->assertSame( 201, $response->get_status() );
-
- $original_file = get_attached_file( $attachment_id, true );
-
- // Sideload a "scaled" version of the image.
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola-scaled.jpg' );
- $request->set_param( 'image_size', 'scaled' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertSame( 200, $response->get_status(), 'Sideloading scaled image should succeed.' );
-
- $metadata = wp_get_attachment_metadata( $attachment_id );
-
- // The original file should now be recorded as original_image.
- $this->assertArrayHasKey( 'original_image', $metadata, 'Metadata should contain original_image.' );
- $this->assertSame( wp_basename( $original_file ), $metadata['original_image'], 'original_image should be the basename of the original attached file.' );
-
- // The attached file should now point to the scaled version.
- $new_file = get_attached_file( $attachment_id, true );
- $this->assertStringContainsString( 'scaled', wp_basename( $new_file ), 'Attached file should now be the scaled version.' );
-
- // Metadata should have width, height, filesize, and file updated.
- $this->assertArrayHasKey( 'width', $metadata, 'Metadata should contain width.' );
- $this->assertArrayHasKey( 'height', $metadata, 'Metadata should contain height.' );
- $this->assertArrayHasKey( 'filesize', $metadata, 'Metadata should contain filesize.' );
- $this->assertArrayHasKey( 'file', $metadata, 'Metadata should contain file.' );
- $this->assertStringContainsString( 'scaled', $metadata['file'], 'Metadata file should reference the scaled version.' );
- $this->assertGreaterThan( 0, $metadata['width'], 'Width should be positive.' );
- $this->assertGreaterThan( 0, $metadata['height'], 'Height should be positive.' );
- $this->assertGreaterThan( 0, $metadata['filesize'], 'Filesize should be positive.' );
- }
-
- /**
- * Tests that sideloading scaled image requires authentication.
- *
- * @ticket 64737
- * @requires function imagejpeg
- */
- public function test_sideload_scaled_image_requires_auth() {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // Create an attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id = $response->get_data()['id'];
-
- // Try sideloading without authentication.
- wp_set_current_user( 0 );
-
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola-scaled.jpg' );
- $request->set_param( 'image_size', 'scaled' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertErrorResponse( 'rest_cannot_edit_image', $response, 401 );
- }
-
- /**
- * Tests that the sideload endpoint includes 'scaled' in the image_size enum.
- *
- * @ticket 64737
- */
- public function test_sideload_route_includes_scaled_enum() {
- $this->enable_client_side_media_processing();
-
- $server = rest_get_server();
- $routes = $server->get_routes();
-
- $endpoint = '/wp/v2/media/(?P[\d]+)/sideload';
- $this->assertArrayHasKey( $endpoint, $routes, 'Sideload route should exist.' );
-
- $route = $routes[ $endpoint ];
- $endpoint = $route[0];
- $args = $endpoint['args'];
-
- $param_name = 'image_size';
- $this->assertArrayHasKey( $param_name, $args, 'Route should have image_size arg.' );
- $this->assertContains( 'scaled', $args[ $param_name ]['enum'], 'image_size enum should include scaled.' );
- }
-
- /**
- * Tests the filter_wp_unique_filename method handles the -scaled suffix.
- *
- * @ticket 64737
- * @requires function imagejpeg
- */
- public function test_sideload_scaled_unique_filename() {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // Create an attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id = $response->get_data()['id'];
-
- // Sideload with the -scaled suffix.
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola-scaled.jpg' );
- $request->set_param( 'image_size', 'scaled' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertSame( 200, $response->get_status(), 'Sideloading scaled image should succeed.' );
-
- // The filename should retain the -scaled suffix without numeric disambiguation.
- $new_file = get_attached_file( $attachment_id, true );
- $basename = wp_basename( $new_file );
- $this->assertMatchesRegularExpression( '/canola-scaled\.jpg$/', $basename, 'Scaled filename should not have numeric suffix appended.' );
- }
-
- /**
- * Tests that sideloading a scaled image for a different attachment retains the numeric suffix
- * when a file with the same name already exists on disk.
- *
- * @ticket 64737
- * @requires function imagejpeg
- */
- public function test_sideload_scaled_unique_filename_conflict() {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // Create the first attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id_a = $response->get_data()['id'];
-
- // Sideload a scaled image for attachment A, creating canola-scaled.jpg on disk.
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id_a}/sideload" );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola-scaled.jpg' );
- $request->set_param( 'image_size', 'scaled' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertSame( 200, $response->get_status(), 'First sideload should succeed.' );
-
- // Create a second, different attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=other.jpg' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id_b = $response->get_data()['id'];
-
- // Sideload scaled for attachment B using the same filename that already exists on disk.
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id_b}/sideload" );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola-scaled.jpg' );
- $request->set_param( 'image_size', 'scaled' );
- $request->set_body( file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertSame( 200, $response->get_status(), 'Second sideload should succeed.' );
-
- // The filename should have a numeric suffix since the base name does not match this attachment.
- $new_file = get_attached_file( $attachment_id_b, true );
- $basename = wp_basename( $new_file );
- $this->assertMatchesRegularExpression( '/canola-scaled-\d+\.jpg$/', $basename, 'Scaled filename should have numeric suffix when file conflicts with a different attachment.' );
- }
-
- /**
- * Tests that the finalize endpoint triggers wp_generate_attachment_metadata.
- *
- * @ticket 62243
- * @covers WP_REST_Attachments_Controller::finalize_item
- * @requires function imagejpeg
- */
- public function test_finalize_item(): void {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // Create an attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( (string) file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id = $response->get_data()['id'];
-
- $this->assertSame( 201, $response->get_status() );
-
- // Track whether wp_generate_attachment_metadata filter fires.
- $filter_metadata = null;
- $filter_id = null;
- $filter_context = null;
- add_filter(
- 'wp_generate_attachment_metadata',
- function ( array $metadata, int $id, string $context ) use ( &$filter_metadata, &$filter_id, &$filter_context ) {
- $filter_metadata = $metadata;
- $filter_id = $id;
- $filter_context = $context;
- $metadata['foo'] = 'bar';
- return $metadata;
- },
- 10,
- 3
- );
-
- // Call the finalize endpoint.
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/finalize" );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertSame( 200, $response->get_status(), 'Finalize endpoint should return 200.' );
- $this->assertIsArray( $filter_metadata );
- $this->assertStringContainsString( 'canola', $filter_metadata['file'], 'Expected the canola image to have been had its metadata updated.' );
- $this->assertSame( $attachment_id, $filter_id, 'Expected the post ID to be passed to the filter.' );
- $this->assertSame( 'update', $filter_context, 'Filter context should be "update".' );
- $resulting_metadata = wp_get_attachment_metadata( $attachment_id );
- $this->assertIsArray( $resulting_metadata );
- $this->assertArrayHasKey( 'foo', $resulting_metadata, 'Expected new metadata key to have been added.' );
- $this->assertSame( 'bar', $resulting_metadata['foo'], 'Expected filtered metadata to be updated.' );
- }
-
- /**
- * Tests that the finalize endpoint requires authentication.
- *
- * @ticket 62243
- * @covers WP_REST_Attachments_Controller::finalize_item
- * @requires function imagejpeg
- */
- public function test_finalize_item_requires_auth(): void {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- // Create an attachment.
- $request = new WP_REST_Request( 'POST', '/wp/v2/media' );
- $request->set_header( 'Content-Type', 'image/jpeg' );
- $request->set_header( 'Content-Disposition', 'attachment; filename=canola.jpg' );
- $request->set_body( (string) file_get_contents( self::$test_file ) );
- $response = rest_get_server()->dispatch( $request );
- $attachment_id = $response->get_data()['id'];
-
- // Try finalizing without authentication.
- wp_set_current_user( 0 );
-
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/finalize" );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertErrorResponse( 'rest_cannot_edit_image', $response, 401 );
- }
-
- /**
- * Tests that the finalize endpoint returns error for invalid attachment ID.
- *
- * @ticket 62243
- * @covers WP_REST_Attachments_Controller::finalize_item
- */
- public function test_finalize_item_invalid_id(): void {
- $this->enable_client_side_media_processing();
-
- wp_set_current_user( self::$author_id );
-
- $invalid_id = PHP_INT_MAX;
- $this->assertNull( get_post( $invalid_id ), 'Expected invalid ID to not exist for an existing post.' );
- $request = new WP_REST_Request( 'POST', "/wp/v2/media/$invalid_id/finalize" );
- $response = rest_get_server()->dispatch( $request );
-
- $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
- }
}
diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php
index 89bf2c481c567..9c6c431e5ef35 100644
--- a/tests/phpunit/tests/rest-api/rest-schema-setup.php
+++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php
@@ -16,9 +16,6 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
public function set_up() {
parent::set_up();
- // Ensure client-side media processing is enabled so the sideload route is registered.
- add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );
-
/** @var WP_REST_Server $wp_rest_server */
global $wp_rest_server;
$wp_rest_server = new Spy_REST_Server();
@@ -112,8 +109,6 @@ public function test_expected_routes_in_schema() {
'/wp/v2/media/(?P[\\d]+)',
'/wp/v2/media/(?P[\\d]+)/post-process',
'/wp/v2/media/(?P[\\d]+)/edit',
- '/wp/v2/media/(?P[\\d]+)/sideload',
- '/wp/v2/media/(?P[\\d]+)/finalize',
'/wp/v2/blocks',
'/wp/v2/blocks/(?P[\d]+)',
'/wp/v2/blocks/(?P[\d]+)/autosaves',
diff --git a/tests/phpunit/tests/script-modules/wpScriptModules.php b/tests/phpunit/tests/script-modules/wpScriptModules.php
index 140531101a1cd..4f647c6a3d2e0 100644
--- a/tests/phpunit/tests/script-modules/wpScriptModules.php
+++ b/tests/phpunit/tests/script-modules/wpScriptModules.php
@@ -1904,24 +1904,22 @@ public function test_dependent_of_default_script_modules() {
}
/**
- * Tests that VIPS script modules always use minified file paths.
+ * Tests that VIPS script modules are not registered in Core.
*
- * Non-minified VIPS files are not shipped because they are ~10MB of
- * inlined WASM with no debugging value, so the registration should
- * always point to the .min.js variants.
+ * The wasm-vips library is plugin-only and should not be included
+ * in WordPress Core builds due to its large size (~16MB per file).
*
- * @ticket 64734
+ * @ticket 64906
*
* @covers ::wp_default_script_modules
*/
- public function test_vips_script_modules_always_use_minified_paths() {
+ public function test_vips_script_modules_not_registered_in_core() {
wp_default_script_modules();
wp_enqueue_script_module( '@wordpress/vips/loader' );
$actual = get_echo( array( wp_script_modules(), 'print_enqueued_script_modules' ) );
- $this->assertStringContainsString( 'vips/loader.min.js', $actual );
- $this->assertStringNotContainsString( 'vips/loader.js"', $actual );
+ $this->assertStringNotContainsString( 'vips', $actual );
}
/**
diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js
index b953a0303537c..003dc397ae305 100644
--- a/tests/qunit/fixtures/wp-api-generated.js
+++ b/tests/qunit/fixtures/wp-api-generated.js
@@ -3148,18 +3148,6 @@ mockedApiResponse.Schema = {
"description": "The ID for the associated post of the attachment.",
"type": "integer",
"required": false
- },
- "generate_sub_sizes": {
- "type": "boolean",
- "default": true,
- "description": "Whether to generate image sub sizes.",
- "required": false
- },
- "convert_format": {
- "type": "boolean",
- "default": true,
- "description": "Whether to convert image formats.",
- "required": false
}
}
}
@@ -3676,68 +3664,6 @@ mockedApiResponse.Schema = {
}
]
},
- "/wp/v2/media/(?P[\\d]+)/sideload": {
- "namespace": "wp/v2",
- "methods": [
- "POST"
- ],
- "endpoints": [
- {
- "methods": [
- "POST"
- ],
- "args": {
- "id": {
- "description": "Unique identifier for the attachment.",
- "type": "integer",
- "required": false
- },
- "image_size": {
- "description": "Image size.",
- "type": "string",
- "enum": [
- "thumbnail",
- "medium",
- "medium_large",
- "large",
- "1536x1536",
- "2048x2048",
- "original",
- "full",
- "scaled"
- ],
- "required": true
- },
- "convert_format": {
- "type": "boolean",
- "default": true,
- "description": "Whether to convert image formats.",
- "required": false
- }
- }
- }
- ]
- },
- "/wp/v2/media/(?P[\\d]+)/finalize": {
- "namespace": "wp/v2",
- "methods": [
- "POST"
- ],
- "endpoints": [
- {
- "methods": [
- "POST"
- ],
- "args": {
- "id": {
- "description": "Unique identifier for the attachment.",
- "type": "integer",
- "required": false
- }
- }
- }
- ]
- },
"/wp/v2/menu-items": {
"namespace": "wp/v2",
"methods": [
@@ -12774,43 +12700,6 @@ mockedApiResponse.Schema = {
]
}
},
- "image_sizes": {
- "thumbnail": {
- "width": 150,
- "height": 150,
- "crop": true
- },
- "medium": {
- "width": 300,
- "height": 300,
- "crop": false
- },
- "medium_large": {
- "width": 768,
- "height": 0,
- "crop": false
- },
- "large": {
- "width": 1024,
- "height": 1024,
- "crop": false
- },
- "1536x1536": {
- "width": 1536,
- "height": 1536,
- "crop": false
- },
- "2048x2048": {
- "width": 2048,
- "height": 2048,
- "crop": false
- }
- },
- "image_size_threshold": 2560,
- "image_output_formats": {},
- "jpeg_interlaced": false,
- "png_interlaced": false,
- "gif_interlaced": false,
"site_logo": 0,
"site_icon": 0,
"site_icon_url": ""
diff --git a/tools/gutenberg/copy.js b/tools/gutenberg/copy.js
index 0f197169f7366..e5ca8eb71dce5 100644
--- a/tools/gutenberg/copy.js
+++ b/tools/gutenberg/copy.js
@@ -259,6 +259,10 @@ function generateScriptModulesPackages() {
const fullPath = path.join( dir, entry.name );
if ( entry.isDirectory() ) {
+ // Skip plugin-only packages (e.g., vips/wasm) that should not be in Core.
+ if ( entry.name === 'vips' ) {
+ continue;
+ }
processDirectory( fullPath, baseDir );
} else if ( entry.name.endsWith( '.min.asset.php' ) ) {
const relativePath = path.relative( baseDir, fullPath );
@@ -344,6 +348,17 @@ function generateScriptLoaderPackages() {
assetData.dependencies = [];
}
+ // Strip plugin-only module dependencies (e.g., vips) that are not in Core.
+ if ( Array.isArray( assetData.module_dependencies ) ) {
+ assetData.module_dependencies =
+ assetData.module_dependencies.filter(
+ ( dep ) =>
+ ! ( dep.id || dep ).startsWith(
+ '@wordpress/vips'
+ )
+ );
+ }
+
assets[ `${ entry.name }.js` ] = assetData;
} catch ( error ) {
console.error(