Combining Cloudflare Page Rules for WordPress Site

Hello,

We are a nonprofit organization and we have 50+ various types of websites in our Cloudflare account (most of which are WordPress). We recently discovered information through the following Cloudflare forum topic and help articles about using page rules on our sites to cache everything to speed up our sites as well as reduce our server load:

Again, since we’re a nonprofit, we don’t have the money to spend on buying extra page rules or paying for the Cloudflare Pro plan for every site. However, we really want to take advantage of what Cloudflare has to offer with page rules, primarily with our WordPress sites, while our websites are each on the Free plan.

Until now we’ve only been using the following page rules for our WordPress sites:

  • *example.com/wp-login*: Browser Integrity Check: On, Security Level: High, Cache Level: Bypass, Disable Performance
  • *example.com/wp-admin/*: Browser Integrity Check: On, Security Level: High, Cache Level: Bypass, Disable Performance

With this new fuller Cloudflare caching discovery we want to add the following new page rule on as many of our WordPress sites as we can:

  • *example.com/*: Cache Level: Cache Everything, Edge Cache TTL: a month

However, even though many of these WordPress sites are quite static with their content, they all usually have at least one dynamic area/page (e.g., contact form or blog posts with a comment area enabled), which doesn’t work so well or at all with the caching everything page rule. Ideally, if we had at least one more page rule, we could exclude the dynamic area/page from that level/type of caching. So we’ve been thinking that there might be a way to combine our two original page rules, since they have the same settings, to free up a page rule for us to use. The main idea we’ve had so far is to try the following URL match to combine those page rules, which should catch /wp-login* and /wp-admin/*:

  • *example.com/wp-*in*

This seemed like a great idea, but when I checked out the page source of one of our simplest sites for example and did some regex searching of the code, I noticed that various items from within the /wp-content/ and /wp-includes/ directories (as well as apparently /wp-json/) get caught with that URL match. For example:

  • <a href="https://example-other.com" target="_blank" rel="noopener"><img style="text-align: center; width: 100%; max-width: 665px; background-color: #e1f3ff;" src="/wp-content/uploads/mmt-banner-logo.png" alt="Mystical Mind Training Logo"></a><p style="margin: 0px; text-align: center;"></p>
  • <link rel='stylesheet' id='twenty-twenty-one-print-style-css' href='https://example.com/wp-content/themes/twentytwentyone/assets/css/print.css?ver=5.7.1' media='print' />
  • <link rel='stylesheet' id='wp-block-library-css' href='https://example.com/wp-includes/css/dist/block-library/style.min.css?ver=5.7.1' media='all' />
  • <script src='https://example.com/wp-includes/js/jquery/jquery.min.js?ver=3.5.1' id='jquery-core-js'></script>
  • <script src='https://example.com/wp-includes/js/jquery/ui/core.min.js?ver=1.12.1' id='jquery-ui-core-js'></script>

So we wanted to ask about all of this here and see if it is important or not that some of these files/items are getting caught with that URL match? Does it seem like if these types of files/items, getting excluded from the cache everything page rule, would make a difference, or at least a significant difference, in page load speed and server load?

Any advice or information is greatly appreciated. Thank you.

Then we have a deal for you! Cloudflare Workers costs $5/month for the entire account. Stay with me for a bit…

The snag with Cache Everything is when a cookie is set for admin, or posting replies, Cache Everything ignores the cookie and you’re stuck with caching when you don’t want it in that moment. You can use Workers to bypass the cache if that cookie is set. And if you have the Cloudflare plugin, it will purge the cache when content changes (post/page updates, comments, admin, etc).

I have a single worker: Seven-Day Cache Everything. A bunch of my sites call this worker. And I bypass the Worker for login and admin:

(My “admin headers” worker is for special HTTP headers, but you can select “None” for that Worker so no worker runs for that route.

Here’s the script:

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')
  const cacheSeconds = 604800
  let url = new URL(request.url)
  if (cookie 
    && (
      cookie.includes(`wordpress_logged`)
      || cookie.includes(`comment_`)
      || cookie.includes(`wordpress_sec`)
      || cookie.includes(`ghost-admin-api-session`)
    )) {
    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 if (url.pathname.startsWith("/admin.php") 
          || url.pathname.startsWith("/ghost/")
         ) {
    const bustedRequest = new Request(request, { cf: { cacheTtl: -1 } })
    const response = await fetch(bustedRequest)

    const newHeaders = new Headers(response.headers)
    newHeaders.append('CF-Bypass-Cache-Path-Url', `true`)
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers: newHeaders
    })
  } else {
    // Edge Cache for 7 days
    return fetch(new Request(request, { cf: { cacheTtl: cacheSeconds } }))
  }
}
3 Likes

Thank you very much for your reply and the information you’ve shared, @sdayman !

As we’re not familiar with this feature or the technicalities with it, is there any way to test out the Cloudflare Workers without having to pay for it first? Also, is that $5/month for the entire account for a single Worker, or is it for multiple or unlimited Workers on the account? If we did go in this direction, we’d ideally like to feel secure and confident that we know what we’re doing before moving ahead with this across our sites. I’ll start reading more about these Workers to try to get a grasp on this.

We don’t have this Cloudflare plugin yet but had recently discovered it and was going to test it out. Would this plugin alone potentially solve our issues then? In other words, if this plugin will automatically clear cache when comments or contact forms are submitted (as well as when other changes on the site are made), then perhaps it doesn’t matter that those areas/pages on our sites are getting cached? Are you able to share whether this cache purge is across the entire site or is it just selective to the page/area on the site that got updated or submitted?

I’m not sure I understand. Do you mean you do this bypass through page rules or is this done in the script of your single Worker somehow?

With all that being said, we’d still appreciate knowing if it seems that our URL match to combine the page rules for /wp-login* and /wp-admin/* would work or not? Due to our lack of familiarity with this type of coding for the Workers to configure it properly on our end, this still seems like it could be our best (while probably also using the Cloudflare plugin).

Again, any advice or information that can be shared is greatly appreciated. Thank you.

$5 (plus excessive use charges) is for your entire account and all domains in it. I have at least a dozen WordPress sites, and use just the two scripts total. You really just need the one: 7-Day-Cache-Everything.

The Worker essentially is a “Cache Everything” Page Rule for any zone (domain) that calls it, but will bypass cache if there’s a login or comment cookie set. You will not any page rules related to caching.

Someone who is logged in, or posted a comment will see live updates, and nobody who follows will see content that was personalized for them.

When someone makes a change, the affected pages are purged from the cache.

1 Like

Thanks again for the information, @sdayman!

I’m still researching and reading about all of this, but I think I’m starting to understand. I did find that there is a limited free plan for Workers, so I will test this out very soon to see how it goes for us.

If we were to use this same cache everything Worker, even though it is already bypassing the caching of the login page and back-end admin area, would you still suggest we use our original two page rules in addition to that for our WordPress sites for extra security and to disable other Cloudflare features from affecting those areas:
*example.com/wp-login*: Browser Integrity Check: On, Security Level: High, Cache Level: Bypass, Disable Performance
*example.com/wp-admin/*: Browser Integrity Check: On, Security Level: High, Cache Level: Bypass, Disable Performance
Note: In this case, I guess we could remove the “Cache Level: Bypass” setting from both since that functionality is being covered.

Or does using this Worker render the page rules ineffective or useless?

I’ve also been doing some testing with the Cloudflare plugin but I am finding that it is unfortunately pretty sensitive and easy to cache the admin toolbar for the public to see while having the auto cache purge option enabled and the “Cache Everything” page rule in place. So it does seem this plugin and the auto cache purge option might work best with the Worker script you’ve shared.

I’ll let you know how this all goes. Thanks again!

By the way, I’ve noticed that you haven’t commented about our page rule combination idea. Is this maybe just because you think it’s a terrible idea and/or that it won’t work well at all? Any thoughts about it are appreciated. :slightly_smiling_face:

The Cloudflare plugin doesn’t do caching. It’s your Cache Everything page rules that’s causing this problem. The Cloudflare plugin just takes care of the purging when content changes.

As for the page rules, you can leave them. I don’t use those, but I can see why you’d want login and admin to have those features

1 Like

Thanks @sdayman. I’ve got into testing this Worker out on my end and it has been going great so far. That being said, I’ve still got some basic questions about the Worker setup and script so far that I’d like to ask you at this point:

  • Is there a reason you don’t write your /wp-admin* route as /wp-admin/*? Is there an added benefit with WordPress sites to the way you’ve written it?
  • In the script, where is the “ghost-admin-api-session” cookie and “/ghost/” path coming from exactly? I haven’t seen this when I’ve been reviewing the header responses on my end. Is this purely unique to your set up and I should remove it from the script I’m testing? Or is this something useful/applies to a general WordPress setup as well?

Thank you for your time and assistance.

  1. I don’t have a reason for leaving the slash off wp-admin. I suppose I could edit that, but it doesn’t make a difference.
  2. I have ghost in there because I share the same Worker across many sites, including those using Ghost instead of WordPress.
1 Like

Wait, this can be done with a $5 worker, and you only need one worker? If you have 50 websites you don’t need 50 workers? I didn’t realise this…

Yep! There’s nothing in there hard-coded for a specific website. And as long as I stay below X number of requests per month, it’s just the $5 for my entire account. I just add the same three routes to all my wordpress zones.

EDIT: The last two routes aren’t generally necessary for most people. I have some CSP headers that interfere with admin and login.

2 Likes

Have you try WP Cloudflare Super Page Cache? WP Cloudflare Super Page Cache – WordPress plugin | WordPress.org

1 Like

Great solution, @sdayman, congrats!

Perhaps @Living-Miracles could consider merging the two routes to bypass /wp-admin* and /wp-login* into one? With a “no route” for /wp-*, Cloudflare would not only exclude /wp-admin/ and / wp-login.php, but also all the backend WordPress and user files under /wp-includes/ and wp-content/, while letting the Cloudflare default to cache static files apply. This way many Workers requests could be saved, though I haven’t tested and therefore don’t know if there could be unintended consequences.

In your case, if I understand how Workers handle routes correctly, you could also add the /wp-* “no-route”, and the headers script would still apply to the routes you’ve set, I believe.

My headers come from the origin, so my admin-headers worker strips them out.

Hmm… not sure I got your point. What I suggested was to add a “no route” for the /wp-* path to save Workers requests.

Then my site’s CSP which blocks connections only only needed in wp-admin, but unwanted on the site itself, would take effect.

You have two routes for the admin-headers worker, and it surely only apply to these routes, right?

You add a route pointing to “none” worker for /wp-*

If I understood the way Workers routing apply, your first 2 routes would still apply to your intended paths (/wp-admin* and wp-login*) because they are more specific than the generic /wp-*.

No worker would run for the subrequests for, say, /wp-content/uploads/, but those assets would still be cached by Cloudflare as they are static files.

https://developers.cloudflare.com/workers/platform/routes#matching-behavior

1 Like

Hey @sdayman,

I’ve been testing out the Dr.FLARE browser extension to inspect the caching that Cloudflare is providing on the site that I’m testing this all out on, and I’m noticing many differences between when using a “Cache Everything” page rule vs using a Worker and the script you provided. In other words, it seems that the “Cache Everything” page rule caches more requests on the site than the Worker and script at the moment. When using the Worker, the page itself gets a header result of “cf-cache-status: HIT” but many of the other resources on the page have Header results of “cf-cache-status: EXPIRED” or “cf-cache-status: MISS” compared to using the page rule.

My understanding was that the Worker and script would essentially do the same thing as the “Cache Everything” page rule, no? Are you experiencing the same thing on the sites that you use Workers and this script for? Any information that you can share about all of this would be helpful as we do like this suggested solution you’ve provided and we’re thinking about implementing it across many more of our WordPress sites soon.

Thank you.

Is there anyone who can respond to my last response? It would be very much appreciated. Thank you.

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.