{"id":306389,"date":"2026-05-16T09:38:52","date_gmt":"2026-05-16T09:38:52","guid":{"rendered":"https:\/\/de.wordpress.org\/plugins\/theme-scss-compiler\/"},"modified":"2026-05-16T09:38:31","modified_gmt":"2026-05-16T09:38:31","slug":"theme-scss-compiler","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/theme-scss-compiler\/","author":17764452,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.0","stable_tag":"1.0.0","tested":"6.9.4","requires":"6.3","requires_php":"8.1","requires_plugins":null,"header_name":"Theme SCSS Compiler","header_author":"Simon Mista","header_description":"Compile multiple SCSS files to CSS in the WordPress admin. Per-file versioning via filter, change detection, optional auto-compile and auto-enqueue. Requires PHP 8.1+.","assets_banners_color":"1c1532","last_updated":"2026-05-16 09:38:31","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/www.simonmista.de\/plugins\/theme-scss-compiler\/","header_author_uri":"https:\/\/www.simonmista.de\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":50,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"simonmista","date":"2026-05-16 09:38:31"}},"upgrade_notice":{"1.0.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3533679,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3533679,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3533679,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3533679,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3533679,"resolution":"1","location":"assets","locale":"","width":1280,"height":1700},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3533679,"resolution":"2","location":"assets","locale":"","width":1280,"height":1700}},"screenshots":{"1":"Settings page under Tools \u2192 Theme SCSS Compiler in production-default mode \u2014 multiple file pairs with per-pair version and Frontend\/Admin context, auto-compile and auto-enqueue enabled.","2":"Same page in development workflow \u2014 Expanded output for readable CSS, manual-compile mode with success feedback after a Compile-now click."},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[40098,356,8862,31643,1141],"plugin_category":[59],"plugin_contributors":[263132],"plugin_business_model":[],"class_list":["post-306389","plugin","type-plugin","status-publish","hentry","plugin_tags-compiler","plugin_tags-css","plugin_tags-sass","plugin_tags-scss","plugin_tags-theme","plugin_category-utilities-and-tools","plugin_contributors-simonmista","plugin_committers-simonmista"],"banners":{"banner":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/banner-772x250.png?rev=3533679","banner_2x":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/banner-1544x500.png?rev=3533679","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/icon-128x128.png?rev=3533679","icon_2x":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/icon-256x256.png?rev=3533679","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/screenshot-1.png?rev=3533679","caption":"Settings page under Tools \u2192 Theme SCSS Compiler in production-default mode \u2014 multiple file pairs with per-pair version and Frontend\/Admin context, auto-compile and auto-enqueue enabled."},{"src":"https:\/\/ps.w.org\/theme-scss-compiler\/assets\/screenshot-2.png?rev=3533679","caption":"Same page in development workflow \u2014 Expanded output for readable CSS, manual-compile mode with success feedback after a Compile-now click."}],"raw_content":"<!--section=description-->\n<p>Theme SCSS Compiler lets you manage <strong>multiple SCSS \u2192 CSS pairs<\/strong> in the active theme directly from the WordPress admin (Tools \u2192 Theme SCSS Compiler). It uses the bundled scssphp library \u2014 no Node.js, no build tools, no command line. SCSS is the modern Sass syntax (CSS-superset with braces and semicolons).<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>Multiple file pairs<\/strong> \u2013 configure as many SCSS \u2192 CSS pairs as your theme needs (paths relative to the active theme).<\/li>\n<li><strong>Per-pair Context<\/strong> \u2013 each pair runs on either the Frontend (<code>wp_enqueue_scripts<\/code>) or the Admin (<code>admin_enqueue_scripts<\/code>).<\/li>\n<li><strong>Per-file versioning<\/strong> \u2013 each pair has its own version. Bumps are applied automatically via the <code>style_loader_src<\/code> filter, so your theme files stay untouched.<\/li>\n<li><strong>Smart change detection<\/strong> \u2013 the version only bumps when the compiled CSS content of that specific pair actually changed. No cache busting for files you didn't touch.<\/li>\n<li><strong><code>@import<\/code>-aware auto-recompile<\/strong> \u2013 every SCSS partial (<code>@import<\/code>, <code>@use<\/code>, <code>@forward<\/code>) is tracked. Editing a partial alone triggers a recompile on the next admin page load \u2014 no need to touch the entry SCSS file.<\/li>\n<li><strong>Compressed (production) or expanded (development)<\/strong> SCSS output.<\/li>\n<li><strong>Auto-compile<\/strong> when an SCSS source (or any of its imports) changes or the CSS output is missing \u2013 no white layouts after a fresh deployment.<\/li>\n<li><strong>Auto-enqueue<\/strong> \u2013 the plugin runs <code>wp_enqueue_style()<\/code> for every configured pair on its respective context. Skips files that are already registered, so it never duplicates output.<\/li>\n<li><strong>Manual compile button<\/strong> with live AJAX feedback and persistent error display in the admin.<\/li>\n<li><strong>Concurrent-compile lock<\/strong> \u2013 a transient-based mutex prevents two admins triggering compiles at the same time from corrupting the CSS output.<\/li>\n<li><strong>Code-first configuration<\/strong> \u2013 every option (pairs, output style, auto-compile, auto-enqueue, bump version) can be defined as a PHP constant in <code>wp-config.php<\/code>, in your theme, or via your <code>.env<\/code> \/ Bedrock workflow.<\/li>\n<li><strong>Admin-only access<\/strong> \u2013 every endpoint requires the <code>manage_options<\/code> capability by default. Filterable via <code>tscsscompiler_capability<\/code> if you need to grant access to a custom role.<\/li>\n<li><strong>Modern codebase<\/strong> \u2013 PHP 8.1+, WCAG 2.1 AA compliant admin UI, fully translated to German out of the box.<\/li>\n<\/ul>\n\n<h4>Privacy \/ GDPR<\/h4>\n\n<p>This plugin makes <strong>no external HTTP requests<\/strong>, sets <strong>no cookies<\/strong>, runs <strong>no telemetry<\/strong>, and does <strong>not<\/strong> track users. All processing happens locally on your server. The bundled libraries (scssphp, league\/uri, symfony\/filesystem, PSR HTTP interfaces) are MIT licensed and GPL-compatible. Source code is included in the plugin's <code>vendor\/<\/code> directory.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>theme-scss-compiler<\/code> folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate the plugin in <strong>Plugins<\/strong>.<\/li>\n<li>Go to <strong>Tools \u2192 Theme SCSS Compiler<\/strong>, configure your SCSS \/ CSS paths and the per-pair context.<\/li>\n<li>Either click <strong>Compile now<\/strong> or simply load any admin page \u2013 auto-compile is on by default and will create the CSS output the first time.<\/li>\n<\/ol>\n\n<p>For developers who prefer code-based configuration, see the FAQ on configuring the plugin via constants \u2014 <code>wp-config.php<\/code>, your theme, or <code>.env<\/code> \/ Bedrock.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"which%20scss%20version%20does%20this%20support%3F\"><h3>Which SCSS version does this support?<\/h3><\/dt>\n<dd><p>The plugin bundles scssphp 2.1, which supports modern SCSS syntax compatible with Dart Sass.<\/p><\/dd>\n<dt id=\"when%20does%20a%20version%20actually%20get%20bumped%3F\"><h3>When does a version actually get bumped?<\/h3><\/dt>\n<dd><p>Only when the compiled CSS output for that specific pair has changed compared to the previously written file. Comments-only edits or no-op SCSS changes that result in identical compressed CSS do not bust the cache. Other pairs keep their existing versions.<\/p><\/dd>\n<dt id=\"how%20does%20the%20per-pair%20context%20%28frontend%20%2F%20admin%29%20setting%20work%3F\"><h3>How does the per-pair Context (Frontend \/ Admin) setting work?<\/h3><\/dt>\n<dd><p>Each pair has a <em>Context<\/em> field. Pairs set to <strong>Frontend<\/strong> are auto-enqueued via <code>wp_enqueue_scripts<\/code> (only on the public site). Pairs set to <strong>Admin<\/strong> are auto-enqueued via <code>admin_enqueue_scripts<\/code> (only on <code>\/wp-admin<\/code> pages). The <code>style_loader_src<\/code> version filter applies in both contexts whenever a configured CSS file is printed. Default for new pairs is <strong>Frontend<\/strong>.<\/p><\/dd>\n<dt id=\"who%20can%20access%20the%20admin%20page%3F\"><h3>Who can access the admin page?<\/h3><\/dt>\n<dd><p>By default only WordPress administrators (users with the <code>manage_options<\/code> capability). The Tools \u2192 Theme SCSS Compiler submenu, the form save handler, the AJAX compile endpoint and the auto-compile hook all enforce this capability. Editors, Authors and other roles cannot see or use the plugin's UI.<\/p>\n\n<p>If you need to grant access to a different role (for example a custom \"Theme Developer\" role), use the <code>tscsscompiler_capability<\/code> filter:<\/p>\n\n<pre><code>add_filter( 'tscsscompiler_capability', static function () {\n    return 'edit_theme_options';\n} );\n<\/code><\/pre><\/dd>\n<dt id=\"what%20happens%20if%20the%20css%20file%20is%20missing%3F\"><h3>What happens if the CSS file is missing?<\/h3><\/dt>\n<dd><p>If <strong>Auto-compile<\/strong> is enabled (default: on), every admin page load checks whether the configured CSS files exist or whether the SCSS source \u2014 or any of its <code>@import<\/code>-ed partials \u2014 is newer. Missing or stale outputs are compiled silently. This protects against white layouts after a fresh deployment or <code>git pull<\/code>.<\/p><\/dd>\n<dt id=\"does%20it%20detect%20changes%20in%20%60%40import%60-ed%20partials%3F\"><h3>Does it detect changes in `@import`-ed partials?<\/h3><\/dt>\n<dd><p>Yes. After every successful compile the plugin records the full list of files that scssphp pulled in (including transitive <code>@import<\/code> \/ <code>@use<\/code> \/ <code>@forward<\/code> chains) into a per-pair dependency map. The auto-compile check compares the modification time of each tracked partial against the CSS output. So if <code>style.scss<\/code> does <code>@import \"menu-styles\";<\/code> and you edit <code>menu-styles.scss<\/code>, the next admin page load triggers a recompile automatically \u2014 you don't have to touch <code>style.scss<\/code>.<\/p><\/dd>\n<dt id=\"should%20i%20let%20the%20plugin%20enqueue%20my%20css%2C%20or%20do%20it%20in%20%60functions.php%60%3F\"><h3>Should I let the plugin enqueue my CSS, or do it in `functions.php`?<\/h3><\/dt>\n<dd><p>Both work. <strong>Auto-enqueue<\/strong> is on by default \u2014 the plugin runs <code>wp_enqueue_style()<\/code> for every configured pair on its respective context (Frontend or Admin). It runs at <code>PHP_INT_MAX<\/code> priority and skips any URL that's already registered, so it never duplicates output. If you'd rather keep full control of the asset pipeline in your theme, just disable the option and call <code>wp_enqueue_style()<\/code> yourself.<\/p><\/dd>\n<dt id=\"can%20i%20configure%20the%20plugin%20from%20code%20instead%20of%20the%20admin%20form%3F\"><h3>Can I configure the plugin from code instead of the admin form?<\/h3><\/dt>\n<dd><p>Yes. Define <code>TSCSSCOMPILER_PAIRS<\/code> and the plugin reads pairs from there instead of the database. The admin form switches to a read-only state and the save handler is disabled.<\/p>\n\n<pre><code>define( 'TSCSSCOMPILER_PAIRS', [\n    [ 'scss_path' =&gt; 'assets\/scss\/style.scss',       'css_path' =&gt; 'assets\/css\/style.css',       'version' =&gt; '1.0.0', 'context' =&gt; 'frontend' ],\n    [ 'scss_path' =&gt; 'assets\/scss\/style-admin.scss', 'css_path' =&gt; 'assets\/css\/style-admin.css', 'version' =&gt; '1.0.0', 'context' =&gt; 'admin'    ],\n] );\n<\/code><\/pre>\n\n<p>The remaining behaviours can be toggled individually:<\/p>\n\n<ul>\n<li><code>TSCSSCOMPILER_AUTO_COMPILE<\/code> \u2013 <code>true<\/code> \/ <code>false<\/code><\/li>\n<li><code>TSCSSCOMPILER_BUMP_VERSION<\/code> \u2013 <code>true<\/code> \/ <code>false<\/code> (note: bumping is a no-op when defined via constant \u2014 versions live in your code)<\/li>\n<li><code>TSCSSCOMPILER_AUTO_ENQUEUE<\/code> \u2013 <code>true<\/code> \/ <code>false<\/code><\/li>\n<li><code>TSCSSCOMPILER_OUTPUT_STYLE<\/code> \u2013 <code>'compressed'<\/code> \/ <code>'expanded'<\/code><\/li>\n<\/ul><\/dd>\n<dt id=\"where%20can%20i%20put%20the%20%60define%28%29%60%20calls%3F\"><h3>Where can I put the `define()` calls?<\/h3><\/dt>\n<dd><p>Three common places:<\/p>\n\n<p><strong>1. <code>wp-config.php<\/code><\/strong> (loaded earliest, recommended for everything):<\/p>\n\n<pre><code>define( 'TSCSSCOMPILER_OUTPUT_STYLE', 'compressed' );\n<\/code><\/pre>\n\n<p><strong>2. Theme <code>functions.php<\/code><\/strong> (use the <code>after_setup_theme<\/code> hook so the constant exists by the time the plugin reads it):<\/p>\n\n<pre><code>add_action( 'after_setup_theme', static function () {\n    if ( ! defined( 'TSCSSCOMPILER_PAIRS' ) ) {\n        define( 'TSCSSCOMPILER_PAIRS', [\n            [ 'scss_path' =&gt; 'assets\/scss\/style.scss', 'css_path' =&gt; 'assets\/css\/style.css', 'version' =&gt; '1.0.0', 'context' =&gt; 'frontend' ],\n        ] );\n    }\n} );\n<\/code><\/pre>\n\n<p><strong>3. <code>.env<\/code> + <code>wp-config.php<\/code> (Bedrock-style)<\/strong>:<\/p><\/dd>\n<dt id=\".env\"><h3>.env<\/h3><\/dt>\n<dd><p>TSCSSCOMPILER_AUTO_ENQUEUE=true\n    TSCSSCOMPILER_OUTPUT_STYLE=compressed<\/p><\/dd>\n<dt id=\"wp-config.php%20%28or%20config%2Fapplication.php%20in%20bedrock%29\"><h3>wp-config.php (or config\/application.php in Bedrock)<\/h3><\/dt>\n<dd><p>if ( getenv( 'TSCSSCOMPILER_AUTO_ENQUEUE' ) !== false ) {\n        define( 'TSCSSCOMPILER_AUTO_ENQUEUE', filter_var( getenv( 'TSCSSCOMPILER_AUTO_ENQUEUE' ), FILTER_VALIDATE_BOOLEAN ) );\n    }\n    if ( $style = getenv( 'TSCSSCOMPILER_OUTPUT_STYLE' ) ) {\n        define( 'TSCSSCOMPILER_OUTPUT_STYLE', $style );\n    }<\/p>\n\n<p>Pairs as a deep array don't fit naturally in <code>.env<\/code> \u2014 define them in <code>wp-config.php<\/code> (or <code>config\/application.php<\/code> in Bedrock) instead.<\/p><\/dd>\n<dt id=\"why%20do%20i%20see%20a%20notice%20%22configured%20via%20wp-config.php%22%20on%20the%20admin%20page%3F\"><h3>Why do I see a notice \"Configured via wp-config.php\" on the admin page?<\/h3><\/dt>\n<dd><p>That means <code>TSCSSCOMPILER_PAIRS<\/code> is defined somewhere (wp-config, theme, .env bridge). The form is intentionally read-only in that state \u2014 to make changes, edit the source where the constant is defined. Boolean toggles like <code>\u2026_AUTO_COMPILE<\/code> defined via constants are also reflected as locked switches.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20accessible%3F\"><h3>Is the plugin accessible?<\/h3><\/dt>\n<dd><p>Yes. The admin UI is built to <strong>WCAG 2.1 AA<\/strong>: semantic HTML with proper heading hierarchy, ARIA roles for status \/ alert regions, keyboard-focusable controls with visible focus rings, sufficient colour contrast (4.5:1 minimum for body text, 3:1 for UI components), and minimum 12px font size for caps-styled labels. All decorative SVG icons are marked <code>aria-hidden=\"true\"<\/code>.<\/p><\/dd>\n<dt id=\"is%20there%20a%20german%20translation%3F\"><h3>Is there a German translation?<\/h3><\/dt>\n<dd><p>Yes, ships out of the box. All admin strings, hints and error messages are translated to German (<code>de_DE<\/code>).<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Multiple SCSS \u2192 CSS pairs with per-pair version and Frontend\/Admin context.<\/li>\n<li><code>@import<\/code>-aware dependency tracking \u2013 every imported partial is recorded; editing a partial alone triggers auto-recompile.<\/li>\n<li>Smart change detection via content comparison \u2013 versions only bump on real CSS changes.<\/li>\n<li>Auto-compile on missing or stale output.<\/li>\n<li>Auto-enqueue with duplicate detection (runs at <code>PHP_INT_MAX<\/code> priority).<\/li>\n<li>Manual compile button with AJAX feedback.<\/li>\n<li>Concurrent-compile lock to prevent race conditions on busy multi-admin sites.<\/li>\n<li>Code-first configuration via <code>TSCSSCOMPILER_*<\/code> constants.<\/li>\n<li><code>tscsscompiler_capability<\/code> filter for granting access to custom roles.<\/li>\n<li>Filesystem writes via WordPress <code>WP_Filesystem<\/code> API.<\/li>\n<li>WCAG 2.1 AA compliant admin UI.<\/li>\n<li>German translation included.<\/li>\n<li>PHP 8.1+ required.<\/li>\n<li>Bundles scssphp 2.1 (MIT) and dependencies.<\/li>\n<\/ul>","raw_excerpt":"Compile SCSS \/ Sass to CSS in the WP admin. Multiple file pairs, per-file versioning, @import-aware change detection, optional auto-compile.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/306389","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=306389"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/simonmista"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=306389"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=306389"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=306389"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=306389"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=306389"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=306389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}