/** * Checks if a user has completed a course by checking every lesson status * * @since 1.7.0 * @param integer $course_id Course ID * @param integer $user_id User ID * @return int */ public static function user_complete_course($course_id = 0, $user_id = 0) { global $wp_version; if ($course_id) { if (!$user_id) { $user_id = get_current_user_id(); } $course_status = 'in-progress'; $course_metadata = array(); $course_completion = Sensei()->settings->settings['course_completion']; $lessons_completed = $total_lessons = 0; $lesson_status_args = array('user_id' => $user_id, 'status' => 'any', 'type' => 'sensei_lesson_status'); // Grab all of this Courses' lessons, looping through each... $lesson_ids = Sensei()->course->course_lessons($course_id, 'any', 'ids'); $total_lessons = count($lesson_ids); // ...if course completion not set to 'passed', and all lessons are complete or graded, // ......then all lessons are 'passed' // ...else if course completion is set to 'passed', check if each lesson has questions... // ......if no questions yet the status is 'complete' // .........then the lesson is 'passed' // ......else if questions check the lesson status has a grade and that the grade is greater than the lesson passmark // .........then the lesson is 'passed' // ...if all lessons 'passed' then update the course status to complete // The below checks if a lesson is fully completed, though maybe should be Utils::user_completed_lesson() $all_lesson_statuses = array(); // In WordPress 4.1 get_comments() allows a single query to cover multiple comment_post_IDs if (version_compare($wp_version, '4.1', '>=')) { $lesson_status_args['post__in'] = $lesson_ids; $all_lesson_statuses = Sensei_Utils::sensei_check_for_activity($lesson_status_args, true); // Need to always return an array, even with only 1 item if (!is_array($all_lesson_statuses)) { $all_lesson_statuses = array($all_lesson_statuses); } } else { foreach ($lesson_ids as $lesson_id) { $lesson_status_args['post_id'] = $lesson_id; $each_lesson_status = Sensei_Utils::sensei_check_for_activity($lesson_status_args, true); // Check for valid return before using if (!empty($each_lesson_status->comment_approved)) { $all_lesson_statuses[] = $each_lesson_status; } } } foreach ($all_lesson_statuses as $lesson_status) { // If lessons are complete without needing quizzes to be passed if ('passed' != $course_completion) { switch ($lesson_status->comment_approved) { // A user cannot 'complete' a course if a lesson... case 'in-progress': // ...is still in progress // ...is still in progress case 'ungraded': // ...hasn't yet been graded break; default: $lessons_completed++; break; } } else { switch ($lesson_status->comment_approved) { case 'complete': // Lesson has no quiz/questions // Lesson has no quiz/questions case 'graded': // Lesson has quiz, but it's not important what the grade was // Lesson has quiz, but it's not important what the grade was case 'passed': // Lesson has quiz and the user passed $lessons_completed++; break; // A user cannot 'complete' a course if on a lesson... // A user cannot 'complete' a course if on a lesson... case 'failed': // ...a user failed the passmark on a quiz // ...a user failed the passmark on a quiz default: break; } } } // Each lesson if ($lessons_completed == $total_lessons) { $course_status = 'complete'; } // Update meta data on how many lessons have been completed $course_metadata['complete'] = $lessons_completed; // update the overall percentage of the course lessons complete (or graded) compared to 'in-progress' regardless of the above $course_metadata['percent'] = abs(round(doubleval($lessons_completed) * 100 / $total_lessons, 0)); $activity_logged = Sensei_Utils::update_course_status($user_id, $course_id, $course_status, $course_metadata); // Allow further actions if ('complete' == $course_status) { do_action('sensei_user_course_end', $user_id, $course_id); } return $activity_logged; } return false; }
/** * Reset user submitted questions * * This function resets the quiz data for a user that has been submitted fro grading already. It is different to * the save_user_answers as currently the saved and submitted answers are stored differently. * * @since 1.7.4 * @access public * * @return bool $reset_success * @param int $user_id * @param int $lesson_id */ public function reset_user_lesson_data($lesson_id, $user_id = 0) { //make sure the parameters are valid if (empty($lesson_id) || empty($user_id) || 'lesson' != get_post_type($lesson_id) || !get_userdata($user_id)) { return false; } //get the users lesson status to make $user_lesson_status = Sensei_Utils::user_lesson_status($lesson_id, $user_id); if (!isset($user_lesson_status->comment_ID)) { // this user is not taking this lesson so this process is not needed return false; } //get the lesson quiz and course $quiz_id = Sensei()->lesson->lesson_quizzes($lesson_id); $course_id = Sensei()->lesson->get_course_id($lesson_id); // reset the transients $answers_transient_key = 'sensei_answers_' . $user_id . '_' . $lesson_id; $grades_transient_key = 'quiz_grades_' . $user_id . '_' . $lesson_id; $answers_feedback_transient_key = 'sensei_answers_feedback_' . $user_id . '_' . $lesson_id; delete_transient($answers_transient_key); delete_transient($grades_transient_key); delete_transient($answers_feedback_transient_key); // reset the quiz answers and feedback notes $deleted_answers = Sensei_Utils::delete_user_data('quiz_answers', $lesson_id, $user_id); $deleted_grades = Sensei_Utils::delete_user_data('quiz_grades', $lesson_id, $user_id); $deleted_user_feedback = Sensei_Utils::delete_user_data('quiz_answers_feedback', $lesson_id, $user_id); // Delete quiz answers, this auto deletes the corresponding meta data, such as the question/answer grade Sensei_Utils::sensei_delete_quiz_answers($quiz_id, $user_id); Sensei_Utils::update_lesson_status($user_id, $lesson_id, 'in-progress', array('questions_asked' => '', 'grade' => '')); // Update course completion Sensei_Utils::update_course_status($user_id, $course_id); // Run any action on quiz/lesson reset (previously this didn't occur on resetting a quiz, see resetting a lesson in sensei_complete_lesson() do_action('sensei_user_lesson_reset', $user_id, $lesson_id); Sensei()->frontend->messages = '<div class="sensei-message note">' . __('Quiz Reset Successfully.', 'woothemes-sensei') . '</div>'; return $deleted_answers && $deleted_grades; }
public function sensei_complete_course() { global $post, $current_user, $wp_query; if (isset($_POST['course_complete']) && wp_verify_nonce($_POST['woothemes_sensei_complete_course_noonce'], 'woothemes_sensei_complete_course_noonce')) { $sanitized_submit = esc_html($_POST['course_complete']); $sanitized_course_id = absint(esc_html($_POST['course_complete_id'])); // Handle submit data switch ($sanitized_submit) { case __('Mark as Complete', 'woothemes-sensei'): // Add user to course $course_metadata = array('start' => current_time('mysql'), 'percent' => 0, 'complete' => 0); $activity_logged = Sensei_Utils::update_course_status($current_user->ID, $sanitized_course_id, 'in-progress', $course_metadata); if ($activity_logged) { // Get all course lessons $course_lesson_ids = Sensei()->course->course_lessons($sanitized_course_id, 'any', 'ids'); // Mark all quiz user meta lessons as complete foreach ($course_lesson_ids as $lesson_item_id) { // Mark lesson as complete $activity_logged = Sensei_Utils::sensei_start_lesson($lesson_item_id, $current_user->ID, $complete = true); } // End For Loop // Update with final stats $course_metadata = array('percent' => 100, 'complete' => count($course_lesson_ids)); $activity_logged = Sensei_Utils::update_course_status($current_user->ID, $sanitized_course_id, 'complete', $course_metadata); do_action('sensei_user_course_end', $current_user->ID, $sanitized_course_id); // Success message $this->messages = '<header class="archive-header"><div class="sensei-message tick">' . sprintf(__('%1$s marked as complete.', 'woothemes-sensei'), get_the_title($sanitized_course_id)) . '</div></header>'; } // End If Statement break; case __('Delete Course', 'woothemes-sensei'): Sensei_Utils::sensei_remove_user_from_course($sanitized_course_id, $current_user->ID); // Success message $this->messages = '<header class="archive-header"><div class="sensei-message tick">' . sprintf(__('%1$s deleted.', 'woothemes-sensei'), get_the_title($sanitized_course_id)) . '</div></header>'; break; default: // Nothing break; } // End Switch Statement } // End If Statement }
/** * Force the re-calculation of all Course statuses working from all Lesson statuses * * @global type $woothemes_sensei * @global type $wpdb * @param type $n * @param type $offset * @return boolean */ function status_changes_repair_course_statuses($n = 50, $offset = 0) { global $wpdb; $count_object = wp_count_posts('lesson'); $count_published = $count_object->publish; if (0 == $count_published) { return true; } // Calculate if this is the last page if (0 == $offset) { $current_page = 1; } else { $current_page = intval($offset / $n); } $total_pages = ceil($count_published / $n); $course_lesson_ids = $lesson_user_statuses = array(); // Get all Lesson => Course relationships $meta_list = $wpdb->get_results("SELECT {$wpdb->postmeta}.post_id, {$wpdb->postmeta}.meta_value FROM {$wpdb->postmeta} INNER JOIN {$wpdb->posts} ON ({$wpdb->posts}.ID = {$wpdb->postmeta}.post_id) WHERE {$wpdb->posts}.post_type = 'lesson' AND {$wpdb->postmeta}.meta_key = '_lesson_course' LIMIT {$n} OFFSET {$offset} ", ARRAY_A); if (!empty($meta_list)) { foreach ($meta_list as $metarow) { $lesson_id = $metarow['post_id']; $course_id = $metarow['meta_value']; $course_lesson_ids[$course_id][] = $lesson_id; } } // Get all Lesson => Course relationships $status_list = $wpdb->get_results("SELECT user_id, comment_post_ID, comment_approved FROM {$wpdb->comments} WHERE comment_type = 'sensei_lesson_status' GROUP BY user_id, comment_post_ID ", ARRAY_A); if (!empty($status_list)) { foreach ($status_list as $status) { $lesson_user_statuses[$status['comment_post_ID']][$status['user_id']] = $status['comment_approved']; } } $course_completion = Sensei()->settings->settings['course_completion']; $per_page = 40; $comment_id_offset = $count = 0; $course_sql = "SELECT * FROM {$wpdb->comments} WHERE comment_type = 'sensei_course_status' AND comment_ID > %d LIMIT {$per_page}"; // $per_page users at a time while ($course_statuses = $wpdb->get_results($wpdb->prepare($course_sql, $comment_id_offset))) { foreach ($course_statuses as $course_status) { $user_id = $course_status->user_id; $course_id = $course_status->comment_post_ID; $total_lessons = count($course_lesson_ids[$course_id]); if ($total_lessons <= 0) { $total_lessons = 1; // Fix division of zero error, some courses have no lessons } $lessons_completed = 0; $status = 'in-progress'; // Some Courses have no lessons... (can they ever be complete?) if (!empty($course_lesson_ids[$course_id])) { foreach ($course_lesson_ids[$course_id] as $lesson_id) { $lesson_status = $lesson_user_statuses[$lesson_id][$user_id]; // If lessons are complete without needing quizzes to be passed if ('passed' != $course_completion) { switch ($lesson_status) { // A user cannot 'complete' a course if a lesson... case 'in-progress': // ...is still in progress // ...is still in progress case 'ungraded': // ...hasn't yet been graded break; default: $lessons_completed++; break; } } else { switch ($lesson_status) { case 'complete': // Lesson has no quiz/questions // Lesson has no quiz/questions case 'graded': // Lesson has quiz, but it's not important what the grade was // Lesson has quiz, but it's not important what the grade was case 'passed': // Lesson has quiz and the user passed $lessons_completed++; break; // A user cannot 'complete' a course if on a lesson... // A user cannot 'complete' a course if on a lesson... case 'failed': // ...a user failed the passmark on a quiz // ...a user failed the passmark on a quiz default: break; } } } // Each lesson } // Check for lessons if ($lessons_completed == $total_lessons) { $status = 'complete'; } // update the overall percentage of the course lessons complete (or graded) compared to 'in-progress' regardless of the above $metadata = array('complete' => $lessons_completed, 'percent' => abs(round(doubleval($lessons_completed) * 100 / $total_lessons, 0))); Sensei_Utils::update_course_status($user_id, $course_id, $status, $metadata); $count++; } // per course status $comment_id_offset = $course_status->comment_ID; } // all course statuses if ($current_page == $total_pages) { return true; } else { return false; } }