How to Speed Up a LifterLMS Site

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 to measure a real improvement.

  • Add as a preferred source on Google
Illustration for “How to Speed Up a LifterLMS Site”

Most WordPress speed advice assumes that visitors are anonymous and that every page can be saved once and served to everyone. An LMS breaks that assumption. Your most important visitors are logged in, and nearly every page they open is built for them alone.

That is why a LifterLMS site can score well on its public sales page and still feel slow to a student halfway through a course. This guide separates the two problems and works through each layer in the order that usually pays off.

Why LMS pages are hard to cache

A page cache stores finished HTML and skips PHP and the database on later visits. That only works when the HTML is the same for everyone. A lesson page is not. LifterLMS checks whether this user is enrolled, whether drip or prerequisite rules allow access and what they have completed, then outputs progress, navigation and a completion button that depend on the answers.

Serve a cached copy to the wrong person and you get the familiar symptoms: a student who paid but sees the enrollment prompt, progress that does not update, or a dashboard that shows someone else's name. Logged-in pages have to be generated per request. The goal shifts from avoiding PHP to making PHP and the database fast.

What you can and cannot page-cache

PagePage cache?Why
Home, landing pages, blogYesSame for every anonymous visitor
Course and membership catalogs, course sales pagesYes, for logged-out visitors onlyStudents see progress and enrollment state
LessonsNot for logged-in studentsAccess and progress are per student
QuizzesNeverAttempts are live data
Student DashboardNeverEntirely personal
CheckoutNeverOrders, coupons and payment forms

LifterLMS does part of this for you. On the Checkout page, the Student Dashboard page and quiz pages it sends no-cache headers and defines the DONOTCACHEPAGE constant that many caching plugins respect. It does not do this for lessons or courses, so those depend on your cache skipping logged-in users. Confirm that setting in your caching plugin, then confirm that any server-level or CDN cache in front of WordPress follows the same rule. The LifterLMS caching FAQ has notes for specific caching plugins and Cloudflare.

Anonymous traffic stays cacheable. Current versions of LifterLMS only set the session cookie, whose name starts with wp_llms_session_, once there is something to remember, such as an applied coupon. Older versions gave it to every visitor, which made some page caches skip those views.

If you build your own page with per-student content, add it to the list LifterLMS protects:

add_filter( 'llms_no_cache_page_ids', 'acme_no_cache_pages' );

function acme_no_cache_pages( $ids ) {
	$ids[] = 1234; // ID of a custom page with per-student content.
	return $ids;
}

Object caching

Since logged-in pages must be generated, reduce what each one costs. A persistent object cache such as Redis or Memcached keeps the results of repeated database lookups in memory between requests. WordPress Site Health recommends one on sites it judges would benefit.

LifterLMS uses the WordPress object cache for lookups such as enrollment status, so with a persistent backend those checks stop hitting the database on every page view. Run a current LifterLMS version if you turn this on. Recent releases fixed several stale-value problems that only appear with a persistent cache.

Database and query hygiene

Student activity lives in LifterLMS tables that grow with every enrollment, lesson and quiz:

  • {prefix}lifterlms_user_postmeta holds enrollment and completion records. It is indexed by user ID and post ID, not by meta key, so custom queries should always filter on one of those.
  • {prefix}lifterlms_quiz_attempts holds one row per attempt, including the questions and answers.
  • {prefix}lifterlms_events records sessions and page activity for logged-in students.

What keeps them fast:

  • Stay current. Recent LifterLMS releases reworked slow reporting and export queries for large sites. Keeping up with them is routine LifterLMS support and maintenance work, not a special project.
  • Keep background jobs moving. LifterLMS charges recurring payments, expires access and delivers webhooks through scheduled actions, and recalculates course statistics such as average grade and progress through WP-Cron. Check LifterLMS > Status > Scheduled Actions for a backlog of past-due actions, and trigger WordPress cron from a real server cron job so none of it waits for a visitor.
  • Expect some lag on big courses. Once a course has 500 or more students, LifterLMS throttles those course-wide recalculations to once every four hours by default. That is deliberate.
  • Audit custom code. Never load every student at once. Page through LLMS_Student_Query, avoid queries inside loops, and use Query Monitor on staging to see slow and duplicate queries grouped by the plugin responsible.
  • Run heavy reports and exports off-peak.

Hosting and PHP

Uncached requests need CPU, so hosting matters more for an LMS than for a brochure site. The plugin's WordPress.org listing sets a low minimum, but the LifterLMS system requirements recommend considerably newer versions: PHP 8.3 and MySQL 8.0 or MariaDB 10.6 at the time of writing. The same page warns that a host caching dynamic pages such as the Student Dashboard will stop the site from working correctly. Questions to ask a host:

  • How many PHP requests can run at the same time on this plan? Every logged-in page view holds one until it finishes.
  • Is OPcache enabled, and is Redis or Memcached available?
  • Can I exclude URLs and logged-in users from the server cache myself?
  • Is there a staging environment for testing updates and load?

Images and video

Do not serve lesson video from your own server. Video files eat bandwidth and compete with students for server resources. LifterLMS embeds video through WordPress oEmbed, and its documentation points to dedicated hosts such as Vimeo, Wistia and YouTube. On sales pages, consider a click-to-load preview image so the player script is not downloaded until someone presses play.

For images, upload at the size they are displayed, use a modern format, and lazy-load what sits below the fold. Do not lazy-load the main image at the top of a course sales page. It is usually the Largest Contentful Paint element, and delaying it makes that score worse.

Front-end weight and plugin bloat

LifterLMS loads its core stylesheet and scripts, including a few jQuery UI components, on every front-end page, not only on LMS pages. That is reasonable for a plugin whose blocks and shortcodes can appear anywhere, but it means your marketing pages carry LMS assets. Removing them selectively is possible and easy to get wrong. Do it from a child theme or small plugin, as described in how to customize LifterLMS without breaking updates, and test on staging with logged-in and logged-out users.

Lesson time tracking is another cost to know about. When a lesson has a minimum time requirement, or tracking is switched on for all lessons under LifterLMS > Settings > Courses, each student with a lesson open sends a small background request every 30 seconds by default. Those requests cannot be cached, so enable tracking where you need it and not everywhere.

The larger savings are usually outside LifterLMS: page builders, sliders, chat widgets, analytics tags and plugins nobody remembers installing. Remove what you do not use.

Core Web Vitals targets and how to measure

MetricGoodWhat it measures
Largest Contentful Paint (LCP)2.5 seconds or lessLoading
Interaction to Next Paint (INP)200 milliseconds or lessResponsiveness
Cumulative Layout Shift (CLS)0.1 or lessVisual stability

These are Google's Core Web Vitals thresholds, judged at the 75th percentile of page loads on mobile and desktop separately. Time to First Byte is not a Core Web Vital, but web.dev suggests 0.8 seconds or less as a rough guide, and on logged-in LMS pages it is usually the first number to check.

Measure before you change anything:

  1. Pick five URLs: a sales page, the Course Catalog, a lesson, the Student Dashboard and the Checkout page.
  2. Test the public ones with PageSpeed Insights.
  3. PageSpeed Insights cannot log in, so test the others in Chrome DevTools while signed in as a test student. Note the server response time in the Network panel.
  4. Record query count and query time per page with Query Monitor on staging.
  5. Change one thing, repeat the tests, write down the result.

What to do next

Work in this order: confirm cache exclusions are correct, add a persistent object cache, update PHP and LifterLMS, move video off the server, trim front-end weight, then look at the database. The first two deal with the classic complaints: students seeing the wrong content, and a slow dashboard.

Bring in help when the site slows down as students log in together, when checkout times out, or when you suspect custom code and cannot prove it. Our LifterLMS optimization service starts with measurement, and if the cause turns out to be custom code, our LifterLMS development guide explains what upgrade-safe fixes look like. You can also get in touch with a slow URL and a description of what students are experiencing.

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