canstockphoto42968493 (1).jpg


Steven Warwick
January 25, 2017

Wordpress-based learning management systems (LMS) like Learndash and LifterLMS use external plugins to enable hosting of lesson content based on the xAPI standard. This type of content can be generated from authoring tools such as Captivate and iSpring. Assuming you have set up xAPI / tincan correctly, you can use an external Learning Record Store (LRS) such as LearningLocker to record learning activities and will see the learning events as expected.

However, these LMS systems will have no communication connection to these lessons — The content is embedded into the LMS an IFRAME, so there is no standard method of notification when the lesson is complete.

If you have restricted students to progress to the next lesson only at completion, these “phantom” lessons will stop you dead. The simplest solution is to expose a “mark complete” button that students can use to signal to the LMS that they are done. The problem is — they can mark the lesson complete whenever they want, even if they have not completed the actual learning module. This completely defeats the purpose of the xAPI tracking.

The following shows how to solve this problem without using any plugins. It assumes a good familiarity with wordpress, the authoring tools, php and javascript. It currently supports Learndash and LifterLMS but can be easily extended to other systems

This assumes that all course content is embedded in the wordpress server. External content is not covered.

The Strategy

  1. Add a way for the external content to signal completion to the LMS.
  2. Disable the “mark complete” button on lessons where completion will be signaled automatically.

The process for signalling will use the capability for the content authoring tools to configure a “next module” html redirect at the completion of a lesson.

This “next module” will be an html file loaded in place of the learning module, inside the IFRAME. It is a simple javascript function that activates the “mark complete” process, as if it were pressed by a user. Upon receiving the mark complete submission, the LMS reloads the page with the next learning module. In LearnDash, we detect the end of the course and return to the course index page.

The file is simply the following:

<!DOCTYPE html>


function next_lms_module() {

// this is for learndash
let np = parent.document.getElementById("sfwd-mark-complete")
if (np != null && mc.length != 0) {
np = parent.document.getElementById("learndash_next_prev_link");
if (np != null && np.length != 0) {

// this is for lifterlms
np = parent.document.getElementById("llms_mark_complete")
if (np != null && np.length != 0) {;
np = parent.document.getElementsByClassName("llms-next-lesson")
if (np != null && np.length != 0) {

np = parent.document.getElementsByClassName("llms-back-to-course")
if (np != null && np.length != 0) {

console.log("Error 1");





This function works independently of the xAPI plugins.

The file needs to be placed in a location that can be accessed through the web server. I have placed it in the directory:


Adobe Captivate and iSpring both have options for “stringing” learning modules together.

In the case of iSpring, under the Resourses->Settings->Presentation Redirectsetting, you can specify a resource to open at the end of the presentation. To specify this, you can provide a “relative” URL rather than an “absolute” one, which makes the content independent of the actual web URL. The correct setting assuming the redirect file is placed in the directory above is:


For Adobe Captivate, the setting can be found at Edit->Preferences-> Project->Start and End -> Project End Options-> Open Url or File

You can use the same file locator string above for Captivate.

Lessons are typically connected into the LMS using a somewhat xAPI plugins for Learndash, the “Grassblade” plugin gives an option for “completion tracking” which should NOT be activated.

Files uploaded with these settings will automatically record the completion and open the next lesson in the sequence.

Hide “Mark Complete”

Lastly, we need to hide the “mark complete” button on these pages, to prevent learners from skipping ahead. To make this relatively general, I chose to tie this capability to a wordpress “tag”. Any page — Lesson, Topic, Quiz etc.. can have the button removed so long as it is tagged with “hide_complete”.

This will require adding a function to the Wordpress theme. Whenever I’m doing work on a theme, I create a “child theme” and make additions/changes there. This ensures that if the theme is updated, my changes remain in place. I’ll assume you know how to do this.

The following code is added to the functions.php file in the theme:


function hide_mark_complete_button(){
global $post;

$tags = wp_get_post_tags( $post->ID );

$tag_found = false;
foreach ($tags as$tag) {
if ($tag->name == 'hide_complete') { $tag_found = true;};

if( $tag_found == true ) {

 #llms_mark_complete {

This simply either submits hides the form with the “mark complete” button, selected by the tag.

On all pages where you have externally authored content, just add this tag and the button will be removed.

The infrastructure for e-learning continues to evolve and new protocols and architectures continue to be developed. It is expected that as these new processes are put into place, less “plumbing” will be needed to create excellent user experiences, even on relatively low cost platforms.