Client-Side Media Everywhere

Beschrijving

In one sentence: this plugin gets client-side media processing working in Safari and Firefox, which WordPress otherwise only does in Chrome.

When you upload an image in Chrome, WordPress resizes and compresses it on your own device before it is sent, so less data goes over the wire and your server does much less work. In Safari and Firefox that is switched off, and uploads fall back to the older server-side path. This plugin switches it back on.

There is nothing to configure – activate the plugin and it works. Chrome is unaffected, because WordPress already handles it there.

One thing to know before you install: this works by turning on cross-origin isolation, which is a real security boundary and can affect embeds and third-party media inside the editor. It is worth reading the Tradeoffs section below first.

Why WordPress switches it off:

WordPress 7.1 and Gutenberg include client-side media processing powered by WebAssembly (wasm-vips). This requires cross-origin isolation, which is achieved via Document-Isolation-Policy (DIP) on Chrome 137+.

However, Firefox and Safari do not yet support DIP, and neither does Chrome before 137, so client-side media processing is disabled on those browsers.

This plugin restores support for Firefox and Safari by sending the older COEP/COOP headers (Cross-Origin-Embedder-Policy / Cross-Origin-Opener-Policy) on browsers where DIP is not available.

Under the hood:

  • Sends Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: credentialless (or require-corp on Safari) headers in the block editor.
  • Adds crossorigin="anonymous" attributes to cross-origin resources.
  • Adds credentialless attribute to iframes so they continue working under COEP.
  • Filters embed previews for providers that do not support credentialless iframes (Facebook, SmugMug).

Requirements:

  • WordPress 6.8+ with the Gutenberg plugin (which provides the client-side media processing feature), or WordPress 7.1+.
  • The client-side media processing feature must be enabled (it is on by default in secure contexts).
  • HTTPS (or localhost): client-side media processing requires a secure context.

Tradeoffs

Cross-origin isolation is a security boundary. It works by making the browser refuse cross-origin resources that have not opted in, or strip their credentials. That is what unlocks SharedArrayBuffer and wasm-vips, but it is also why Chrome moved to Document-Isolation-Policy: DIP gives the same isolation without imposing these restrictions on the rest of the page.

Only browsers that receive the COEP/COOP headers are affected – Firefox, Safari, and Chrome < 137 – and only on block editor screens (post editor, site editor, block widgets) for users who can upload files. The front-end, the rest of wp-admin, and Chrome 137+ are untouched.

What can break on those screens:

  • oEmbed previews. Embeds are iframed. Under credentialless (Firefox, Chrome < 137) the plugin adds the credentialless attribute so they still load, but without cookies – embeds that need a logged-in session render logged-out or not at all. Facebook and SmugMug do not work with credentialless iframes, so their live previews are disabled in the editor and the placeholder is shown instead. Safari does not support credentialless at all, so under require-corp any embed whose provider does not send its own COEP header is blocked outright.
  • Media served from third-party origins. Images, video, audio, and fonts loaded into the editor from a CDN or another domain must opt in with Cross-Origin-Resource-Policy. Under credentialless they load but without credentials, so anything behind a signed cookie fails. Under require-corp (Safari) they are blocked unless the server sends CORP – the plugin adds crossorigin="anonymous" to cross-origin images to give them a CORS path instead, which only helps if the server sends Access-Control-Allow-Origin.
  • Popup-based authentication. Cross-Origin-Opener-Policy: same-origin severs the window.opener link to cross-origin popups. Plugins that connect to an external service by opening an OAuth popup and waiting for it to call back into the opener will hang.
  • Plugins that load editor assets cross-origin. Any third-party script, stylesheet, or font pulled into the editor from another origin is subject to the same rules.
  • The classic block. The classic block and other TinyMCE-based UIs commonly load third-party assets, and are a frequent place for the failures above to surface.

These are the same constraints the block editor lived with before Chrome shipped Document-Isolation-Policy. If you hit one, suppress the headers with the csme_use_coep_coop filter or deactivate the plugin – media processing then falls back to the server on the affected browsers, which is the behavior without this plugin installed.

Installatie

  1. Upload the client-side-media-everywhere folder to /wp-content/plugins/.
  2. Activate the plugin through the ‘Plugins’ menu in WordPress.
  3. The plugin activates automatically on browsers that need COEP/COOP headers.

FAQ

Why is media still processed server-side?

Check that your site is served over HTTPS (or localhost). Client-side media processing requires a secure context; without one, cross-origin isolation is unavailable and WordPress silently falls back to server-side processing. The editor logs an informational message in the browser console explaining the reason for the fallback.

Do I need this plugin on Chrome?

No. Chrome 137+ uses Document-Isolation-Policy, which is handled by WordPress core / Gutenberg. This plugin only activates on browsers that do not support DIP.

Will this break my site?

Not the front-end: the COEP/COOP headers are only sent on block editor admin pages, and only on browsers that need them (Firefox, Safari, Chrome < 137). Within the editor on those browsers, cross-origin isolation can break oEmbed previews, media served from third-party origins, popup-based authentication flows, and plugins that load editor assets cross-origin. See the Tradeoffs section for the details and for how to turn the headers off if you hit one.

Can I disable the COEP/COOP behavior?

Yes – deactivate the plugin. Sending the COEP/COOP headers is the plugin’s only job, so there is no separate settings toggle: activating the plugin turns the behavior on, deactivating it turns it off.

To keep the plugin active but suppress the headers programmatically (for example, per environment), use the csme_use_coep_coop filter:

add_filter( 'csme_use_coep_coop', '__return_false' );

How do HEIC uploads work?

WordPress 7.1 converts HEIC images client-side where possible and server-side otherwise. This plugin no longer includes any HEIC handling of its own.

Beoordelingen

Er zijn geen beoordelingen voor deze plugin.

Bijdragers & ontwikkelaars

“Client-Side Media Everywhere” is open source software. De volgende personen hebben bijgedragen aan deze plugin.

Bijdragers

Vertaal “Client-Side Media Everywhere” naar jouw taal.

Interesse in de ontwikkeling?

Bekijk de code, haal de SVN repository op, of abonneer je op het ontwikkellog via RSS.

Changelog

1.1.1

  • Reworked the description to open with a plain explanation of what the plugin does, instead of leading with wasm-vips, Document-Isolation-Policy and COEP/COOP. The technical explanation is still there, further down.
  • Added safari and firefox to the plugin tags, since that is what people are likely searching for.
  • No functional changes: the plugin code is identical to 1.1.0.

1.1.0

  • Renamed the plugin from “Client-Side Media Experiments” to “Client-Side Media Everywhere” to better describe what it does: bringing the WordPress client-side media processing feature to browsers that core does not cover.
  • Removed the settings screen and the csme_enabled option. Activating the plugin now always enables the COEP/COOP headers; deactivate the plugin to turn them off. Note: sites that had unchecked Enable under Settings > Media will have the headers re-enabled after updating. Use the csme_use_coep_coop filter to disable the behavior programmatically.
  • Added crossorigin=”anonymous” to cross-origin images on Safari (require-corp), where they would otherwise be blocked by the embedder policy. Covers src and srcset, including protocol-relative URLs.
  • Included the GPL-2.0 license text in the plugin package.
  • Excluded development files (package.json, package-lock.json, .wp-env.json) from the distribution zip.

1.0.0

  • First stable release, fully compatible with the WordPress 7.1 client-side media processing feature.
  • Removed the HEIC conversion module (heic2any/CDN): WordPress 7.1 handles HEIC uploads in core.
  • Fixed Chromium detection against WordPress 7.1 function names, so no COEP/COOP headers are sent where DIP applies.
  • Deferred initialization to plugins_loaded so plugin activation order no longer matters.
  • The csme_enabled setting default no longer depends on the browser saving the settings.
  • Scoped the __coepCoopIsolation flag to block editor screens instead of every admin page.
  • Added an uninstall handler that removes the plugin option on deletion.

0.2.0

  • Added optional HEIC/HEIF upload support with client-side conversion to JPEG.
  • HEIC conversion library loaded dynamically from CDN (heic2any / libheif).
  • New setting under Settings > Media to enable HEIC support.
  • Filterable CDN URL via csme_heic_library_url.

0.1.0

  • Initial release.
  • COEP/COOP header support for Firefox and Safari.
  • Credentialless iframe handling.
  • Embed preview filtering for incompatible providers.