diff --git a/packages/playground/remote/iframes-trap.js b/packages/playground/remote/iframes-trap.js
new file mode 100644
index 0000000000..21bbc4f598
--- /dev/null
+++ b/packages/playground/remote/iframes-trap.js
@@ -0,0 +1,545 @@
+'use strict';
+
+/**
+ * Controlled iframe bootstrap.
+ * Converts srcdoc/blob/data/about:blank iframes into real navigations that stay
+ * under the page's Service Worker control. Also rescues already-inserted
+ * same-origin iframes by virtualizing their DOM and reloading through a loader.
+ *
+ * This file is loaded in multiple contexts (loader, wp-admin, etc.). It must be
+ * safe to include more than once, so we guard on a global flag and avoid
+ * top-level const redefinitions.
+ */
+function setupIframesTrap() {
+ // Document.prototype.write = function (html) {
+ // console.log('intercepting document.write', html);
+ // // return Native.write.call(this, html);
+ // };
+
+ if (!window.__controlled_iframes_loaded__) {
+ window.__controlled_iframes_loaded__ = true;
+
+ const iframeCacheBucket = 'iframe-virtual-docs-v1';
+
+ // Best-effort synchronous scope guess so we can seed src immediately in createElement.
+ const inferredSiteScope =
+ document.currentScript?.dataset.scope ??
+ location.pathname.match(/^\/scope:[^/]+/)?.[0] ??
+ '';
+
+ // Authoritative scope from the SW registration (async fallback to sync guess).
+ const scopePromise = (async () => {
+ try {
+ const reg = await navigator.serviceWorker.ready;
+ return new URL(reg.scope).pathname.replace(/\/$/, '');
+ } catch {
+ return inferredSiteScope.replace(/\/$/, '');
+ }
+ })();
+
+ const scopedPaths = (scope) => {
+ const base = scope.replace(/\/$/, '');
+ return {
+ VIRTUAL_PREFIX: `${base}/__iframes/`,
+ LOADER_PATH: `${base}/wp-includes/empty.html`,
+ };
+ };
+
+ // Snapshot natives before we patch prototypes.
+ const Native = {
+ write: Document.prototype.write,
+ createElement: Document.prototype.createElement,
+ setAttribute: Element.prototype.setAttribute,
+ iframeSrc: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'src'
+ ),
+ iframeSrcdoc: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'srcdoc'
+ ),
+ src: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'src'
+ ),
+ srcdoc: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'srcdoc'
+ ),
+ contentWindow: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'contentWindow'
+ ),
+ contentDocument: Object.getOwnPropertyDescriptor(
+ HTMLIFrameElement.prototype,
+ 'contentDocument'
+ ),
+ };
+
+ const setIframeSrc = (iframe, url) => {
+ if (Native.iframeSrc?.set) {
+ Native.iframeSrc.set.call(iframe, url);
+ } else {
+ Native.setAttribute.call(iframe, 'src', url);
+ }
+ };
+
+ const uid = () =>
+ `${Date.now().toString(36)}-${Math.random()
+ .toString(36)
+ .slice(2, 10)}`;
+
+ async function cacheIframeContents(id, html) {
+ const cache = await caches.open(iframeCacheBucket);
+ const scope = await scopePromise;
+ const { VIRTUAL_PREFIX } = scopedPaths(scope);
+ await cache.put(
+ `${VIRTUAL_PREFIX}${id}.html`,
+ new Response(html, {
+ headers: { 'Content-Type': 'text/html; charset=utf-8' },
+ })
+ );
+ }
+
+ async function toLoaderUrl({
+ id,
+ prettyUrl = '',
+ base = document.baseURI,
+ } = {}) {
+ const scope = await scopePromise;
+ const { LOADER_PATH } = scopedPaths(scope);
+ const queryString = new URLSearchParams({ base, url: prettyUrl });
+ if (id) {
+ queryString.set('id', id);
+ }
+ return `${LOADER_PATH}#${queryString.toString()}`;
+ }
+
+ async function rewriteSrcdoc(iframe, html, opts = {}) {
+ const id = uid();
+ await cacheIframeContents(id, html);
+ const url = await toLoaderUrl({ id, ...opts });
+ setIframeSrc(iframe, url);
+ iframe.setAttribute('data-controlled', '1');
+ }
+
+ async function rewriteDataOrBlob(el, url) {
+ const res = await fetch(url);
+ const html = await res.text();
+ await rewriteSrcdoc(el, html);
+ }
+
+ // --- Interceptors ---
+ Document.prototype.write = function (html) {
+ console.log('intercepting document.write', html);
+ // @TODO: parse etc.
+ // Ensure is correctly set before writing HTML to the document
+ if (typeof html === 'string' && html.trim().length > 0) {
+ let baseHref = document.baseURI;
+ let baseTag = ``;
+ // Only inject if one does not exist in the html being written
+ if (!/, or at the top if
not present
+ if (//i.test(html)) {
+ html = html.replace(
+ /()/i,
+ `$1${baseTag}`
+ );
+ } else {
+ html = baseTag + html;
+ }
+ }
+ }
+ return Native.write.call(this, html);
+ };
+
+ // Stash this realm's native createElement on both Document and HTMLDocument
+ // so other realms (or our own helpers) can find it without re-entering the wrapper.
+ for (const proto of [
+ Document.prototype,
+ HTMLDocument?.prototype,
+ ].filter(Boolean)) {
+ if (!proto.__playground_native_createElement) {
+ Object.defineProperty(
+ proto,
+ '__playground_native_createElement',
+ {
+ value: Native.createElement,
+ configurable: true,
+ }
+ );
+ }
+ }
+
+ const createElementWrapper = function (...args) {
+ /**
+ * Always call the native createElement belonging to the receiver's realm.
+ * Using a cached native from a different realm triggers "Illegal invocation".
+ */
+ const receiver = this ?? document;
+ // Same realm: safe to call our captured native.
+ if (receiver instanceof Document) {
+ return handleCreateElement(
+ callRealmCreateElement(receiver, args),
+ args
+ );
+ }
+
+ // Other realm: reach for that realm's native createElement if exposed.
+ const element = callRealmCreateElement(receiver, args);
+ return element;
+ };
+
+ function callRealmCreateElement(receiver, args) {
+ const attempts = [];
+
+ // 1) Receiver's own realm-native (if we, or that realm, stashed it).
+ const proto = receiver && Object.getPrototypeOf(receiver);
+ if (proto?.__playground_native_createElement) {
+ attempts.push(proto.__playground_native_createElement);
+ }
+
+ // 2) Receiver prototype's current createElement (native if that realm
+ // hasn't been patched yet; safe if it's not our wrapper).
+ if (
+ proto?.createElement &&
+ proto.createElement !== createElementWrapper
+ ) {
+ attempts.push(proto.createElement);
+ }
+
+ // 3) Our own captured native for this realm.
+ attempts.push(Native.createElement);
+
+ // 4) Bound document.createElement as a last resort.
+ attempts.push(document.createElement.bind(document));
+
+ for (const fn of attempts) {
+ if (typeof fn !== 'function') {
+ continue;
+ }
+ try {
+ return Reflect.apply(fn, receiver, args);
+ } catch (e) {
+ // Try the next candidate.
+ }
+ }
+
+ throw new Error('createElement failed across all candidates');
+ }
+
+ function handleCreateElement(element, args) {
+ const tagName = args[0];
+ const options = args[1];
+ if (String(tagName).toLowerCase() === 'iframe') {
+ const iframe = element;
+ try {
+ // console.log(
+ // 'intercepting iframe createElement',
+ // tagName,
+ // options
+ // );
+ const { LOADER_PATH } = scopedPaths(inferredSiteScope);
+ if (
+ !iframe.hasAttribute('src') &&
+ !iframe.hasAttribute('srcdoc')
+ ) {
+ // console.log('initializing to loader', LOADER_PATH);
+ if (LOADER_PATH) {
+ // console.log('setting iframe src', LOADER_PATH);
+ const url = `${LOADER_PATH}#${new URLSearchParams({
+ base: document.baseURI,
+ }).toString()}`;
+ setIframeSrc(iframe, url);
+ iframe.setAttribute('data-controlled', '1');
+ }
+ } else {
+ const script = document.createElement('script');
+ script.src = `${LOADER_PATH}#${new URLSearchParams({
+ base: document.baseURI,
+ }).toString()}`;
+ iframe.contentDocument.head.prepend(script);
+ }
+ // On every iframe load, disable document.write in it
+ iframe.addEventListener('load', function () {
+ try {
+ if (
+ iframe.contentWindow &&
+ iframe.contentWindow.document
+ ) {
+ iframe.contentWindow.document.write =
+ function () {
+ throw new Error(
+ 'document.write is disabled in this iframe'
+ );
+ };
+ }
+ } catch (e) {
+ // Could be cross-origin or not ready, ignore
+ }
+ });
+ } catch (error) {
+ console.error('error setting iframe src', iframe);
+ console.error(error);
+ /* ignore */
+ }
+ }
+ return element;
+ }
+
+ // 1) createElement: seed blank iframes with a real loader src synchronously.
+ Document.prototype.createElement = createElementWrapper;
+
+ // 2) Attribute setter patch.
+ Element.prototype.setAttribute = function (name, value) {
+ if (this instanceof HTMLIFrameElement) {
+ const nameLower = name.toLowerCase();
+ const valueString = String(value);
+ if (nameLower === 'srcdoc') {
+ // console.log('intercepting iframe srcdoc', valueString);
+ void rewriteSrcdoc(this, valueString);
+ return;
+ }
+ if (nameLower === 'src') {
+ // console.log('intercepting iframe set src', valueString);
+ if (
+ valueString.startsWith('data:text/html') ||
+ valueString.startsWith('blob:')
+ ) {
+ void rewriteDataOrBlob(this, valueString);
+ return;
+ }
+ if (
+ valueString === 'about:blank' ||
+ valueString === '' ||
+ valueString.startsWith('javascript:')
+ ) {
+ // Treat javascript:/blank src as a request for a controlled, empty doc.
+ // We route it through the loader so the iframe is SW-controlled from
+ // the very first real navigation.
+ void rewriteSrcdoc(this, '', {
+ base: document.baseURI,
+ prettyUrl: location.href,
+ });
+ return;
+ }
+ }
+ }
+ return Native.setAttribute.call(this, name, value);
+ };
+
+ Object.defineProperty(HTMLIFrameElement.prototype, 'src', {
+ configurable: true,
+ enumerable: Native.src?.enumerable ?? true,
+ get() {
+ return Native.src.get.call(this);
+ },
+ set(v) {
+ console.log('intercepting iframe src', v);
+ Element.prototype.setAttribute.call(this, 'src', String(v));
+ },
+ });
+
+ Object.defineProperty(HTMLIFrameElement.prototype, 'srcdoc', {
+ configurable: true,
+ enumerable: Native.srcdoc?.enumerable ?? true,
+ get() {
+ return Native.srcdoc.get.call(this);
+ },
+ set(v) {
+ console.log('intercepting iframe srcdoc', v);
+ Element.prototype.setAttribute.call(this, 'srcdoc', String(v));
+ },
+ });
+
+ Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
+ configurable: true,
+ enumerable: Native.contentWindow?.enumerable ?? true,
+ get() {
+ // console.trace('intercepting iframe contentWindow get', this);
+ const iframe = this;
+ const contentWindow = Native.contentWindow.get.call(this);
+ if (contentWindow) {
+ // contentDocument may be undefined, so wait for iframe to load before injecting script
+ const injectScript = () => {
+ const doc =
+ contentWindow.document ||
+ contentWindow.contentDocument;
+ // console.log('pre inject script', doc);
+ if (doc && doc.head) {
+ // console.log('injecting script', setupIframesTrap);
+ // const script = document.createElement('script');
+ // script.src =
+ // setupIframesTrap + ';setupIframesTrap();';
+ // doc.head.prepend(script);
+ }
+ };
+ // attach event; contentWindow.frameElement is the