Skip to content

Commit f4e6cbd

Browse files
committed
Inline TinyMCE content_css to fix service worker gap
TinyMCE loads its content_css (editor styles, dashicons, theme CSS) via <link> tags inside an about:blank iframe it creates for the editing area. The Playground service worker cannot intercept sub-resource requests from about:blank documents, so those CSS files return 404 — visible as "Failed to load content css" in TinyMCE's notification bar. This affects all WP versions that use TinyMCE (3.9–4.9, and modern WP with Classic Editor) on both localhost and 127.0.0.1 with a fresh browser context. Add a mu-plugin that hooks tiny_mce_before_init, reads each content_css file from disk, and passes the combined CSS inline via TinyMCE's content_style setting. This bypasses the network request entirely. Written in PHP 5.2-compatible syntax so it works across all supported PHP versions.
1 parent 4418547 commit f4e6cbd

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

  • packages/playground/wordpress/src

packages/playground/wordpress/src/index.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,43 @@ function playground_load_mu_plugins() {
822822
`
823823
);
824824

825+
// TinyMCE's editor iframe uses document.open(), which creates a
826+
// document not controlled by the service worker. Sub-resource
827+
// requests from it (content_css) bypass the SW and 404.
828+
// Inline the CSS via content_style so no network request is needed.
829+
await php.writeFile(
830+
'/internal/shared/mu-plugins/inline-tinymce-content-css.php',
831+
`<?php
832+
function playground_inline_tinymce_content_css($settings) {
833+
if (empty($settings['content_css'])) return $settings;
834+
$css_urls = explode(',', $settings['content_css']);
835+
$inline_css = '';
836+
$doc_root = isset($_SERVER['DOCUMENT_ROOT'])
837+
? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
838+
foreach ($css_urls as $url) {
839+
$url = trim($url);
840+
if (!$url) continue;
841+
$parsed = parse_url($url);
842+
if (!isset($parsed['path'])) continue;
843+
$path = preg_replace('#^/scope:[^/]+#', '', $parsed['path']);
844+
$file = $doc_root . $path;
845+
if (file_exists($file)) {
846+
$inline_css .= @file_get_contents($file) . "\\n";
847+
}
848+
}
849+
if ($inline_css !== '') {
850+
if (!empty($settings['content_style'])) {
851+
$inline_css = $settings['content_style'] . "\\n" . $inline_css;
852+
}
853+
$settings['content_style'] = $inline_css;
854+
$settings['content_css'] = '';
855+
}
856+
return $settings;
857+
}
858+
add_filter('tiny_mce_before_init', 'playground_inline_tinymce_content_css');
859+
`
860+
);
861+
825862
// Load the error handler before any other PHP file to ensure it
826863
// treats all the errors, even those trigerred before mu-plugins
827864
// are loaded.

0 commit comments

Comments
 (0)