LifterLMS and Redis: Persistent Object Caching and What 10.x Changed

How a Redis or Memcached object cache speeds up LifterLMS, what LifterLMS keeps in the object cache, the 10.x fixes for persistent caches, and a safe setup that avoids stale progress and staging leaks.

  • Add as a preferred source on Google
Illustration for “LifterLMS and Redis: Persistent Object Caching and What 10.x Changed”

A persistent object cache, usually Redis or Memcached, is one of the most effective performance upgrades for a LifterLMS site. Course sites are full of logged-in students, and logged-in pages mostly bypass page caching. Each lesson view loads options, post meta, user meta and enrollment data, and an object cache keeps much of that in memory instead of asking MySQL again.

This guide is for site owners and developers who run LifterLMS with Redis, or are about to. It explains what object caching does and does not speed up, what LifterLMS stores in the object cache, what changed in the 10.x releases to make it more reliable, and how to set it up without the classic problems: stale progress and staging sites reading production data.

For the wider performance picture, including hosting, page caching and video, see our guide on how to speed up a LifterLMS site.

What a persistent object cache does for LifterLMS

WordPress has a built-in object cache, but by default it lasts only for a single request. The WP_Object_Cache reference explains that it persists between requests only when a persistent cache backend such as Redis or Memcached is installed through a drop-in.

With Redis in place:

  • Core WordPress data is cached across requests: options, posts, post meta, user meta and terms. LifterLMS models read heavily from post meta and user meta, so course, lesson, order and student objects load faster.
  • LifterLMS's own cached values persist, such as computed grades and membership content lists, instead of being recalculated on every page.
  • Database load falls, which matters most at busy moments: a cohort starting, a launch email, or an exam deadline.

What it does not do: it does not cache custom-table queries that LifterLMS runs directly, such as many enrollment and reporting queries against wp_lifterlms_user_postmeta, unless the code caches them explicitly. It does not replace good hosting, and it does not fix slow queries in a heavy report. Think of it as removing repeated reads, not as a fix for every slow page.

What LifterLMS stores in the object cache

From the 10.3 source, these are the main cache groups LifterLMS uses:

GroupHoldsExpiry
llms_user_{id}Per-student values such as enrollment datesNone; replaced when data changes
student_{id}Calculated grades, invalidated with a group prefixOne hour
Per-membership groupsPosts associated with a membershipOne hour
llms_product_subscriptions_countActive subscription counts per productOne hour
Default groupCore form definitionsOne hour
llms_session_idFront-end session data, also stored in its own tableSession lifetime
llms_template_functionsTheme template override directoriesOne day; cleared on theme switch
llms_media_authorizationWhether a user may load a protected fileOne minute, filterable with llms_media_protection_cache_expiration_time
llms_customersCustomer metrics for the Customers screen added in 10.3Cleared when orders change

Student progress is cached differently: LLMS_Student::get_progress() stores results in user meta (keys such as llms_course_456_progress), and LifterLMS resets them when lessons are completed or the course outline changes. With Redis, those user meta reads also come from memory.

LifterLMS uses a "prefix" pattern for groups it needs to clear at once. LLMS_Cache_Helper::get_prefix() returns a prefix stored in the cache, and LLMS_Cache_Helper::invalidate_group() replaces it, so every old key in the group is orphaned in one call. This works with any backend because it does not need group flushing, which Redis drop-ins do not all support.

What changed in LifterLMS 10.x

Several 10.x releases fixed problems that only appeared with a persistent object cache. If you run Redis or Memcached, these are good reasons to stay current:

  • 10.1.0 fixed the media protection URL rewrite failing when a persistent object cache was enabled.
  • 10.2.0 improved cache miss detection and added expiry times to object cache entries "for more reliable behavior on persistent object cache backends". It also fixed stale cached values for core forms, membership-associated posts, student grades, active subscription counts and theme template override directories, and reset cached student progress when lessons or sections are trashed, restored, deleted or moved.
  • The code now treats a cached empty string as a miss in places where a persistent backend can turn a stored null into an empty string, such as enrollment date lookups.

In practice, sites on older versions sometimes saw students who had to wait for a value to expire, or clear a cache, before a change showed up. Upgrade first, then enable or tune Redis.

Setting up Redis for a LifterLMS site

  1. Get Redis from your host. Most managed WordPress hosts offer Redis as a toggle or add-on. Use a Redis instance on the same server or private network, never one exposed to the internet.
  2. Install the object cache drop-in. Your host may provide one. Otherwise the Redis Object Cache plugin by Till Krüss is the common choice; install it and enable the drop-in from its settings screen.
  3. Set a unique key prefix. In wp-config.php, define WP_REDIS_PREFIX with a value unique to this site and environment, for example the domain plus -prod. If several sites or a staging copy share a Redis instance with the same prefix, they read each other's cached options and user data.
  4. Consider a maximum TTL. The same plugin supports WP_REDIS_MAXTTL to force expiry of keys that were stored without one. A day or a week is a sensible safety net.
  5. Give Redis enough memory and an eviction policy. If Redis fills up and refuses writes, cache behaviour becomes unpredictable. Ask your host for a memory limit sized to your site and an eviction policy that removes the least recently used keys.
  6. Flush and test. Flush the cache once with wp cache flush, then log in as a test student, complete a lesson, take a quiz and buy a plan in test mode. Check that progress, grades and access update instantly.

Object cache vs page cache on course sites

Do not confuse the two. A page cache stores whole HTML pages and is ideal for anonymous visitors on sales pages and the blog. An object cache stores data and helps every request, logged in or not.

LifterLMS protects its personal pages from page caching. On the checkout page, the student dashboard and quizzes, it sends no-cache headers and defines DONOTCACHEPAGE, DONOTCACHEOBJECT and DONOTCACHEDB, constants that many caching plugins respect, plus a WP Engine specific exclusion. You can add other pages with the llms_no_cache_page_ids filter. Our article on LifterLMS caching conflicts covers page cache rules in detail.

Caching your own LifterLMS data correctly

If you build custom reports or widgets, use the same pattern core uses: a group prefix, an expiry, and the $found argument so a cached zero is not treated as a miss.

<?php
/**
 * Cache an expensive report value the way LifterLMS 10.x does:
 * a group prefix for one-call invalidation, an expiry, and $found
 * so a cached zero is not mistaken for a cache miss.
 */
function llmsx_course_completion_count( $course_id ) {
	global $wpdb;

	$group = 'llmsx_reports';
	$key   = LLMS_Cache_Helper::get_prefix( $group ) . 'completions_' . absint( $course_id );
	$found = null;
	$count = wp_cache_get( $key, $group, false, $found );

	if ( $found ) {
		return (int) $count;
	}

	$count = (int) $wpdb->get_var(
		$wpdb->prepare(
			"SELECT COUNT(*) FROM {$wpdb->prefix}lifterlms_user_postmeta
			 WHERE post_id = %d AND meta_key = '_is_complete' AND meta_value = 'yes'",
			$course_id
		)
	);

	wp_cache_set( $key, $count, $group, HOUR_IN_SECONDS );

	return $count;
}

// Invalidate every cached report value when a course is completed.
add_action(
	'lifterlms_course_completed',
	function () {
		LLMS_Cache_Helper::invalidate_group( 'llmsx_reports' );
	}
);

Troubleshooting

  • Progress or access looks out of date. Check the LifterLMS version first. Then flush the object cache, and use the Student Progress Cache tool under LifterLMS > Status > Tools & Utilities to clear cached overall progress and grades.
  • Changes made directly in the database do not appear. SQL edits bypass the cache. Always run wp cache flush after imports, migrations or manual fixes.
  • Staging shows production data or vice versa. Both environments share a Redis prefix. Give each a unique WP_REDIS_PREFIX and flush both.
  • Protected files fail to load. Update to 10.1 or later, which fixed media protection with a persistent object cache.
  • Redis connection errors. The site falls back to the database, which is slower but safe. Check the drop-in's status screen and your host's Redis service.

Frequently asked questions

Does LifterLMS work with Redis?

Yes. LifterLMS uses the standard WordPress object cache API, so it works with any persistent backend, and 10.x specifically improved reliability on Redis and Memcached.

Redis or Memcached?

Either works. Redis is more common on WordPress hosts and has a well-maintained drop-in, so it is our default choice. Use whichever your host supports best.

Will Redis make my reports fast?

It helps, but heavy reports are limited by custom-table queries. For large sites, see our guide to scaling LifterLMS.

Next steps

Update LifterLMS to the latest 10.x release, enable Redis with a unique prefix on staging, run a full student journey, then repeat on production.

If your site still feels slow for logged-in students, or you see stale data you cannot explain, our LifterLMS optimization service profiles the queries and cache behaviour on your site. Get in touch and we will find where the time goes.

Add LifterLMS Expert to your preferred sources

Add lifterlmsexpert as a preferred source on Google, or open this article in your AI assistant to use it as a source.

  • Add as a preferred source on Google
VishavjeetChoubeyLifterLMS Expert
Free consultation

Prefer expert help over DIY?

Skip the trial and error. Get specialist LifterLMS help and ship faster.

Talk to a LifterLMS Expert Explore our services

Replies within one business day