Custom automated User Journeys with Enrollment API

Introduction

LifterLMS has a really simple, straightforward and clean API to manage user enrollment into courses and memberships.

In this tutorial, we’ll explore this API in some detail. Using a couple of examples, we’ll build a few custom and automated user journeys. Finally, we’ll leave you with a couple of exercises that you can use to strengthen your understanding of the Enrollment API and explore its possibilities.

Is this for only for Programmers?

This tutorial is written for the benefit of non-programmers too. Concepts are simplified and abstracted for lesser details. Developers are encouraged to check the source code (linked to wherever relevant).

The focus is more on concepts so that course creators can use them to design user journeys that could then be implemented by a developer.

Enrollment API

Functions

There are three functions available in this API:

llms_is_user_enrolled( $user_id, $product_ids, $relation ); [source, deeper source]

A yes/no kind of function that checks if a user is enrolled into one or more courses or memberships. Given a user ID and a product ID (or an array of product IDs), it tells you whether a student is enrolled in them.

(In LifterLMS, “product” is a generic name for both courses and memberships.)

If you provide an array of product IDs, you can check if the student is enrolled into all ($relation = 'all') or any ($relation = 'any') of the given products.

llms_enroll_student( $user_id, $product_id, $trigger ); [source, deeper source]

This simply enrolls a student into a single course or membership. It also allows you to indicate the trigger for the enrollment. This trigger can just be anything you like. LifterLMS internally uses $trigger = 'admin_' . $user_id for manual enrollments and $trigger = 'order_' . $order_id for enrollments triggered by orders.

You could maybe integrate with an events plugin and the value for trigger could be $trigger = 'event_rsvped_' . $event_id. You could have a marketing funnel implemented in any way and store $trigger = 'funnel_' . $funnel_identifier.

The trigger can establish a relationship between any external or third party trigger by storing its ID in this way. Using this information, you could then do many more things to integrate the related trigger’s processes with the user’s enrollment, unenrollment and progress within a course.

llms_unenroll_student( $user_id, $product_id, $new_status, $trigger ); [source, deeper source]

This is the exact opposite of llms_enroll_student(). It unenrolls a given student from a given product.

At the time of unenrollment, you can also control the status which is 'expired' by default. Along with 'enrolled' (which is the status set on enrollment), LifterLMS uses 'cancelled'.

You could use a custom status but you’d have to modify more things for your custom status to function well (for example, inside reporting).

Hooks

In addition to these functions, there are action hooks triggered during the process of enrollment and unenrollment. This can be really useful to trigger other things.

do_action( 'before_llms_user_enrollment', $user_id, $product_id ); [source]

This can be used to trigger things just before a user is about to enroll into a product.

do_action( 'llms_user_enrolled_in_course', $user_id, $product_id ); [source]

This action is triggered specifically for courses after a user is enrolled into a course.

do_action( 'llms_user_added_to_membership_level', $user_id, $product_id ); [source]

This is the equivalent action for memberships.

Examples

Let’s consider some examples where we can use our knowledge of the Enrollment API to implement a few simple but interesting functionality.

Example 1 : Welcome or Onboarding Course

When a new student signs up for any course or membership on your site, you’d like to automatically enroll them in a welcome course.

This welcome course could be an onboarding course to familiarise the user with the workings and functionality of your site. It could also be a course that covers the fundamentals of your domain. For some of you, it could be a way to offer an additional incentive of a free course to new users.

In any case, what basically needs to happen is that

  • as soon as a user enrolls into any course or membership on your site
  • they are also enrolled into a particular course.
  • the welcome course itself should be exempted from this rule, otherwise, we’ll be in an endless loop: A user will enroll into a course, they’ll get enrolled into the welcome course, this will trigger another enrollment for the welcome course which will trigger another and so on.
  • We need to either check if a user is already enrolled in the welcome course before triggering another enrollment or, better still,
  • check if the course that the user has just enrolled into is definitely not the welcome course and save the additional code execution and database lookup needed to check an enrollment.

The technical implementation will be:

  1. Hook into llms_user_enrolled_in_course and llms_user_added_to_membership_level actions.
  2. These actions will provide the product (course/membership) ID and the student’s user ID.
  3. Get the welcome courses’ ID.
  4. Make sure the rest of the process doesn’t happen if the action was triggered for the welcome course itself.
  5. Enroll the student into the welcome course using llms_enroll_student().

Written as code, this looks like:

<?php 

add_action( 'llms_user_enrolled_in_course', 'llms_enroll_in_welcome_course', 10, 2 );

add_action( 'llms_user_added_to_membership_level', 'llms_enroll_in_welcome_course', 10, 2 );

function llms_enroll_in_welcome_course( $student_id, $product_id ){
  
	/* 
	 * the welcome course's id.
	 * You can get this by editing the course and getting the value of the post parameter of the screen's url
	 * https://yoursite.com/wp-admin/post.php?post=123&action=edit
	 */
  	$welcome_course_id = 456;
  
  	// prevent an endless enrollment loop
  	if( (int) $product_id === (int) $welcome_course_id ){
		return;
	}
	
	// enroll student into the addon course
	llms_enroll_student( $student_id, $welcome_course_id, 'welcome-enrollment' );
	
}

You could easily modify this to enroll them into the welcome course before they are actually enrolled in the new course. You could modify this to work only for courses or only for memberships.

Additionally, you could extend this to set up multiple welcome courses for different signups by storing and retrieving welcome courses from the course’s meta data:

<?php 

add_action( 'llms_user_enrolled_in_course', 'llms_enroll_in_welcome_course', 10, 2 );

add_action( 'llms_user_added_to_membership_level', 'llms_enroll_in_welcome_course', 10, 2 );

function llms_enroll_in_welcome_course( $student_id, $product_id ){

	// this assumes that mechanisms to store these course IDs already exists
	$welcome_course_id = get_post_meta( $product_id, 'llms_welcome_course', true );
  
  	// prevent an endless enrollment loop
  	if( (int) $product_id === (int) $welcome_course_id ){
		return;
	}
	
	// enroll student into the addon course
	llms_enroll_student( $student_id, $welcome_course_id, 'welcome-enrollment' );
	
}

Example 2: Welcome Memberships

Instead of a welcome course, you could easily have a welcome membership in Example 1.

Example 3: Automated Prerequisite Sign Ups

Instead of a welcome course, you could fetch the ID of the prerequisite course and automatically enroll them into it.

Let’s say you have a sequence of courses where each course in the sequence is a prerequisite of the next course. What you could do is not add any access plans to any of the courses in the sequence except the last one.

Using our logic, as soon as the user signs up for this course, they’ll be automatically signed up for all the courses in the sequence. The prerequisite API will take over and force them to complete the courses in the set sequence.

The possible advantages of this strategy are:

  1. Not having to create a membership.
  2. By selling the last course, you are effectively selling a bundle of courses or a course track itself. You can concentrate your sales and marketing efforts on just one course and have only basic landing pages on the other courses.

Written as code, it’d look like this (source 1,source 2 ):

<?php 

add_action( 'llms_user_enrolled_in_course', 'llms_enroll_in_prerequisite', 10, 2 );


function llms_enroll_in_prerequisite( $student_id, $course_id ){
  
	$course_object = new LLMS_Course( $course_id );

	// bail if there's no prerequisite
	if ( ! $course_object->has_prerequisite( 'course' ) ){
		return;
	}

  	$prerequisite_id = (int) $course_object->get_prerequisite_id();
  
	
	// enroll student into the addon course
	llms_enroll_student( $student_id, $prerequisite_id, 'automated-budle' );
	
}

Example 4: Course Bundles

A membership is a really simple way of bundling courses. For some reason you may not want to use a membership. Maybe because you don’t want to pollute your memberships with measly bundles.

In that case, with additional code to render a UI for selecting bundled courses and storing their IDs in the course’s post meta, the following will work just fine:

<?php 

add_action( 'llms_user_enrolled_in_course', 'llms_enroll_in_bundled_courses', 10, 2 );


function llms_enroll_in_bundled_courses( $student_id, $course_id ){
  
	// this assumes that mechanisms to store these course IDs already exists
	$bundled_courses = get_post_meta( $course_id, 'llms_bundled_courses', true );

  	foreach( $bundled_courses as $bundled_course_id ){
	
		// enroll student into the bundled course
		llms_enroll_student( $student_id, $bundled_course_id, 'automated-bundle' );
	}
	
}

Example 5: Membership Bundles

Just like course bundles, you could bundle memberships together:

<?php 

add_action( 'llms_user_added_to_membership_level', 'llms_enroll_in_bundled_memberships', 10, 2 );


function llms_enroll_in_bundled_courses( $student_id, $membership_id ){
  
	// this assumes that mechanisms to store these membership IDs already exists
	$bundled_memberships = get_post_meta( $membership_id, 'llms_bundled_memberships', true );

  	foreach( $bundled_memberships as $bundled_membership_id ){
	
		// enroll student into the bundled course
		llms_enroll_student( $student_id, $bundled_membership_id, 'automated-bundle' );
	}
	
}

Example 6: Course + Membership Bundles

There’s an existing way in LifterLMS to auto-enroll students into a bunch of courses as soon as they sign up for a membership. If you want to do the reverse – add a user to one or more Memberships as soon as they sign up for a course, the previous example can be modified as:

add_action( 'llms_user_enrolled_in_course', 'llms_enroll_in_bundled_memberships', 10, 2 );


function llms_enroll_in_bundled_courses( $student_id, $course_id ){
  
	// this assumes that mechanisms to store these membership IDs already exists
	$bundled_memberships = get_post_meta( $course_id, 'llms_bundled_memberships', true );

  	foreach( $bundled_memberships as $bundled_membership_id ){
	
		// enroll student into the bundled course
		llms_enroll_student( $student_id, $bundled_membership_id, 'automated-bundle' );
	}
	
}

Exercises

Consider these as thought experiments and maybe answer in comments. Let’s see if you can work these out. Developers could attempt writing the code and share your gists in comments.

  1. There is an existing method in LifterLMS to auto-enroll students in a list of courses when they join a membership. Could you think of a way to automatically unenroll them from all such courses as soon as they unenroll from the membership.
  2. How would you be able to sell a course track?
  3. Can you think of a workaround to be able to sell individual sections of a course separately?
  4. Consider an elearning site where you have a concept of levels. Let’s say there are two levels (1 & 2) with two courses (Yoga & Meditation) at the each level. Furthermore, Level 1 & Level 2 Yoga are variations of the same topic. Maybe Level 2 has premium additional content. Same with Meditation. This means that, if a user chooses to upgrade to Level 2, they must be unenrolled from the Level 1 courses and enrolled into Level 2 instead. Can you think of one or more ways to implement that?

Conclusion

Familiarity with the Enrollment API opens up a lot of possibilities for automation and custom user journeys. The examples and the exercises cover some basics. You might already have some ideas of your own. If you do, let’s discuss those in the comments.

However, the true ability of LifterLMS to implement powerful user journeys can only be realised by digging into its Completion API.

Think about

  1. Enrolling users into courses or memberships as soon as they complete a lesson, section, course or course track.
  2. Setting prerequisite qualifying courses for memberships or other courses so that a user can join a membership or enroll in a course only when they successfully complete a particular course.
  3. Exclusive memberships that a user is added to as a reward or achievement for completing a lesson, section, course or course track.
  4. Automated progression of a student along a sequence of courses and memberships in any combination so that they only sign up for the first step.

That’s what I hope to cover in the next tutorial. In subsequent tutorials, I hope to cover aspects of content restriction, prerequisites and drips so that you get extremely familiar and comfortable with really advanced and complex user journeys that can be automated.

Think about dripping courses, setting courses/ memberships as prerequisites of each other, complex ways of restricting content, restricting just parts of courses or just some lessons from some users, etc. Stick around for that and more!

Before you go!

Was this useful? Let us know in your comments. Your feedback motivates us to write more tutorials like this and tune them to your needs.

Did you know that we have started writing recipes that a developer can use to build interesting custom features on top of LifterLMS? Check them out right now!

Leave a Comment

Your email address will not be published. Required fields are marked *