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(