WP Manifestindependent plugin directory
manifest / performance / wp-404-caching

WP 404 Caching WP Registry grade C-. High-severity findings · 1 findingWP RegistryHigh-severity findings · 1 findingOpen the reportC-

Enables caching on 404 pages to prevent performance issues related to bad request flooding.

★ 13stars
448kcomposer installs
v1.3.0latest · 1 year ago

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/alleyinteractive/wp-404-caching/archive/refs/heads/develop.zip

On Packagist as alleyinteractive/wp-404-caching:

composer require alleyinteractive/wp-404-caching
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

A WordPress plugin to provide full page caching for 404 pages, improving performance and reducing server load.

Requirements

  • SSL enabled on the website.
  • An external object cache setup (e.g., Redis, Memcached).
  • Requires at least: 6.3
  • Tested up to: 6.4
  • Requires PHP: 8.1
  • License: GPL v2 or later

Description

WP 404 Caching is a lightweight plugin that efficiently serves cached 404 pages to non-logged-in users. It reduces server load by storing the cached 404 page in an external object cache and returning it early in the request process.

The plugin uses a dual regular/stale caching strategy to minimize cache misses. It maintains a regular cache with a 1-hour expiration and a stale cache with a 1-day expiration. If the regular cache is empty, the stale cache is served.

Features

  • Full page caching for 404 pages
  • Utilizes external object cache for storing cached 404 pages
  • Dual regular/stale caching strategy to minimize cache misses
  • Automatically generates and caches 404 page via a "guaranteed 404 URI"
  • Triggers cache generation hourly via a cron job and immediately on cache misses
  • Sends X-WP-404-Cache header to indicate cache HIT/MISS status
  • Ensures compatibility with analytics by replacing the "guaranteed 404 URI" with the actual requested URI in the cached page

Installation

Via Composer (recommeded):

You can install the package via composer:

composer require alleyinteractive/wp-404-caching

Manual install:

  1. Upload the wp-404-caching directory to your /wp-content/plugins/ directory.
  2. Activate the plugin through the 'Plugins' menu in WordPress.

Usage

The plugin works out of the box with default settings. You can customize the cache expiration times by modifying the CACHE_TIME and STALE_CACHE_TIME constants in the Full_Page_Cache_404 class. Activate the plugin in WordPress and use it like so:

add_filter( 'wp_404_caching_cache_time', function( $cache_time ) {
    return 2 * HOUR_IN_SECONDS; // Set cache time to 2 hours.
} );

add_filter( 'wp_404_caching_stale_cache_time', function( $stale_cache_time ) {
    return 2 * DAY_IN_SECONDS; // Set stale cache time to 2 days.
} );

// Programmatically bypass the cache.
add_filter( 'wp_404_caching_enabled', '__return_false' );

Changelog

Please see CHANGELOG for more information on what has changed recently.

Credits

This project is actively maintained by Alley Interactive. Like what you see? Come work with us.

License

The GNU General Public License (GPL) license. Please see License File for more information.


Developer Notes

Testing

Run composer test to run tests against PHPUnit and the PHP code in the plugin.

Releases

7 releases.

Tag
Published
v1.3.0 latest
Sep 26, 2025 1 year ago
Jun 30, 2025 1 year ago
Jun 11, 2025 1 year ago
Dec 6, 2024 1 year ago
Mar 22, 2024 2 years ago
Mar 22, 2024 2 years ago
Mar 15, 2024 2 years ago

These releases are tags only. The author does not attach a packaged zip, so there are no download counts to report.

C- grade

Security

WP 404 Caching 1.3.0 · audited by WP Registry

High-severity findings.

1 high
Audited release
1.3.0
Findings
1
Worst severity
high
Content hash
8f956c48279bd38cf65f3d3e…

Findings

  • high Unauthenticated reflected XSS via 404 cache URI replacement

    xss_reflected

    On a cache HIT, action__template_redirect calls prepare_response() and echoes the result as the full 404 document for any logged-out visitor (SSL + external object cache required, which is the plugin's normal mode). prepare_response() takes sanitize_text_field($_SERVER['REQUEST_URI']) and str_replaces four encodings of TEMPLATE_GENERATOR_URI (/wp-404-caching/404-template-generator/?generate=1&uri=1). The json/html/url replacements re-escape the attacker URI, but the first replacement inserts the raw sanitized string. sanitize_text_field strips tags and percent-encoded octets but does not encode quotes or apostrophes, so it is not an output escape. The plugin exists specifically to splice the real request URI into analytics markup that was captured when the generator URI was rendered (safe characters only at prime time). When that snapshot still contains the unescaped generator URI — typical of a JS string such as ga('set','page','…') or JSON_UNESCAPED_SLASHES output — a request like GET /'+alert(1)+' turns into executable JavaScript in the victim's browser. This is reflected, not stored: each response is rewritten from the current REQUEST_URI. Logged-in users never receive the cache.

    src/features/class-full-page-cache-404.php:155-177,342-360

    Recommendation

    Drop the raw $uri replacement. Only rewrite encodings you can round-trip with a matching escaper (wp_json_encode, esc_html, esc_url, and esc_js if you need a JS-string form). Never splice REQUEST_URI into HTML/JS without context-appropriate escaping. sanitize_text_field is not an output escape for attributes or JavaScript.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.