/** * Update question answers to use new data structure * * @since 1.3.0 * @access public * @return void */ public function update_question_answer_data($n = 50, $offset = 0) { // Get Total Number of Updates to run $quiz_count_object = wp_count_posts('quiz'); $quiz_count_published = $quiz_count_object->publish; // Calculate if this is the last page if (0 == $offset) { $current_page = 1; } else { $current_page = intval($offset / $n); } // End If Statement $total_pages = intval($quiz_count_published / $n); $args = array('post_type' => 'quiz', 'numberposts' => $n, 'offset' => $offset, 'post_status' => 'publish', 'suppress_filters' => 0); $quizzes = get_posts($args); $old_answers = array(); $right_answers = array(); $old_user_answers = array(); if (is_array($quizzes)) { foreach ($quizzes as $quiz) { $quiz_id = $quiz->ID; // Get current user answers $comments = WooThemes_Sensei_Utils::sensei_check_for_activity(array('post_id' => $quiz_id, 'type' => 'sensei_quiz_answers'), true); // Need to always return an array, even with only 1 item if (!is_array($comments)) { $comments = array($comments); } foreach ($comments as $comment) { $user_id = $comment->user_id; $content = maybe_unserialize(base64_decode($comment->comment_content)); $old_user_answers[$quiz_id][$user_id] = $content; } // Get correct answers $questions = WooThemes_Sensei_Utils::sensei_get_quiz_questions($quiz_id); if (is_array($questions)) { foreach ($questions as $question) { $right_answer = get_post_meta($question->ID, '_question_right_answer', true); $right_answers[$quiz_id][$question->ID] = $right_answer; } } } } if (is_array($right_answers)) { foreach ($right_answers as $quiz_id => $question) { $count = 0; if (is_array($question)) { foreach ($question as $question_id => $answer) { ++$count; if (isset($old_user_answers[$quiz_id])) { $answers_linkup[$quiz_id][$count] = $question_id; } } } } } if (is_array($old_user_answers)) { foreach ($old_user_answers as $quiz_id => $user_answers) { foreach ($user_answers as $user_id => $answers) { foreach ($answers as $answer_id => $user_answer) { $question_id = $answers_linkup[$quiz_id][$answer_id]; $new_user_answers[$question_id] = $user_answer; WooThemes_Sensei_Utils::sensei_grade_question_auto($question_id, '', $user_answer, $user_id); } $lesson_id = get_post_meta($quiz_id, '_quiz_lesson', true); WooThemes_Sensei_Utils::sensei_start_lesson($lesson_id, $user_id); WooThemes_Sensei_Utils::sensei_save_quiz_answers($new_user_answers, $user_id); } } } if ($current_page == $total_pages) { return true; } else { return false; } // End If Statement }
public function add_new_learners() { $result = false; if (!isset($_POST['add_learner_submit'])) { return $result; } if (!isset($_POST['add_learner_nonce']) || !wp_verify_nonce($_POST['add_learner_nonce'], 'add_learner_to_sensei')) { return $result; } if (!isset($_POST['add_user_id']) || '' == $_POST['add_user_id'] || !isset($_POST['add_post_type']) || !isset($_POST['add_course_id']) || !isset($_POST['add_lesson_id'])) { return $result; } $post_type = $_POST['add_post_type']; $user_id = absint($_POST['add_user_id']); $course_id = absint($_POST['add_course_id']); switch ($post_type) { case 'course': $result = WooThemes_Sensei_Utils::user_start_course($user_id, $course_id); // Complete each lesson if course is set to be completed if (isset($_POST['add_complete_course']) && 'yes' == $_POST['add_complete_course']) { $lesson_ids = Sensei()->course->course_lessons($course_id, 'any', 'ids'); foreach ($lesson_ids as $id) { WooThemes_Sensei_Utils::sensei_start_lesson($id, $user_id, true); } // Updates the Course status and it's meta data WooThemes_Sensei_Utils::user_complete_course($course_id, $user_id); do_action('sensei_user_course_end', $user_id, $course_id); } break; case 'lesson': $lesson_id = absint($_POST['add_lesson_id']); $complete = false; if (isset($_POST['add_complete_lesson']) && 'yes' == $_POST['add_complete_lesson']) { $complete = true; } $result = WooThemes_Sensei_Utils::sensei_start_lesson($lesson_id, $user_id, $complete); // Updates the Course status and it's meta data WooThemes_Sensei_Utils::user_complete_course($course_id, $user_id); break; } // Set redirect URL after adding user to course/lesson $query_args = array('page' => $this->page_slug, 'view' => 'learners'); if ($result) { if ($course_id) { $query_args['course_id'] = $course_id; } if ($lesson_id) { $query_args['lesson_id'] = $lesson_id; } $query_args['message'] = 'success'; } else { $query_args['message'] = 'error'; } $redirect_url = apply_filters('sensei_learners_add_learner_redirect_url', add_query_arg($query_args, admin_url('admin.php'))); wp_safe_redirect(esc_url_raw($redirect_url)); exit; }
public function sensei_complete_course() { global $post, $woothemes_sensei, $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 apply_filters('sensei_mark_as_complete_text', __('Mark as Complete', 'woothemes-sensei')): // Add user to course $course_metadata = array('start' => current_time('mysql'), 'percent' => 0, 'complete' => 0); $activity_logged = WooThemes_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 = $woothemes_sensei->post_types->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 = WooThemes_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 = WooThemes_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 apply_filters('sensei_delete_course_text', __('Delete Course', 'woothemes-sensei')): WooThemes_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 }
public function sensei_complete_quiz() { global $post, $woothemes_sensei, $current_user; // Default grade $grade = 0; // Get Quiz Questions $lesson_quiz_questions = $woothemes_sensei->post_types->lesson->lesson_quiz_questions($post->ID); $quiz_lesson_id = absint(get_post_meta($post->ID, '_quiz_lesson', true)); // Get quiz grade type $quiz_grade_type = get_post_meta($post->ID, '_quiz_grade_type', true); // Get quiz pass setting $pass_required = get_post_meta($post->ID, '_pass_required', true); // Get quiz pass mark $quiz_passmark = abs(round(doubleval(get_post_meta($post->ID, '_quiz_passmark', true)), 2)); // Handle Quiz Completion if (isset($_POST['quiz_complete']) && wp_verify_nonce($_POST['woothemes_sensei_complete_quiz_noonce'], 'woothemes_sensei_complete_quiz_noonce')) { $sanitized_submit = esc_html($_POST['quiz_complete']); $questions_asked = array_filter(array_map('absint', $_POST['questions_asked'])); $questions_asked_string = implode(',', $questions_asked); switch ($sanitized_submit) { case apply_filters('sensei_complete_quiz_text', __('Complete Quiz', 'woothemes-sensei')): // Mark the Lesson as in-progress (if it isn't already), the entry is needed for WooThemes_Sensei_Utils::sensei_grade_quiz_auto() (optimise at some point?) $activity_logged = WooThemes_Sensei_Utils::sensei_start_lesson($quiz_lesson_id); $lesson_status = 'ungraded'; // Default when completing a quiz // Save questions that were asked in this quiz if (!empty($questions_asked_string)) { update_comment_meta($activity_logged, 'questions_asked', $questions_asked_string); } // Save Quiz Answers if (isset($_POST['sensei_question'])) { WooThemes_Sensei_Utils::sensei_save_quiz_answers($_POST['sensei_question']); } // Grade quiz // 3rd arg is count of total number of questions but it's not used by sensei_grade_quiz_auto() $grade = WooThemes_Sensei_Utils::sensei_grade_quiz_auto($post->ID, $_POST['sensei_question'], count($lesson_quiz_questions), $quiz_grade_type); $lesson_metadata = array(); // Get Lesson Grading Setting if (is_wp_error($grade) || 'auto' != $quiz_grade_type) { $lesson_status = 'ungraded'; // Quiz is manually graded and this was a user submission } else { // Quiz has been automatically Graded if ($pass_required) { // Student has reached the pass mark and lesson is complete if ($quiz_passmark <= $grade) { $lesson_status = 'passed'; } else { $lesson_status = 'failed'; } // End If Statement } else { $lesson_status = 'graded'; } $lesson_metadata['grade'] = $grade; // Technically already set as part of "WooThemes_Sensei_Utils::sensei_grade_quiz_auto()" above } WooThemes_Sensei_Utils::update_lesson_status($current_user->ID, $quiz_lesson_id, $lesson_status, $lesson_metadata); switch ($lesson_status) { case 'passed': case 'graded': do_action('sensei_user_lesson_end', $current_user->ID, $quiz_lesson_id); break; } do_action('sensei_user_quiz_submitted', $current_user->ID, $post->ID, $grade, $quiz_passmark, $quiz_grade_type); break; case apply_filters('sensei_save_quiz_text', __('Save Quiz', 'woothemes-sensei')): $activity_logged = WooThemes_Sensei_Utils::sensei_start_lesson($quiz_lesson_id); if ($activity_logged) { // Save questions that were asked in this quiz if (!empty($questions_asked_string)) { update_comment_meta($activity_logged, 'questions_asked', $questions_asked_string); } if (isset($_POST['sensei_question'])) { WooThemes_Sensei_Utils::sensei_save_quiz_answers($_POST['sensei_question']); } } // Need message in case the data wasn't saved? $this->messages = '<div class="sensei-message note">' . apply_filters('sensei_quiz_saved_text', __('Quiz Saved Successfully.', 'woothemes-sensei')) . '</div>'; break; case apply_filters('sensei_reset_quiz_text', __('Reset Quiz', 'woothemes-sensei')): // Don't want to remove the lesson status (such as start meta data etc), just remove the answers, the questions asked meta and any grade meta // Delete quiz answers, this auto deletes the corresponding meta data, such as the question/answer grade WooThemes_Sensei_Utils::sensei_delete_quiz_answers($post->ID, $user_id); WooThemes_Sensei_Utils::update_lesson_status($current_user->ID, $quiz_lesson_id, 'in-progress', array('questions_asked' => '', 'grade' => '')); // 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', $current_user->ID, $quiz_lesson_id); $this->messages = '<div class="sensei-message note">' . apply_filters('sensei_quiz_reset_text', __('Quiz Reset Successfully.', 'woothemes-sensei')) . '</div>'; break; default: // Nothing break; } // End Switch Statement // Refresh page to avoid re-posting ?> <script type="text/javascript"> window.location = '<?php echo get_permalink($post->ID); ?> '; </script> <?php } // End If Statement, submission of quiz $this->data = new stdClass(); // Get latest quiz answers and grades $user_quizzes = $this->sensei_get_user_quiz_answers($post->ID); $user_lesson_status = WooThemes_Sensei_Utils::user_lesson_status($quiz_lesson_id, $current_user->ID); $user_quiz_grade = 0; if (isset($user_lesson_status->comment_ID)) { $user_quiz_grade = get_comment_meta($user_lesson_status->comment_ID, 'grade', true); } if (!is_array($user_quizzes)) { $user_quizzes = array(); } // Check again that the lesson is complete $user_lesson_end = WooThemes_Sensei_Utils::user_completed_lesson($user_lesson_status); $user_lesson_complete = false; if ($user_lesson_end) { $user_lesson_complete = true; } // End If Statement $reset_allowed = get_post_meta($post->ID, '_enable_quiz_reset', true); // Build frontend data object $this->data->user_quizzes = $user_quizzes; $this->data->user_quiz_grade = $user_quiz_grade; $this->data->quiz_passmark = $quiz_passmark; $this->data->quiz_lesson = $quiz_lesson_id; $this->data->quiz_grade_type = $quiz_grade_type; $this->data->user_lesson_end = $user_lesson_end; $this->data->user_lesson_complete = $user_lesson_complete; $this->data->lesson_quiz_questions = $lesson_quiz_questions; $this->data->reset_quiz_allowed = $reset_allowed; }
/** * This test Woothemes_Sensei()->quiz->get_user_answers_feedback transients only * * @group transient */ function testGetUserFeedbackTransients() { // setup the test data global $woothemes_sensei; $test_user_id = wp_create_user('studFBTransientsGet', 'studFBTransientsGet', '*****@*****.**'); $test_lesson_id = $this->factory->get_random_lesson_id(); $transient_key = 'sensei_answers_feedback_' . $test_user_id . '_' . $test_lesson_id; $transient_get_test = array(base64_encode('studFBTransientsGet')); $transient_get_test_decoded = array('studFBTransientsGet'); set_transient($transient_key, $transient_get_test, 10 * DAY_IN_SECONDS); $users_retrieved_answers = $woothemes_sensei->quiz->get_user_answers_feedback($test_lesson_id, $test_user_id); // test if the answer is taken from the transient $this->assertEquals($transient_get_test_decoded, $users_retrieved_answers, 'The transient was not used before proceeding to get the users answers from DB'); //setup next assertion $test_quiz_id = $woothemes_sensei->lesson->lesson_quizzes($test_lesson_id); $test_user_answers_feedback = $this->factory->generate_user_answers_feedback($test_quiz_id); WooThemes_Sensei_Utils::sensei_start_lesson($test_lesson_id, $test_user_id); $woothemes_sensei->quiz->save_user_answers_feedback($test_user_answers_feedback, $test_lesson_id, $test_user_id); delete_site_transient($transient_key); $woothemes_sensei->quiz->get_user_answers_feedback($test_lesson_id, $test_user_id); $transient_data_after_get_call = get_transient($transient_key); // test if a transient is created when one does not exist // in this test we first delete the transient after it is been added in the save_user_answers // function above, then we get the data again and test if the function added the transient $this->assertNotFalse($transient_data_after_get_call, ' The get_user_answers function does not set the transient after retrieving the data '); // make sure the one of the keys passed in is in the transient $random_key = array_rand($test_user_answers_feedback); $this->assertArrayHasKey($random_key, $transient_data_after_get_call, 'The transient does not contain the same elements that we passed in'); //make sure the number of elements passes in is the same as what is in the new transient cache $this->assertEquals(count($test_user_answers_feedback), count($transient_data_after_get_call), 'The number of elements in the transient does not match those the user submitted'); }
/** * Save the user's answers feedback * * For this function you must supply all three parameters. If will return false one is left out. * The data will be saved on the lesson ID supplied. * * @since 1.7.5 * @access public * * @param array $answers_feedback{ * $type int $question_id * $type string $question_feedback * } * @param int $lesson_id * @param int $user_id * * @return false or int $feedback_saved */ public function save_user_answers_feedback($answers_feedback, $lesson_id, $user_id = 0) { // make sure the parameters are valid before continuing if (empty($lesson_id) || empty($user_id) || 'lesson' != get_post_type($lesson_id) || !get_userdata($user_id) || !is_array($answers_feedback)) { return false; } global $woothemes_sensei; // check if the lesson is started before saving, if not start the lesson for the user if (!(0 < intval(WooThemes_Sensei_Utils::user_started_lesson($lesson_id, $user_id)))) { WooThemes_Sensei_Utils::sensei_start_lesson($lesson_id, $user_id); } // encode the feedback $encoded_answers_feedback = array(); foreach ($answers_feedback as $question_id => $feedback) { $encoded_answers_feedback[$question_id] = base64_encode($feedback); } // save the user data $feedback_saved = WooThemes_Sensei_Utils::add_user_data('quiz_answers_feedback', $lesson_id, $encoded_answers_feedback, $user_id); //Were the the question feedback save correctly? if (intval($feedback_saved) > 0) { // save transient to make retrieval faster in future $transient_key = 'sensei_answers_feedback_' . $user_id . '_' . $lesson_id; set_transient($transient_key, $encoded_answers_feedback, 10 * DAY_IN_SECONDS); } return $feedback_saved; }