🚀 Nginx Cache Purge Preload — v2.1.7
Cache More. Block Less.
🛠️ 71 files changed | ➕ 8,902 lines | ➖ 1,941 lines — Terminal Control. Wider Coverage. Smarter Preloading.
✨ What's New
🖥️ WP-CLI Integration (major milestone)
Full cache management now lives in the terminal — no browser required.
The wp npp command exposes 10 subcommands covering every core NPP operation. Destructive commands support --dry-run for safe inspection, and --porcelain on purge/preload for clean shell-script output.
| Subcommand | Description |
|---|---|
wp npp purge |
Purge the entire cache, or a single URL via --page-url=<url> |
wp npp preload |
Full-site crawl, single URL via --page-url=<url>, or --stop to kill a running job |
wp npp status |
Runtime status summary — outputs table, json, yaml, or csv |
wp npp log |
Tail the operation log (--lines=<n>) or truncate it (--clear) |
wp npp settings |
get / set any plugin setting; --pretty adds a human-readable name column |
wp npp settings-reset |
Reset a specific setting to its plugin default value |
wp npp flush |
Clear all NPP transients — use after path changes or binary installs (rg, safexec, wget) |
wp npp index-clear |
Clear the persistent URL→filepath index when entries go stale |
wp npp schedule |
List all active NPP cron events |
wp npp schedule-set |
Configure (--freq, --time) or cancel (--cancel) the scheduled preload |
Common patterns:
# Purge a single URL — emit only the outcome token for scripting
wp npp purge --page-url=https://example.com/shop/ --porcelain
# Full-site preload — spawns wget crawl in the background, returns immediately
wp npp preload
# Kill a running preload without touching the cache
wp npp preload --stop
# Inspect all current settings as JSON
wp npp settings get --format=json
# Update a single setting
wp npp settings set nginx_cache_path /var/cache/nginx/fastcgi
# Reset the preload exclude-endpoints regex to the plugin default
wp npp settings-reset nginx_cache_reject_regex
# Schedule a daily preload at 03:00
wp npp schedule-set --freq=daily --time=03:00
# Clear the URL→filepath index after moving the cache directory
wp npp index-clear
# Flush transients after installing ripgrep, safexec, or wget
wp npp flushIdeal for CI/CD pipelines, deployment hooks, post-migration cleanup scripts, and headless server management.
⚡ Smarter Preload Engine — Coverage Breakthrough (major milestone)
The core motivation for v2.1.7: cache every URL that is safe to cache — not blindly deny everything with a query string.
Prior versions excluded any URL containing a query string from preload, silently leaving entire classes of safe, cacheable URLs as permanent MISSes. The preload reject regex has been completely overhauled — from a blanket query-string exclusion to a surgical, named-parameter denylist that blocks only the handful of parameters that genuinely break caching.
| Before | After | |
|---|---|---|
| Rule | Any ?... → skipped |
Only known-bad params → skipped |
| Coverage | Low — broad exclusion | High — surgical exclusion |
| Result | Invisible cache gaps | HITs where there were MISSes |
Sites upgrading from earlier versions will see a significant increase in preload scope and cache coverage — URLs with benign query strings that were previously skipped are now preloaded and cached.
⚠️ Preload behavior changes significantly after upgrading. Use the "Reset Default" button for "Exclude Endpoints" in Settings → Preload Options to activate the new defaults.One more thing — check your Nginx config. Nearly every Nginx cache tutorial on the internet includes this rule:
if ($query_string != "") { set $skip_cache 1; }This blanket rule silently defeats the entire point of this release. If it's in your Nginx config, URLs with query strings will be preloaded by NPP but immediately bypassed by Nginx — they will never be served from cache. Replace it with surgical per-parameter conditions that match only the parameters that genuinely break caching (session tokens, cart IDs, etc.) and let everything else through. Your
skip-cachelogic and your preload denylist should mirror each other exactly. A compatible, production-tested Nginx configuration is available in the NPP Dockerized repository.
The same release also extends the default Cache Key Regex to support three additional $fastcgi_cache_key formats beyond the original:
$scheme://$host$request_uri
$host$request_uri
$host$uri$is_args$args
Use "Reset Default" on "Cache Key Regex" in Settings → Advanced to activate.
📡 Preload Feeds (new)
RSS and Atom feeds are now first-class citizens in the preload pipeline.
Previously excluded from preload by default, feed URLs can now be fully controlled at both site-wide and per-URL levels:
- Main site feed (
/feed/,/feed/atom/) — preloaded on demand or on schedule - Per-post comment feeds — preloaded alongside their parent post
- Per-taxonomy RSS feeds — preloaded together with their archive pages
Toggle via the new "Preload Feeds" option in Settings → Preload Options. The expanded Purge Scope extensions (see below) ensure feeds are automatically invalidated on relevant content updates.
🎯 Advanced Tab — Preload All MISS (new)
A lighter, smarter alternative to Preload All — purpose-built for sites where the cache is already mostly warm.
| Preload All | Preload All MISS | |
|---|---|---|
| First step | Full cache purge | No purge |
| Scope | Every URL | Only MISSes |
| Best for | Cold cache / full refresh | Cache already > 50% warm |
| Cost | High | Low |
When cache coverage is already high, Preload All wastes resources: it wipes the cache, then re-crawls everything from zero. Preload All MISS skips the purge entirely and crawls only the URLs currently absent from cache — significantly lower I/O and CPU cost for large, mostly-warm caches.
Available directly in the Advanced Tab (Cache Manager). Activates only when coverage exceeds 50% to prevent accidental use on cold caches.
🗂️ Expanded Purge Scope (extended)
Purge Scope now reaches further than ever — every major URL type is covered automatically when content changes:
| Event | Newly Purged |
|---|---|
| Post save / update | Author archives |
| Post save / update | Date-based archives (year, month, day) |
| Post publish / update | Main site RSS feed |
| Comment activity | Per-post comment feeds |
| Taxonomy update | Per-taxonomy RSS feeds + archive pages |
| Comment pagination enabled | Paginated comment URLs (pretty + query-string variants) |
| Any taxonomy update | All public registered taxonomies + WooCommerce product attribute archives |
No configuration changes required — existing Purge Scope settings are extended automatically.
🧡 Walkie (fun)
Meet Walkie — a tiny animated character who lives in the plugin header, strolls along the ribbon, and delivers cache-related commentary during long preload runs.
He fully believes he is a real AI assistant. He is not. But he is excellent company when a full-site preload has 4,000 URLs left to go.
Purely cosmetic. Zero performance impact.
🐾 Additional Highlights
- "Test Regex" button — live-verify your Cache Key Regex against a real cache file directly from the settings page, without guesswork.
- ripgrep
--no-mmapflag — added to all cache scans for faster I/O on large directories of small binary cache files. - Related Preload engine refactor — collapsed dozens of parallel background operations into a maximum of 2 (Desktop + Mobile), sharply reducing server load spikes on Purge Scope triggers.
- ripgrep version enforcement — strict minimum of
>= 14.0.0now required. Outdated binaries are flagged in the Status tab and gracefully demoted to the PHP fallback on FP3. open_basedircompatibility detection — admin warning now fires when required plugin paths are blocked byopen_basedirrestrictions.- aaPanel compatibility — fully tested and functional across both Single and Multi WebServer architectures. (Thanks to @neikoloves)
🔒 Performance & Reliability
- Critical Fix: Advanced Tab single Purge action no longer freezes the browser on large caches (30,000+ rows) when Purge Scope sub-triggers are enabled. Replaced O(N) full-table scans with an O(1) URL→row index cache and batched DataTable redraws.
- Critical Fix: False-negative in Nginx detection on Nginx+Apache proxy stacks that rendered the plugin completely non-functional even when Nginx was active as the front proxy.
- Fixed unprotected
shell_execandexeccalls across the REST API, WP Cron, Dashboard Widget, and all other relevant execution paths. - Fixed recurring cron events (
nppp_index_updater_event,npp_cache_preload_event) silently dying after their first run. - Fixed
nppp_index_updater_eventself-healing — event now auto-reschedules on the next admin load if wiped externally by WP-CLI, a cron manager plugin, or a database import. - Fixed URL→Filepath index not auto-flushing on WordPress permalink structure changes.
- Fixed URL→Filepath index not auto-flushing when the Nginx Cache Path setting changes.
- Fixed settings and option updates (REST / WP-CLI / UI) being permitted during active purge or preload operations.
- Fixed an edge case where users were locked out by the transient cache when the Status tab and "Clear Plugin Cache" button became inaccessible while plugin functionality was disabled.
- Fixed broken Nginx cache keys listing in the Status tab.
- Fixed redundant process-killing by separating safexec and native kill paths in premature process detection logic.
- Fixed missing
getenv/putenvcheck for URL Normalization (safexec). - Fixed default Cache Key regex embedding non-GET/HEAD HTTP methods into the host segment on
$scheme$request_method$host$request_urikeys — resolving silent purge failures on affected configurations. - Resolved multiple PHP 8+ deprecation warnings for
nullandfalsevalues passed totrim()andend(). - Lowered TTLs of several internal plugin transients — the UI now reflects configuration changes more quickly, reducing the need for manual "Clear Plugin Cache" after adjustments.
🗑️ Changed / Updated
- Hard dependency extended: both
shell_execandexecare now required.⚠️ REGRESSION — verify these are not blocked bydisable_functionsin your PHP configuration before upgrading. - ripgrep minimum version
>= 14.0.0is now strictly enforced. FP3 Purge degrades to PHP recursive fallback on detection of an older binary. - DataTables assets bumped to v2.3.8 for improved Advanced Tab rendering and stability.
nppp_purged_allaction hook — fired after every successful full Nginx cache purge, enabling third-party plugins to trigger their own cache flush in sync.- Tested up to: WordPress 7.0
🧩 Where to Find Things
| Feature | Location |
|---|---|
| WP-CLI commands | Terminal → wp help npp |
| Preload Feeds toggle | Settings → Preload Options |
| Exclude Endpoints (Reset Default) | Settings → Preload Options |
| Cache Key Regex (Reset Default + Test) | Settings → Advanced |
| Preload All MISS | Advanced Tab → Cache Manager |
| ripgrep version status | Status Tab |
| open_basedir warning | Admin notice (fires automatically if applicable) |
| Walkie | Plugin header — always on |
🔄 Upgrade Notes
- Update the plugin to v2.1.7 as usual.
⚠️ Use "Reset Default" on "Exclude Endpoints" in Settings → Preload Options — the preload reject regex has been completely overhauled. Preload behavior changes significantly. Verify your Nginxskip-cacherules are compatible with the expanded preload scope before going live.⚠️ Use "Reset Default" on "Cache Key Regex" in Settings → Advanced to activate expanded cache key format support.- Confirm ripgrep ≥ 14.0.0 is installed on your server. Check the Status tab — outdated binaries are flagged and degraded automatically.
- Confirm both
shell_execandexecare enabled in your PHP configuration — these are now hard dependencies. Sites withdisable_functionsrestrictions blocking either function will lose cache management functionality.
🙏 Credits
Huge thanks to everyone who tested and reported issues. Special shout-out to @neikoloves for thorough aaPanel compatibility issues and detailed reporting across both WebServer architectures. 💙
📜 Changelog
- Added (Milestone): Full WP-CLI integration —
wp nppcommand with 10 subcommands:purge,preload,status,log,settings,settings-reset,flush,index-clear,schedule, andschedule-set. Supports--dry-run,--porcelain, and multiple output formats (json,yaml,csv) across subcommands. - Added: "Preload Feeds" — full control over site-wide and per-URL feed caching (main RSS/Atom, per-post comment feeds, taxonomy RSS feeds).
- Added: Advanced Tab "Preload All MISS" — lightweight alternative to Preload All; skips purge step and only preloads currently-missing cache entries. Activates when cache coverage exceeds 50%.
- Added: Walkie — animated plugin header character with cache-related commentary. Purely cosmetic.
- Added: "Test Regex" button — live-verify Cache Key Regex against a real cache file from the settings page.
- Added: Strict ripgrep minimum version requirement (
>= 14.0.0). - Added: Cache Key Regex validation — global admin warning when custom or default regex fails validation.
- Added:
open_basedircompatibility detection with admin warning for missing required paths. - Added: Detection for
Vary: Accept-Encodingdouble-cache issue (fully dismissable). - Added:
nppp_purged_alldeveloper action hook — fires after every successful full Nginx cache purge. - Improved (Requires Action): Preload engine reject regex overhauled from blanket query-string exclusion to selective named-parameter denylist — significant increase in preload scope and cache coverage. Use "Reset Default" on "Exclude Endpoints" to activate.
- Improved (Requires Action): Default Cache Key Regex extended to support
$scheme://$host$request_uri,$host$request_uri, and$host$uri$is_args$argsformats. Use "Reset Default" on "Cache Key Regex" to activate. - Improved: Nginx detection and Setup (Assume Nginx Mode) — detection is now prioritized before all other environment checks with clear instructions.
- Improved: Setup Page UI/UX.
- Improved: aaPanel compatibility — fully tested across Single and Multi WebServer architectures. (Thanks to @neikoloves)
- Improved: Status tab diagnostic reporting — explicitly flags outdated ripgrep binaries.
- Improved: FP3 Purge degrades gracefully to PHP recursive fallback when an outdated ripgrep binary is detected.
- Extended: Purge Scope now purges Author archives on post save/update.
- Extended: Purge Scope now purges Date-based archives (year, month, day) on post save/update.
- Extended: Purge Scope now purges RSS feeds on relevant events — main feed on post publish/update, per-post comment feeds on comment activity, per-taxonomy RSS feeds alongside archive pages.
- Extended: Purge Scope now purges paginated comment URLs (pretty-permalink and query-string variants) when WordPress comment pagination is enabled.
- Extended: Purge Scope taxonomy purging now covers all public registered taxonomies generically, including WooCommerce product attribute archives.
- Performance (Critical Fix): Advanced Tab single Purge action no longer freezes the browser on 30,000+ row caches with Purge Scope sub-triggers enabled — replaced O(N) full-table scans with O(1) URL→row index cache and batched DataTable redraws.
- Performance: Added
--no-mmapflag to all ripgrep cache scans for faster I/O on large directories of small binary cache files. - Performance: Related Preload engine restructured into a single process — collapsed dozens of background operations into a maximum of 2 (Desktop + Mobile).
- Fixed: False-negative Nginx detection on Nginx+Apache proxy stacks rendering the plugin non-functional.
- Fixed: Unprotected
shell_execandexeccalls across REST API, WP Cron, Dashboard Widget, and all relevant execution paths. - Fixed: Missing
getenv/putenvcheck for URL Normalization (safexec). - Fixed: User lockout edge case — transient cache blocking access to Status tab and "Clear Plugin Cache" when plugin functionality is disabled.
- Fixed: Broken Nginx cache keys listing in the Status tab.
- Fixed: Settings/option updates now blocked during active purge/preload operations to ensure process state consistency.
- Fixed: Redundant process-killing — separated safexec and native kill paths in premature process detection logic.
- Fixed: Recurring cron events (
nppp_index_updater_event,npp_cache_preload_event) silently dying after their first run. - Fixed:
nppp_index_updater_eventself-healing — auto-reschedules on next admin load if wiped externally. - Fixed: URL→Filepath index now auto-flushed on WordPress permalink structure changes.
- Fixed: URL→Filepath index now auto-flushed when Nginx Cache Path changes.
- Fixed: Default Cache Key regex no longer embeds non-GET/HEAD methods into the host segment on
$scheme$request_method$host$request_urikeys. - Resolved: Multiple PHP 8+ deprecation warnings for
null/falsevalues passed totrim()andend(). - Changed: Hard dependency extended to require both
shell_execandexec.⚠️ REGRESSION — verify PHP configuration before upgrading. - Removed: False-positive and redundant warning messages from Status and Advanced tabs.
- Balanced: Lowered TTLs of several internal plugin transients for faster UI reflection of configuration changes.
- Updated: DataTables assets to v2.3.8.
- Updated: Tested up to WordPress 7.0.
- Compatibility: Tested with Nginx (1.31.1), FUSE (3.18.2), bindfs (1.18.4), safexec (1.9.6), ripgrep (15.1.0), wget (1.25.0), and aaPanel (8.0.3).