litespeedtech / litespeedtech/lscache_wp
Page Optimize: CSS Combine emits an unstyled page
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 257
- Forks
- 123
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
With **CSS Combine** enabled, a page can be served with **no CSS at all** — every original `` stripped, the combined `` never injected, and the `litespeed-dummy.css` placeholder left in the output. The combined CSS file is generated on disk correctly; only its injection into the HTML fails. Fully reproducible and survives every regeneration, so a cache purge does not help — it just re-caches another unstyled page.
**Affected versions:** 7.8, 7.8.0.1, 7.8.1 (latest), and `master`/trunk — the relevant code is identical in all.
## Root cause — two compounding defects in `src/optimize.cls.php`
### 1) `DUMMY_CSS_REGEX` only tolerates a single space between the `id` and `href` attributes
```php
const DUMMY_CSS_REGEX = "#";
$two = "";
// ^ two spaces before href
var_dump(preg_match($re, $one)); // int(1)
var_dump(preg_match($re, $two)); // int(0) <-- extra whitespace => no match
```
### 2) The injection guard treats "no match" as success, silently dropping the optimized CSS instead of falling back
The head-injection site is guarded with `false !== preg_match(...)`:
```php
// Put header content to dummy css position
if (false !== preg_match(self::DUMMY_CSS_REGEX, $this->content)) {
self::debug('Put optm data to dummy css location');
$this->content = preg_replace(self::DUMMY_CSS_REGEX, $this->html_head, $this->content);
}
elseif ( /* present */ ) {
self::debug('Put optm data to be after ');
// ...inject $this->html_head after
}
else {
self::debug('Put optm data to be after ');
// ...inject $this->html_head after
}
```
`preg_match()` returns `0` on no-match and `false` only on error, so `false !== preg_match(...)` is true **even when the pattern does not match**. On the 2-space tag, `preg_match` returns `0`, the code wrongly enters the "matched" branch, runs a `preg_replace` that changes nothing, and never reaches the `` / `` fallback — so `$this->html_head` (which contains the combined CSS ``) is discarded entirely.
The "drop dummy" fallback has the same guard and so also no-ops, which is why the placeholder is additionally left behind in the output:
```php
// Fallback to replace dummy css placeholder
if (false !== preg_match(self::DUMMY_CSS_REGEX, $content)) {
self::debug('Fallback to drop dummy CSS');
$content = preg_replace(self::DUMMY_CSS_REGEX, '', $content);
}
```
Debug-log fingerprint (every generation of an affected page):
```
🎢 Put optm data to dummy css location
🎢 Fallback to drop dummy CSS
```
## Steps to reproduce
1. **Page Optimization → CSS Settings:** enable **CSS Combine** (with Minify / Combine External & Inline).
2. On a site where some `style_loader_tag` filter (or markup) renders the enqueued `litespeed-cache-dummy-css` `` with **two spaces** between `id='…'` and `href` (verify in the raw, unoptimized HTML).
3. Load any cacheable front-end page.
**Result:** the served HTML contains the un-replaced `litespeed-dummy.css` placeholder, no `…/wp-content/litespeed/css/.css` link, and none of the original stylesheets → unstyled page. The combined file exists under `wp-content/litespeed/css/` but is never referenced.
## Suggested fix
- Correct the guards from `false !== preg_match(...)` to `1 === preg_match(...)` so a non-match correctly falls through to the `` / `` insertion. This alone prevents the unstyled-page failure regardless of the regex.
- Additionally, make `DUMMY_CSS_REGEX` whitespace-tolerant (e.g. ` +href=` / `\s+` instead of the single literal space) so the placeholder is matched and replaced in place.
## Environment
- LiteSpeed Cache 7.8.1 (also confirmed in `master`)
- WordPress 6.x
- PHP 7.4
- LiteSpeed Web Server
Combine generation works; only HTML injection fails.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/optimize.cls.php by reading DUMMY_CSS_REGEX and the head-injection and dummy-CSS fallback guards. Reproduce the two-space placeholder case, then verify that the combined CSS link is injected, the placeholder is removed, and the meta/head fallback still works when the regex does not match.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- performance
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100