Skip to content

WIP: Fix Gutenberg site editor under Document-Isolation-Policy#3320

Closed
adamziel wants to merge 1 commit intotrunkfrom
fix/dip-gutenberg-site-editor
Closed

WIP: Fix Gutenberg site editor under Document-Isolation-Policy#3320
adamziel wants to merge 1 commit intotrunkfrom
fix/dip-gutenberg-site-editor

Conversation

@adamziel
Copy link
Collaborator

@adamziel adamziel commented Feb 27, 2026

Summary

Gutenberg 26.2 uses SharedArrayBuffer in the site editor. That requires cross-origin isolation. WordPress serves the editor frame with COEP/COOP headers. It's pretty difficult to do the same in Playground, so instead we rewrite those headers as Document-Isolation-Policy. However, DIP has subtle side effect that breaks how Gutenberg sets up its editor canvas. I think (?) it wasn't a problem at the time #3028 was merged, but Gutenberg internals changed in WordPress/gutenberg#74418 (and likely a few other PRs) so the situation needs to be re-evaluated now.

This is a WIP branch capturing the debugging so far.

Why Playground can't use COEP/COOP

COEP/COOP require the entire frame ancestry to participate. To get SharedArrayBuffer inside the site editor iframe, headers must be set on:

  • The site editor iframe itself
  • The remote.html Playground frame above it
  • The playground.wordpress.net host page above that
  • Any third-party page that embeds Playground

That last point is the blocker. Playground is embedded on WordPress.org, in documentation, in tutorials. Those pages don't send COEP/COOP, and we can't make them.

Native WordPress doesn't have this problem — wp-admin does full-page reloads, so COEP/COOP only needs to cover the current page. In Playground, the top-level frame stays alive for the entire session.

Perhaps we could introduce a query param such as ?coop=1 or so and use a magic default value depending on whether Playground is loaded from an iframe, but that sounds fragile.

The DIP problem

Document-Isolation-Policy isolates a single document without requiring parent cooperation. But it has a catch:

When only the child frame has DIP but the parent doesn't:

  • window.frameElement becomes null
  • Parent-to-child contentDocument access is blocked

Gutenberg's site editor calls iframe.contentWindow.contentDocument directly to set up the block editor canvas. When contentDocument is blocked, it crashes.

When both parent and child have DIP:

  • window.frameElement is defined
  • contentDocument access works
dip-dual-parent-child

What this branch does

Serves Document-Isolation-Policy: isolate-and-credentialless on all HTML responses in Playground — from the service worker and from both Vite dev servers — so that the parent-child DIP requirement is satisfied.

To try it, go to http://localhost:5400/website-server/?wp=beta&url=%2Fwp-admin%2Fsite-editor.php#ewogICJwbHVnaW5zIjogW10sCiAgInN0ZXBzIjogW10sCiAgInByZWZlcnJlZFZlcnNpb25zIjogewogICAgInBocCI6ICI4LjMiLAogICAgIndwIjogImJldGEiCiAgfSwKICAiZmVhdHVyZXMiOiB7fSwKICAibG9naW4iOiB0cnVlLAogICJsYW5kaW5nUGFnZSI6ICIvd3AtYWRtaW4vc2l0ZS1lZGl0b3IucGhwIgp9

It has some very rough edges, e.g. all the blocks crash and I don't know why. Also, I'm not sure about the impact of this on Playgrounds embedded on sites without the Document-Isolation-Policy header. Also, it further complicates the Chrome vs FF/Safari maintenance split. Finally, I'm not sure if client-side media processing actually works in this PR. But I know SharedArrayBuffer is available in the right iframe, and that's already a lot. This PR is just a debugging exploration to understand the phenomenon. It's not meant for merging.

cc @brandonpayton @JanJakes @adamsilverstein @swissspidy

related to #2954

…Gutenberg site editor

Gutenberg 26.2 uses SharedArrayBuffer in the site editor, which requires
cross-origin isolation. Playground achieves this via Document-Isolation-Policy
(DIP) instead of COEP/COOP because the entire parent frame chain would need
COEP/COOP headers – including third-party sites that embed Playground.

However, when only the child iframe has DIP but the parent doesn't,
window.frameElement becomes null and contentDocument access is blocked.
Gutenberg's site editor directly manipulates iframe.contentDocument to build
the editing canvas, so it breaks.

The fix is to serve DIP on all HTML responses in Playground – both from the
service worker and from the Vite dev servers. When both parent and child frames
have DIP, frameElement and contentDocument access work correctly.

This is WIP/exploratory – several guards are commented out and debug logging is
present.
@adamziel adamziel closed this Feb 27, 2026
@adamziel
Copy link
Collaborator Author

adamziel commented Feb 27, 2026

I'm closing this since it's not meant for merging. It's more of a demonstration of the problem. I won't be able to keep advancing this stream of work, please feel free to take over.

*/
add_filter('wp_client_side_media_processing_enabled', '__return_false');
// add_filter('wp_client_side_media_processing_enabled', '__return_false');
define( 'DISABLE_WP_CRON', true );
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's so slow on beta-2, I don't know why. Should we disable it entirely until we have multi-worker in the browser? @brandonpayton

Copy link
Collaborator

Choose a reason for hiding this comment

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

@adamziel did you test with the #3306 fix? It reduces the number of situations where requests are waiting on cron jobs.

@adamsilverstein
Copy link
Member

@bgrgicak / @adamziel - Would it help Pl;yground using DIP if we use DIP in core/Gutenberg instead of COEP/COOP? I am proposing we do that and support firefox/safari via a plugin. See WordPress/wordpress-develop#11098 / WordPress/gutenberg#75991

@adamziel
Copy link
Collaborator Author

I think so @adamsilverstein, thank you so much for following up here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants