/** * Renders WP-Coursware unit detail over [op-courseware] shortcode * @return string */ public static function renderCoursewareUnitDetails() { global $post; if (class_exists('WPCW_UnitFrontend')) { $fe = new WPCW_UnitFrontend($post); return $fe->render_detailsForUnit(""); } }
/** * Handle showing the box that allows a user to mark a unit as completed. */ function WPCW_units_processUnitContent($content) { // #### Ensure we're only showing a course unit, a single item if (!is_single() || 'course_unit' != get_post_type()) { return $content; } // Use object to handle the rendering of the unit on the frontend. include_once WPCW_plugin_getPluginDirPath() . 'classes/class_frontend_unit.inc.php'; global $post; $fe = new WPCW_UnitFrontend($post); // #### Get associated data for this unit. No course/module data, then it's not a unit if (!$fe->check_unit_doesUnitHaveParentData()) { return $content; } // #### Ensure we're logged in if (!$fe->check_user_isUserLoggedIn()) { return $fe->message_user_notLoggedIn(); } // #### User not allowed access to content, so certainly can't say they've done this unit. if (!$fe->check_user_canUserAccessCourse()) { return $fe->message_user_cannotAccessCourse(); } // #### Is user allowed to access this unit yet? if (!$fe->check_user_canUserAccessUnit()) { return $fe->message_user_cannotAccessUnit(); } // ### Do the remaining rendering... return $fe->render_detailsForUnit($content); }
/** * Checks the supplied answers to see which questions are correct. * * @return Boolean Returns true if the trainee can continue (either passed in blocking, or survey/non-blocking), false otherwise. */ function check_quizzes_gradeQuestionsForQuiz() { // Use the quiz answers that need grading, stored in the local variable. $resultsList = $this->unchecked_QuizAnswersToGrade; $resultDetails = array('correct' => array(), 'wrong' => array()); // Flag to indicate if grading is needed before the user continues. $gradingNeeded = false; $gradingNeededBeforeContinue = false; // If true, then we notify the user of the grade. $quizGradeNotificationNeeded = false; // ### 3 - Do we need to check for correct answers? if ('survey' == $this->unitQuizDetails->quiz_type) { // Show answers only if this is a survey where we want trainees to see the results. // @since V2.90 $this->unitQuizDetails->quiz_show_answers = 'hide_answers'; if ('show_responses' == $this->unitQuizDetails->quiz_show_survey_responses) { $this->unitQuizDetails->quiz_show_answers = 'show_answers'; } // No answers to check. Say thanks echo WPCW_UnitFrontend::message_createMessage_success(__('Thank you for your responses. This unit is now complete.', 'wp_courseware')); } else { $resultDetails = $this->check_quizzes_checkForCorrectAnswers($resultsList['answer_list']); // #### Step A - have open-ended questions that need marking. if (!empty($resultDetails['needs_marking'])) { $gradingNeeded = true; $courseDetails = WPCW_courses_getCourseDetails($this->unitQuizDetails->parent_course_id); // Non-blocking quiz - so allowed to continue, but will be graded later. if ('quiz_block' == $this->unitQuizDetails->quiz_type) { // Grading is needed before they continue, but don't want them to re-take the quiz. $gradingNeededBeforeContinue = true; } } else { // Copy over the wrong answers. $resultsList['wrong_answer_list'] = $resultDetails['wrong']; // Some statistics $correctCount = count($resultDetails['correct']); $totalQuestions = count($this->unitQuizDetails->questions); $correctPercentage = number_format($correctCount / $totalQuestions * 100, 1); // Non-blocking quiz. if ('quiz_noblock' == $this->unitQuizDetails->quiz_type) { // Store user quiz results // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes. /* echo WPCW_UnitFrontend::message_createMessage_success(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage ))*/ // Notify the user of their grade. $quizGradeNotificationNeeded = true; } else { // 2014-01-15 - Added ceil() calculation to ensure calculation is consistent when showing the quiz title // above around the .wpcw_fe_quiz_title div. $minPassQuestions = ceil($this->unitQuizDetails->quiz_pass_mark / 100 * $totalQuestions); // They've passed. Report how many they got right. if ($correctPercentage >= $this->unitQuizDetails->quiz_pass_mark) { // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes. /*echo WPCW_UnitFrontend::message_createMessage_success(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage ));*/ // Notify the user of their grade. $quizGradeNotificationNeeded = true; } else { // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes. // Show error that they've failed /*echo WPCW_UnitFrontend::message_createMessage_error( sprintf(__('Unfortunately, you only got <b>%d out of %d (%d%%)</b> questions correct. You need to correctly answer <b>at least %d questions (%d%%)</b>.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage, $minPassQuestions, $this->unitQuizDetails->quiz_pass_mark ));*/ // Save the user progress anyway, so that we can record attempts. $this->update_quizzes_saveUserProgress_completeQuiz($resultDetails, $resultsList['answer_list']); // Have they run out of quiz attempts? If so, we need to notify the admin and mark the latest attempt // as being the the last blocked one they can use. if (!$this->check_quizzes_canUserRequestRetake()) { // Update progress in database with next new step. $this->update_quizzes_setNextStepData('quiz_fail_no_retakes', false); // Notify the admin that this user is blocked and needs unblocking do_action('wpcw_quiz_user_needs_unblocking', $this->currentUserID, $this->unitQuizDetails); } // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes. // How many attempts have they now had? /* $attemptCount = $this->fetch_quizzes_getQuizAttemptCount(); echo WPCW_UnitFrontend::message_createMessage_error( ($attemptCount == 1 ? __('You have already had 1 previous attempt at this quiz.', 'wp_courseware') : sprintf(__('You have already had %d previous attempts at this quiz.', 'wp_courseware'), $attemptCount) ));*/ // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes. // If quiz is a no-answers quiz, show the form without the errors, so that the user cannot keep guesssing to pass. //echo $this->render_quizzes_old_handleQuizRendering($resultsList, ('no_answers' != $this->unitQuizDetails->quiz_show_answers)); // Errors, so the user cannot progress yet. return false; } } // end of blocking quiz check } } // end of survey check // ### 4 - Save the user progress $this->update_quizzes_saveUserProgress_completeQuiz($resultDetails, $resultsList['answer_list']); // ### 5 - Notify the user of their grade. if ($quizGradeNotificationNeeded) { do_action('wpcw_quiz_graded', $this->currentUserID, $this->unitQuizDetails, false, false); } // Questions need grading, notify the admin if ($gradingNeeded) { // Notify the admin that questions need answering. do_action('wpcw_quiz_needs_grading', $this->currentUserID, $this->unitQuizDetails); } // Questions need grading, so don't allow user to continue if ($gradingNeededBeforeContinue) { return false; } // If we get this far, the user may progress to next unit return true; }
/** * Given a frontend object with user progress data, replace the tags with quiz-related information * based on the tags that have been found in the email. * * @param WPCW_UnitFrontend $feObj The frontend object with details. * @param Array $tagList The list of tags found in the template. * @param String $emailData The data to replace the strings with. * @param String $additionalData Any additional data triggered from the trainer. * * @return The modified email data ready for sending. */ function WPCW_email_replaceTags_quizData($feObj, $tagList, $emailData, $additionalData = false) { if (!$feObj || empty($tagList)) { return $emailData; } $quizDetails = $feObj->fetch_getUnitQuizDetails(); $progressData = $feObj->fetch_getQuizProgressDetails(); // Replace each tag for quiz-related data. foreach ($tagList as $tagToReplace) { switch ($tagToReplace) { case '{QUIZ_TITLE}': $emailData = str_replace('{QUIZ_TITLE}', $quizDetails->quiz_title, $emailData); break; case '{QUIZ_GRADE}': $emailData = str_replace('{QUIZ_GRADE}', $progressData->quiz_grade . '%', $emailData); break; case '{QUIZ_ATTEMPTS}': $emailData = str_replace('{QUIZ_ATTEMPTS}', $progressData->attempt_count, $emailData); break; case '{QUIZ_TIME}': $timeToShare = __('n/a', 'wp_courseware'); if ($progressData->quiz_completion_time_seconds > 0) { $timeToShare = WPCW_time_convertSecondsToHumanLabel($progressData->quiz_completion_time_seconds); } $emailData = str_replace('{QUIZ_TIME}', $timeToShare, $emailData); break; case '{QUIZ_RESULT_DETAIL}': $emailData = str_replace('{QUIZ_RESULT_DETAIL}', $additionalData, $emailData); break; case '{QUIZ_GRADES_BY_TAG}': // Use existing frontend code to get the list of messages relating to tags. $msgList = $feObj->fetch_quizzes_questionResultsByTag(); $msgSummary = false; if (!empty($msgList)) { foreach ($msgList as $tagDetails) { // Got open questions if ($tagDetails['question_open_count'] > 0) { $msgSummary .= sprintf("%s: %s\n", $tagDetails['tag_details']->question_tag_name, sprintf(__('Your grade is %d%%', 'wp_courseware'), $tagDetails['score_total'])); } else { $msgSummary .= sprintf("%s: %s\n", $tagDetails['tag_details']->question_tag_name, sprintf(__('%d out of %d correct (%d%%)', 'wp_courseware'), $tagDetails['score_correct_questions'], $tagDetails['question_count'], $tagDetails['score_total'])); } // end of question type check } } $emailData = str_replace('{QUIZ_GRADES_BY_TAG}', $msgSummary, $emailData); break; case '{CUSTOM_FEEDBACK}': // Use existing frontend code to get the list of custom feedback messages. $customFeedback = false; $msgList = $feObj->fetch_customFeedbackMessage_calculateMessages(); if (!empty($msgList)) { $customFeedback = apply_filters('wpcw_email_feedback_separator_top', "\n\n------\n\n"); foreach ($msgList as $singleMsg) { // Separate each custom feedback message slightly $customFeedback .= $singleMsg . apply_filters('wpcw_email_feedback_separator', "\n\n------\n\n"); } } $emailData = str_replace('{CUSTOM_FEEDBACK}', $customFeedback, $emailData); break; } } return $emailData; }
/** * Function called when user starting a quiz and needs to kick off the timer. */ function WPCW_AJAX_units_handleQuizTimerBegin() { // Security check if (!wp_verify_nonce(WPCW_arrays_getValue($_POST, 'progress_nonce'), 'wpcw-progress-nonce')) { die(__('Security check failed!', 'wp_courseware')); } // Get unit and quiz ID $unitID = intval(WPCW_arrays_getValue($_POST, 'unitid')); $quizID = intval(WPCW_arrays_getValue($_POST, 'quizid')); // Get the post object for this quiz item. $post = get_post($unitID); if (!$post) { echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('Could not find training unit.', 'wp_courseware')); die; } // Initalise the unit details $fe = new WPCW_UnitFrontend($post); // #### Get associated data for this unit. No course/module data, then it's not a unit if (!$fe->check_unit_doesUnitHaveParentData()) { echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('Could not find course details for unit.', 'wp_courseware')); die; } // #### User not allowed access to content if (!$fe->check_user_canUserAccessCourse()) { echo $fe->message_user_cannotAccessCourse(); die; } // #### See if we're in a position to retake this quiz? if (!$fe->check_quizzes_canUserRequestRetake()) { echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('You are not permitted to retake this quiz.', 'wp_courseware')); die; } // Trigger the upgrade to progress so that we can start the quiz, and trigger the timer. $fe->update_quizzes_beginQuiz(); // Only complete if allowed to continue. echo $fe->render_detailsForUnit(false, true); die; }
// Check that plugin is active (so that this cannot be accessed if plugin isn't). require dirname(__FILE__) . '/../../../wp-config.php'; // Can't find active WP Courseware init function, so cannot be active. if (!function_exists('WPCW_plugin_init')) { WPCW_export_results_notFound(); } // Get unit and quiz ID $unitID = intval(WPCW_arrays_getValue($_GET, 'unitid')); $quizID = intval(WPCW_arrays_getValue($_GET, 'quizid')); // Get the post object for this quiz item. $post = get_post($unitID); if (!$post) { WPCW_export_results_notFound(__('Could not find training unit.', 'wp_courseware')); } // Initalise the unit details $fe = new WPCW_UnitFrontend($post); // #### Get associated data for this unit. No course/module data, then it's not a unit if (!$fe->check_unit_doesUnitHaveParentData()) { WPCW_export_results_notFound(__('Could not find course details for unit.', 'wp_courseware')); } // #### User not allowed access to content if (!$fe->check_user_canUserAccessCourse()) { WPCW_export_results_notFound($fe->fetch_message_user_cannotAccessCourse()); } include_once 'pdf/pdf_quizresults.inc.php'; $qrpdf = new WPCW_QuizResults(); $parentData = $fe->fetch_getUnitParentData(); $quizDetails = $fe->fetch_getUnitQuizDetails(); // Set values for use in the results $qrpdf->setTraineeName(WPCW_users_getUsersName($current_user)); $qrpdf->setCourseName($parentData->course_title);