Skip Navigation

[Resolved] Best practice for setting up an LMS for blended learning

This support ticket is created 3 years, 5 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

No supporters are available to work today on Toolset forum. Feel free to create tickets and we will handle it as soon as we are online. Thank you for your understanding.

Sun Mon Tue Wed Thu Fri Sat
- 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 9:00 – 13:00 -
- 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 14:00 – 18:00 -

Supporter timezone: Asia/Karachi (GMT+05:00)


Tell us what you are trying to do? I am setting up an LMS site for a school with offline students who access lesson videos and resources online. More advanced LMS features are not needed - just a simple and robust way for students to log in, browse their courses, modules and watch lesson videos. A 'mark as complete' would be nice like on the training courses on the Toolset website, but not essential. Registering students and adding roles/post groups is done manually. I am trying to follow Toolset best practice but have run into a few challenges. So far, courses are a CPT with a relationship to a lesson CPT. Lessons are categorised by taxonomies for the course modules and year, and lesson access is controlled by Toolset post groups.

The main problem is that within each course there are different years, so different users need access to different content. Conceptually the best way would be to restrict content by taxonomy.. but I realise that isn't how Toolset likes to do it. Is there a better way?

A second problem comes with displaying Views lists of only the content the student has access to. So they go to their account and see a list of only the courses and modules they have access to. Should I abandon taxonomy and just stick with content types and relationships? How does the hidden field on post groups work? is it added to the users as well?

Content structure:

Course 01
---> 2020 + Module 01 > lessons
---> 2020 + Module 02 > lessons
---> 2020 + Module 03 > lessons

---> 2021 + Module 07 > lessons
---> 2021 + Module 08 > lessons
---> 2021 + Module 09 > lessons

Student A registers in 2020..Admin adds the 2020 role/tag and has access to all lessons from modules 1,2 and 3.
Student B registers the following year and has access to all the 2021 content.

Student A goes to his account and sees a list of modules 1, 2 and 3 - but not 7, 8,and 9.

What's the best way to organise this, also considering the site admins are not very technical? I want to keep as much as possible in front end CRED forms.

The second challenge is that I'd need a private area where admins can upload grades and invoice PDFs for each student (only visible to the admin and specific student. I'd thought about a CPT, but didn't want to create a new post group for each student. Could this be added to user fields and then placed on a page via shortcodes to guarantee that only the logged in user sees their information?

For now those are the most pressing issues. Thanks for any help!



Thank you for contacting us and I'd be happy to assist.

Your observation is correct and for the requirement of restricting content access based on year and course, the Toolset Access standard post groups would become too complex to manage.

A workaround can be to use the conditional display of content, instead of using the post group restrictions.

For blocks based content, you can use the "Conditional" block:

And for the legacy/classic content editor, you can use the conditional shortcode:

You can add a user custom field "Year", which will save the enrollment year with each user's profile at the time of registration.

And with each lesson/course item that needs restrictive access, you can attach a year taxonomy, to specify which year's enrolled students can access it.

After that, you can show the content of these restricted items conditionally only when the "current logged in user's enrollment year and the current post/item taxonomy year are the same".

For the second challenge too, the same condition display approach can be used. You can keep storing the grading information in the custom fields for each user and display them on the front-end, only for certain user roles, for example, the "administrator".

I hope this helps and please let me know if you need any further assistance around this.



Hi Waqar,

Thanks so much for your reply. Very useful in putting me on the right track. One quick question before I have a go at this:

- Can this user field be a checkbox, so that multiple values can be passed? Would it be possible to use 'contains' instead of '=' on the HTML conditional?

Thanks, Joe


Hi Joe,

Thanks for writing back and glad my message was useful.

It is possible to use the "checkboxes" type user field too, but for the conditional evaluation, you'll need some custom code, that can get the current user's years values from the user field ( ) and then can return 1 or 0, based on whether same years terms are attached to the current post/page.

For example, suppose you have a checkboxes type user field "user-checkboxes", with year options.
( screenshot: hidden link )

And you've also added a custom taxonomy "Years", with numerical year values as term names and slugs.

The custom shortcode in this case would look like this:

function get_user_years_func()
	$field_slug = "user-checkboxes";
	$taxonomy_slug = "year";
	$field_value = types_render_usermeta( $field_slug, array("user_current" => "true", "separator" => ",") );
	$taxonomy_value = do_shortcode('[wpv-post-taxonomy type="'.$taxonomy_slug.'" format="slug" separator=","]');

	$field_value_arr = explode(',', $field_value);
	$taxonomy_value_arr = explode(',', $taxonomy_value);

	$common_arr = array_intersect($field_value_arr, $taxonomy_value_arr);
	if (count($common_arr) > 0) {
		return '1';
	else {
		return '0';
add_shortcode('get_user_years', 'get_user_years_func');

This shortcode will return 1 if at least one common year exist in the current logged-in user's checkboxes field and the year taxonomy terms attached to the current page/post and 0, if not.

The above code snippet can be included through either Toolset's custom code feature ( ref: ) or through active theme's "functions.php" file.

Don't forget to add "get_user_years" in the "Third-party shortcode arguments" section, at WP Admin -> Toolset -> Settings -> Front-end Content.

After that you'll be able to use this shortcode's value in conditional block conditions by comparing to the static value of 1 for the "allowed" case and 0 for the "not allowed" case.
( screenshot: hidden link )

Note: The custom code examples from our forum are shared to get you started in the right direction. You're welcome to adjust them as needed and for more personalized customization assistance, you can consider hiring a professional from our list of recommended contractors:



Thanks Waqar,

I finally had a chance to get this working and it's a really great solution... In fact, it's essential to me using Toolset for this project. I was considering moving to a dedicated LMS plugin, but this is not necessary now.

A bonus is that site editors can manage it all from the front end just by adding and removing fields/taxonomy terms from users/courses, all on front end forms.

I can also use it with the content template to show/hide certain sections of the page so that guest users are shown a login/ buy course button while users who have been added to the course now see a 'start course now' button.

A limitation is that I have to add checkboxes to the user field manually for every new course I create, and I'm not sure how to do automatic purchases yet - but these things can be manual for now, and I'll open new tickets in the future if I decide to try to automate these.

Thanks again!

This ticket is now closed. If you're a Toolset client and need related help, please open a new support ticket.