• Skip to main content
  • Skip to primary sidebar
  • Skip to footer

nSiteful Web Builders

Building a Better Web - One Site at a Time.

  • Home
  • About
    • Testimonials
    • Resources
  • Web Sites
  • Online Marketing
  • WordPress Support
    • Customized WordPress Training
    • 60-for-60 Sessions
  • Web Applications
  • Blog
    • Archive Listing Minimalistic
    • Blog Articles Grouped by Category
    • Case Studies
    • General
    • Portfolio
    • Reviews
    • Snippets
    • Techniques
  • Contact Jeff
    • Purchase Retainer Consulting Hours
    • About Retainer Consulting Hours

By Jeff Cohan, August 30, 2023

How to Create a Custom MemberPress Course Progress Page

On This Page...

  • Overview
    • Screen Shots of the Final Product
      • Course Progress Grouped by User:
      • Course Progress Grouped by Course:
    • Components of the Solution:
      • 1. Custom Function
      • 2. Protected Page
      • 3. Protected Nav Menu Items
  • The Code:
  • In Closing

Last updated September 22nd, 2023 at 01:00 pm

This post is inspired by a question that was posed in Facebook MemberPress Unofficial User Group:

Is there a way to see all of the users’ course progress in one place? I know I can access each user and see their progress that way. I was just hoping that there might be an easier way to see all of the members at once. Does anyone have any ideas on how to do this? Thanks in advance!

This is exactly what I implemented — a custom memberpress course progress page — in one of my WordPress/MemberPress websites that has three courses using the MemberPress Courses addon. In my case, I wanted to offer two views of course progress: one grouped by User; the other grouped by Course.

Overview

Screen Shots of the Final Product

Here are two screen shots displaying small sections of the course progress reports. The names and usernames of actual members are blurred out.

Course Progress Grouped by User:

Custom MemberPress Course Progress Page
Course Progress Grouped by User

Course Progress Grouped by Course:

Custom MemberPress Course Progress Page
Course Progress Grouped by Course

Components of the Solution:

1. Custom Function

A custom function in the /wp-content/mu-plugins/ folder which generates the code using a WordPress shortcode: [course_progress]. The shortcode accepts one parameter: group_by,  with the possible values of user and course. The full script is provided below.

2. Protected Page

I created a protected page which only site Admins can access, using a rule based on role.

Aside from the page title and a short, 2-line intro paragraph, the page consists of a single containing block — the Kadence Tabs block, with two tabs: one for Course Progress Grouped by User; the other for Course Progress Grouped by Course. I inserted the shortcode [course_progress group_by="user"] in the first tab and [course_progress group_by="course"] in the second tab.

3. Protected Nav Menu Items

We already had a top-level navigation menu item called “Resources”, so I added a link to the protected page there. Using the Nav Menu Roles WordPress plugin, I hid this nav menu item from anyone who is not a logged-in Admin. (I also assigned the class name of “admin-only” to this nav menu link and used CSS to render it with red text over a yellow background to highlight it and remind Admins that no one else can see it.)

The Code:

Here is the complete script. I disabled wrapping of lines because I find that hurts more than it helps. If you want to inspect the code more closely, it’s probably best to click on the “view source” button, and then copy/paste it into your script editor. Comments within the script may be enough to explain what’s going on here. If you have questions or comments, please write them in the comments section below. (Big hat tip to MemberPress support staff who have shared code snippets with me over the years, especially TylerG.)


function shortcode_nwb_course_progress($atts) {
	$atts = shortcode_atts( array(
		'group_by' => 'user',
	), $atts, 'course_progress' );	
	$group_by = $atts['group_by'];
	
	$users = get_users(	
		array( 
			'role__in' => array( 'customer_free', 'customer_premium'), 
			'orderby' => 'name',
			'order' => 'ASC',
		) 
	);

	// Grab all courses and see if the sub account has access.
	$course_posts = get_posts(array(
		'post_type' => 'mpcs-course', 
		'post_status' => 'publish', 
		'numberposts' => -1, 
		'orderby' => 'title', 
		'order' => 'ASC'),
	);

	$output = ''; 	/* Init $output */
	switch ( $group_by ) {
		case 'user':

			if(!empty($users)) {

				/* Start a div */
				$output .= '<div class="course-progress-wrap">';
				$output .= '<h2>Course Progress Grouped by User</h2>';
				$output .= '<table class="course-progress__table" style="width:auto;">';
				foreach($users as $user) {
					$courses = array(); // I moved down
					$user_id = $user->ID;
					$mepr_user = new MeprUser($user_id);
					
					$registration_timestamp = strtotime($user->user_registered); // 2023-03-22 14:02:55
					$registration_date = date('m-d-Y', $registration_timestamp);
					$elapsed_days = round((time() - $registration_timestamp) / (24*60*60));
					

					/* Now get memberships */
					$this_user = MeprUtils::get_user_by('id', $user_id);
					$his_products = array(); // Init
					$his_product_ids = array(); // Init
					
					$active_products = $mepr_user->active_product_subscriptions('products');
					
					
					if(!empty($active_products)) {
						foreach($active_products as $membership_id) {
							$his_products[] = $membership_id->post_title;
							$his_product_ids[] = $membership_id->ID; // for class name
						}
						$his_products_cos = implode(', ' , $his_products);
					}					
					/* Product Class 2023-03-22 14:35:00 */
					$product_class = ( in_array(203, $his_product_ids) ) ? 'master' : 'intro';
					
					
					// Now loop through courses.
					if(!empty($course_posts)) {
						$output .= '<tr>';
						/* Add user_login 2022-11-02 17:32:01 */
						$output .= '<td colspan="2" class="' . $product_class . '"><h3>' . $user->display_name . ' <span class="user_login">(' . $user->user_login . ')</span> - <span class="program_name ' . $product_class . '">' . $his_products_cos . '</span></h3>';
						/* 2023-03-22 14:15:30, Add reg info */
						$output .= 'Registered: <span class="registration_date">' . $registration_date . '</span>';
						$output .= '&nbsp;(<span class="elapsed-days">' . $elapsed_days . ' days ago</span>)';
						$output .= '</td>';
						foreach($course_posts as $course_post) {
							if(!MeprRule::is_locked_for_user($mepr_user, $course_post)) {
								$courses[] = $course_post;
							}
						}
						foreach($courses as $course) {
							$course = new memberpress\courses\models\Course($course->ID);
							$progress = $course->user_progress($user_id);
							$prog_pct = $progress / 100;
							$output .= '<tr>';
							$output .= '<td class="col-1">' . $course->post_title .'</td>';
							$output .= '<td><span class="course-progress">' . 
								'<span class="user-progress" data-value="'. $progress . '" style="width: ' . $progress . '%;">' .
									$progress . 
								'</span>
							</span>
							<span>%</span></td>';
						}
						$output .= '</tr>';
					}
				}
			}
			$output .= '</table>';
			$output .= '</div>';
		
		break;
		
		case 'course':
			if ( !empty($course_posts) ) {
				$output .= '<div class="course-progress-wrap">';
				$output .= '<h2>Course Progress Grouped by Course</h2>';
				$output .= '<table class="course-progress__table" style="width:auto;">';
				
				foreach($course_posts as $course_post) {
					$courses = array();
					$courses[] = $course_post;
					foreach ( $courses as $course ) {
						$course = new memberpress\courses\models\Course($course->ID);
						$output .= '<tr>';
						
						$output .= '<td colspan="2"><h3>' . $course->post_title . '</h3></td>';
						$output .= '</tr>';
						
						foreach($users as $user) {
							$user_id = $user->ID;
							$mepr_user = new MeprUser($user_id);
							$output .= '<tr>';
							$progress = $course->user_progress($user_id);
							/* Add user_login 2022-11-02 17:33:58 */
							$output .= '<td class="col-1">' . $user->display_name . ' (' . $user->user_login . ')</td>';
							$output .= '<td><span class="course-progress">' . 
								'<span class="user-progress" data-value="'. $progress . '" style="width: ' . $progress . '%;">' .
									$progress . 
								'</span>
							</span>
							<span>%</span>
							</td>';
							$output .= '</tr>';
						}
					}
				}
				$output .= '</table>';
				$output .= '</div><!-- end wrap -->';
			}
		break;
	}
	return $output;
}
add_shortcode('course_progress', 'shortcode_nwb_course_progress');


In Closing

I hope that the solution I’ve offered here might be of help to some of you. If so, let me know in the comments.

If you build membership websites with MemberPress, you might want to see other MemberPress-related posts I’ve written.

Related Posts

  1. How to Override MemberPress Template Files
  2. Create a Custom Shortcode to Display a MemberPress Membership Price ANYWHERE on Your Website
  3. Use Custom Lesson Icons for MemberPress Courses
  4. Customize User Roles & Capabilities in WordPress: How (and Why)
  5. How to Create a Simple Custom Events Plugin

Written by Jeff Cohan · Categorized: Snippets · Tagged: MemberPress, MemberPress Courses, Membership Sites, WordPress

Reader Interactions

Leave a Reply Cancel reply

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

Primary Sidebar

mailchimp signup

Subscribe to get notified when new articles are published. Unsubscribe any time. No spam. I promise. Check out my newsletter archives.

social

Twitter Facebook LinkedIn

Recent Articles

  • Southeastern Bluegrass Association Membership Site September 8, 2023
  • How to Create a Custom MemberPress Course Progress Page August 30, 2023
  • 10 Tips for Using Basecamp Like a Pro August 17, 2023
  • How (and Why) to Partially Protect Content on your Membership Site July 24, 2023
  • Customize User Roles & Capabilities in WordPress: How (and Why) July 18, 2023

Filter By Category/Tag

Categories

  • Case Studies (7)
  • General (61)
  • Portfolio (6)
  • Reviews (12)
  • Snippets (17)
  • Techniques (41)

Popular Tags

Advanced Custom Fields Blogging Child Themes Content Marketing CSS Customer Service Custom Fields Custom Post Types Diagnostics Facebook FooGallery Genesis HTML Images iPhone Libra Live Chat Marketing Media MemberPress MemberPress Courses Membership Sites MySQL Photo Gallery php Pinterest Plugins Post Formats Pricing Project Management SEBA SEO Seth Godin Shortcodes Social Networking SurveyMonkey Surveys Taxonomies Twitter Video Web design Web forms WooCommerce WordPress YouTube

Footer

Background

Web Sites | WordPress Support | Web Applications.

Formally trained in liberal arts and education (I have a B.A. in Government from Harvard and studied Secondary Education at Rutgers Graduate School), I have honed my skills in the communication arts and sciences as a teacher, trainer, instructional designer, writer, photographer, calligrapher, helpdesk manager, database programmer, and multimedia developer.

(I've also been a group counselor, waiter, bartender, bicycle messenger boy, computer salesman, carpenter's helper, financial analyst, and school board president.)

Tech

Systems since 1983.
Web sites since 1994.
PHP since 2001.
WordPress since 2007.

Contact

770-772-5134
Email Jeff
Send Money
All Ways

Copyright 2023, nSiteful Web Builders, Inc.

 

Subscribe

Pardon the interruption. I know popups can be annoying. But I’d love to have you as a subscriber.

Sign up to be notified when new articles are published. Unsubscribe any time.

* indicates required

Powered by MailChimp

×