Avoid Caching logged in user with Cloudflare Workers – Effective way to Cache Everything

Cache everything in Cloudflare also caches logged in users which makes admin bar in WordPress to appear to anonymous users. It is not a good thing and cause negative effect to user experience. We can disable admin bar in WordPress from dashboard settings but there is comment section which also shows logged in as message to not logged in users.

So, is it a good idea to use cache everything in Cloudflare? The answer is yes because I am going to show you how to avoid caching logged in users and how to only purge single page which is modified.

There is a plugin, Cloudflare Page Cache which does the same but it purges all the cache including HTML and static contents like image & CSS. Therefore this article is not only about avoiding logged in user in Cloudflare edge cache but also purging those pages only which are changed.

We are going to use Cloudflare WordPress Plugin along with a Cloudflare Workers script. Cloudflare WordPress Plugin handles cache purging while Cloudflare Workers script enables Edge Cache HTML ensuring no logged in users are being cached and bypass HTML cache for users with cookies. Using this method when a comment is made then only that single page is purged from Cloudflare edge cache and when appearance is changed, everything is purged.

To do so you need to install Cloudflare WordPress Plugin and enable automatic cache management.

For this you need to setup plugin with Global API key first. Which can be found in https://dash.cloudflare.com/profile.

Now you need to run a Cloudflare Workers script that enables HTML edge caching.

Clear all previous code and paste this Workers Script then click save. Gist link – Cloudflare edge-cache-only

// Stop CF edge from caching your site when specific wordpress cookies are present
// script found in https://www.mmaton.com/2018/07/02/cloudflare-cache-anonymous-requests/
addEventListener('fetch', event => {
  event.respondWith(noCacheOnCookie(event.request))
})
async function noCacheOnCookie(request) {
  // Determine which group this request is in.
  const cookie = request.headers.get('Cookie')
  // Edge Cache for 1 month
  const cacheSeconds = 2592000
  if (cookie
    && (
      cookie.includes(`wordpress_logged`)
      || cookie.includes(`comment_`)
      || cookie.includes(`wordpress_sec`)
      || cookie.includes(`woocommerce_`)
    )) {
    const bustedRequest = new Request(request, { cf: { cacheTtl: -1 } })
    const response = await fetch(bustedRequest)
    const newHeaders = new Headers(response.headers)
    newHeaders.append('wp-cache-busted', `true`)
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers: newHeaders
    })
  } else {
    return fetch(new Request(request, { cf: { cacheTtl: cacheSeconds } }))
  }
}

You can change const cacheSeconds = 2592000 to adjust the cache time. It is in second and is equivalent to Edge Cache TTL available in Cloudflare page rules. To deploy workers you have to add a route.

Now your website also became cachy like mine. After doing all the setup, disable your Cache Everything page rule if you have enabled it before. Also you don’t need Edge Cache TTL page rule since it will not work without Cache Everything. The Cloudflare Workers script will take care of both of them.

Cloudflare Workers can do even more. Some examples are changing header on the go and Fast Google Fonts. See How to solve font loading issues due to CORS.

Your super cachy website may also send cache-control header like cache-control: max-age=3600, which tells browser to store cache for that time period.

Since we are also caching HTML pages, it will be also stored in browser cache. Due to this page will not load from server when next time user visits that page again instead it will load from users browser cache unless user refreshes the page.

To avoid this you have to set max-age to low as much as you can. It may depend on how active your site is. I have set it to an hour (3600 seconds). So you don’t get this page updated unless you hit that reload button for an hour. You can set cache-control header using mod_expires rule in Apache web server. This can be done by using ExpiresByType text/html "access 1 hour" inside <IfModule mod_expires.c> </IfModule>. This is what my .htaccess file have in root folder of the site.

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access 1 hour"
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 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/x-icon "access 1 year"
ExpiresByType image/svg+xml "access 1 year"
ExpiresDefault "access 1 hour"
</IfModule>

You can adjust it like ExpiresByType text/html "access 60 seconds".

You also need to set Browser Cache Expiration in Cloudflare to Respect Existing Headers. By doing this Cloudflare will not add its own max-age header.

For the users who are using WP Super Cache plugin, it sets default expire time is 3 seconds only. You need to check that from browser console. If it is you don’t need to edit .htaccess like above. But you can always edit to fine tune Browser Cache Expiration. W3 Total Cache plugin users can set Browser Cache Expiration from settings.

You can check if HTML Edge Cache is working or not using browser’s developer tools (Ctrl+Shift+I).

When user is logged in you can see the wp-cache-busted: true header.

When you browse in private (incognito) mode, you will see cf-cache-status: hit

My site is already boosted with Cloudflare workers let me know how it is working on your site.

This Post Has 24 Comments

  1. S DHINESH KUMAR

    The above script is not working in my wordpress…I have tried with below cookies as well
    // Stop CF edge from caching your site when specific wordpress cookies are present
    // script found in https://www.mmaton.com/2018/07/02/cloudflare-cache-anonymous-requests/
    addEventListener(‘fetch’, event => {
    event.respondWith(noCacheOnCookie(event.request))
    })
    async function noCacheOnCookie(request) {
    // Determine which group this request is in.
    const cookie = request.headers.get(‘Cookie’)
    // Edge Cache for 1 month
    const cacheSeconds = 2592000
    if (cookie
    && (
    cookie.includes(`wordpress_logged`)
    || cookie.includes(`comment_`)
    || cookie.includes(`wordpress_sec`)
    || cookie.includes(`woocommerce_`)
    || cookie.includes(`wordpress_logged_in_`)
    || cookie.includes(`wordpress_logged_out_`)
    || cookie.includes(`wp-`)
    || cookie.includes(`wordpressuser_`)
    || cookie.includes(`wordpresspass_`)
    || cookie.includes(`wordpress_sec_`)
    )) {
    const bustedRequest = new Request(request, { cf: { cacheTtl: -1 } })
    const response = await fetch(bustedRequest)
    const newHeaders = new Headers(response.headers)
    newHeaders.append(‘wp-cache-busted’, `true`)
    return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers: newHeaders
    })
    } else {
    return fetch(new Request(request, { cf: { cacheTtl: cacheSeconds } }))
    }
    }

    1. Sangam

      There is a plugin (WP Cloudflare Super Page Cache) available now, that also caches all pages as static html in Cloudflare. This article is for that same purpose. You can use that plugin to avoid all these mess. Plugin also avoid caching logged in user efficiently. You should try that plugin.

  2. Sallida

    Hello Sangam,
    thanks so much for the information. I created now a new CF Account and tried with your previous Worker Script again, and the Script is working, so the answer from CF Support was not correct…
    When testing with Chrome Dev Tools I get on the Pages cf-cache-status: HIT, and logged in to Admin cf-cache-status: DYNAMIC wp-cache-busted: true, perfect.
    Following now the Tutorial is set in the worker script const cacheSeconds = 3600 , and in the htaccess File as well ExpiresByType text/html “access 3600 seconds”
    Cloudflare Caching:
    Caching Level: Standard
    Browser Cache TTL: Respect Existing Headers
    In my Page Rule, I disabled Cache Everything Rule and Edge Cache TTL
    Page Rules:
    *.domain.com/blog/wp-admin/*
    Disable Security, Browser Integrity Check: Off, Always Online: Off, Security Level: High, Disable Apps, Disable Performance: Off
    2
    *.domain.com/blog/wp-login.php*
    Disable Security, Browser Integrity Check: Off, Always Online: Off, Security Level: High, Disable Apps, Disable Performance: Off
    3
    *.domain.com/*
    Always Online: On, Security Level: Medium, Origin Cache Control: On
    Testing Chrome for the cache-control: max-age=3600 Response Header, nothing displayed ..
    The Request Header show cache-control: max-age=0 .
    Do you have an Idea if something else has to be adapted to get the correct max-age=3600 Response Header?
    Thank You,
    Sallida

    1. Sangam

      You can use caching plugin to achieve this. Try with WP Super Cache or W3 Total Cache.

      1. Sallida

        Hello Sangam, get it to work now 🙂 I use WP-Rocket Caching Plugin, i had to set there ExpiresByType text/html “access plus 3600 seconds” Thx

        1. Sangam

          I am glad, it is fully working.

  3. Sallida

    Hello,
    thanks for sharing this article Sangam! I created worker and route with the script in CF Dashboard, when i test the worker script with Get https://worker.domain.workers.dev/ i get 522 Origin Connection Time-out Error
    Do you know, if there is any specific DNS Setup?
    Thank you!
    Sallida

    1. Sangam

      No there is not any DNS setup needed. Have you checked with real website?

      1. Sallida

        I wrote to the CF Support, this is what they answered me:
        You have done this correctly and your workers is retuning 522 due to an issue with the code, which I am afraid we can’t help.
        If you are trying to avoid cache with specific cookies present you can make use of the Caching API this can be used to conditionally set content in CF’s cache.
        Here is a Cookie Script that you can use to extract the cookie value. This can be combined with our conditional caching template.
        The Caching API Script is a little robust as it has more content than needed, but it also demos the way to put() assets into cache from a subrequest.
        Basically you can use the Cookie Script combined with the Caching Script to build up the conditions you want for caching/bypassing cache.
        Caching Api – https://developers.cloudflare.com/workers/reference/apis/cache/
        Cookie Script – https://developers.cloudflare.com/workers/templates/pages/cookie_extract/
        Caching Api Script – https://developers.cloudflare.com/workers/templates/pages/cache_api/
        Do you have any suggestions?
        Thx

    2. Sallida

      yes, i have tried on real live website. Now i have setup a Testpage on a other Domain, and connected cloudflare, and added worker and route new, but get the same 522 Error when trying get to worker address..

  4. Joe

    Great work Sangam – this is a fantastic tutorial and the results are exactly as described for logged out and logged in users. A major step for us. Thanks a lot!

    1. Sangam

      I am glad it is helpful for you.

  5. OhMyMi

    Hi Sangam,
    i followed this tutorial from FB group.
    but i have an issue with your code when i have wpallexport and wpallimport running in the background. the url for triggering and processing is apparently cache by this method.
    is there any way i add a bypass for the url?
    example of the url is like this:
    https://domain.com/wp-load.php?export_key=XXX&export_id=8&action=trigger
    hope you can help me
    Jo

    1. Sangam

      You can use page rule to avoid caching.

    1. Sangam

      The script by Cloudflare purges everything when post or comment is updated if KV is not being used. With the script I described in this blog do not purge caches it only caches and bypass is logged in. Purge is done by Cloudflare plugin.
      I already described all these stuffs in this blog and you are asking it.

      1. Mohammad Tahir

        ahan. With that said. Have you tried their 5$ paid worker?
        https://workers.cloudflare.com/
        Its says in the free version we get low latency after the first request.
        but in the unlimited plan its always the lowest.
        Will paid worker give some more boost?

        1. Sangam

          The first request will have higher latency in free plan. If your site is large and need better performance you can pay. Paid plan is always better than free.

    1. Sangam

      When you make a request to website from new location Cloudflare caches files at their Edge Server (near that location). You can see ‘cf-ray
      5302f099edd7e634-LHR’ header in your files and html. So for the first time cf-cache-status will be MISS. When the cache is cleared and request is made it will be EXPIRED. If you request again then it will be HIT. You can read more about this here – https://support.cloudflare.com/hc/en-us/articles/200172516.
      So a question for you, have you tried testing again? If you did please reply.

  6. Kushal

    Hello Sangam, thank you for the guide. I followed the steps and it’s working great.
    However, I got one questions – do we need to disable the `Cache Everying` after adding the edge-cache service worker in CF?

    1. Sangam

      Yes you need disable it when caching is done via Cloudflare Workers. Sorry I missed that to include in the article. I will update the article. Please let me know how it is going. And also please share your website link if you would like to.

      1. Kushal Azza

        Thank you! I figured that out later in the day.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.