Make WordPress Core

Opened 5 hours ago

Last modified 5 hours ago

#65399 assigned defect (bug)

Skip Document-Isolation-Policy on the classic-theme site preview

Reported by: adamsilverstein's profile adamsilverstein Owned by: adamsilverstein's profile adamsilverstein
Milestone: 7.1 Priority: normal
Severity: normal Version:
Component: Media Keywords: has-patch has-unit-tests
Focuses: Cc:

Description

The site editor renders the front end of a classic theme inside a same-origin ?wp_site_preview=1 iframe. To neutralize the interactive elements of that preview (links, forms, etc.), the editor reads and manipulates the iframe's contentDocument.

WordPress 7.1 sends a Document-Isolation-Policy: isolate-and-credentialless (DIP) header on block-editor screens (including the site editor) so that client-side media processing has access to SharedArrayBuffer and high-resolution timers. On Chromium 137+, DIP places the document into its own agent cluster. When the parent editor document is isolated but the same-origin preview iframe is not (or vice versa), the browser refuses cross-document contentDocument access, and neutralizing the classic-theme preview fails.

Steps to reproduce

  1. Activate a classic theme (for example, Twenty Twenty-One).
  2. In Chrome 137 or newer, open the Site Editor (wp-admin/site-editor.php).
  3. Observe the front-end site preview rendered in the iframe.

Expected: The preview loads and its interactive elements are neutralized by the editor.

Actual: The editor cannot reach the iframe's contentDocument because DIP has placed the editor in a separate agent cluster, so neutralization fails.

Proposed fix

Skip cross-origin isolation in wp_set_up_cross_origin_isolation() for the classic-theme site editor home route only. The output buffer / DIP header is not started for that request, restoring same-origin contentDocument access.

The guard is scoped narrowly:

<?php
if ( 'site-editor' === $screen->id && ! wp_is_block_theme() && ( ! isset( $_GET['p'] ) || '/' === $_GET['p'] ) ) {
        return;
}

Behavior matrix:

Theme Screen Route DIP
Classic Site editor Home (p unset or /) Skipped
Classic Site editor Non-home (e.g. p=/page/about) Applied
Block Site editor Any route Applied

Block themes do not render the classic site preview iframe, so they are unaffected. All non-home routes continue to receive DIP.

Patch

  • src/wp-includes/media.php — early return in wp_set_up_cross_origin_isolation() for the classic-theme site editor home route.
  • tests/phpunit/tests/media/wpCrossOriginIsolation.php — coverage for the skip (home route, p unset and p=/), and for DIP still being applied on classic-theme non-home routes and on block-theme routes.

GitHub PR: https://github.com/WordPress/wordpress-develop/pull/12004

Change History (1)

This ticket was mentioned in PR #12004 on WordPress/wordpress-develop by @adamsilverstein.


5 hours ago
#1

  • Keywords has-patch has-unit-tests added

## Summary

  • Skip cross-origin isolation (Document-Isolation-Policy) on the classic-theme site editor home route in wp_set_up_cross_origin_isolation().
  • Block themes and all other site editor routes are unaffected and continue to receive DIP.

## Why

The site editor renders the front end of a classic theme in a same-origin ?wp_site_preview=1 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.

Skipping cross-origin isolation for the classic-theme site editor home route keeps the preview working. The new early return is scoped narrowly:

if ( 'site-editor' === $screen->id && ! wp_is_block_theme() && ( ! isset( $_GET['p'] ) || '/' === $_GET['p'] ) ) {
        return;
}
Condition Behavior
Classic theme, site editor, home route (p unset or /) DIP skipped
Classic theme, site editor, non-home route (e.g. p=/page/about) DIP applied
Block theme, site editor, any route DIP applied

Block themes do not render the classic site preview iframe, so they are unaffected.

## Changes

### src/wp-includes/media.php

  • wp_set_up_cross_origin_isolation() — early return for the classic-theme site editor home route so DIP / the cross-origin isolation output buffer is not applied there.

### tests/phpunit/tests/media/wpCrossOriginIsolation.php

  • test_skips_cross_origin_isolation_for_classic_theme_site_editor_home() (data-provided: no p, and p=/).
  • test_sets_up_cross_origin_isolation_for_classic_theme_site_editor_non_home_route().
  • test_sets_up_cross_origin_isolation_for_block_theme_site_editor_home().

## Backport scope

Backport of WordPress/gutenberg#78404. Server-side only.

## Test plan

  • [ ] vendor/bin/phpunit tests/phpunit/tests/media/wpCrossOriginIsolation.php — all existing + new tests pass.
  • [ ] As an admin in Chrome 137+, open the site editor on a classic theme and confirm the front-end preview iframe loads and is interactive-neutralized (no DIP on the home route).
  • [ ] Navigate to a non-home site editor route on a classic theme and confirm DIP is still applied.
  • [ ] Open the site editor on a block theme and confirm DIP is applied on every route, including the home route.

## Related

Note: See TracTickets for help on using tickets.