get_curriculum( $course_id ); foreach ($course_materials['sections'] as $section) { $section['number'] = $section['id']; $sections[ $section['id'] ] = $section; } foreach ($course_materials['materials'] as $post) { $post_type = $post['post_type']; if($post_type == 'stm-lessons') { $lesson_ids[] = $post['post_id']; $section_items[ $post['section_id'] ][$post_type][] = $post['post_id']; } if($post_type == 'stm-quizzes') { $quiz_ids[] = $post['post_id']; $section_items[ $post['section_id'] ][$post_type][] = $post['post_id']; } $section_items[ $post['section_id'] ]['all_items'][$post['post_id']] = $post; } return [ "section_items" => $section_items, "lesson_ids" => $lesson_ids, "quiz_ids" => $quiz_ids, 'sections' => $sections ]; } function get_progress_report_data($r, $params) { global $wpdb; $course_id = intVal($params["course_id"]); $group_id = intVal($params["group_id"]); $course = get_post($course_id); if(empty($course) || empty($course->post_type) || $course->post_type != "stm-courses") return $r; $course_structure = self::course_structure($course_id); $lesson_ids = array_map("intval", $course_structure['lesson_ids']); $quiz_ids = array_map("intval", $course_structure['quiz_ids']); $section_items = $course_structure['section_items']; $sections = $course_structure['sections']; $lesson_completion_results_raw = array(); if (!empty( $lesson_ids ) ) { $lessson_ids_strings = implode( "','", $lesson_ids ); $sql = "SELECT user_id, lesson_id, end_time FROM {$wpdb->prefix}stm_lms_user_lessons WHERE lesson_id IN ('$lessson_ids_strings') AND course_id = %d"; $sql = $wpdb->prepare($sql, $course_id); $sql = grassblade_add_group_user_query($sql, $group_id); //echo $sql; $lesson_completion_results_raw = $wpdb->get_results($sql); } $quiz_completion_results_raw = array(); $quiz_ids_strings = implode( "','", $quiz_ids ); $sql = "SELECT * FROM {$wpdb->prefix}stm_lms_user_quizzes WHERE quiz_id IN ('$quiz_ids_strings') AND course_id = %d AND status = 'passed' "; $sql = $wpdb->prepare($sql, $course_id); $sql = grassblade_add_group_user_query($sql, $group_id); //echo $sql; $quiz_completion_results_raw = $wpdb->get_results($sql); $users = array(); if(!empty($lesson_completion_results_raw)) foreach ($lesson_completion_results_raw as $key => $value) { if(empty($lesson_completion_results[$value->user_id])) $lesson_completion_results[$value->user_id] = array(); if(empty($lesson_completion_results[$value->user_id][$value->lesson_id])) $lesson_completion_results[$value->user_id][$value->lesson_id] = array(); $lesson_completion_results[$value->user_id][$value->lesson_id] = $value; $users[$value->user_id] = 1; } unset($lesson_completion_results_raw); if(!empty($quiz_completion_results_raw)) foreach ($quiz_completion_results_raw as $key => $value) { if(empty($quiz_completion_results[$value->user_id])) $quiz_completion_results[$value->user_id] = array(); if(empty($quiz_completion_results[$value->user_id][$value->quiz_id])) $quiz_completion_results[$value->user_id][$value->quiz_id] = array(); $quiz_completion_results[$value->user_id][$value->quiz_id] = $value; $users[$value->user_id] = 1; } unset($quiz_completion_results_raw); $k = 0; $ret = array(); foreach ($users as $user_id => $v) { $user = get_user_by("id", $user_id); if(!empty($user->ID)) { $data = array( "sno" => $k, "name" => function_exists("gb_name_format")? gb_name_format($user) : $user->last_name.", ".$user->first_name, "user_id" => $user->ID, "user_email" => $user->user_email, ); foreach ($sections as $section_id => $section) { $user_quiz_completion_results = !empty($quiz_completion_results[$user->ID]) ? $quiz_completion_results[$user->ID] : array(); $user_lesson_completion_results = !empty($lesson_completion_results[$user->ID]) ? $lesson_completion_results[$user->ID] : array(); $data[$section['number']] = $this->section_completion_date($section_items[ $section["number"] ], $user_quiz_completion_results, $user_lesson_completion_results); } $ret[$k++] = $data; } } $module_order = $modules_list = array(); $k = 1; foreach ($sections as $section_id => $section) { $modules_list[$section['number']] = urldecode( $section['title'] ); $module_order[$k++] = $section['number']; } $return = array("data" => $ret, "lessons" => $modules_list, 'lesson_order' => $module_order); return $return; } function section_completion_date($section_items, $user_quiz_completion_results, $user_lesson_completion_results) { $total_steps = 0; $completed_steps = 0; $date = 0; if(!empty($section_items['stm-lessons'])) { foreach($section_items['stm-lessons'] as $lesson_id) { $total_steps++; if(!empty($user_lesson_completion_results[$lesson_id])) { $completed_steps++; $completion_date = $user_lesson_completion_results[$lesson_id]->end_time; if($completion_date >= $date) { $date = $completion_date; } } } } if( !empty($section_items['stm-quizzes']) ) { foreach( $section_items['stm-quizzes'] as $quiz_id ) { $user_id = !empty($user_quiz_completion_results[$quiz_id]->user_id) ? $user_quiz_completion_results[$quiz_id]->user_id : "" ; $course_id = !empty($user_quiz_completion_results[$quiz_id]->course_id) ? $user_quiz_completion_results[$quiz_id]->course_id : ""; $quiz_id = !empty($user_quiz_completion_results[$quiz_id]->quiz_id) ? $user_quiz_completion_results[$quiz_id]->quiz_id : ""; $total_steps++; if( !empty($user_quiz_completion_results[$quiz_id]) ) { $quiz_attempt = $user_quiz_completion_results[$quiz_id]; $completed_steps++; $completion_date = !empty($quiz_attempt->created_at) ? strtotime($quiz_attempt->created_at) : self::get_step_start_time($course_id, $user_id, $quiz_id); if( $completion_date >= $date ) { $date = $completion_date; } } } } if($completed_steps >= $total_steps) return empty($date)? "":wp_date("Y-m-d", $date); else return "$completed_steps/$total_steps"; } function get_progress_report_details($return, $gb_lesson_id, $course_id, $user) { if(!empty($return)) return $return; $course_structure = self::course_structure($course_id); if(empty($course_structure['section_items']) || empty($course_structure['section_items'][$gb_lesson_id]) || empty($course_structure['sections'][$gb_lesson_id])) return $return; $section = $course_structure['sections'][$gb_lesson_id]; $section_items = $course_structure['section_items'][$gb_lesson_id]; $total_steps = 0; $total_steps += !empty($section_items['stm-lessons'])? count($section_items['stm-lessons']) : 0; $total_steps += !empty($section_items['stm-quizzes'])? count($section_items['stm-quizzes']) : 0; $return['course_id'] = $course_id; $return['user_id'] = $user->ID; $return['user_email'] = $user->user_email; $return['user_name'] = gb_name_format($user); $return['section_id'] = $gb_lesson_id; $return['name'] = $section['title'] ?? ''; $return['sub_steps'] = []; $return['total_steps'] = $total_steps; $return['completed_steps'] = 0; $last_activity_time = ''; $completed_steps = 0; $is_section_started = false; $count = 1; foreach($section_items['all_items'] as $ID => $item) { if( $item['post_type'] == 'stm-lessons' ) { $lesson_progress = stm_lms_get_user_lesson($user->ID, $course_id, $ID, ['user_id', 'course_id', 'lesson_id', 'start_time', 'end_time']); $lesson_start_time = self::get_step_start_time($course_id, $user->ID, $ID); if(!empty($lesson_progress) && !empty($lesson_progress[0])) { $completed_steps++; $lesson_status_msg = __("Completed on") . ' ' . gb_datetime($lesson_progress[0][4]); $lesson_status = 'completed'; $is_section_started = !$is_section_started ? true : $is_section_started; $last_activity_time = $lesson_progress[0][4] > $last_activity_time ? $lesson_progress[0][4] : $last_activity_time; } else if( !empty($lesson_start_time) ) { $is_section_started = !$is_section_started ? true : $is_section_started; $lesson_status_msg = __('In Progress', 'grassblade'); $lesson_status = 'in_progress'; } else { $lesson_status_msg = __('Not Started', 'grassblade'); $lesson_status = 'not_started'; } $lesson_xapi_attempts = grassblade_reports_progress_snapshot::get_xapi_content_attempts($ID, $user->ID); $return['sub_steps'][$count] = [ 'count' => $count, 'id' => $ID, 'name' => $item['title'], 'status' => $lesson_status, 'status_msg' => $lesson_status_msg, 'type' => 'lesson', 'attempts' => $lesson_xapi_attempts['attempts'], 'percentage' => $lesson_xapi_attempts['percentage'], 'attempts_count' => $lesson_xapi_attempts['attempts_count'], 'has_xapi' => $lesson_xapi_attempts['has_xapi'], 'sub_steps' => [] ]; } if( $item['post_type'] == 'stm-quizzes' ) { $quiz_start_time = self::get_step_start_time($course_id, $user->ID, $ID); $quiz_attempts_raw = stm_lms_get_user_quizzes($user->ID, $ID); $hightest_percentage = 0; $quiz_attempts = []; $is_quiz_passed = false; foreach($quiz_attempts_raw as $key => $attempt) { $is_quiz_passed = $is_quiz_passed || $attempt['status'] == "passed"; $hightest_percentage = max($hightest_percentage, $attempt['progress']); $quiz_attempt_status_msg = $attempt['status'] == "passed" ? __('Passed', 'grassblade') : __('Failed', 'grassblade'); $quiz_attempts[] = [ 'id' => $key, 'percentage' => $attempt['progress'] . '%', 'status' => $attempt['status'], 'status_msg' => $quiz_attempt_status_msg, 'timespent' => '-', 'completed' => !empty($attempt['created_at']) ? gb_datetime($attempt['created_at']) : "-", ]; } if( $is_quiz_passed ) { $completed_steps++; $quiz_status_msg = __('Completed On ','grassblade') . gb_datetime($quiz_start_time); $quiz_status = 'completed'; $is_section_started = !$is_section_started ? true : $is_section_started; $last_activity_time = $quiz_start_time > $last_activity_time ? $quiz_start_time : $last_activity_time; } else if(!empty($quiz_attempts_raw)) { $is_section_started = !$is_section_started ? true : $is_section_started; $quiz_status_msg = __('In Progress', 'grassblade'); $quiz_status = 'in_progress'; } else { $quiz_status_msg = __('Not Started', 'grassblade'); $quiz_status = 'not_started'; } $xapi_content_ids = grassblade_xapi_content::get_post_xapi_contents($ID, true); $return['sub_steps'][$count] = [ 'count' => $count, 'id' => $ID, 'name' => $item['title'], 'status_msg' => $quiz_status_msg, 'status' => $quiz_status, 'type' => 'quiz', 'attempts' => $quiz_attempts, 'percentage' => $hightest_percentage . '%', 'attempts_count' => count($quiz_attempts), 'has_xapi' => intval(!empty($xapi_content_ids)), ]; } $count++; } $return['completed_steps'] = $completed_steps; if($completed_steps == $total_steps) { $section_status_msg = __("Completed On ", 'grassblade') . gb_datetime($last_activity_time); $section_status = 'completed'; } else if($is_section_started) { $section_status_msg = __('In Progress', 'grassblade'); $section_status = 'in_progress'; } else { $section_status_msg = __('Not Started', 'grassblade'); $section_status = 'not_started'; } $return['status_msg'] = $section_status_msg; $return['status'] = $section_status; return $return; } function get_step_start_time($course_id, $user_id, $step_id) { if(empty($course_id) || empty($user_id) || empty($step_id)) return 0; $start_time = get_user_meta($user_id, "stm_lms_course_started_{$step_id}_{$course_id}", true); if(!empty($start_time)) return $start_time; $old_time = get_user_meta($user_id, "stm_lms_course_started_{$course_id}_{$step_id}", true); if(!empty($old_time)) return $old_time; return 0; } } $grassblade_masterstudy_progress_snapshot_report = new grassblade_masterstudy_progress_snapshot_report();