Ran a website performance test on your URL and saw a “Specify a cache validator” warning? It means your website is lacking HTTP caching headers, forcing new requests to be generated at every visit. The solution? Include them in every response of the origin server because they validate and configure the length of the cache. That way, the requests don’t need to be generated and loaded each time, reducing bandwidth usage, boosting website load speed, and improving user experience. Now, let’s jump straight into how to fix “Specify a cache validator” in WordPress.
Things to note
Always run the website performance tool more than once, especially with Pingdom. The warning might disappear the second time because the first scan was reserved for priming the assets’ cache from the server. Check whether the issue exists using multiple tools, too; GTmetrix and Google PageSpeed Insights are notable alternatives. Also, only the issue that’s caused by the requests on your server can be fixed. If none of the four header types remove the warning, the problem lies in third-party requests. Contact them and point them to this guide.
1. Fix “Specify a cache validator” using headers that validate cache
Headers that validate the cache, ETag, and Last-Modified, help the browser discover whether the file has changed since the last time it was requested. Here’s what you can do:
1. Last-Modified
Last-Modified is commonly sent from the server to the browser automatically. In the vast majority of cases, it isn’t the source of the “Specify a cache validator” warning. In rare cases when it is, you can determine that using these instructions:
- Visit your website in Google Chrome.
- Right-click and select Inspect.
- Switch to the Network tab.
- Relead the tab. Click the main item under Names (usually the first).
- On the right-hand side, under Headers, find Last-Modified.
- Check whether the date and time match the current one.
2. ETag
ETag is related to Last-Modified and the server also automatically adds and sends it to the browser. For Apache 2.4, it is generated using the FileETag Directive. As for NGINX, it’s been automatically enabled since 2016. However, unlike Apache, you might fix “Specify a cache validator” in a WordPress website hosted on an NGINX server by double-checking the ETag header is active. Simply enter this code:
etag on
2. Fix “Specify a cache validator” via headers that control cache length
These types of headers control how long the file is held in cache before a new copy is fetched from the servers. We’ll define two, Cache-Control and Expires, then showcase their practical application.
1. Cache-Control
Cache-Control header uses various directives to set the length of the cache. First, we’ll explain what the configurations represent, then demonstrate how to apply them.
1. Explaining directives
Note that the following are some of the many available directives. We’ll showcase three, but only use two out of three. You might use a different one, based on your goals. These are the Cache-Control directives you can utilize:
- max-age: Represents the time, defined in seconds, a file will be cached for before having to be cached again. We’ll use 604800 seconds or 7 days in the code below.
- private: Only allows the browser accessing the file to cache it.
- public Configures the header so that any public cache can store the response. We’ll use this one.
2. Adding Cache-Control directives
Follow these instructions to fix “Specify a cache validator” in WordPress via Cache-Control header:
Apache
To configure the Cache-Control header in Apache, edit the .htaccess file in the root folder of your website after you access it via FTP. Add the following code at the bottom:
<filesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
Header set Cache-Control "max-age=604800, public"
</filesMatch>
NGINX
If you’re using NGINX as the origin server, like the majority of high-performing websites, you need to edit the configuration file located at /etc/nginx/nginx.conf. Insert the following code:
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
add_header Cache-Control "public";
}
2. Expires
Technically, you don’t need Expires at all. According to the HTTP/1.1 specification, Cache-Control supersedes it. As such, only one of the two will be in use, and Cache-Control has priority. But if the code above doesn’t produce results, it’s worth a try. Note that Expires uses date instead of precise time. With that said, here’s how to solve the “Specify a cache validator” warning on a WordPress website via Expires:
Apache
Once again, open and edit the .htaccess file. Paste the code below to the bottom of the document, so it doesn’t conflict with GZIP compression, mod_rewrite, and other cache configurations you might have:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 7 days"
</IfModule>
NGINX
Adding Expires headers to NGINX is significantly easier. Open the nginx.conf file we mentioned above, and replace the Cache-Control code with this one:
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 7d;
}
Combine Cache-Control and Expires headers in NGINX (Optional)
Don’t feel comfortable replacing? You can combine the two headers, although this is redundant. As we pointed out, browsers will only use one when both are present, which is Cache-Control. Firm in your decision? Edit the code so that it looks like this:
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 7d;
add_header Cache-Control "public";
}