WpW: ESI and LiteSpeed Cache

WordPress Wednesday: Edge Side Includes Caching

Written by

in

WordPress Wednesday: Edge Side Includes Caching

Welcome to another installment of WordPress Wednesday!

As you may know, our LiteSpeed Cache for WordPress plugin supports Edge Side Includes, also known as ESI. Today we are going to talk about why this is such awesome news for your website.

Please note: OpenLiteSpeed does not support ESI functionality. You will need LiteSpeed Web Server Enterprise, LiteSpeed Web ADC, or QUIC.cloud CDN in order to use ESI.

What is ESI?

ESI is a markup language that allows you to designate parts of your dynamic page as separate fragments that are then assembled together to make the whole page. To put it more quaintly, ESI lets you “punch holes” in a publicly cached page, and then fill those holes with privately cached content.

With ESI, punched holes can be treated differently than the rest of the page. They can have different TTLs and be purged by events that are completely separate from the page they are on. This allows you to cache more of your site for more of your visitors.

Public Cache vs. Private Cache

LiteSpeed Cache is tag-based (which means that each page is stored with an identifier that allows it to be purged from cache as part of a specific subset) and has built-in public and private caches. In the public cache you will find pages that are exactly the same for everyone. Private caches contain content that pertains only to a specific user specified by their IP address and session ID.

Until now, you’ve had to think about your site’s pages in their entirety. Is this page publicly cacheable? Is that one publicly cacheable? If a page had any private data on it at all, you’d have to say “no, it cannot be stored in the public cache.” This issue of having to cache a full page in its entirety is why our WordPress plugin until 2017 only cached pages for non-logged-in users. In WordPress, non-logged-in users are almost always served only public content. And in the few cases where they are not (password-protected posts, moderated comments, etc.), that content is usually considered non-cacheable for that user. ESI changes this.

How do ESI and Public/Private Cache Work Together?

ESI allows you to disassemble a full page and treat the pieces differently from each other.

LiteSpeed Web Server allows you to store content in either the public cache or a private cache.

Combine these two elements and you get something very powerful. You get a system that can break apart a page into public and private pieces, cache each piece appropriately, and then re-compose the full-page content from the relevant caches and serve it to a user without ever hitting the PHP backend.

That is pretty amazing.

Edge Side Includes Caching

This combination allows you to cache content for logged-in WordPress users. With ESI enabled you can say, “Hey this page is mostly public. Let’s cache it, punch a few holes in it for the private content, and save that content in the private cache.”

Examples

Let’s look at a few common scenarios and see how they play out with ESI enabled and without ESI.

Example #1: Admin Bar

You’re the site admin, you are logged in, and you visit your site’s home page, which is in the public cache.

Without ESI: your request hits the backend, because the admin bar at the top of the page is private content, and as such this page (and every other page on your site, for that matter) cannot be served to you from cache.

With ESI: most of this page is served to you from the public cache, while the admin bar is served to you from your private cache. There is no need to invoke PHP.

Example #2: Recent Posts Widget

You have a large site with much static content that rarely changes. Every page has a sidebar, and the sidebar widget “Recent Posts” appears on each page.

Without ESI: Every time a new post is published, every single page in the site must be purged so that the widget displays up-to-date data. Re-populating the entire cache requires a crawler to run, or visitors to hit all of the pages of the site.

With ESI: All of the pages in the site can remain cached with a nice long TTL, while the Recent Posts widget is the only thing that needs to be purged. Re-populating that one bit of the cache requires just one visitor to request any page one time.

You can see how ESI + LSCache can have huge implications for the speed of your site!

Enabling and Configuring ESI

LiteSpeed Cache for WordPress considers all cacheable full pages to be publicly cached.

When you enable ESI, you instruct LSCWP to punch holes in public pages. LiteSpeed then caches the content according to the settings for each block: public, private or not at all, and with its own TTL, independent of the page it is on.

When you enable ESI, LSCWP creates the following ESI blocks:

  • Admin Bar
  • Comments
  • Comment form
  • Recent Posts widget
  • Recent Comments widget

Any widget can be an ESI block if you want it to be. By default, ESI is disabled for all but the two widgets listed above, but you can change that in WP Admin.

Note: ESI doesn’t come without a cost. It is much simpler for the server to return fully-cached pages than it is for it to piece together pages from several different blocks (although it’s still more efficient than invoking PHP would be), and so this must be a factor in your decision to enable ESI. Will the speed benefits outweigh the efficiency hit? It depends on your site, really, and it may require some experimentation on your part.

Basic ESI Settings

Edge Side Includes in LiteSpeed Cache

Navigate to WP Admin > LiteSpeed Cache > Cache> ESI. Set Enable ESI to ON.

This creates the ESI blocks listed above. The blocks will be uncached, unless you enable caching for them via the Cache Admin Bar and Cache Comment Form settings.

Creating new Widget ESI Blocks

If you are using Classic Widgets, you can turn any widget into an ESI block. (Please note that at this time, ESI is only available for classic widgets, and not for the new block-style widgets.)

ESI Classic Widgets with LiteSpeed Cache

Navigate to WP Admin > Appearance > Widgets and select the widget that you want to turn into an ESI block.

Within the widget settings area, you will see a shaded box entitled “LiteSpeed Cache.” By default a widget is not considered an ESI block (unless it is Recent Posts or Recent Comments, as mentioned above). If you want the widget to be treated differently than the pages on which it appears, there are a few possible configurations:

Private widget

LSCWP will store the contents in private cache, with different copies for each user by IP/session ID. (Examples: a list of recently viewed posts, or a personalized greeting.)

  • Set Enable ESI to Private.
  • Set Widget Cache TTL to a value appropriate for the contents of the widget.

Public widget

LSCWP will store the contents in public cache, with each user seeing the exact same thing. (Examples: a list of recent posts, or a calendar of upcoming events).

  • Set Enable ESI to Public.
  • Set Widget Cache TTL to a value appropriate for the contents of the widget.

Uncached widget

LSCWP will not cache the contents at all, and WordPress will dynamically-generate the widget each time it displays on the page.

  • Set Enable ESI to either Public or Private (it makes no difference, as long as it’s not Disable)
  • Set Widget Cache TTL to 0.

ESI and Third Party Plugins

Our ESI implementation supports a few other blocks that belong to third-party plugins. For instance, we consider the WooCommerce shopping cart to be a private ESI block.

As we mentioned earlier, with ESI enabled, your site pages are now considered publicly-cacheable, because we are able to punch holes for the occasional non-public content. This is true for all native WordPress pages, and for all WooCommerce pages. It is not, however, true with bbPress.

A bbPress page contains so many areas of private data, that it’s actually much more efficient to consider the entire page to be private. So, that’s what we’ve done. LSCache considers all bbPress pages to be private.

If one of your favorite plugins warrants special consideration, we encourage you to get in touch with us via the WordPress plugin support forum and tell us about it.

Or try turning third party shortcodes into ESI blocks.

P.S. Want to know more technical details about ESI? Check out the official specs.


This content was last verified and updated in April of 2023. If you find an inaccuracy, please let us know! In the meantime, see our documentation site for the most up-to-date information.

Have some of your own ideas for future WordPress Wednesday topics? Leave us a comment!

Don’t forget to meet us back here next week for the next installment. In the meantime, here are a few other things you can do:

Comments

22 responses to “WpW: ESI and LiteSpeed Cache”

  1. Jon Avatar

    This is great, thanks for the update. One question on applying this properly, here’s my situation.

    I don’t use the recent posts or recent comments widget but I do have a featured content widget. I’d like to set it to return a random selection of posts from one category. So for example, show 5 posts out of a possible 20. This means every page is different (at least in terms of this widget) every time it is loaded. Should I set this widget as public ESI? Will that allow the rest of the page (that doesn’t change) to be cached or does that already happen without ESI enabled?

    I also have a social media counter in a widget that updates every 8 hours…I’m assuming that could be handled the same way?

    Thanks!

    1. Lisa Clarke Avatar
      Lisa Clarke

      Hi, Jon.

      These are perfect cases for ESI widgets. For the social media counter, you can turn on Public ESI and give it a TTL around 8 hours. For the featured content widget, you can turn on Public ESI, and give it a very short TTL, say, 5 minutes. You could also set it to be uncached, but I wouldn’t do that unless it is crucial for the widget to show new content with every page load. You get better performance if you cache it, even for a very short TTL.

      I hope this helps. Let us know if you have any other questions!

      1. Jon Avatar

        Wonderful, thank you.

        On a related note, what about category/archive pages? The majority of the traffic to my site goes to archive pages (or what I’ve re-branded as “Best Of” lists). These are static listings of the most recent posts in that category until a new post is published in that category (which happens maybe once a week for an individual category). Here’s an example: https://www.reversewinesnob.com/search/label/costco/

        Would ESI be useful here at all (if that’s even possible)? I have a large number of category pages.

        Thanks!

        1. Lisa Clarke Avatar
          Lisa Clarke

          If that is a basic WordPress archive page of anything with a label of “costco,” then it should already be purged from the cache any time a new post labeled “costco” is published (or modified). You can configure this behavior in the Purge tab of the settings.

          ESI wouldn’t be necessary here, because it’s really the whole page that is changing when there’s new content.

          Does that answer your question?

          1. Jon Avatar

            Ah yes, that makes sense, thank you!

          2. Lisa Clarke Avatar
            Lisa Clarke

            My pleasure!

  2. Stevo Novkovski Avatar
    Stevo Novkovski

    About your performance note, do you mean having multiple ESI blocks may be slower compared to be executed dynamically by PHP?
    Have you made some test to see the average response time of ESI block?
    How many ESI blocks are too much?

    1. Lisa Clarke Avatar
      Lisa Clarke

      Hi, Stevo.

      No, I mean that multiple ESI blocks may be slower compared to whole-page caching. I’ll update the blog post to be more clear. Thanks for asking!

      As far as how many ESI blocks are too many ESI blocks? It’s not an easy question to answer, as it varies considerably depending on your system resources. I wish I could be more specific! I would start with a widget or two, and see how it goes.

      –Lisa

  3. Kenny Avatar
    Kenny

    Is there mark up I can put in my theme to create ESI blocks?

    1. Kenny Avatar
      Kenny

      this is specifically so I can create an ESI block for my custom theme ajax cart.

    2. Lisa Clarke Avatar
      Lisa Clarke

      Hi, Kenny.

      We have an API with some ESI functions that you may find helpful. The API is here. And some ESI examples are here.

      Hope this helps!

  4. Arran Avatar
    Arran

    Hi,

    I’m not having much luck getting this to work.

    I have a basic plugin that returns the time() via short code. https://pastebin.com/JCKjENGz

    How would I use an esi block with the above code to not cache the shortcode output.

    Regards
    Arran

  5. Jon Avatar

    Playing around with this a bit more…is this really needed for something like a recent post widget if you only post once every day or two? Or does WordPress dynamically “rebuild” the widget every time the page is loaded, checking each time for the latest posts — in which case I could see this being very helpful.

    1. Lisa Clarke Avatar
      Lisa Clarke

      Hi, Jon. Here’s how it works:

      • If your page were completely uncached, then WordPress would rebuild the widget every time the page is loaded.
      • If your page were cached without ESI, then the widget would only be rebuilt the one time that the page is dynamically created before being cached. So, if your page had a TTL of one week, then the widget would be regenerated only once per week.
      • With ESI enabled, you can configure the widget to be uncached (so it is rebuilt with every page load), or give it a different TTL (so it is rebuilt more or less frequently than the rest of the page).

      Whether or not ESI is necessary for a recent posts widget depends on how frequently you post, your site’s TTL, and how OK you are with the possibility the widget’s content may sometimes be stale.
      If you post once per day, and your site’s TTL is set for 24 hours, and you don’t mind your widget being slightly behind the times now and then, then ESI would not be necessary in your case.
      Does that clear it up?

      1. Jon Avatar

        Yes, thank you!

        1. Lisa Clarke Avatar
          Lisa Clarke

          Happy to help 🙂

  6. Dmytro Avatar
    Dmytro

    Hi. Do you have any example of code how can I implement esi, private and public caches on the site without CMS?

    1. Lisa Clarke Avatar
      Lisa Clarke

      Hi, Dmytro.
      You can find some information about setting up various caching scenarios through rewrite rules here. For ESI, specifically, see this wiki.

      Please let us know if there is anything you need to know that is not covered in our documentation!

  7. Bee Avatar
    Bee

    Ive activated ESI in the settings panel, but there is not a single place in my entire wp-admin where I can find anything related to ESI. I want to add ESI blocks, or at least add ESI tags to my pages. I followed your instructions to the T, but I am unable to access this functionality.

    1. Lisa Clarke Avatar
      Lisa Clarke

      Hi! In the LiteSpeed settings area, how many tabs do you see? If it’s only four (or five, if you have WooCommerce), click `Advanced Settings` to see the other eight tabs. ESI should be one of them.

      You can also set up ESI for each widget within the widget’s own settings (under Appearance > Widgets).

      And lastly, you can use ESI with shortcodes. That’s documented here.

      If you need something more customized than that, you’ll have to use the API.

      Hope this helps!

  8. Mark Avatar
    Mark

    Great article, thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *