litespeedtech / litespeedtech/lscache_wp

Page Optimize: CSS Combine emits an unstyled page

Open Beginner friendly
#999 5 comments 0 reactions 0 assignees View on GitHub

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.

Image

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.