Repository navigation
[Web] Avoid cross-origin policy errors in editor - #3312
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses a critical issue where Gutenberg v22.6.0 and WordPress 7.0 beta editors fail to load in Playground due to cross-origin policy conflicts. The change implements a temporary workaround by disabling client-side media processing, which prevents the problematic cross-origin-embedder-policy: credentialless header from being sent.
Changes:
- Added a filter to disable client-side media processing as a temporary workaround for cross-origin policy errors
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }); | ||
|
|
||
| /** | ||
| * ¡TEMPORARY WORKAROUND! |
There was a problem hiding this comment.
The inverted exclamation mark '¡' at the beginning should be replaced with a standard exclamation mark '!' for consistency with typical code documentation practices.
| * ¡TEMPORARY WORKAROUND! | |
| * !TEMPORARY WORKAROUND! |
| /** | ||
| * ¡TEMPORARY WORKAROUND! | ||
| * On 2026-02-26, with Gutenberg v22.6.0 and above, the site editor and post | ||
| * editor fail to load. This appears related the `cross-origin-embedder-policy: credentialless` |
There was a problem hiding this comment.
Missing word 'to' after 'related'. Should read 'This appears related to the'.
| * editor fail to load. This appears related the `cross-origin-embedder-policy: credentialless` | |
| * editor fail to load. This appears related to the `cross-origin-embedder-policy: credentialless` |
…n-Policy (#3515) ## Motivation for the change, related issues Fixes #3514. Playground currently disables Gutenberg's **client-side media processing** experiment via an `__return_false` filter in the mu-plugin ([0-playground.php#L265-L274](https://github.com/WordPress/wordpress-playground/blob/trunk/packages/playground/remote/src/lib/playground-mu-plugin/0-playground.php#L265-L274)). That workaround was added in #3312 because, at the time, Gutenberg was emitting COEP/COOP for the editor and — even when rewritten to `Document-Isolation-Policy` by the service worker — the editor's inner iframe was crashing. [Gutenberg PR #75991](WordPress/gutenberg#75991) (shipped in 22.6+) changed the isolation strategy: on Chromium 137+ Gutenberg now sends `Document-Isolation-Policy: isolate-and-credentialless` **directly** on editor screens and no longer sends COEP/COOP. That removes the root cause of the breakage — but it also means Playground's existing COEP→DIP rewrite path never fires on current Gutenberg, so the scope is never added to `scopesWithCrossOriginIsolation`, `empty.html` doesn't receive DIP, and parent/child DIP parity breaks inside the block editor canvas (see #3320 for why parity matters). ## Implementation details Two small, coordinated changes: 1. **`packages/playground/remote/service-worker.ts`** — broaden the post-response handler (now `applyCrossOriginIsolationHeaders`) so that: - If a response already carries `Document-Isolation-Policy`, the scope is added to `scopesWithCrossOriginIsolation` and the response passes through unchanged. This is the modern path once Gutenberg serves DIP directly. - If a response carries COEP/COOP, the existing rewrite path continues to operate unchanged (covers older Gutenberg, WP core's `wp_set_up_cross_origin_isolation`, or custom plugins). The existing `empty.html` branch (which adds DIP to the inner editor iframe when the scope is tracked) needs no change — it now gets populated in both cases. 2. **`packages/playground/remote/src/lib/playground-mu-plugin/0-playground.php`** — remove `add_filter('wp_client_side_media_processing_enabled', '__return_false')` and its comment block. The workaround is no longer necessary. ## Tests New Playwright spec: `packages/playground/website/playwright/e2e/client-side-media.spec.ts` - Chromium-only (skipped in Firefox/Safari — DIP and client-side media are Chromium-only today). - Boots Playground with Gutenberg + `gutenberg-media-processing` experiment on `/wp-admin/post-new.php` and asserts, inside the WP admin iframe: - `window.crossOriginIsolated === true` - `typeof SharedArrayBuffer !== 'undefined'` - `window.__clientSideMediaProcessing === true` (Gutenberg's own enablement flag) Editor rendering under DIP is already covered by the existing `document-isolation-policy.spec.ts` suite, which implicitly verifies parent/child DIP parity. ## Testing instructions Manual (Chromium ≥ 137): 1. Run `npm run dev` and open `http://127.0.0.1:5400/website-server/`. 2. Load Guetnberg with this Blueprint (paste into the URL after `#`): ```json { "$schema": "https://playground.wordpress.net/blueprint-schema.json", "landingPage": "/wp-admin/post-new.php", "plugins": ["gutenberg"], "login": true, "steps": [ { "step": "runPHP", "code": "<?php require '/wordpress/wp-load.php'; update_option('gutenberg-experiments', array('gutenberg-media-processing' => true));" } ] } ``` 3. The post editor loads without crashing. 4. In the WP iframe's DevTools console: - `crossOriginIsolated` → `true` - `typeof SharedArrayBuffer` → `"function"` - `window.__clientSideMediaProcessing` → `true` 5. The admin document response carries `Document-Isolation-Policy: isolate-and-credentialless` and no COEP/COOP. 6. Upload an image — it is processed client-side (wasm-vips loads; no server-side sub-size generation request). 7. Upload a small AVIF image (sample attached below) - it works (before this PR it fails) 8. Non-Chromium (Firefox/Safari): editor still opens; client-side media is simply not engaged (unchanged behavior). 9. Embedded Playground on a 3rd-party page with no COEP/COOP still loads (DIP is per-document, so this should hold). 10. Embedding 3p elements on the page, eg. a YouTube embed, still work 11. Iframe using elements such as the classic block work as expected Automated: ``` npx nx e2e playground-website --grep="Document-Isolation-Policy|client-side media|crossOriginIsolated" ``` ## Notes on backwards compatibility - No user-facing breaking changes. - The COEP→DIP rewrite path is preserved, so older WordPress/Gutenberg versions, or plugins that set COEP/COOP themselves, keep working as they do today. - Non-Chromium browsers: no regression — DIP is unsupported there, Playground's feature detection returns `false`, headers pass through, and Gutenberg's JS feature detection falls back the same as before.
Motivation for the change, related issues
When using Gutenberg v22.6.0 or WordPress 7.0 beta, the site and post editors fail to load when the
cross-origin-embedder-policy: credentiallessheader is sent for the editor parent document.Implementation details
We don't yet know why this is an issue for Playground, and we'll be looking into it. But in the meantime, disabling client-side media processing avoids the issue:
Testing Instructions (or ideally a Blueprint)