Improving Course Navigation User Experience [Part 3]: Implementing the Navigation Model

In Part 1 of this series, we discussed possible mental models that could be used to enhance or replace the current lesson navigation component in LifterLMS.

In Part 2, we went a step ahead and planned the markup and the copy that would be involved in implementing such revisions.

This concluding part discusses the actual code needed to implement the ideas discussed in the earlier parts.

LifterLMS Version 3.37.1

  • TwentyTwenty Theme: Fixed course information block misalignment.
  • Fixed conflict with WooCommerce resulting from the movement of the deprecated LiftreLMS function is_filtered().

LifterLMS Version 3.37.0

Updates
  • Tested and compatible with WordPress core 5.3.
  • Add theme support for the TwentyTwenty core default theme.
  • Improved security and data sanitization in with regards to the SendWP integration connector.
LifterLMS Rest API 1.0.0-beta.8
  • Added memberships controller, huge thanks to @pondermatic!

  • Added new filters:

  • llms_rest_lesson_filters_removed_for_response

  • llms_rest_course_item_schema

  • llms_rest_pre_insert_course

  • llms_rest_prepare_course_object_response

  • llms_rest_course_links

  • Improved validation when defining instructors for courses.

  • Improved performance on post collection listing functions.

  • Ensure that a course instructor is always set for courses.

  • Fixed sales_page_url not returned in edit context.

  • In update_additional_object_fields() method, use WP_Error::$errors in place of WP_Error::has_errors() to support WordPress version prior to 5.1.

LifterLMS REST API Version 1.0.0-beta.9

Updates
  • Added memberships controller, huge thanks to @pondermatic!

  • Added new filters:

  • llms_rest_lesson_filters_removed_for_response

  • llms_rest_course_item_schema

  • llms_rest_pre_insert_course

  • llms_rest_prepare_course_object_response

  • llms_rest_course_links

  • Improved validation when defining instructors for courses.

  • Improved performance on post collection listing functions.

Bug fixes
  • Ensure that a course instructor is always set for courses.
  • Fixed sales_page_url not returned in edit context.
  • In update_additional_object_fields() method, use WP_Error::$errors in place of WP_Error::has_errors() to support WordPress version prior to 5.1.

LifterLMS WooCommerce Version 2.0.12

  • Tested to WordPress 5.3, LifterLMS 3.36.5, and WooCommerce 3.8.
  • Only print WC Notices if wc_print_notices() is defined. Fixes issue when using the LifterLMS Rest API.
  • Fix issue producing malformed enrollment trigger encountered when updating the enrollment status to “enrolled” during order updates.

LifterLMS Blocks Version 1.7.0

Updates
  • Membership post types can now use the LifterLMS Pricing Table block.
  • Membership post types are automatically migrated to the block editor (use the pricing table block instead of the pricing table action).
  • Added a block editor template for the Membership post type.
  • The block ‘llms/form-field-redeem-voucher’ is now only available on registration forms.
Bug Fixes
  • Backwards compatibility fixes for WP Core 5.2 and earlier.
  • Perform post migrations on current_screen instead of admin_enqueue_scripts.
  • Fix an issue causing “No HTML Returned” to be displayed in place of the Lesson Progression block on free lessons when viewed by a logged-out user.
  • Import InspectorControls from wp.blockEditor and fallback to wp.editor to maintain backwards compatibility.
  • Fall back to wp.editor for RichText import when wp.blockEditor is not found.
  • Import from wp.editor when wp.blockEditor is not available.
  • Return early during renders on WP Core 5.2 and earlier where the PluginDocumentSettingPanel doesn’t exist.

Improving Course Navigation User Experience [Part 2]: Planning UI Copy & Markup

In Part 1 of this recipe, we explored various UX patterns for Course Navigation where one of the central theme was that the Mark Complete (or similar) and Next Lesson actions are subtypes of the same Next Step action in a basic intuitive course model.

For the UI, this means that the Mark Complete button and the Next Lesson button become citizens of the same visual space – the right column (next step) of a two column navigation.

For that to happen, we need to change the markup of the navigation component in the template system.

Default Navigation Templates

The two templates responsible for the two distinct experiences are:

Within the lesson-navigation.php template, another template is used to generate the Previous and Next Lesson links’ markup:

https://github.com/gocodebox/lifterlms/blob/3.34.4/templates/course/lesson-preview.php

This lesson-preview.php template is also used within the Syllabus component. So, we’ll also need to differentiate between the use of this template in these two contexts, either by splitting it into two separate templates or by modifying the output for each context.

Lesson Navigation Templates

Restructuring Navigation

Now, we’re looking to do something like this:

Which means that whatever the final pattern we build, we’ll have to redo the templates. What we’re looking for is a two-column layout where the left column will always contain only one action but the right column may contain more than one actions.

If you spend some time going through the code in the templates above, you’ll notice that the current markup is structured like this:

  • div.llms-lesson-button-wrapper (complete-lesson-link.php)
    • button (Mark Complete/ Take Quiz/ Start Assignment)
  • nav.llms-course-navigation (lesson-navigation.php)
    • div.llms-course-nav.llms-prev-lesson (lesson-preview.php)
    • div.llms-course-nav.llms-next-lesson (lesson-preview.php)

In this markup, like we’ve discussed in the earlier part, the task completion model and the navigation model have two distinct spaces. What we want to do instead is to rearrange them into a structure similar to this:

  • nav.llms-course-navigation
    • div.llms-course-nav-step.llms-prev-step
      • div.llms-course-nav.llms-prev-lesson
    • div.llms-course-nav-step.llms-next-step
      • div.llms-lesson-button-wrapper.llms-next-action.llms-next-primary-action
      • div.llms-course-nav.llms-next-lesson.llms-next-action.llms-next-secondary-action

We’ve divided the navigation using two new top-level div’s while moving the existing navigation elements a level deeper. In the div for the next action, we’re attempting to differentiate between the primary and secondary actions. This will help us prioritise the primary action visually, irrespective of its order in markup.

At the same time, we don’t want to modify the selectors so that any existing functionality doesn’t break and we achieve what we need with minimum code.

Various States of the Navigation UX

Before going further, let’s take the various permutations in stock. I have listed five states of the navigation

  1. Standard Lesson not yet completed.
    1. with a regular Mark Complete button
    2. with a Take Quiz/Start Assignment button
  2. Completed Lesson.
    1. with a Mark Incomplete button
  3. Next Lesson is Restricted (via prerequisite/drip)
  4. First Lesson (No Previous Lesson, so replaced by Back to Course link)
  5. Last Lesson (No Next Lesson, so replaced by Back to Course link)

We’re considering all the variables in this part of the tutorial. In a subsequent part, we’ll look at special cases where some of these variations will either not exist (for eg, Mark Incomplete) or will be implemented differently.

It is also important to note that at this stage, the Take Quiz and the Start Assignment buttons can be considered as the same UI component as the Mark Complete button.

Also, this doesn’t claim to be exhaustive and cover every possibility, just most of them. Even the copy is something you can obviously modify. (If you do see something missing, let us know in the comments and we’ll try and update this series accordingly!)

Explicit Next Step Choice

An important principle of design is providing clear and explicit choice to a user when there are options for an action. This is why you see wordy CTA buttons. For more, see: https://www.smashingmagazine.com/2015/05/designing-for-explicit-choice/

So, we’re going to change the text of the buttons a bit for explicit choice and an interactive human voice.

State 1. Standard Lesson

In situation 1, for example, we could use:

  • Primary Action: Mark Complete & Go to Next Lesson
  • Secondary Action: Next Lesson without completing
State 2. Completed Lesson

Once the lesson is complete (situation 2), we could use:

  • Primary Action: Go to Next Lesson.
  • Secondary Action: Mark Incomplete.

At this point, it is useful to note that, the text Lesson Complete is displayed in place of the Mark Complete button irrespective of whether marking incomplete is enabled. When Mark Incomplete is enabled, there is a button as well as this text.

In another recipe, we’ve discussed ways to move this indicator and make it more obvious. This way, the Lesson Complete text becomes redundant. One less element to worry about in our navigation.

Now that that’s out of our way, let’s try rewording the options for a lesson with a Quiz:

  • Primary Action: Take Quiz to Complete Lesson.
  • Secondary Action: Next Lesson without completing.

For a lesson with an Assignment:

  • Primary Action: Start Assignment to Complete Lesson.
  • Secondary Action: Next Lesson without completing.
State 3. Restricted Next Lesson

When the next lesson is restricted because of a prerequisite:

  • Primary Action: Mark Complete & Go to Next Lesson.
  • Secondary Action (disabled): Next Lesson unavailable before completing {lesson link}.

The primary action may not lead the user to the Next Lesson if it’s prerequisite is a completely different lesson. So, we need to differentiate between scenarios where the current lesson is a prerequisite of the next lesson and where another lesson is a prerequisite instead.

In the former, the copy can stay as it is. In case of the latter, the primary action can’t say Go to Next Lesson, it’d have to just say Mark Complete.

When the next lesson is restricted because of a drip:

  • Primary Action: Mark Complete & Go to Next Lesson.
  • Secondary Action: Next Lesson unavailable before {date}.
State 4. First Lesson

On the Last Lesson:

  • Primary Action: Complete and go back to Course.
  • Secondary Action: none.

On the First Lesson, nothing changes with respect to the next step. Only the Previous Step is a little different.

State 5. Last Lesson

To summarise, here are all the variations we’ve discussed, placed together for clarity and context:

  • Default
    • Primary Action: Mark Complete & Go to Next Lesson
    • Secondary Action: Next Lesson without completing
  • Completed
    • Primary Action: Go to Next Lesson.
    • Secondary Action: Mark Incomplete.
  • With Quiz
    • Primary Action: Take Quiz to Complete Lesson.
    • Secondary Action: Next Lesson without completing.
  • With Assignment
    • Primary Action: Start Assignment to Complete Lesson.
    • Secondary Action: Next Lesson without completing.
  • Prerequisite
    • Primary Action: Mark Complete & Go to Next Lesson.
    • Secondary Action (disabled): Next Lesson unavailable before completing {lesson link}.
  • Drip
    • Primary Action: Mark Complete & Go to Next Lesson.
    • Secondary Action: Next Lesson unavailable before {date}.
  • Last Lesson
    • Primary Action: Mark Complete & Go Back to Course
    • Secondary Action: NA

Now, that we have almost all the pieces in place, we can start building this navigation.

Depending on what model you prefer, you could easily use a bit of CSS to achieve any of these with the same markup guidelines shared at the start.

If you’re a developer, this should be enough to get you started on the code modifications needed to implement these. If you are planning to do so or have already implemented this, share your results with us in the comments.

If you’re looking for copyable code that you’d like to repurpose, part 3 is underway.

LifterLMS Advanced Videos Version 1.0.0-beta.6

Updates
  • Wistia: Add option to enable/disable the video player’s “playbar” (progress bar, scrubbing, and timestamp review).
Bug Fixes
  • Fix issue causing the lesson progression button from being disabled for videos that don’t explicitly have video completion progression requirements enabled.
  • Wistia: Ensure that all oEmbed fetches always fetch the supported iframe embed type.
  • Wistia: Automatically remove videoFoam from embeds.
  • Wistia: Set default theme color option value to match the documented default theme color.

LifterLMS Version 3.36.5

  • Add filter: llms_user_caps_edit_others_posts_post_types to allow 3rd parties to utilize core methods for determining if a user can manage another users LMS content on the admin panel.