/** * Creates a box to show that a unit is currently pending. * * @param Object $parentData A copy of the parent course and module details for this unit. * @param Integer $unitID The ID of the unit that's currently pending. */ function WPCW_units_getCompletionBox_pending($parentData, $unitID) { // See if we have a quiz for this unit? If so, render it and allow the trainee to complete it. $quizDetails = WPCW_quizzes_getAssociatedQuizForUnit($unitID); $html = false; // See if we have a quiz for this unit, if we do, see if the user has completed it or not. if ($quizDetails && $quizDetails->questions && count($quizDetails) > 0) { // Got the user progress, determine if it's pending marking or not. $quizProgress = WPCW_quizzes_getUserResultsForQuiz(get_current_user_id(), $unitID, $quizDetails->quiz_id); if ($quizProgress && 'retake_quiz' == $quizProgress->quiz_next_step_type) { // Show a generic message that the quiz needs to be re-taken. $messageToShow = wpautop(__('The course instructor has required that you retake this quiz.')); $messageToShow .= '<p>' . sprintf(__('Your previous grade was: <b>%s</b>'), number_format($quizProgress->quiz_grade, 1) . '%') . '</p>'; // Add the custom message if there was one, which is personalised from the instructor. if ($quizProgress->quiz_next_step_msg) { $messageToShow .= wpautop($quizProgress->quiz_next_step_msg); } $html .= WPCW_units_createWarningMessage($messageToShow); } // User has completed this quiz, so we need to indicate if it's been marked or not. If it's not been marked // we show a message saying they are blocked until it's marked. if ($quizProgress && $quizProgress->quiz_needs_marking > 0) { // Blocking quiz - show a status message saying that they can't continue until the quiz is graded. if ('quiz_block' == $quizDetails->quiz_type) { $html .= WPCW_units_createSuccessMessage($parentData->course_message_quiz_open_grading_blocking); } } else { $html .= WPCW_quizzes_handleQuizRendering($unitID, $quizDetails); } } else { // Render the message $html .= sprintf(' <div class="wpcw_fe_progress_box_wrap" id="wpcw_fe_unit_complete_%d"> <div class="wpcw_fe_progress_box wpcw_fe_progress_box_pending wpcw_fe_progress_box_updating"> <div class="wpcw_fe_progress_box_mark"> <img src="%s/ajax_loader.gif" class="wpcw_loader" style="display: none;" /> <a href="#" class="fe_btn fe_btn_completion btn_completion" id="unit_complete_%d">%s</a> </div> %s</div> </div>', $unitID, WPCW_plugin_getPluginPath() . 'img', $unitID, __('Mark as Completed', 'wp_courseware'), $parentData->course_message_unit_pending); } return $html; }
/** * Tries to get the quiz data for each unit that's in this list of units. Each unit is updated with * the quiz details if any are associated with a unit. Kept in this function as not needed elsewhere * so saving processing by putting it here. * * @param Array The list of units to check * @return Array The same list of units passed as a parameter. */ function WPCW_quizzes_fetchQuizzesForUnits($unitList) { if (!empty($unitList)) { // Add quiz data for each unit in the list. foreach ($unitList as $unitID => $unitObj) { // Create field anyway, but update with quiz details if one was found. $unitObj->extradata_quiz_details = WPCW_quizzes_getAssociatedQuizForUnit($unitID, false, false); } } return $unitList; }
/** * Function that shows details to the admin telling them what to do next. */ function WPCW_showPage_UserProgess_quizAnswers_whatsNext($quizDetails, $results, $page, $userID, $unitID) { // Tell admin still questions that need marking if ($results->quiz_needs_marking > 0) { printf('<div id="message" class="wpcw_msg wpcw_msg_info"><span class="wpcw_icon_pending"><b>%s</b></span></div>', __('This quiz has questions that need grading.', 'wp_courseware')); } else { // Show the form only if the quiz is blocking and they've failed. if ('quiz_block' == $quizDetails->quiz_type && $results->quiz_grade < $quizDetails->quiz_pass_mark) { $showAdminProgressForm = true; $showAdminMessageCustom = false; // Show admin which method was selected. if ($results->quiz_next_step_type) { switch ($results->quiz_next_step_type) { case 'progress_anyway': printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('You have allowed the user to <b>progress anyway</b>, despite failing the quiz.', 'wp_courseware')); $showAdminProgressForm = false; break; case 'retake_quiz': printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('You have requested that the user <b>re-takes the quiz</b>.', 'wp_courseware')); $showAdminProgressForm = false; break; case 'retake_waiting': printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('The user has requested a retake, but they have not yet completed the quiz.', 'wp_courseware')); $showAdminProgressForm = false; break; case 'quiz_fail_no_retakes': $showAdminMessageCustom = __('The user has <b>exhausted all of their retakes</b>.', 'wp_courseware'); $showAdminProgressForm = true; break; } } // Next step has not been specified, allow the admin to choose one. if ($showAdminProgressForm) { $attempts_taken = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizDetails->quiz_id); $unitQuizDetails = WPCW_quizzes_getAssociatedQuizForUnit($unitID, true, $userID); printf('<div class="wpcw_user_progress_failed"><form method="POST">'); // Show the main message or a custom message from above. printf('<div id="message" class="wpcw_msg wpcw_msg_error">%s %s</span></div>', $showAdminMessageCustom, __('Since this is a <b>blocking quiz</b>, and the user has <b>failed</b>, what would you like to do?', 'wp_courseware')); printf(' <div class="wpcw_user_progress_failed_next_action"> <label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_progress_anyway" value="progress_anyway" checked="checked" /> <span><b>%s</b> %s</span></label><br/> ', __('Allow the user to continue anyway.', 'wp_courseware'), __(' (User is emailed saying they can continue)', 'wp_courseware')); //if ($results->quiz_next_step_type == 'quiz_fail_no_retakes'){ if ($attempts_taken->attempt_count >= $unitQuizDetails->quiz_attempts_allowed && $unitQuizDetails->quiz_attempts_allowed != -1) { printf(' <label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_retake_quiz" value="retake_quiz" /> <span><b>%s</b> %s</span></label> ', __('Allow the user one more attempt.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware')); } else { printf(' <label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_retake_quiz" value="retake_quiz" /> <span><b>%s</b> %s</span></label> ', __('Require the user to re-take the quiz.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware')); } printf(' </div> <div class="wpcw_user_progress_failed_reason" style="display: none;"> <label><b>%s</b></label><br/> <textarea name="wpcw_user_progress_failed_reason"></textarea><br/> <small>%s</small> </div> <div class="wpcw_user_progress_failed_btns"> <input type="submit" name="failed_quiz_next_action" value="%s" class="button-primary" /> </div> ', __('Require the user to re-take the quiz.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware'), __('Custom Message:', 'wp_courseware'), __('Custom message for the user that\'s sent to the user when asking them to retake the quiz.', 'wp_courseware'), __('Save Preference', 'wp_courseware')); printf('</form></div>'); } } } }
/** * Update the progress for this quiz to allow a retake to happen. */ function update_quizzes_requestQuizRetake() { if ($this->check_quizzes_canUserRequestRetake()) { global $wpdb, $wpcwdb; $wpdb->show_errors(); // Update the quiz progress so that the next step is showing the quiz so that the user can complete it. $this->update_quizzes_setNextStepData('retake_waiting', false); // Remove any locks for this unit for this user, if there are any random questions. $wpdb->query($wpdb->prepare("\n\t\t\t\tDELETE FROM {$wpcwdb->question_rand_lock} \n\t\t\t\tWHERE question_user_id = %d\n\t\t\t\t AND parent_unit_id = %d\n\t\t\t", $this->currentUserID, $this->unitPost->ID)); // Reload any questions, as we've just deleted random locks. $this->unitQuizDetails = WPCW_quizzes_getAssociatedQuizForUnit($this->unitPost->ID, true, $this->currentUserID); // Change the status of the user progress without reloading all of the data again. $this->unitQuizProgress->quiz_next_step_type = 'retake_waiting'; } }
/** * Page where the modules of a course can be ordered. */ function WPCW_showPage_CourseOrdering_load() { $page = new PageBuilder(false); $page->showPageHeader(__('Order Course Modules & Units', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $courseDetails = false; $courseID = false; // Trying to edit a course if (isset($_GET['course_id'])) { $courseID = $_GET['course_id'] + 0; $courseDetails = WPCW_courses_getCourseDetails($courseID); } // Abort if course not found. if (!$courseDetails) { $page->showMessage(__('Sorry, but that course could not be found.', 'wp_courseware'), true); $page->showPageFooter(); return; } // ###ÊGenerate URLs for editing $modifyURL_quiz = admin_url('admin.php?page=WPCW_showPage_ModifyQuiz'); $modifyURL_module = admin_url('admin.php?page=WPCW_showPage_ModifyModule'); $modifyURL_unit = admin_url('post.php?action=edit'); // Title of course being editied printf('<div id="wpcw_page_course_title"><span>%s</span> %s</div>', __('Editing Course:', 'wp_courseware'), $courseDetails->course_title); // Overall wrapper printf('<div id="wpcw_dragable_wrapper">'); printf('<div id="wpcw_unassigned_wrapper" class="wpcw_floating_menu">'); // ### Show a list of units that are not currently assigned to a module printf('<div id="wpcw_unassigned_units" class="wpcw_unassigned">'); printf('<div class="wpcw_unassigned_title">%s</div>', __('Unassigned Units', 'wp_courseware')); printf('<ol class="wpcw_dragable_units_connected">'); // Render each unit so that it can be dragged to a module. Still render <ol> list // even if there are no units to show so that we can drag units into unassociated list. $units = WPCW_units_getListOfUnits(0); if ($units) { foreach ($units as $unassUnit) { // Has unit got any existing quizzes? $existingQuiz = false; $quizObj = WPCW_quizzes_getAssociatedQuizForUnit($unassUnit->ID, false, false); if ($quizObj) { $existingQuiz = sprintf('<li id="wpcw_quiz_%d" class="wpcw_dragable_quiz_item"> <div><a href="%s&quiz_id=%d" target="_blank" title="%s">%s (ID: %d)</a></div> <div class="wpcw_quiz_des">%s</div> </li>', $quizObj->quiz_id, $modifyURL_quiz, $quizObj->quiz_id, __('Edit this quiz...', 'wp_courseware'), $quizObj->quiz_title, $quizObj->quiz_id, $quizObj->quiz_desc); } printf('<li id="wpcw_unit_%d" class="wpcw_dragable_unit_item"> <div><a href="%s&post=%d" target="_blank" title="%s">%s (ID: %d)</a></div> <div class="wpcw_dragable_quiz_holder"><ol class="wpcw_dragable_quizzes_connected wpcw_one_only">%s</ol></div> </li>', $unassUnit->ID, $modifyURL_unit, $unassUnit->ID, __('Edit this unit...', 'wp_courseware'), $unassUnit->post_title, $unassUnit->ID, $existingQuiz); } } printf('</ol>'); printf('</div>'); // ### Show a list of quizzes that are not currently assigned to units printf('<div id="wpcw_unassigned_quizzes" class="wpcw_unassigned">'); printf('<div class="wpcw_unassigned_title">%s</div>', __('Unassigned Quizzes', 'wp_courseware')); printf('<ol class="wpcw_dragable_quizzes_connected">'); // Render each unit so that it can be dragged to a module. Still render <ol> list // even if there are no units to show so that we can drag units into unassociated list. $quizzes = WPCW_quizzes_getListOfQuizzes(0); if ($quizzes) { foreach ($quizzes as $quizObj) { printf('<li id="wpcw_quiz_%d" class="wpcw_dragable_quiz_item"> <div><a href="%s&quiz_id=%d" target="_blank" title="%s">%s (ID: %d)</a></div> <div class="wpcw_quiz_des">%s</div> </li>', $quizObj->quiz_id, $modifyURL_quiz, $quizObj->quiz_id, __('Edit this quiz...', 'wp_courseware'), $quizObj->quiz_title, $quizObj->quiz_id, $quizObj->quiz_desc); } } printf('</ol>'); printf('</div>'); printf('</div>'); // end of printf('<div class="wpcw_unassigned_wrapper">'); // ### Show list of modules and current units $moduleList = WPCW_courses_getModuleDetailsList($courseID); if ($moduleList) { printf('<ol class="wpcw_dragable_modules">'); foreach ($moduleList as $item_id => $moduleObj) { // Module printf('<li id="wpcw_mod_%d" class="wpcw_dragable_module_item"> <div> <a href="%s&module_id=%d" target="_blank" title="%s"><b>%s %d - %s (ID: %d)</b></a> </div>', $item_id, $modifyURL_module, $item_id, __('Edit this module...', 'wp_courseware'), __('Module', 'wp_courseware'), $moduleObj->module_number, $moduleObj->module_title, $item_id); // Test Associated Units printf('<ol class="wpcw_dragable_units_connected">'); $units = WPCW_units_getListOfUnits($item_id); if ($units) { foreach ($units as $unassUnit) { $existingQuiz = false; // Has unit got any existing quizzes? $quizObj = WPCW_quizzes_getAssociatedQuizForUnit($unassUnit->ID, false, false); $existingQuiz = false; if ($quizObj) { $existingQuiz = sprintf('<li id="wpcw_quiz_%d" class="wpcw_dragable_quiz_item"> <div><a href="%s&quiz_id=%d" target="_blank" title="%s">%s (ID: %d)</a></div> <div class="wpcw_quiz_des">%s</div> </li>', $quizObj->quiz_id, $modifyURL_quiz, $quizObj->quiz_id, __('Edit this quiz...', 'wp_courseware'), $quizObj->quiz_title, $quizObj->quiz_id, $quizObj->quiz_desc); } printf('<li id="wpcw_unit_%d" class="wpcw_dragable_unit_item"> <div><a href="%s&post=%d" target="_blank" title="%s">%s (ID: %d)</a></div> <div class="wpcw_dragable_quiz_holder"><ol class="wpcw_dragable_quizzes_connected wpcw_one_only">%s</ol></div> </li>', $unassUnit->ID, $modifyURL_unit, $unassUnit->ID, __('Edit this unit...', 'wp_courseware'), $unassUnit->post_title, $unassUnit->ID, $existingQuiz); } } printf('</ol></li>'); } printf('</ol>'); } else { _e('No modules yet.', 'wp_courseware'); } ?> <div id="wpcw_sticky_bar" style="display: none"> <div id="wpcw_sticky_bar_inner"> <a href="#" id="wpcw_dragable_modules_save" class="button-primary"><?php _e('Save Changes to Ordering', 'wp_courseware'); ?> </a> <span id="wpcw_sticky_bar_status" title="<?php _e('Ordering has changed. Ready to save changes?', 'wp_courseware'); ?> "></span> </div> </div> <?php // Close overall wrapper printf('</div>'); $page->showPageFooter(); }
/** * Shows a detailed summary of the user progress. */ function WPCW_showPage_UserProgess_load() { global $wpcwdb, $wpdb; $wpdb->show_errors(); $page = new PageBuilder(false); $page->showPageHeader(__('Detailed User Progress Report', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); // Check passed user ID is valid $userID = WPCW_arrays_getValue($_GET, 'user_id'); $userDetails = get_userdata($userID); if (!$userDetails) { $page->showMessage(__('Sorry, but that user could not be found.', 'wp_courseware'), true); $page->showPageFooter(); return false; } printf(__('<p>Here you can see how well <b>%s</b> (Username: <b>%s</b>) is doing with your training courses.</p>', 'wp_courseware'), $userDetails->data->display_name, $userDetails->data->user_login); // #### 1 - Show a list of all training courses, and then list the units associated with that course. $SQL = "SELECT * \n\t\t\tFROM {$wpcwdb->courses}\n\t\t\tORDER BY course_title ASC \n\t\t\t"; $courseCount = 0; $courses = $wpdb->get_results($SQL); if ($courses) { foreach ($courses as $course) { $up = new UserProgress($course->course_id, $userID); // Skip if user is not allowed to access the training course. if (!WPCW_courses_canUserAccessCourse($course->course_id, $userID)) { continue; } printf('<h3 class="wpcw_tbl_progress_course">%s</h3>', $course->course_title); printf('<table class="widefat wpcw_tbl wpcw_tbl_progress">'); printf('<thead>'); printf('<th>%s</th>', __('Unit', 'wp_courseware')); printf('<th class="wpcw_center">%s</th>', __('Completed', 'wp_courseware')); printf('<th class="wpcw_center wpcw_tbl_progress_quiz_name">%s</th>', __('Quiz Name', 'wp_courseware')); printf('<th class="wpcw_center">%s</th>', __('Quiz Status', 'wp_courseware')); printf('<th class="wpcw_center">%s</th>', __('Actions', 'wp_courseware')); printf('</thead><tbody>'); // #### 2 - Fetch all associated modules $modules = WPCW_courses_getModuleDetailsList($course->course_id); if ($modules) { foreach ($modules as $module) { // #### 3 - Render Modules as a heading. printf('<tr class="wpcw_tbl_progress_module">'); printf('<td colspan="3">%s %d - %s</td>', __('Module', 'wp_courseware'), $module->module_number, $module->module_title); // Blanks for Quiz Name and Actions. printf('<td> </td>'); printf('<td> </td>'); printf('</tr>'); // #### 4. - Render the units for this module $units = WPCW_units_getListOfUnits($module->module_id); if ($units) { foreach ($units as $unit) { $showDetailLink = false; printf('<tr class="wpcw_tbl_progress_unit">'); printf('<td class="wpcw_tbl_progress_unit_name">%s %d - %s</td>', __('Unit', 'wp_courseware'), $unit->unit_meta->unit_number, $unit->post_title); // Has the unit been completed yet? printf('<td class="wpcw_tbl_progress_completed">%s</td>', $up->isUnitCompleted($unit->ID) ? __('Completed', 'wp_courseware') : ''); // See if there's a quiz for this unit? $quizDetails = WPCW_quizzes_getAssociatedQuizForUnit($unit->ID, false, $userID); // Render the quiz details. if ($quizDetails) { // Title of quiz printf('<td class="wpcw_tbl_progress_quiz_name">%s</td>', $quizDetails->quiz_title); // No correct answers, so mark as complete. if ('survey' == $quizDetails->quiz_type) { $quizResults = WPCW_quizzes_getUserResultsForQuiz($userID, $unit->ID, $quizDetails->quiz_id); if ($quizResults) { printf('<td class="wpcw_tbl_progress_completed">%s</td>', __('Completed', 'wp_courseware')); // Showing a link to view details $showDetailLink = true; printf('<td><a href="%s&user_id=%d&quiz_id=%d&unit_id=%d" class="button-secondary">%s</a></td>', admin_url('users.php?page=WPCW_showPage_UserProgess_quizAnswers'), $userID, $quizDetails->quiz_id, $unit->ID, __('View Survey Details', 'wp_courseware')); } else { printf('<td class="wpcw_center">%s</td>', __('Pending', 'wp_courseware')); } } else { $quizResults = WPCW_quizzes_getUserResultsForQuiz($userID, $unit->ID, $quizDetails->quiz_id); // Show the admin how many questions were right. if ($quizResults) { // -1% means that the quiz is needing grading. if ($quizResults->quiz_grade < 0) { printf('<td class="wpcw_center">%s</td>', __('Awaiting Final Grading', 'wp_courseware')); } else { printf('<td class="wpcw_tbl_progress_completed">%d%%</td>', number_format($quizResults->quiz_grade, 1)); } // Showing a link to view details $showDetailLink = true; printf('<td><a href="%s&user_id=%d&quiz_id=%d&unit_id=%d" class="button-secondary">%s</a></td>', admin_url('users.php?page=WPCW_showPage_UserProgess_quizAnswers'), $userID, $quizDetails->quiz_id, $unit->ID, __('View Quiz Details', 'wp_courseware')); } else { printf('<td class="wpcw_center">%s</td>', __('Pending', 'wp_courseware')); } } // end of if survey } else { printf('<td class="wpcw_center">-</td>'); printf('<td class="wpcw_center">-</td>'); } // Quiz detail link if (!$showDetailLink) { printf('<td> </td>'); } printf('</tr>'); } } } } printf('</tbody></table>'); // Track number of courses user can actually access $courseCount++; } // Course is not allowed to access any courses. So show a meaningful message. if ($courseCount == 0) { $page->showMessage(sprintf(__('User <b>%s</b> is not currently allowed to access any training courses.', 'wp_courseware'), $userDetails->data->display_name), true); } } else { printf('<p>%s</p>', __('There are currently no courses to show. Why not create one?', 'wp_courseware')); } $page->showPageFooter(); }
/** * Creates the column columns of data. * * @param String $column_name The name of the column we're changing. * @param Integer $post_id The ID of the post we're rendering. * * @return String The formatted HTML code for the table. */ function WPCW_units_addCustomColumnContent($column_name, $post_id) { switch ($column_name) { // Associated quiz link case 'wpcw_col_quiz': if ($quizDetails = WPCW_quizzes_getAssociatedQuizForUnit($post_id)) { printf('<a href="%s&quiz_id=%d">%s</a>', admin_url('admin.php?page=WPCW_showPage_ModifyQuiz'), $quizDetails->quiz_id, $quizDetails->quiz_title); } else { echo '-'; } break; case 'wpcw_col_module_and_course': $parentObj = WPCW_units_getAssociatedParentData($post_id); if (!$parentObj) { _e('n/a', 'wp_courseware'); } else { printf('<span class="wpcw_col_cell_module"><b>%s %d</b> - %s</span> <span class="wpcw_col_cell_course"><b>%s:</b> %s</span>', __('Module', 'wp_courseware'), $parentObj->module_number, $parentObj->module_title, __('Course', 'wp_courseware'), $parentObj->course_title); } break; // wpcw_col_module_and_course } }