millipress/millicache

The most flexible Full Page Cache for scaling WordPress sites. Enterprise-grade in-memory store with Redis, ValKey, Dragonfly, KeyDB, or any alternative.

Installs: 3

Dependents: 0

Suggesters: 0

Security: 0

Stars: 5

Watchers: 1

Forks: 0

Open Issues: 2

Type:wordpress-plugin

pkg:composer/millipress/millicache

v1.0.0-rc.3 2025-12-09 11:53 UTC

README

e2e-Tests

MilliCache is a fast & flexible full-page caching solution for WordPress. It uses in-memory key-value stores like Redis, Valkey, KeyDB, or Dragonfly as its backend to store cached pages. By leveraging in-memory storage capabilities, MilliCache is exceptionally fast, reliable, and scalable. Moreover, it allows for highly efficient and targeted cache invalidation, greatly increasing both efficiency and flexibility. This is especially important for the future of WordPress, as it enables more dynamic content and complex caching strategies — for example, with the use of the Block Editor.

Optimized for both WordPress Multisite and Single Site setups, MilliCache provides a versatile and robust caching solution for all types of WordPress environments.

Important

This plugin is currently in the Release Candidate stage and approaching a stable release. While suitable for testing in production-like environments, please exercise caution and report any problems you encounter.

Table of Contents

Features

  • Lightning Fast: In-memory full-page caching using Redis or an alternative.
  • Settings UI: Easy configuration and cache management through the WordPress admin.
  • Cache RequestFlags: High efficiency by supporting complex cache logic and selective clearing.
  • Expired Cache Handling: Regenerates cache in the background.
  • Multisite Optimized: Ideal for WordPress Multisite and Multi-Network.
  • Extensible: Provides various hooks & filters.
  • Gzip Compression: Compresses cache to reduce memory usage.
  • WP-CLI Commands: Manage cache via command line.
  • Debugging: Provides cache information in headers.
  • Scalable: Works with server clusters.
  • Object Cache: Works with Redis object cache plugins like WP Redis & Redis Object Cache.
  • Flexible Storage: Compatible with Redis Server, Valkey, KeyDB & Dragonfly.

Requirements

  • PHP 7.4 or higher (PHP 8.x recommended for performance)
  • A compatible in-memory storage server, either installed locally or accessible via network:
    • Redis (traditional option)
    • Valkey (Redis fork with enhanced features)
    • KeyDB (Redis-compatible with multi-threading)
    • Dragonfly (modern Redis alternative)

Storage Server Configuration

Make sure your storage server has enough memory allocated to store your cached pages. MilliCache compresses cached pages using gzip to reduce memory usage. However, you need to keep an eye on your cache size in the Dashboard to increase according to your hit rate.

For Redis, Valkey, and KeyDB, we recommend disabling persistence to disk and using the allkeys-lru eviction policy to ensure the server can make more room for new cached pages by evicting old ones. Here is an example configuration:

# Set maximum memory e.g. to 16 megabytes
maxmemory 16m

# Set eviction policy to remove less recently used keys first
maxmemory-policy allkeys-lru

Remember to restart your storage server after making changes to the configuration file.

Installation

  1. Install via:

    • ZIP-File:

      • Download the latest release.
      • Upload the ZIP file in your WordPress admin area under Plugins > Add New > Upload Plugin.
    • Composer:

      $ composer config repositories.millicache vcs https://github.com/millipress/millicache
      $ composer require millipress/millicache
  2. Activate the plugin in your WordPress installation.

  3. Configure the plugin in your Dashboard Settings -> MilliCache or by defining constants in your wp-config.php.

  4. Enable WordPress caching by adding to wp-config.php:

    define('WP_CACHE', true);

Configuration

Configure MilliCache either in your Dashboard Settings -> MilliCache or by setting constants in your wp-config.php file. You can combine both methods, the constants overwrite the settings with higher priority.

# Optional: Set Settings with Constants
define('MC_STORAGE_HOST', '127.0.0.1');
define('MC_STORAGE_PORT', 6379);

General Configuration

Constant Description Default
MC_CACHE_DEBUG Enable Debugging false
MC_CACHE_GZIP Enable Gzip Compression true
MC_CACHE_TTL Default Cache TTL (Time To Live) DAY_IN_SECONDS
MC_CACHE_GRACE Grace Period of stale cache for regenerating content MONTH_IN_SECONDS
MC_CACHE_NOCACHE_PATHS Paths which are not cached []
MC_CACHE_NOCACHE_COOKIES Cookies which avoid caching ['comment_author']
MC_CACHE_IGNORE_COOKIES Cookies that are ignored/stripped from the request []
MC_CACHE_IGNORE_REQUEST_KEYS Request keys that are ignored ['_*', 'utm_*', ...]
MC_CACHE_UNIQUE Variables that make the request & cache entry unique []

Note

MilliCache supports wildcard patterns and Regex for path, cookie and request key configurations, allowing for more flexible cache control: ['cookie_*', 'coo*_*', /^/(product|category)/.*/].

Storage Server Connection Configuration

Constant Description Default
MC_STORAGE_HOST Storage Server Host 127.0.0.1
MC_STORAGE_PORT Storage Server Port 6379
MC_STORAGE_PASSWORD Storage Server Password ''
MC_STORAGE_DB Storage Server Database 0
MC_STORAGE_PERSISTENT Storage Server Persistent Connection true
MC_STORAGE_PREFIX Storage Server Key Prefix mll

Cache Flags

MilliCache supports cache flags to group and clear caches based on flags, useful for complex cache handling.

What are Cache Flags?

A single post or page can generate multiple cache entries because the cache keys change based on the request details, such as different cookies or query parameters. For example, the following URLs, although they refer to the same content, will have separate cache entries:

  • https://example.org/?p=123
  • https://example.org/post-slug/
  • https://example.org/post-slug/page/2/
  • https://example.org/post-slug/?show_comments=1

These different cache entries are necessary because each URL might serve slightly different content. However, they are all related to the same post or page. To manage these related entries efficiently, MilliCache groups them using cache flags. In this case, all entries might share a flag like post:123.

Cache flags allow you to:

  • Identify cache entries
  • Assign multiple flags to a cache entry for flexible grouping.
  • Group entries logically under a common identifier.
  • Target cache entries for clearing at once by targeting a specific flag.
  • Provide extension points for custom flags from themes/plugins.

For example, to clear all cache entries related to a specific post, you can use the flag post:123 with WP-CLI commands, the Settings UI or MilliCache's clearing functions.

Built-in Flags

Important

Flag prefixes are only added in multisite and multinetwork installations. Here's how the same flag appears in different WordPress setups:

Installation Type Example Flag Format Examples
Single site flag:value post:123, home, custom_flag
Multisite site_id:flag:value 1:post:123, 2:home, 3:custom_flag
Multinetwork network_id:site_id:flag:value 1:2:post:123, 1:3:home, 2:1:custom_flag

When using WP-CLI or API functions, you must include these prefixes appropriately for multisite/multinetwork environments.

The basic built-in flags are:

Flag Description
home Added to home & blog pages
post:{post_id} Added to all posts, pages & CPT (Post ID)
archive:{post_type} Added to all post type archive pages (Post Type)
archive:{taxonomy}:{tax_id} Added to taxonomy archives (e.g. category or tag archives)
archive:author:{author_id} Added to author archive pages (Author ID)
archive:{year} Added to date archive pages for a specific year
archive:{year}:{month} Added to date archive pages for a specific month
archive:{year}:{month}:{day} Added to date archive pages for a specific day
feed Added to all feed pages

Flags dynamically adapt based on the content and current page context, ensuring maximum control and flexibility when managing the cache.

Adding Custom Cache Flags:

You can define your own cache flags to group entries based on specific conditions by using the millicache_custom_flags filter. For instance, if you want to group all posts containing a particular Gutenberg block:

  1. Add a Custom Flag:

    add_filter('millicache_custom_flags', function( $flags ) {
        if ( has_block('my-custom/block') ) {
            $flags[] = 'block:my-custom/block';
        }
        return $flags;
    });
  2. Clear the Cache Using the Custom Flag: Instead of clearing the entire cache, you can clear only the entries with the custom flag:

    # Single site - clear all pages with the custom block
    wp millicache clear --flag="block:my-custom/block"
    
    # Single site - clear all posts and home page
    wp millicache clear --flag="post:123,home"
    
    # Multisite - clear all posts on site 1
    wp millicache clear --flag="1:post:*"
    
    # Multisite - clear home pages across all sites
    wp millicache clear --flag="*:home"
    
    # Multinetwork - clear all content on network 2, site 3
    wp millicache clear --flag="2:3:*"

This way, you efficiently manage your cache by only refreshing the parts that need updating, saving resources, and improving performance.

Clearing Cache

By default, MilliCache uses two key time settings to control cache behavior:

  1. TTL (Time-To-Live): Period when cache is considered fresh
  2. Grace Period: Additional time after TTL expires when stale cache can still be served

When a cache entry reaches its TTL, it becomes "stale" but isn't immediately deleted. Instead, MilliCache serves the stale copy to visitors while regenerating a fresh cache in the background. This ensures users experience no delay during cache regeneration.

Cache entries expire whenever necessary. For example, when a post is published or updated, the cache entry for the post and the front page is cleared. When a site option is updated, all cache entries of the site are cleared, and so on.

Using the Settings UI

The MilliCache Settings UI provides a user-friendly way to clear cache:

  1. Navigate to Settings -> MilliCache in your WordPress admin
  2. In the "Cache Management" section:
    • Use "Clear All Cache" to remove all cached entries
    • Use "Clear By Flag" to selectively clear the cache by specific flags
    • View the current cache statistics (size, entry count)

This interface makes it easy to manage cache without writing code or running CLI commands.

Using the Adminbar

MilliCache integrates with the WordPress admin bar for quick cache management:

  1. While logged in as an administrator, the admin bar displays a "MilliCache" menu item
  2. Click on the menu to reveal options:
    • Clear All Cache: Immediately clear all cached content
    • Clear by Flag: Expand to see common flag options (Home, Current Page, etc.)
    • Settings: Quick access to the MilliCache settings page

This provides convenient access to cache management functions from any page of your site without having to navigate to the settings page.

Using PHP Functions

MilliCache offers various methods to clear the cache by flags, URLs, or IDs programmatically. You can also create custom hooks to clear or expire the cache whenever needed.

The $expire parameter in cache-clearing methods is optional:

  • Set to true: Cache entries expire and regenerate in the background on the next request.
  • Default (false): Cache entries are deleted immediately.

Decide whether to expire or delete cache entries based on your requirements and how time-critical the content is.

  • Reset Cache

    To reset the full cache.

    /**
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_reset_cache( $expire );
  • Clear Cache

    A convenient method to clear the cache based on different target types in a single call. This method automatically determines the target type by its format (URL, numeric Post ID, or cache flag).

    /**
     * @param string|array $targets String or array of targets to clear:
     *   - URLs (any valid URL that starts with your site URL)
     *   - Post IDs (any numeric value will be treated as a post-ID)
     *   - Cache flags (any non-numeric, non-URL string will be treated as a flag)
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache( $targets, $expire );

    Example usage:

    // Clear cache for multiple types of targets, such as post-IDs, flags, or URLs.
    millipress_clear_cache( [
        'home',                             // Treated as a flag
        'post:123',                         // Treated as a flag
        123,                                // Treated as a post-ID
        'https://example.com/special-page/' // Treated as a URL
    ] );

    In multisite installations, the method automatically limits flag-based clearing to the current site when called from a non-network admin context.

  • Clear Cache by Flags

    To clear the cache by specific flags. Please note the wildcard support below.

    /**
     * @param string|array $flags Flag or array of flags to clear.
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache_by_flags( $flags, $expire );

    Wildcards

    MilliCache supports wildcards when clearing cache by flags. The way these wildcards are used depends on your WordPress installation type.

    • *-Wildcards

      The * can be used to match any number of characters. Here are examples of different WordPress installations:

      Installation Type Example Pattern What It Matches
      Single site post:* All posts (matches post:1, post:123, etc.)
      Single site archive:* All archive pages (matches archive:post, etc.)
      Multisite 1:post:* All posts on site 1
      Multisite *:home Home page on all sites (matches 1:home, 2:home)
      Multinetwork 1:*:post:* All posts on all sites in network 1
      Multinetwork *:*:home Home pages across all sites in all networks
    • ?-Wildcards

      The ? matches exactly one character:

      Installation Type Example Pattern What It Matches
      Single site post:? Posts with single-digit IDs (1-9)
      Multisite ?:home Home pages on sites with single-digit IDs
      Multinetwork ?:?:* All content on sites with single-digit IDs in networks with single-digit IDs
  • Clear Cache by URLs

    To clear the cache by specific URLs.

    /**
     * @param string|array $urls URL or array of URLs to clear.
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache_by_urls( $urls, $expire );
  • Clear Cache by Post IDs

    To clear the cache of specific posts, pages, or CPTs.

    /**
     * @param int|array $post_ids Post ID or array of Post IDs to clear.
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache_by_post_ids( $post_ids, $expire );
  • Clear Cache by Site IDs

    To clear the cache of specific sites in a WordPress Multisite network.

    /**
     * @param int|array $site_ids Site ID or array of Site IDs to clear.
     * @param int|null $network_id Network ID (optional).
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache_by_site_ids( $site_ids, $network_id, $expire );
  • Clear Cache by Network ID

    To clear the full cache of each site in a given network.

    /**
     * @param int|null $network_id Network ID (optional, defaults to current network).
     * @param bool $expire Expire cache if set to true, or delete by default. (optional)
     */
    millipress_clear_cache_by_network_id( $network_id, $expire );

Managing Cache Flags

MilliCache provides functions to manage flags for the current request, which are used to tag cache entries for efficient clearing.

  • Add Flag to Current Request

    Add a flag to the current request. Flags are labels attached to cache entries that allow for efficient cache clearing.

    /**
     * @param string $flag The flag name (e.g., 'post:123', 'custom-flag').
     */
    millipress_add_flag( $flag );

    Example usage:

    // Check if we're using a specific page template
    if ( is_page_template( 'templates/landing-page.php' ) ) {
        $flags[] = 'template:landing-page';
    }
  • Remove Flag from Current Request

    Remove a flag from the current request.

    /**
     * @param string $flag The flag name to remove.
     */
    millipress_remove_flag( $flag );
  • Get Flag Prefix

    Get the prefix for flags based on site and network IDs. In multisite environments, flags are automatically prefixed with site and network IDs.

    /**
     * @param int|string|null $site_id Site ID (null for current).
     * @param int|string|null $network_id Network ID (null for current).
     * @return string The prefix string (empty string for non-multisite).
     */
    $prefix = millipress_get_flag_prefix( $site_id, $network_id );
  • Prefix Flags

    Prefix an array of flags with site/network prefix. Useful when you need to manually construct prefixed flags in multisite environments.

    /**
     * @param string|array $flags Flags to prefix (string or array).
     * @param int|string|null $site_id Site ID (null for current).
     * @param int|string|null $network_id Network ID (null for current).
     * @return array Array of prefixed flags.
     */
    $prefixed_flags = millipress_prefix_flags( $flags, $site_id, $network_id );

    Example usage:

    // Prefix flags for a specific site in a multisite installation
    $flags = [ 'home', 'post:123' ];
    $prefixed = millipress_prefix_flags( $flags, 2 ); // For site ID 2
    // Result in multisite: [ '2:home', '2:post:123' ]

WP-CLI Commands

Note

WP-CLI is not context-aware of the current site in a multisite installation. Therefore, when using flags in a multisite setup, you must explicitly include the site ID as a prefix (e.g., 1:home for site ID 1). If you're running multiple networks and issuing site-specific commands, you must also include the network ID (e.g., 1:2:home for network ID 1 and site ID 2).

Get Stats

Get cache statistics such as the number of cache entries and cache size. The optional flag parameter can be used to filter the cache entries by a specific flag.

$ wp millicache stats [--flag="<flag>"]

Clear Cache

Clear the cache for specific flags, post-IDs, URLs, site IDs, or network IDs. The optional --expire flag can be used to regenerate the cache entries in the background on the next request.

$ wp millicache clear [--flag="<flag>"] [--id="<id>"] [--url="<url>"] [--site="<site>"] [--network="<network>"] [--expire]

--flag supports wildcards and can be a single flag or a comma-separated list of flags, as with --id, --url, --site and --network.

Debugging

Enable debug mode by setting MC_CACHE_DEBUG to true in your wp-config.php. This adds headers to the response:

define('MC_CACHE_DEBUG', true);

Inspect response headers using cURL or browser developer tools:

curl -I https://example.com

Headers include:

  • X-MilliCache-Flags: The cache flags for the current request.
  • X-MilliCache-Status: The cache status of the current request.
  • X-MilliCache-Expires: The left TTL of the current request.
  • X-MilliCache-Time: The cache time for the current request.
  • X-MilliCache-Key: The cache key of the current request.
  • X-MilliCache-Gzip: If Gzip compression is enabled.

Hooks & Filters

MilliCache provides several hooks and filters to extend functionality. Some examples:

millicache_should_cache_request

If the current request should be cached.

add_filter(`millicache_should_cache_request`, function( $should_cache ) {
    // E.g. do cache 404 pages
    if ( is_404() ) {
        return true;
    }

    return $should_cache;
});

millicache_flags_for_request

Filter to add additional cache flags when creating a cache entry for the current request. These flags are stored alongside the cache and determine when and how it can be targeted & invalidated. This hook runs with WordPress fully loaded, so you may use conditional logic based on user roles, templates, queries, etc.

add_filter('millicache_flags_for_request', function( $flags ) {
    // Add a flag if a specific block is used.
    if ( is_singular() ) {
		$post = get_post();

		if ( has_block( 'plugin/slider', $post ) ) {
			$flags[] = 'has_slider';
		}
	}

    return $flags;
});

millicache_flags_related_to_post

Filters the list of cache flags that are considered related to a specific post. This hook is used during invalidation (e.g., when a post is updated or deleted) to determine which cache entries should be cleared. The returned flags are not saved, only used for lookups during cache clearing operations.

add_filter('millicache_flags_related_to_post', function( $flags, $post ) {
    // If the post is of the type 'my_cpt'
    if ( $post->post_type === 'my_cpt' ) {
        // All entries with the 'cpt:my_cpt' flag are related and should be cleared
        $flags[] = 'cpt:' . get_post_type();
    }

    return $flags;
});

millicache_settings_clear_site_hooks

Filters the list of action hooks that trigger a full site cache clear. When one of these hooks is fired anywhere in your codebase, MilliCache will automatically clear the cache for the current site.

The array key is the hook name, and the value is the priority at which MilliCache should attach its clearing logic.

add_filter('millicache_settings_clear_site_hooks', function( $hooks ) {
    
    // Add a custom hook with priority that clears the cache
    $hooks['my_custom_hook'] = 10;
    
    return $hooks;
});

Example: do_action( 'my_custom_hook' );

millicache_settings_clear_site_options

Filters the list of site options that trigger a full site cache clear when their value changes.

This is useful for ensuring that updates to critical settings — such as theme options, layout toggles, or feature flags — automatically invalidate the cache.

Each option name in the array refers to a top-level option stored via update_option() or the Settings API.

add_filter('millicache_settings_clear_site_options', function( $options ) {
    
    // Add a site option that clears the cache
    $options[] = 'my_custom_option';
    
    return $options;
});

Example:

update_option( 'my_custom_option', 'new_value' );
// → MilliCache detects this change and clears the full cache for the current site

User Capability Management

MilliCache provides a filter hook to customize which user capability is required for cache clearing operations. This allows you to control who can clear cache based on your site's specific needs, while settings access remains restricted to administrators for security.

millicache_clear_cache_capability

Controls the capability required to clear cache via admin bar and REST API endpoints.

add_filter('millicache_clear_cache_capability', function( $capability ) {
    // Allow authors to clear cache (default: 'publish_pages' for editors)
    return 'publish_posts';
});

Default: 'publish_pages' (Editor role and above)

Applied to:

  • Admin bar cache clearing menu
  • REST API /wp-json/millicache/v1/cache endpoint

Settings Access

Settings access is always restricted to the 'manage_options' capability (Administrator role and above) for security reasons. This ensures that only administrators can:

  • Access the MilliCache settings page in WordPress admin
  • Use the REST API /wp-json/millicache/v1/settings endpoint
  • Use the REST API /wp-json/millicache/v1/status endpoint

Testing

Testing is automated with tools such as PHPUnit, PHPStan, and PHP CodeSniffer. For e2e-tests, we use Playwright running on @wordpress/env. That makes it basic for you to test the plugin in a real WordPress environment. To play with MilliCache or to run the tests, you need to have Docker and Node.js installed.

Start the Test Environment

The following commands will start the WordPress environment with MilliCache Plugin installed under http://localhost:8888.

Note

Another WordPress environment will be available under http://localhost:8889 for the Playwright tests. Please note that this instance is configured for testing, e.g., with 5-second Cache-TTL. So better to play with the first instance.

$ npm install
$ npm run env:start

You can log in with admin and password.

Run the e2e-Tests

To run the Playwright tests under http://localhost:8889:

$ npm run env:e2e

Stop the Test Environment

To stop the environments:

$ npm run env:stop

Destroy the Test Environment

To destroy and remove the environments:

$ npm run env:destroy

Further useful commands

  • npm run env:cli wp ... - Run WP-CLI command at the WordPress environment. E.g. npm run env:cli wp millicache stats
  • npm run env:redis-cli - Open the Redis CLI
  • npm run env:reset - Reset the WordPress environments and start from scratch

Credits

MilliCache is inspired by: