Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -682,10 +682,8 @@
// 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' );
add_action( 'admin_init', 'wp_set_up_cross_origin_isolation' );
add_action( 'template_redirect', 'wp_set_up_cross_origin_isolation_for_preview' );
// 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
39 changes: 30 additions & 9 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -6475,12 +6475,17 @@ function wp_get_chromium_major_version(): ?int {
}

/**
* Enables cross-origin isolation in the block editor.
* Enables cross-origin isolation on admin pages.
*
* Required for enabling SharedArrayBuffer for WebAssembly-based
* media processing in the editor. Uses Document-Isolation-Policy
* on supported browsers (Chromium 137+).
*
* Applied to all admin pages so that navigations between editor pages
* and other admin screens (site editor, template operations, pattern
* editing) remain in the same agent cluster, preserving cross-window
* communication.
*
* 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.
Expand All @@ -6492,13 +6497,8 @@ function wp_set_up_cross_origin_isolation(): void {
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() ) ) {
// Cross-origin isolation is not needed if users can't upload files anyway.
if ( ! current_user_can( 'upload_files' ) ) {
return;
}

Expand All @@ -6511,7 +6511,28 @@ function wp_set_up_cross_origin_isolation(): void {
return;
}

// Cross-origin isolation is not needed if users can't upload files anyway.
wp_start_cross_origin_isolation_output_buffer();
}

/**
* Sets up cross-origin isolation for front-end preview pages.
*
* When the block editor sends the Document-Isolation-Policy header and opens
* a preview popup, the preview page must also send the header to remain in
* the same agent cluster. Without this, cross-window communication between
* the editor and preview breaks in Chromium 137+.
*
* @since 7.1.0
*/
function wp_set_up_cross_origin_isolation_for_preview(): void {
if ( ! is_preview() ) {
return;
}

if ( ! wp_is_client_side_media_processing_enabled() ) {
return;
}

if ( ! current_user_can( 'upload_files' ) ) {
return;
}
Expand Down
35 changes: 32 additions & 3 deletions tests/phpunit/tests/media/wpCrossOriginIsolation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*
* @group media
* @covers ::wp_set_up_cross_origin_isolation
* @covers ::wp_set_up_cross_origin_isolation_for_preview
* @covers ::wp_start_cross_origin_isolation_output_buffer
* @covers ::wp_is_client_side_media_processing_enabled
*/
Expand Down Expand Up @@ -89,13 +90,15 @@ public function test_returns_early_when_client_side_processing_disabled() {
/**
* @ticket 64766
*/
public function test_returns_early_when_no_screen() {
// No screen is set, so it should return early.
public function test_returns_early_when_user_cannot_upload() {
$user_id = self::factory()->user->create( array( 'role' => 'subscriber' ) );
wp_set_current_user( $user_id );

$level_before = ob_get_level();
wp_set_up_cross_origin_isolation();
$level_after = ob_get_level();

$this->assertSame( $level_before, $level_after );
$this->assertSame( $level_before, $level_after, 'Output buffer should not start for users who cannot upload files.' );
}

/**
Expand Down Expand Up @@ -362,4 +365,30 @@ public function test_output_buffer_handles_mixed_tags() {
// Script and audio should have crossorigin.
$this->assertSame( 2, substr_count( $output, 'crossorigin="anonymous"' ), 'Script and audio should both get crossorigin, but not img.' );
}

/**
* @ticket 64766
*/
public function test_preview_returns_early_when_not_preview() {
add_filter( 'wp_client_side_media_processing_enabled', '__return_true' );

$level_before = ob_get_level();
wp_set_up_cross_origin_isolation_for_preview();
$level_after = ob_get_level();

$this->assertSame( $level_before, $level_after, 'Output buffer should not start on non-preview pages.' );
}

/**
* @ticket 64766
*/
public function test_preview_returns_early_when_processing_disabled() {
add_filter( 'wp_client_side_media_processing_enabled', '__return_false' );

$level_before = ob_get_level();
wp_set_up_cross_origin_isolation_for_preview();
$level_after = ob_get_level();

$this->assertSame( $level_before, $level_after, 'Output buffer should not start when client-side processing is disabled.' );
}
}
Loading