Skip to content

[Web] Avoid cross-origin policy errors in editor - #3312

Merged
brandonpayton merged 1 commit into
trunkfrom
workaround/gutenberg-empty-html-loading-issue
Feb 27, 2026
Merged

brandonpayton merged 1 commit into
trunkfrom
workaround/gutenberg-empty-html-loading-issue

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Feb 27, 2026 •

Copy link
Copy Markdown
Member

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: credentialless header 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:

add_filter('wp_client_side_media_processing_enabled', '__return_false');

Testing Instructions (or ideally a Blueprint)

  • CI
  • Load Playground with the latest Gutenberg plugin and make sure the site and post editors load completely.

@brandonpayton brandonpayton added the [Type] Bug An existing feature does not function as intended label Feb 27, 2026
Copilot AI review requested due to automatic review settings February 27, 2026 04:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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!

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

The inverted exclamation mark '¡' at the beginning should be replaced with a standard exclamation mark '!' for consistency with typical code documentation practices.

Suggested change
* ¡TEMPORARY WORKAROUND!
* !TEMPORARY WORKAROUND!

Copilot uses AI. Check for mistakes.
/**
* ¡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`

Copilot AI Feb 27, 2026

Copy link

Choose a reason for hiding this comment

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

Missing word 'to' after 'related'. Should read 'This appears related to the'.

Suggested change
* 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`

Copilot uses AI. Check for mistakes.
@brandonpayton
brandonpayton merged commit db2eb07 into trunk Feb 27, 2026
42 checks passed
@brandonpayton
brandonpayton deleted the workaround/gutenberg-empty-html-loading-issue branch February 27, 2026 05:10
bgrgicak pushed a commit that referenced this pull request Apr 23, 2026
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package][@wp-playground] Website [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants