I'm trying to use Nginx page caching instead of Wordpress caching. The caching seems to work fine, but I'm having trouble setting conditional caching headers based on a variable - whether a user is logged into wordpress. If a user is logged in I want no-cache headers applied, if not the page can be cached for a day by both Wordpress and the CDN. I'm finding I can only add one header inside an if statement.
I have read (but not fully understood, because it's late here) [if is evil][1]. I also found an answer on stack exchange (on my laptop, can't find it now) that said inside an if block only one add_header works.
Can anyone give me ideas for an alternative that might work better? I know I can combine the expires with the cache-control, but I want more headers in there, plus I want to understand and learn.
Here's a significantly simplified config with the relevant parts in place.
server {
server_name example.com;
set $skip_cache 0;
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache uris containing the following segments.
if ($request_uri ~* "/wp-admin/|/admin-*|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /blog/index.php?args;
}
location ~ \.(hh|php)$ {
fastcgi_keep_conn on;
fastcgi_intercept_errors on;
fastcgi_pass php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Cache Stuff
fastcgi_cache CACHE_NAME;
fastcgi_cache_valid 200 1440m;
add_header X-Cache $upstream_cache_status;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header Z_ABCD "Test header";
if ($skip_cache = 1) {
add_header Cache-Control "private, no-cache, no-store";
add_header CACHE_STATUS "CACHE NOT USED";
}
if ($skip_cache = 0) {
add_header Cache-Control "public, s-maxage = 240";
expires 1d;
add_header CACHE_STATUS "USED CACHE";
}
add_header ANOTHER_HEADER "message";
}
}
An alternative to the
if
directive is themap
directive. And assuming theCACHE_STATUS
vsCACHE_STATIC
is just a typo in your question, you could try this:The
map
directives should be placed inside thehttp
container (at the same level as theserver
block) as shown above.The
map
directive is documented here.I've come up with one solution myself, based on the answer @Richard Smith provided that didn't quite do what I needed. I've used the more cache-control header rather and dropped the unnecessary expires directive.
This sits inside the server block
Then this goes inside every applicable location block
This means no "if" is required inside the location block. I think this solves the problem, but I'm still interested if anyone has alternative ideas.