Skip to content

Version 2.0.0 - #25

Merged
alaca merged 4 commits into
masterfrom
v2-rewrite
Aug 19, 2026
Merged

Version 2.0.0#25
alaca merged 4 commits into
masterfrom
v2-rewrite

Conversation

@alaca

@alaca alaca commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Ground up rewrite. The plugin keeps every v1 option but replaces the implementation and the admin.

Architecture

  • Modular PHP 8.1 codebase under src/ (container, modules, hook providers)
  • React admin built with wp-scripts, REST backed (wpp/v1)
  • Grouped settings: one option per group instead of ~110 wpp_* options, with automatic migration of existing installs
  • No third party PHP dependencies: own cache engine, asset parser and CSS/JS/HTML minifiers

New

  • Overview dashboard with environment health checks
  • One click presets (Safe, Balanced, Aggressive)
  • Block cache for parts of a page, via the Cache block, the [wpp_cache] shortcode or wpp_cache_start()
  • Delay JavaScript until interaction
  • Remove unused CSS per page
  • Self host Google Fonts
  • WebP and AVIF conversion
  • LCP preload with fetchpriority, and missing image dimensions for CLS
  • Redis object cache drop in
  • Link prefetch add on rewritten on the Speculation Rules API

Removed

  • AMP support

alaca added 4 commits August 18, 2026 14:36
Ground up rewrite. The plugin keeps every v1 option but replaces the
implementation and the admin.

Architecture
* Modular PHP 8.1 codebase under src/ (container, modules, hook providers)
* React admin built with wp-scripts, REST backed (wpp/v1)
* Grouped settings: one option per group instead of ~110 wpp_* options,
  with automatic migration of existing installs
* No third party PHP dependencies: own cache engine, asset parser and
  CSS/JS/HTML minifiers

New
* Overview dashboard with environment health checks
* One click presets (Safe, Balanced, Aggressive)
* Block cache for parts of a page, via the Cache block, the [wpp_cache]
  shortcode or wpp_cache_start()
* Delay JavaScript until interaction
* Remove unused CSS per page
* Self host Google Fonts
* WebP and AVIF conversion
* LCP preload with fetchpriority, and missing image dimensions for CLS
* Redis object cache drop in
* Link prefetch add on rewritten on the Speculation Rules API

Removed
* AMP support

Also adds a standalone test suite (755 assertions, no database required),
release tooling for WordPress.org, and refreshed plugin artwork.
WordPress enforces the plugin header at activation and WordPress.org reads
readme.txt, so a mismatch lets a site activate a version the readme says is
unsupported.
The cache directory sits in the web root and the .htaccess rules there are
ignored by nginx, so the runtime config, the troubleshooting log and cached
fragments were all fetchable directly. The config lists the URLs an admin
deliberately excluded, the log records every cached request path, and a
fragment can hold markup rendered for a logged in visitor.

Those three now carry a .php extension and a leading exit guard, so a direct
request returns nothing whatever the server config says. Files written by an
earlier release are removed on the first admin request after an update, but
only once the refreshed drop-in is confirmed installed, since deleting the
config a stale drop-in still reads would stop page caching outright.

Also fixes the fragment expiry sweep, which read the guard line as the
timestamp and so treated every entry as permanent.
The worst one made the whole release inert for existing users: the 1.x loader
in wp-content/advanced-cache.php was classified as another plugin's drop-in, so
install() refused to touch it and 2.0's cache engine was never installed. The
abandoned 1.x loader kept running against a settings file 2.0 does not write.

Data leaks, each reproduced before fixing:
- A returning commenter's render, which core prefills with their name, email and
  URL, was written to the shared anonymous page cache. The drop-in already
  refused to serve those visitors; only the writer had no matching check.
- The block cache had no per-user vary, so one logged-in visitor's markup, nonce
  included, was served to another with the same role.
- Disk fragments were not namespaced per blog, so multisite sites served each
  other's cached block HTML.

Multisite lifecycle: network deactivation left the drop-in, WP_CACHE, the cache
and the server rules in place; deactivating one blog kept its pages being served;
one blog's cache clear purged the whole network.

Asset pipeline: a bundle built from unreadable sources was written once and then
served for good, after the original tags had already been removed; relative
url() and @import broke when the stylesheet URL had no host; @import was emitted
after other rules, so browsers discarded it; next-gen sources advertised width
descriptors with no sizes; an img already inside a picture was wrapped again.

Settings: browser_expire could not be set to 0, so "respect existing headers"
was unreachable; restore points and imports merged instead of replacing, so no
rule could ever be removed; v1 critical CSS was deleted rather than migrated.

Also: a failed font download no longer caches a stylesheet still pointing at
gstatic, a non-200 body can no longer be baked into a bundle, and the health
check now says another plugin owns the drop-in instead of calling it missing.

Fixes are covered by seven new suites; the whole suite is 1030 assertions. Each
fix was mutation checked by reverting it and confirming the test fails.
@alaca
alaca merged commit f0a7263 into master Aug 19, 2026
4 checks passed
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