Skip to content

Commit 84902ef

Browse files
Media: Skip Document-Isolation-Policy on the classic-theme site preview.
The site editor renders the front end of a classic theme in a same-origin iframe and must reach the iframe's `contentDocument` to neutralize its interactive elements. Document-Isolation-Policy isolates the editor into its own agent cluster, which blocks that same-origin access. Skip cross-origin isolation in `wp_set_up_cross_origin_isolation()` for the classic-theme site editor home route so the preview keeps working. Block themes and other routes are unaffected. Backport of WordPress/gutenberg#78404.
1 parent 51a5f4d commit 84902ef

2 files changed

Lines changed: 124 additions & 0 deletions

File tree

src/wp-includes/media.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6549,6 +6549,15 @@ function wp_set_up_cross_origin_isolation(): void {
65496549
return;
65506550
}
65516551

6552+
/*
6553+
* Skip when rendering the classic-theme home route, which shows the site
6554+
* preview in an iframe and must reach its `contentDocument` to neutralize
6555+
* interactive elements. DIP would block that same-origin access.
6556+
*/
6557+
if ( 'site-editor' === $screen->id && ! wp_is_block_theme() && ( ! isset( $_GET['p'] ) || '/' === $_GET['p'] ) ) {
6558+
return;
6559+
}
6560+
65526561
/*
65536562
* Skip when a third-party page builder overrides the block editor.
65546563
* DIP isolates the document into its own agent cluster,

tests/phpunit/tests/media/wpCrossOriginIsolation.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,18 @@ class Tests_Media_wpCrossOriginIsolation extends WP_UnitTestCase {
3030
*/
3131
private ?string $original_get_action;
3232

33+
/**
34+
* Original $_GET['p'] value.
35+
*/
36+
private ?string $original_get_p;
37+
3338
public function set_up() {
3439
parent::set_up();
3540
$this->original_user_agent = $_SERVER['HTTP_USER_AGENT'] ?? null;
3641
$this->original_http_host = $_SERVER['HTTP_HOST'] ?? null;
3742
$this->original_https = $_SERVER['HTTPS'] ?? null;
3843
$this->original_get_action = $_GET['action'] ?? null;
44+
$this->original_get_p = $_GET['p'] ?? null;
3945
}
4046

4147
public function tear_down() {
@@ -63,11 +69,19 @@ public function tear_down() {
6369
$_GET['action'] = $this->original_get_action;
6470
}
6571

72+
if ( null === $this->original_get_p ) {
73+
unset( $_GET['p'] );
74+
} else {
75+
$_GET['p'] = $this->original_get_p;
76+
}
77+
6678
// Clean up any output buffers started during tests.
6779
while ( ob_get_level() > 1 ) {
6880
ob_end_clean();
6981
}
7082

83+
$GLOBALS['current_screen'] = null;
84+
7185
remove_all_filters( 'wp_client_side_media_processing_enabled' );
7286
parent::tear_down();
7387
}
@@ -159,6 +173,107 @@ public function test_does_not_start_output_buffer_for_safari() {
159173
$this->assertSame( $level_before, $level_after, 'Output buffer should not be started for Safari.' );
160174
}
161175

176+
/**
177+
* The site editor home route on a classic theme skips DIP, because the
178+
* editor renders the front end in a same-origin iframe and must reach its
179+
* `contentDocument` to neutralize interactive elements. DIP would block
180+
* that access.
181+
*
182+
* @ticket 64766
183+
*
184+
* @dataProvider data_classic_theme_site_editor_home_routes
185+
*
186+
* @param array $get The $_GET state representing the home route.
187+
*/
188+
public function test_skips_cross_origin_isolation_for_classic_theme_site_editor_home( array $get ) {
189+
$_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';
190+
$_SERVER['HTTP_HOST'] = 'localhost';
191+
192+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
193+
switch_theme( 'twentytwentyone' );
194+
set_current_screen( 'site-editor' );
195+
196+
unset( $_GET['p'] );
197+
foreach ( $get as $key => $value ) {
198+
$_GET[ $key ] = $value;
199+
}
200+
201+
$level_before = ob_get_level();
202+
wp_set_up_cross_origin_isolation();
203+
$level_after = ob_get_level();
204+
205+
$this->assertSame( $level_before, $level_after, 'DIP should be skipped on the classic-theme site editor home route.' );
206+
}
207+
208+
/**
209+
* Data provider for the classic-theme site editor home route.
210+
*
211+
* @return array[]
212+
*/
213+
public function data_classic_theme_site_editor_home_routes() {
214+
return array(
215+
'no p query var' => array( array() ),
216+
'p query var is /' => array( array( 'p' => '/' ) ),
217+
);
218+
}
219+
220+
/**
221+
* The site editor on a classic theme still sets up cross-origin isolation
222+
* for routes other than the home route.
223+
*
224+
* @ticket 64766
225+
*
226+
* @runInSeparateProcess
227+
* @preserveGlobalState disabled
228+
*/
229+
public function test_sets_up_cross_origin_isolation_for_classic_theme_site_editor_non_home_route() {
230+
$_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';
231+
$_SERVER['HTTP_HOST'] = 'localhost';
232+
233+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
234+
switch_theme( 'twentytwentyone' );
235+
set_current_screen( 'site-editor' );
236+
237+
$_GET['p'] = '/page/about';
238+
239+
$level_before = ob_get_level();
240+
wp_set_up_cross_origin_isolation();
241+
$level_after = ob_get_level();
242+
243+
$this->assertSame( $level_before + 1, $level_after, 'DIP should be set up on a non-home site editor route.' );
244+
245+
ob_end_clean();
246+
}
247+
248+
/**
249+
* The site editor on a block theme always sets up cross-origin isolation,
250+
* including on the home route, because block themes do not render the
251+
* classic site preview iframe.
252+
*
253+
* @ticket 64766
254+
*
255+
* @runInSeparateProcess
256+
* @preserveGlobalState disabled
257+
*/
258+
public function test_sets_up_cross_origin_isolation_for_block_theme_site_editor_home() {
259+
$_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';
260+
$_SERVER['HTTP_HOST'] = 'localhost';
261+
262+
wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) );
263+
switch_theme( 'twentytwentyfour' );
264+
set_current_screen( 'site-editor' );
265+
266+
unset( $_GET['p'] );
267+
268+
$level_before = ob_get_level();
269+
wp_set_up_cross_origin_isolation();
270+
$level_after = ob_get_level();
271+
272+
$this->assertSame( $level_before + 1, $level_after, 'DIP should be set up on the block-theme site editor home route.' );
273+
274+
ob_end_clean();
275+
}
276+
162277
/**
163278
* @ticket 64803
164279
*/

0 commit comments

Comments
 (0)