Skip to content
Closed
4 changes: 1 addition & 3 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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/**',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure no vips included from GB

],
dest: WORKING_DIR + 'wp-includes/js/dist/script-modules/',
} ],
Expand Down
7 changes: 0 additions & 7 deletions src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
44 changes: 0 additions & 44 deletions src/wp-includes/media-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
__( '<a href="%1$s" %2$s>Learn how to describe the purpose of the image%3$s</a>. Leave empty if the image is purely decorative.' ),
Expand Down Expand Up @@ -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 <script type="text/html"> tags,
* whose content is treated as raw text by the HTML Tag Processor.
* Extract each script block's content, process it separately,
* then reassemble the full output.
*/
$script_processor = new WP_HTML_Tag_Processor( $html );
while ( $script_processor->next_tag( 'SCRIPT' ) ) {
if ( 'text/html' !== $script_processor->get_attribute( 'type' ) ) {
continue;
}
/*
* Unlike wp_add_crossorigin_attributes(), this does not check whether
* URLs are actually cross-origin. Media templates use Underscore.js
* template expressions (e.g. {{ data.url }}) as placeholder URLs,
* so actual URLs are not available at parse time.
* The crossorigin attribute is added unconditionally to all relevant
* media tags to ensure cross-origin isolation works regardless of
* the final URL value at render time.
*/
$template_processor = new WP_HTML_Tag_Processor( $script_processor->get_modifiable_text() );
while ( $template_processor->next_tag() ) {
if (
in_array( $template_processor->get_tag(), array( 'AUDIO', 'IMG', 'VIDEO' ), true )
&& ! is_string( $template_processor->get_attribute( 'crossorigin' ) )
) {
$template_processor->set_attribute( 'crossorigin', 'anonymous' );
}
}
$script_processor->set_modifiable_text( $template_processor->get_updated_html() );
}

echo $script_processor->get_updated_html();
}
}
231 changes: 0 additions & 231 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -6400,234 +6400,3 @@ function wp_get_image_editor_output_format( $filename, $mime_type ) {
return apply_filters( 'image_editor_output_format', $output_format, $filename, $mime_type );
}

/**
* Checks whether client-side media processing is enabled.
*
* Client-side media processing uses the browser's capabilities to handle
* tasks like image resizing and compression before uploading to the server.
*
* @since 7.0.0
*
* @return bool Whether client-side media processing is enabled.
*/
function wp_is_client_side_media_processing_enabled(): bool {
// This is due to SharedArrayBuffer requiring a secure context.
$host = strtolower( (string) strtok( $_SERVER['HTTP_HOST'] ?? '', ':' ) );
$enabled = ( is_ssl() || 'localhost' === $host || str_ends_with( $host, '.localhost' ) );

/**
* Filters whether client-side media processing is enabled.
*
* @since 7.0.0
*
* @param bool $enabled Whether client-side media processing is enabled. Default true if the page is served in a secure context.
*/
return (bool) apply_filters( 'wp_client_side_media_processing_enabled', $enabled );
}

/**
* Sets a global JS variable to indicate that client-side media processing is enabled.
*
* @since 7.0.0
*/
function wp_set_client_side_media_processing_flag(): void {
if ( ! wp_is_client_side_media_processing_enabled() ) {
return;
}

wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true;', 'before' );

$chromium_version = wp_get_chromium_major_version();

if ( null !== $chromium_version && $chromium_version >= 137 ) {
wp_add_inline_script( 'wp-block-editor', 'window.__documentIsolationPolicy = true;', 'before' );
}

/*
* Register the @wordpress/vips/worker script module as a dynamic dependency
* of the wp-upload-media classic script. This ensures it is included in the
* import map so that the dynamic import() in upload-media.js can resolve it.
*/
wp_scripts()->add_data(
'wp-upload-media',
'module_dependencies',
array( '@wordpress/vips/worker' )
);
}

/**
* Returns the major Chrome/Chromium version from the current request's User-Agent.
*
* Matches all Chromium-based browsers (Chrome, Edge, Opera, Brave).
*
* @since 7.0.0
*
* @return int|null The major Chrome version, or null if not a Chromium browser.
*/
function wp_get_chromium_major_version(): ?int {
if ( empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
return null;
}
if ( preg_match( '#Chrome/(\d+)#', $_SERVER['HTTP_USER_AGENT'], $matches ) ) {
return (int) $matches[1];
}
return null;
}

/**
* Enables cross-origin isolation in the block editor.
*
* Required for enabling SharedArrayBuffer for WebAssembly-based
* media processing in the editor. Uses Document-Isolation-Policy
* on supported browsers (Chromium 137+).
*
* Skips setup when a third-party page builder overrides the block
* editor via a custom `action` query parameter, as DIP would block
* same-origin iframe access that these editors rely on.
*
* @since 7.0.0
*/
function wp_set_up_cross_origin_isolation(): void {
if ( ! wp_is_client_side_media_processing_enabled() ) {
return;
}

$screen = get_current_screen();

if ( ! $screen ) {
return;
}

if ( ! $screen->is_block_editor() && 'site-editor' !== $screen->id && ! ( 'widgets' === $screen->id && wp_use_widgets_block_editor() ) ) {
return;
}

/*
* Skip when a third-party page builder overrides the block editor.
* DIP isolates the document into its own agent cluster,
* which blocks same-origin iframe access that these editors rely on.
*/
if ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) {
return;
}

// Cross-origin isolation is not needed if users can't upload files anyway.
if ( ! current_user_can( 'upload_files' ) ) {
return;
}

wp_start_cross_origin_isolation_output_buffer();
}

/**
* Sends the Document-Isolation-Policy header for cross-origin isolation.
*
* Uses an output buffer to add crossorigin="anonymous" where needed.
*
* @since 7.0.0
*/
function wp_start_cross_origin_isolation_output_buffer(): void {
$chromium_version = wp_get_chromium_major_version();

if ( null === $chromium_version || $chromium_version < 137 ) {
return;
}

ob_start(
static function ( string $output ): string {
header( 'Document-Isolation-Policy: isolate-and-credentialless' );

return wp_add_crossorigin_attributes( $output );
}
);
}

/**
* Adds crossorigin="anonymous" to relevant tags in the given HTML string.
*
* @since 7.0.0
*
* @param string $html HTML input.
* @return string Modified HTML.
*/
function wp_add_crossorigin_attributes( string $html ): string {
$site_url = site_url();

$processor = new WP_HTML_Tag_Processor( $html );

// See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin.
$cross_origin_tag_attributes = array(
'AUDIO' => array( 'src' => false ),
'LINK' => array( 'href' => false ),
'SCRIPT' => array( 'src' => false ),
'VIDEO' => array(
'src' => false,
'poster' => false,
),
'SOURCE' => array( 'src' => false ),
);

while ( $processor->next_tag() ) {
$tag = $processor->get_tag();

if ( ! isset( $cross_origin_tag_attributes[ $tag ] ) ) {
continue;
}

if ( 'AUDIO' === $tag || 'VIDEO' === $tag ) {
$processor->set_bookmark( 'audio-video-parent' );
}

$processor->set_bookmark( 'resume' );

$sought = false;

$crossorigin = $processor->get_attribute( 'crossorigin' );

$is_cross_origin = false;

foreach ( $cross_origin_tag_attributes[ $tag ] as $attr => $is_srcset ) {
if ( $is_srcset ) {
$srcset = $processor->get_attribute( $attr );
if ( is_string( $srcset ) ) {
foreach ( explode( ',', $srcset ) as $candidate ) {
$candidate_url = strtok( trim( $candidate ), ' ' );
if ( is_string( $candidate_url ) && '' !== $candidate_url && ! str_starts_with( $candidate_url, $site_url ) && ! str_starts_with( $candidate_url, '/' ) ) {
$is_cross_origin = true;
break;
}
}
}
} else {
$url = $processor->get_attribute( $attr );
if ( is_string( $url ) && ! str_starts_with( $url, $site_url ) && ! str_starts_with( $url, '/' ) ) {
$is_cross_origin = true;
}
}

if ( $is_cross_origin ) {
break;
}
}

if ( $is_cross_origin && ! is_string( $crossorigin ) ) {
if ( 'SOURCE' === $tag ) {
$sought = $processor->seek( 'audio-video-parent' );

if ( $sought ) {
$processor->set_attribute( 'crossorigin', 'anonymous' );
}
} else {
$processor->set_attribute( 'crossorigin', 'anonymous' );
}

if ( $sought ) {
$processor->seek( 'resume' );
$processor->release_bookmark( 'audio-video-parent' );
}
}
}

return $processor->get_updated_html();
}

28 changes: 0 additions & 28 deletions src/wp-includes/rest-api/class-wp-rest-server.php
Original file line number Diff line number Diff line change
Expand Up @@ -1368,34 +1368,6 @@ public function get_index( $request ) {
'routes' => $this->get_data_for_routes( $this->get_routes(), $request['context'] ),
);

// Add media processing settings for users who can upload files.
if ( wp_is_client_side_media_processing_enabled() && current_user_can( 'upload_files' ) ) {
// Image sizes keyed by name for client-side media processing.
$available['image_sizes'] = array();
foreach ( wp_get_registered_image_subsizes() as $name => $size ) {
$available['image_sizes'][ $name ] = $size;
}

/** This filter is documented in wp-admin/includes/image.php */
$available['image_size_threshold'] = (int) apply_filters( 'big_image_size_threshold', 2560, array( 0, 0 ), '', 0 );

// Image output formats.
$input_formats = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/heic' );
$output_formats = array();
foreach ( $input_formats as $mime_type ) {
/** This filter is documented in wp-includes/media.php */
$output_formats = apply_filters( 'image_editor_output_format', $output_formats, '', $mime_type );
}
$available['image_output_formats'] = (object) $output_formats;

/** This filter is documented in wp-includes/class-wp-image-editor-gd.php */
$available['jpeg_interlaced'] = (bool) apply_filters( 'image_save_progressive', false, 'image/jpeg' );
/** This filter is documented in wp-includes/class-wp-image-editor-gd.php */
$available['png_interlaced'] = (bool) apply_filters( 'image_save_progressive', false, 'image/png' );
/** This filter is documented in wp-includes/class-wp-image-editor-gd.php */
$available['gif_interlaced'] = (bool) apply_filters( 'image_save_progressive', false, 'image/gif' );
}

$response = new WP_REST_Response( $available );

$fields = $request['_fields'] ?? '';
Expand Down
Loading
Loading