Customized Cache Tags With LSCWP API

March 6th, 2023 by LSCache 0 Comments

Customized Cache Tags With LSCWP API

LiteSpeed Cache, the powerful cache engine that ships with all LiteSpeed server products, features the clever “smart purge” technology. This system uses tags to group pages together based on a particular set of rules. This grouping then allows them to all be purged together at one time after a single triggering event. In the LiteSpeed Cache plugin for WordPress, this tagging system is at work behind the scenes, using the rules of WordPress publishing to know exactly when to purge posts, pages, products, categories, and more.

But imagine that you have a plugin, or some customized behavior for your WordPress site, and you would like to be able to group pages together in your own special way, so that they may be purged by your own unique triggering event. How cool would that be?

Well, it turns out, you can build this functionality into your plugin with the tag-based actions of the LSCWP API.

LSCache Tags

Before we get into creating your own custom tags, let’s look at LSCWP’s built-in tagging behavior.

Here’s an example that shows the “smart purge” system in action:

You have the following post on your WordPress site:

  • Title: Unique American Towns
  • Category: United States

People visit your site, and LiteSpeed caches all of the pages that your visitors read, including the Unique American Towns post page.

Later, you edit that post, change the Title and add a second Category:

  • Title: Unique North American Towns
  • Category: United States, Canada

Since there have been changes to the post, the following pages are purged from the cache according to the rules set up in LSCWP admin:

  • The post itself
  • The front page and/or home page of your site
  • The author archive page
  • The post type archive page
  • The monthly archive page
  • The United States and Canada category pages

You can change the rules to purge even more pages than this (or fewer), if it’s appropriate for your website.

This purge tag functionality is very powerful. It means that LSCache can do a targeted purge like we saw above, removing the edited post, as well as every other page that is influenced by that post. Without a tagging system, we would have to either purge too little (just the post) or too much (all of the site’s pages).

This functionality allows you to specify relatively long TTLs (Times to Live) for your pages, knowing that LSCache will step in and purge any pages that are affected by recent activities.

Customized cache tags with LSCWP API

Now imagine you have your own plugin that generates its own content using custom URLs. LSCWP will cache those pages, but it has only the most basic concept of when to purge them: it will purge the pages when the TTL is reached (that is, when the cache expires).

If your plugin was using custom cache tags, you could group pages together, and purge them together before they expire, using whatever logic makes sense for your plugin.

Here’s a simple example: Let’s say you have a widget with a countdown for the number of days remaining until a big event that your site promotes. The widget only changes once per day, but when it does, you would want to purge any page where the widget is displayed. Using the following LSCWP API hooks, this is possible:

Add a custom $tag to the cached page:

do_action( 'litespeed_tag_add', $tag );

Purge all pages tagged with the custom $tag:

do_action( 'litespeed_purge', $tag );

Example

Here’s a more in-depth example that shows you how to create a basic set of functions which will create a form, and cache or purge that form based on the form’s input values.

Basic Plugin

For this plugin, we’ll use a query string parameter called greet, which will store the visitor’s name.

<?php
/**
 * Plugin Name:  LiteSpeed Cache API Tag Demo
 * ...
 */
namespace LscwpApiTagDemo;
defined( 'WPINC' ) || exit;
add_action( 'init', function () {
	if ( ! isset( $_GET['greet'] ) ) {
		return;
	}
	$visitor = $_GET['greet'];
	# ...

Dynamic Tag Name

We create a custom tag based on the value of the greet parameter. So, if our URL was https://.example.com/?greet=Lauren, our custom tag would be LscwpApiTagDemo\greet.lauren, and we would add that tag to the current page.

add_action( 'init', function () {
	if ( ! isset( $_GET['greet'] ) ) {
		return;
	}
	$visitor = $_GET['greet'];
	$tag =
		__NAMESPACE__ . '\greet.'
		. mb_strtolower( $visitor, 'UTF-8' );
	$visitor = stripslashes( $visitor );
	do_action( 'litespeed_tag_add', $tag );
	# ...

Greeting Content

We replace WordPress’s content loop with our greeting.

add_action( 'init', function () {
	# ...
	add_action( 'loop_start', 'ob_start', 0, 0 );
	add_action( 'loop_end', function () use ( $visitor ) {
		ob_end_clean();
		?>
		<article class="page entry">
			<div class="entry-content">
				<?php greet( $visitor ); ?>
			</div>
		</article>
		<?php
	}, 0, 999 );
} );

Greeting Function

We display a message and include a form that accepts a reply.

function greet( $visitor ) {
	?>
	<h2><?php
		printf( esc_html__( 'Howdy, %1$s!' ), $visitor );
	?></h2>
	<form method="get">
		<input name="greet" type="hidden"
			value="<?php echo $visitor; ?>">
		<label for="reply">
			<h3><?php esc_html_e( 'Care to Respond?' ); ?></h3>
		</label>
		<input id="reply" name="reply" type="text" value=""
			placeholder="<?php
				esc_html_e( 'Type your reply here ...' );
			?>">
		<button type="submit"><?php
			esc_html_e( 'Send' );
		?></button>
	</form>
	<?php
}

Reply Content

We revise our main function to add a condition that displays alternative content if the user replied to our greeting.

add_action( 'init', function () {
	# ...
		?>
		<article class="page entry">
			<div class="entry-content">
				<?php
				if ( isset( $_GET['reply'] ) ) {
					reply( $visitor );
				} else {
					greet( $visitor );
				}
				?>
			</div>
		</article>
		<?php
	}, 0, 999 );
} );

Reply Function

We display a thank you note and show that we remember the user’s reply.

function reply( $visitor ) {
	?>
	<h2><?php
		printf( esc_html__( 'Thank you, %1$s.' ), $visitor );
	?></h2>
	<h3><?php
		esc_html_e( "I'll always remember your kind words." );
	?></h3>
	<?php
	$reply = stripslashes( $_GET['reply'] );
	if ( ! empty( $reply ) ) {
		?>
		<blockquote><?php
			echo esc_html( $reply );
		?></blockquote>
		<?php
	}
	# ...

And we add a Forget about me … button that will trigger a cache purge targeting every item associated with the visitor’s name.

function reply( $visitor ) {
	# ...
	}
	?>
	<form method="post" action="<?php
			echo drop_query_var(
				$_SERVER['REQUEST_URI'],
				'reply'
			);
		?>">
		<input name="reset" type="hidden">
		<button type="submit"><?php
			esc_html_e( 'Forget about me ...' );
		?></button>
	</form>
	<?php
}

Putting It All Together

We update our main function once more, so that any page tagged LscwpApiTagDemo\greet.lauren will be deleted if the button is pressed.

add_action( 'init', function () {
	# ...
	$tag =
		__NAMESPACE__ . '\greet.'
		. mb_strtolower( $visitor, 'UTF-8' );
	$visitor = stripslashes( $visitor );
	if ( isset( $_POST['reset'] ) ) {
		do_action( 'litespeed_purge', $tag );
	}
	do_action( 'litespeed_tag_add', $tag );
	# ...

Behavior

So, here’s how that looks in action.:

Lauren visits the site and provides her name. LiteSpeed doesn’t find the page in cache, so the page is generated, served to Lauren, and cached:

https://example.com/?greet=lauren
	x-litespeed-cache: miss

She fills in the form saying, Hello world. LiteSpeed doesn’t find the page in cache, so the page is generated, served to Lauren, and cached:

https://example.com/?greet=Lauren&reply=Hello%20world
	x-litespeed-cache: miss

She fills in the form again saying, I love LiteSpeed. LiteSpeed doesn’t find the page in cache, so the page is generated, served to Lauren, and cached:

https://example.com/?greet=LAUREN&reply=I%20love%20LiteSpeed
	x-litespeed-cache: miss

Note that the greet parameter is not case sensitive. Our plugin converts it to lowercase before setting the $tag value..

She goes back to the form again saying, Hello world one more time. LiteSpeed does find the page in cache, so the cached page is served to Lauren:

https://example.com/?greet=Lauren&reply=Hello%20world
	x-litespeed-cache: hit

Lauren goes back and presses the Forget about me … button, which triggers a purge of every page where LscwpApiTagDemo\greet.lauren is a tag.

Because of this, when she goes back to the form and repeats I love LiteSpeed, the page is not found in the cache.

https://example.com/?greet=LAUREN&reply=I%20love%20LiteSpeed
	x-litespeed-cache: miss

Conclusion

As you can see, the API tag functions are a powerful way to customize the caching and purging behavior of your plugins. Without the API, your plugin would have to maintain its own record of which pages need to be purged from the cache when some event mandates it, and then send individual purge requests for each of those pages.

Using LiteSpeed’s API hooks takes this burden off of your plugin and allows you to let the cache engine do the work.

For more information about customized cache tags with LSCWP API and other API functions, please see our documentation.


Thank you to Tynan Beatty for his contributions to this post, including the sample plugin code.


Tags: ,
Categories:LSCache

Related Posts


Comments