LifterLMS Template Overrides: Do Them Safely and Keep Them Current

How LifterLMS finds template files, how to override one in a child theme, when a hook is the better choice, and a repeatable way to spot and update outdated overrides after every LifterLMS release.

  • Add as a preferred source on Google
Illustration for “LifterLMS Template Overrides: Do Them Safely and Keep Them Current”

A LifterLMS template override lets you change the HTML of any front-end LifterLMS screen, from the syllabus to the pricing table, without editing the plugin. Done well, it survives updates. Done carelessly, it quietly freezes part of your site on an old version of LifterLMS, including old bugs and old security fixes.

This guide is for developers and technically confident site owners. It explains how LifterLMS looks up templates, walks through a safe override in a child theme, shows when a hook is the better tool, and gives you a repeatable process, including a short WP-CLI script, for keeping overrides current after each release.

Everything here was checked against the LifterLMS 10.3.2 source code. For the wider picture of safe customisation, read how to customize LifterLMS without breaking updates.

How LifterLMS finds a template

LifterLMS keeps its front-end templates in the plugin's templates folder, for example templates/course/syllabus.php. When it needs one, it looks in this order:

  1. A lifterlms folder in the active child theme.
  2. A lifterlms folder in the parent theme.
  3. The plugin's own templates folder.

The first match wins. So wp-content/themes/your-child-theme/lifterlms/course/syllabus.php replaces the plugin's syllabus template. The path inside lifterlms mirrors the path inside templates, without the word "templates".

The list of folders is filterable with lifterlms_theme_override_directories. That is how you keep overrides in a custom plugin instead of a theme, which is often the better home for them on client sites where the theme might change:

<?php
/**
 * Plugin Name: LLMSX Template Overrides
 */
add_filter( 'lifterlms_theme_override_directories', 'llmsx_add_override_dir' );

function llmsx_add_override_dir( $dirs ) {
	// Checked before the theme folders.
	array_unshift( $dirs, plugin_dir_path( __FILE__ ) . 'templates' );
	return $dirs;
}

Block themes have one more set: LifterLMS's catalog and restricted-access block templates can be overridden with HTML files in lifterlms/block-templates/. Our guide to block themes and the Site Editor covers those.

Override or hook? Decide first

Most LifterLMS screens are assembled from small templates attached to action hooks. That gives you a cheaper option than an override for many changes.

You want toUse
Remove an element, such as the course authorA hook: remove_action()
Move an element, such as the progress bar above the descriptionA hook: remove it and add it at another position
Add something new, such as a notice above the syllabusA hook: add_action()
Change textA translation file or gettext filter
Change the markup inside an elementA template override

Hooks keep working when LifterLMS changes a template, because you never copied the template. An override takes ownership of the whole file. For example, removing the author from course pages needs one line, not an override:

<?php
add_action( 'init', 'llmsx_remove_course_author' );

function llmsx_remove_course_author() {
	remove_action( 'lifterlms_single_course_after_summary', 'lifterlms_template_course_author', 40 );
}

Our LifterLMS hooks and filters guide lists the hooks and priorities for course and lesson pages.

Create a LifterLMS template override step by step

  1. Use a child theme or a custom plugin. Never put overrides in a theme you do not control, because the next theme update deletes them. The WordPress child theme handbook covers setup.
  2. Find the right template. Pick the smallest file that contains your change. To change one row of the syllabus, override course/lesson-preview.php, not course/syllabus.php.
  3. Copy it, keeping the path. templates/course/lesson-preview.php becomes your-child-theme/lifterlms/course/lesson-preview.php.
  4. Keep the header comment. Each template's docblock ends with an @version line. Leave it exactly as it was in the file you copied. That number is how you will know later whether your copy is out of date.
  5. Make the smallest change you can, and mark it with a comment such as // LLMSX change: show lesson duration.
  6. Commit it to version control with a note of the LifterLMS version you copied from.
  7. Test as a visitor, an enrolled student and an admin.

The LifterLMS templates documentation describes the same folder structure.

Why overrides go stale

LifterLMS changes templates in normal releases: new features, accessibility fixes, and security hardening such as better escaping. When it does, your override keeps the old markup. Sometimes that is harmless. Sometimes a template starts expecting a variable or function your copy does not provide, a feature silently disappears, or a security fix never reaches your site.

Every LifterLMS changelog entry that touches templates ends with an "Updated Templates" list, linking each changed file at that version on GitHub. LifterLMS 10.1.0, for instance, updated more than twenty templates, including the lesson completion link, access plan button and quiz start button. If you override any of those, you have work to do after updating.

Keeping overrides current after updates

Check the System Report

Go to LifterLMS > Status and open the System Report tab. The Template Overrides section lists each override with two version numbers: the plugin's template version and your copy's version. When they differ, the plugin's file has changed since you copied it.

One limitation: the report scans templates at the top level and one folder deep, such as course/ and loop/. Deeper templates, such as those under admin/reporting/tabs/, are not listed, so track those yourself.

Check with WP-CLI

For agencies managing several sites, a script is faster. Save this as llmsx-check-overrides.php and run wp eval-file llmsx-check-overrides.php. It walks every override folder recursively and reports outdated or orphaned files:

<?php
function llmsx_template_version( $path ) {
	$head = file_get_contents( $path, false, null, 0, 8192 );
	return preg_match( '/@version\s+(\S+)/', $head, $m ) ? $m[1] : '';
}

$core_dir = trailingslashit( llms()->plugin_path() ) . 'templates/';

foreach ( llms_get_template_override_directories() as $dir ) {
	$dir   = trailingslashit( wp_normalize_path( $dir ) );
	$files = new RecursiveIteratorIterator(
		new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS )
	);
	foreach ( $files as $file ) {
		if ( 'php' !== $file->getExtension() ) {
			continue;
		}
		$relative = str_replace( $dir, '', wp_normalize_path( $file->getPathname() ) );
		$core     = $core_dir . $relative;
		if ( ! file_exists( $core ) ) {
			WP_CLI::warning( "{$relative}: no matching LifterLMS template" );
			continue;
		}
		$mine   = llmsx_template_version( $file->getPathname() );
		$theirs = llmsx_template_version( $core );
		if ( version_compare( $mine, $theirs, '<' ) ) {
			WP_CLI::warning( "{$relative}: override {$mine}, LifterLMS {$theirs}" );
		} else {
			WP_CLI::log( "{$relative}: current ({$mine})" );
		}
	}
}

Merge the changes

  1. Diff the plugin's old version of the template against its new version, using the GitHub links in the changelog or your own copy of the plugin in version control.
  2. Apply that diff to your override, keeping your marked changes.
  3. Update the @version line in your copy to the new number.
  4. Test the screen on staging.
  5. If your change is now possible with a hook, delete the override instead.

Add-on templates and pluggable functions

Many LifterLMS add-ons load their front-end files through the same template functions, so the same lifterlms folder in your child theme is usually where their overrides go too. Folder structures differ between add-ons, so check each add-on's documentation and copy the path exactly as the add-on's own templates folder lays it out.

There is also an older technique you will meet on inherited sites: redefining a template function. Many functions that print LifterLMS elements, such as lifterlms_template_single_reviews(), are wrapped in function_exists() checks, so a theme can declare a function with the same name first and replace it. It works, but it fails silently if load order changes and it hides the change from the System Report. We convert these to hooks or proper overrides when we find them.

Finally, keep an eye on output that is not a template at all. Some markup is built in PHP classes or blocks, and no override will reach it. If you cannot find the HTML you want to change in the templates folder, search for a filter near the code that produces it before reaching for heavier tools.

Troubleshooting overrides

  • Override ignored. Check the path mirrors the plugin's path exactly, without templates, and that it is in the active theme. On sites with a persistent object cache such as Redis, the list of override folders is cached; if you just created the lifterlms folder, flush the object cache.
  • Template disappears entirely after updating to 10.3.2. LifterLMS 10.3.2 added checks that a template file resolves inside an allowed folder. An override that is a symlink to a file elsewhere on the server now fails that check and is not loaded. Copy the file into the theme instead of linking it.
  • Undefined variable notices. The plugin now passes different variables to that template. Merge the latest version.
  • A page builder ignores your override. Builder elements still use LifterLMS templates, but a builder can replace the whole page layout around them. Confirm which part of the page your template controls.
  • Override works in one theme only. It lives in the theme. Move it to a plugin folder with the filter above if the theme might change.

Frequently asked questions

Can I override LifterLMS email templates the same way?

Yes. Email templates live in templates/emails/ and follow the same lookup, so lifterlms/emails/ in your child theme overrides them.

Will a LifterLMS update delete my overrides?

No. Overrides live in your theme or plugin, which LifterLMS never touches. The risk is the opposite: they stay the same while the plugin changes.

Can I override admin templates?

Some admin screens use templates from the same folder, but overriding admin output is rarely a good idea. Use hooks and filters for admin changes where they exist.

How many overrides is too many?

There is no limit, but every override is maintenance. If you have more than a handful, review which could become hooks.

What to do next

Open the System Report today and note any override whose versions differ. Merge those first, then add the WP-CLI check to your update routine so it runs before and after every LifterLMS update on staging.

If your site has many overrides, or a previous developer left you overrides nobody understands, our LifterLMS customization service can audit them, convert what we can to hooks, and bring the rest up to date. Ongoing checks after each release are part of our support plans. Get in touch with your LifterLMS version and a list of your overrides.

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
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