Skip to content

refactor(breakpoints): apply custom breakpoints to the built CSS instead of compiling SCSS on the site - #259

Merged
nk-o merged 7 commits into
masterfrom
claude/ghost-kit-critical-error-26e519
Sep 14, 2026
Merged

nk-o merged 7 commits into
masterfrom
claude/ghost-kit-critical-error-26e519

Conversation

@nk-o

@nk-o nk-o commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Custom breakpoints were applied by compiling the shipped SCSS on the user's site with scssphp, php-css-parser and rtlcss-php, through a cron queue. Those libraries were bundled unprefixed, so a second copy of php-css-parser in another plugin made the site fatal (Declaration of Sabberworm\CSS\Value\Size::render(...) must be compatible with ..., reported on 3.7.0). The four default values (576, 768, 992, 1200) only ever appear inside @media preludes of the built CSS, so the plugin now replaces them there and writes the result to uploads/ghostkit/build/, mirroring the plugin paths. The compiler, its four libraries and the SCSS sources leave the plugin and the release zip.

The migration keyed 3.7.2 waits for the release that bumps GHOSTKIT_VERSION; the runner now skips migrations keyed above the plugin version, so this branch alone changes nothing on existing sites until the version bump. It also keys on ghostkit_db_version instead of vpf_db_version, which is the option Visual Portfolio's migrations write: on a site with both plugins VP's higher version blocked every Ghost Kit migration. Both existing migrations are idempotent, so the one extra pass of v_2_25_1 is harmless.

Why replacement rather than prefixing the libraries: prefixing (Strauss) would have closed this one collision and kept the compiler, the in-place rewriting of shipped SCSS, the queue and the RTL naming bug below. The replacement is a single regex pass measured at 1.6 to 9.3 ms over all 66 built files, so it runs synchronously on the same trigger as before (a change of breakpoints or of the plugin version) and the background queue goes with the compiler. The cost is that the build becomes a contract: a px width inside an @media prelude that is not one of the four defaults would ship unreplaced. BreakpointsCssTest::test_build_media_queries_use_known_widths fails the suite when one appears.

The .min suffix style data on ghostkit, the block styles, ghostkit-editor, ghostkit-admin and ghostkit-settings existed for the compiler's -rtl.min.css naming. WordPress derives the RTL URL with str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $href ), which never matched our build/*.css hrefs, so RTL sites with default breakpoints were loading the LTR files. The suffix is gone; BreakpointsRtlTest fails on the old code for all four handles.

Ghost Kit Pro is not in this PR. The free plugin steps aside when Pro is active, so Pro sites run the core bundled inside Pro until its core-plugin submodule is bumped and its GhostKit_PRO_Breakpoints drops the compiler overrides. That is a separate PR. Known and left as is: a Pro installed in a folder not named ghostkit-pro loads both cores, the free one wins by sort order, and the un-updated Pro subclass would fatal on the deleted classes/class-scss-compiler.php. Also left: sites that ran Ghost Kit without Visual Portfolio keep a stale vpf_db_version, which is what the old runner wrote.

How to check: activate ghostkit-test-plugin-custom-breakpoints (mapped in .wp-env.json, sets gkt_breakpoint_sm to 700), open any page with a Ghost Kit block, and the ghostkit-css link points at /wp-content/uploads/ghostkit/build/gutenberg/style.css?ver=<hash> with (max-width:700px) inside; deactivate it and the link is the plugin file again. tests/e2e/specs/breakpoints.spec.js does exactly that. Unit tests cover the replacement on literal input, the single pass when a custom value equals another default, the LTR and RTL twins, the src filter, the return to defaults, the migration and the RTL hrefs.

Custom breakpoints were produced by compiling the shipped SCSS on the
site with scssphp, php-css-parser and rtlcss through a cron queue. The
four default values only ever appear inside `@media` preludes of the
built CSS, so replacing them there gives the same files for a few
milliseconds, with no bundled library to collide with another plugin's
copy (the php-css-parser fatal reported on 3.7.0).

The `.min` suffix style data existed for the compiler's `-rtl.min.css`
naming and left RTL sites with the LTR file whenever breakpoints were
default; the RTL unit test fails without its removal.

Spec: .specs/002-breakpoints-search-replace
The generator from the previous commit leaves nothing for scssphp,
php-css-parser, rtlcss-php and wp-background-processing to do, nor for
the SCSS sources the compiler read on the site and rewrote in place, so
they leave the plugin and the release zip. A migration keyed 3.7.2
removes the compiled files in uploads, the queue's cron event and its
options.

Spec: .specs/002-breakpoints-search-replace
A helper plugin sets `gkt_breakpoint_sm` the way Pro does, so the spec
can see the main and form stylesheets served from uploads with the
custom value and from the plugin again once the helper is inactive.

Spec: .specs/002-breakpoints-search-replace
wp-background-processing stored its batches and status through
update_site_option(), so on multisite they sit in sitemeta rather than
options. The test writes the legacy cron entry the way an old site holds
it, on an interval that no longer exists.

Spec: .specs/002-breakpoints-search-replace
Three more style handles carried the `.min` suffix data that made RTL
sites load the LTR file; the RTL test now covers all four handles. A
migration keyed above the current plugin version waited for nothing and
ran on every request, so the runner skips it until the release that
carries it. A directory PHP cannot open threw out of the CSS walks and
took the site down; both walks stop there instead.

Spec: .specs/002-breakpoints-search-replace
`vpf_db_version` is the option Visual Portfolio's migrations write, and
its higher version blocked every Ghost Kit migration on sites running
both plugins. Both migrations are idempotent, so the one extra pass of
`v_2_25_1` on existing sites changes nothing.

Spec: .specs/002-breakpoints-search-replace
Ending the walk at the first directory PHP could not open cached a
truncated file list until the next hash change, and a file listed
without its RTL twin sent RTL sites to a 404 because WordPress derives
the -rtl.css URL after the filter. The walk now skips such a directory,
and a written file whose twin was not written is dropped with it.

Spec: .specs/002-breakpoints-search-replace
@nk-o
nk-o merged commit c8d1c29 into master Sep 14, 2026
7 checks passed
@nk-o
nk-o deleted the claude/ghost-kit-critical-error-26e519 branch September 14, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant