WP-Rocket: serve the same cache to everyone

Gepubliceerd op:

Tags: caching | english | webdevelopment | wordpress

Most WordPress website owners are familiar with the WP-Rocket plugin. A caching plugin that speeds up loading times for almost every website or webshop. What people might not know is that it generates different caches for every logged-in user. But what if you wanted to serve the same cache files to guests and logged-in users?

Photo by SpaceX on Unsplash


Background

One of the built-in options of WP-Rocket is the user cache. This option allows WP-Rocket to generate and serve cache files to logged-in users. It generates separate caches for every user, which is particularly useful is some content differs from user to user.

But what if you don’t have any personalized content? Also, this options has a major downside: for every page and whenever any user visites it for the first time, it has to be generated on the fly. After the first visit, it will be stored in the cache and can be served faster. But this does mean the initial visit is always slow.

Luckily the developers of WP-Rocket thought of a solution and released a helper called Common Cache For Logged-in Users. This helper allows WP-Rocket to serve a single user cache to all logged-in users. Now, only one logged-in user will experience the initial slow load, while all other users will benefit from the cached page. However, it is essential to install the No Cache for Admins helper (also from WP-Rocket). Otherwise page visits by admins are also cached, causing ‘normal’ users to see the adminbar.

Even though cache is now shared between logged-in users, it isn’t shared with guests. WP-Rocket will still generate separate caches for guests and logged-in users. On top of that: it is not possible to preload the cache for logged-in users, only for guests.

What if you wanted to serve the same cache for guests to logged-in users? Well now you can! The first thing you would need to do is to make sure there isn’t any personalized information on any page. If it’s limited to only a few pages, you could consider excluding those from caching.

Next, install and follow the instructions of this little helper plugin I made: WP Rocket Guest Cache.

How does it work?

With both helpers enabled, WP-Rocket will generate two folders in /wp-content/cache/wp-rocket/: one with your website name (for example: website.dev) and one with a -loggedin-<secret_hash> suffix (for example: website.dev-loggedin-<secret_hash>). Then, in one of their classes, the path to the correct cache folder is generated. If WP-Rocket detects that a user is logged-in, it will load the cache file (if any) from the website.dev-loggedin-<secret_hash> folder. But what if we could trick WP-Rocket into always loading the guest cache?

Unfortunately, WP-Rocket doesn’t have an easy way to achieve this. The class WP_Rocket\Buffer\Cache handles locating the cache path, but there isn’t any filter in it to change its behaviour. On top of that, the Cache class loads through the advanced-cache.php file. This is a special file in WordPress (a ‘dropin’) which loads before a lot of plugins and themes are loading. This means we probably need to edit the advanced-cache.php to inject anything custom.

So, I opted to replace the original Cache class with a custom implementation. Then I would modify the contents of the advanced-cache.php file, so that it would use the custom implementation instead of its default.

1. Custom implementation

I created a class which extends the original implementation. It overwrites the get_cache_path() method and does a str_replace() on the cache path. This will strip off the -loggedin- path, resulting in the path to the guest cache.

<?php

class SdkGuestCache extends \WP_Rocket\Buffer\Cache
{
    protected $sdkConfig;

    public function __construct(
        \WP_Rocket\Buffer\Tests $tests,
        \WP_Rocket\Buffer\Config $config,
        array $args
    ) {
        parent::__construct($tests, $config, $args);
        $this->sdkConfig = $config;
    }

    public function get_cache_path($args = [])
    {
        $path = parent::get_cache_path($args);

        if (strpos($path, "-loggedin-") === false) {
            return $path;
        }

        return str_replace(
            "-loggedin-" . $this->sdkConfig->get_config("secret_cache_key"),
            "",
            $path
        );
    }
}

2. Overwriting advanced-cache.php

In WP-Rocket there is a filter called rocket_advanced_cache_file. It allows to modify the buffer (contents) of the advanced-cache.php file when WP-Rocket is about to write it to disk. With str_replace we can inject our custom implementation in our file and replace the call to the default implementation (new Cache) to our own (new SdkGuestCache).

<?php

add_filter('rocket_advanced_cache_file', 'editAdvancedCache');

function editAdvancedCache(string $buffer): string
{
    $classInject = '.... class contents from above';

    return str_replace(
        '( new Cache(',
        $classInject . "\n\n" . '( new SdkGuestCache(',
        $buffer
    );
}

3. Delete advanced-cache.php

The advanced-cache.php file is not updated automatically. So the last step is deleting the ‘old’ advanced-cache.php file, so WP-Rocket will generate a new one. After deleting, vist any WP-Admin page and WP-Rocket should generate the new file.

4. Go like a ?

If everything went well, the website will now load like a rocket ? for both guests and logged-in users. Don’t forget to enable the preload functionality, so every page will always be in cache

Download my helper plugin from Github here.