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…
Read articleLifterLMS has no built-in student limit. The free core plugin places no cap on courses, memberships or enrollments, and sites with tens of thousands of students run on it. What changes at that scale is everything around the plugin: how many students are logged in at once, how big a handful of tables grow, how background jobs are run, and how heavy your reports are.
This guide is for owners and developers of LifterLMS sites that are already large, or are about to be: an academy with a big launch list, a corporate training rollout, an association moving thousands of members onto CE courses. It covers hosting, the database tables that grow fastest, cron and background processing, and reporting, with specific settings and hooks from LifterLMS 10.3.
If your site is slow today with modest traffic, start with our guide on how to speed up a LifterLMS site. This article assumes the basics are in place.
| Source | Why it grows | Main fix |
|---|---|---|
| Concurrent logged-in students | Lesson, quiz, dashboard and checkout pages are personal, so page caching does not serve them | Enough PHP workers, fast PHP, persistent object cache |
wp_lifterlms_user_postmeta | Several rows per enrollment, plus one or more per completed lesson, section and course | Good indexes and efficient queries |
wp_lifterlms_events | Page load, exit, focus and blur events on course content, plus session events | Narrow tracking, archive old rows |
wp_lifterlms_notifications | One row per notification per subscriber | Archive old rows |
| Action Scheduler queue | Recurring payments, delayed engagements, notifications, webhooks, expirations | Real cron and a dedicated queue runner |
| Reports and exports | Aggregates over every enrolled student | Current 10.x, off-peak exports, reporting copies |
For a large course site, the number that matters most is concurrency: how many students are clicking at the same moment. A site with 50,000 students and a steady trickle of activity needs less than a site with 5,000 students who all start a live cohort at 9am.
wp_lifterlms_user_postmeta holds enrollments, completions and award links. It is indexed on user_id and on post_id, and most queries also filter by meta_key. At hundreds of thousands or millions of rows, check your slowest queries with EXPLAIN on a production-sized copy. If a composite index (for example on post_id, meta_key) clearly helps, test it on staging first, document it, and recheck after LifterLMS updates, since the plugin manages this table's schema. Our article on how LifterLMS stores its data explains the table's structure.
LifterLMS records client-side events (page load, exit, focus and blur) on its own public post types and on account and checkout pages, plus sign-on, sign-out and session events. On a busy site that is a lot of rows. They feed activity and session information in reporting, so do not switch them off blindly, but you can narrow them with the llms_tracking_post_types filter:
<?php
// Record client-side events (page load, exit, focus, blur) on lessons and quizzes only.
// Account and checkout pages are still tracked by core.
add_filter(
'llms_tracking_post_types',
function () {
return array( 'lesson', 'llms_quiz' );
}
);
For a finer rule, llms_tracking_should_track_client_events receives the final yes or no for the current page.
We found no scheduled clean-up of the events or notifications tables in the LifterLMS 10.3 core. If they run into millions of rows, archive older records, for example events older than two years, to a separate table or export, in small batches during quiet hours and after a backup. Decide the retention period with whoever owns your reporting and privacy policy.
LifterLMS relies on background jobs more than most plugins. Recurring payments, access plan expirations, delayed engagements, notifications and webhook deliveries run through Action Scheduler, which LifterLMS bundles. Its own WP-Cron events include llms_end_idle_sessions every five minutes, llms_delete_expired_session_data hourly, and daily log backup, temporary file clean-up and tracking jobs.
By default, WP-Cron runs only when someone visits the site, and Action Scheduler is driven from it. On a large site that is unreliable in two directions: jobs run late when traffic is quiet, and big batches run during busy page loads. The fix is to run them from the server:
define( 'DISABLE_WP_CRON', true ); to wp-config.php, as the WordPress handbook on system cron describes.*/5 * * * * cd /var/www/example.com && wp cron event run --due-now --quiet
* * * * * cd /var/www/example.com && wp action-scheduler run --batch-size=50 --batches=4 --quiet
The wp action-scheduler run command and its --batch-size, --batches, --group and --hooks options are documented in the Action Scheduler WP-CLI guide. Tune batch sizes to your server.
Then watch the queue. LifterLMS > Status > Scheduled Actions lists pending, past-due and failed actions. A growing number of past-due llms_charge_recurring_payment actions means renewals are late, which is lost revenue. If background processors get stuck, the Tools & Utilities tab has Delete processor batches and Delete course data locks, and Reschedule Recurring Payments repairs active orders whose next payment is missing from the queue.
Reporting is where large sites feel pain first, because a single screen can aggregate every student in a course. LifterLMS 10.2 made several changes aimed at big sites:
Average progress, average grade and enrolled student counts for each course are calculated by a background processor and stored on the course, so the course overview stays fast. Beyond that, run large exports outside peak hours, and for heavy analytics feed a separate reporting database from the REST API or a read replica rather than querying production directly. Our article on slow LifterLMS admin and reports covers specific screens.
There is no limit in the software. The practical limit is your infrastructure and how many students are active at the same time. With the setup above, tens of thousands of students is a hosting and tuning question, not a platform one.
Not at first. Once your database competes with PHP for memory and CPU, or slow queries appear during busy periods, a separate or managed database is usually the best next step.
On a large site, yes. Recurring payments, expirations and delayed emails all depend on it. Running it from the system scheduler makes them predictable.
Measure before you buy hardware: enable the slow query log, look at PHP worker usage at peak, and check the Scheduled Actions queue. Those three numbers show where your site will break first.
If you are planning for significant growth or a large rollout, our LifterLMS optimization service audits hosting, database and background jobs and gives you a prioritised plan. Contact us with your student numbers and peak patterns.
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…
Read article
LMS sites are slow for different reasons than blogs. Here is what you can and cannot cache on a LifterLMS site, where the database work goes, and how…
Read article
A step-by-step plan for moving from Teachable to LifterLMS: what Teachable lets you export, how to rebuild courses, import and enroll students…
Read articleSkip the trial and error. Get specialist LifterLMS help and ship faster.