/** * Shows a detailed summary of the user's quiz or survey answers. */ function WPCW_showPage_UserProgess_quizAnswers_load() { global $wpcwdb, $wpdb; $wpdb->show_errors(); $page = new PageBuilder(false); $page->showPageHeader(__('Detailed User Quiz/Survey Results', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $userID = WPCW_arrays_getValue($_GET, 'user_id') + 0; $unitID = WPCW_arrays_getValue($_GET, 'unit_id') + 0; $quizID = WPCW_arrays_getValue($_GET, 'quiz_id') + 0; // Create a link back to the detailed user progress, and back to all users. printf('<div class="wpcw_button_group">'); // Link back to all user summary printf('<a href="%s" class="button-secondary">%s</a> ', admin_url('users.php'), __('« Return to User Summary', 'wp_courseware')); if ($userDetails = get_userdata($userID)) { // Link back to user's personal summary printf('<a href="%s&user_id=%d" class="button-secondary">%s</a> ', admin_url('users.php?page=WPCW_showPage_UserProgess'), $userDetails->ID, sprintf(__('« Return to <b>%s\'s</b> Progress Report', 'wp_courseware'), $userDetails->display_name)); } // Try to get the full detailed results. $results = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizID); // No results, so abort. if (!$results) { // Close the button wrapper for above early printf('</div>'); // .wpcw_button_group $page->showMessage(__('Sorry, but no results could be found.', 'wp_courseware'), true); $page->showPageFooter(); return; } // Could potentially have an issue where the quiz has been deleted // but the data exists.. small chance though. $quizDetails = WPCW_quizzes_getQuizDetails($quizID, true, true, $userID); // Extra button - return to gradebook printf('<a href="%s&course_id=%d" class="button-secondary">%s</a> ', admin_url('admin.php?page=WPCW_showPage_GradeBook'), $quizDetails->parent_course_id, __("« Return to Gradebook", 'wp_courseware')); printf('</div>'); // .wpcw_button_group // #### 1 - Handle grades being updated $results = WPCW_showPage_UserProgess_quizAnswers_handingGrading($quizDetails, $results, $page, $userID, $unitID); // #### 2A - Check if next action for user has been triggered by the admin. $results = WPCW_showPage_UserProgess_quizAnswers_whatsNext_savePreferences($quizDetails, $results, $page, $userID, $unitID); // #### 2B - Handle telling admin what's next WPCW_showPage_UserProgess_quizAnswers_whatsNext($quizDetails, $results, $page, $userID, $unitID); //Ê#### 3 - Handle sending emails if something has changed. if (isset($results->sendOutEmails) && $results->sendOutEmails) { $extraDetail = isset($results->extraEmailDetail) ? $results->extraEmailDetail : ''; // Only called if the quiz was graded. if (isset($results->quiz_has_just_been_graded) && $results->quiz_has_just_been_graded) { // Need to call the action anyway, but any functions hanging off this // should check if the admin wants users to have notifications or not. do_action('wpcw_quiz_graded', $userID, $quizDetails, number_format($results->quiz_grade, 1), $extraDetail); } $courseDetails = WPCW_courses_getCourseDetails($quizDetails->parent_course_id); if ($courseDetails->email_quiz_grade_option == 'send_email') { // Message is only if quiz has been graded. if (isset($results->quiz_has_just_been_graded) && $results->quiz_has_just_been_graded) { $page->showMessage(__('The user has been sent an email with their grade for this course.', 'wp_courseware')); } } } // #### - Table 1 - Overview printf('<h3>%s</h3>', __('Quiz/Survey Overview', 'wp_courseware')); $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_progress_quiz_info', 'class' => 'widefat wpcw_tbl'); $tblCol = new TableColumn(false, 'quiz_label'); $tblCol->cellClass = 'wpcw_tbl_label'; $tbl->addColumn($tblCol); $tblCol = new TableColumn(false, 'quiz_detail'); $tbl->addColumn($tblCol); // These are the base details for the quiz to show. $summaryData = array(__('Quiz Title', 'wp_courseware') => $quizDetails->quiz_title, __('Quiz Description', 'wp_courseware') => $quizDetails->quiz_desc, __('Quiz Type', 'wp_courseware') => WPCW_quizzes_getQuizTypeName($quizDetails->quiz_type), __('No. of Questions', 'wp_courseware') => $results->quiz_question_total, __('Completed Date', 'wp_courseware') => __('About', 'wp_courseware') . ' ' . human_time_diff($results->quiz_completed_date_ts) . ' ' . __('ago', 'wp_courseware') . '<br/><small>(' . date('D jS M Y \\a\\t H:i:s', $results->quiz_completed_date_ts) . ')</small>', __('Number of Quiz Attempts', 'wp_courseware') => $results->attempt_count, __('Permitted Quiz Attempts', 'wp_courseware') => -1 == $quizDetails->quiz_attempts_allowed ? __('Unlimited', 'wp_courseware') : $quizDetails->quiz_attempts_allowed); // Quiz details relating to score, etc. if ('survey' != $quizDetails->quiz_type) { $summaryData[__('Pass Mark', 'wp_courseware')] = $quizDetails->quiz_pass_mark . '%'; // Still got items to grade if ($results->quiz_needs_marking > 0) { $summaryData[__('No. of Questions to Grade', 'wp_courseware')] = '<span class="wpcw_status_info wpcw_icon_pending">' . $results->quiz_needs_marking . '</span>'; $summaryData[__('Overall Grade', 'wp_courseware')] = '<span class="wpcw_status_info wpcw_icon_pending">' . __('Awaiting Final Grading', 'wp_courseware') . '</span>'; } else { $summaryData[__('No. of Question to Grade', 'wp_courseware')] = '-'; // Show if PASSED or FAILED with the overall grade. $gradeData = false; if ($results->quiz_grade >= $quizDetails->quiz_pass_mark) { $gradeData = sprintf('<span class="wpcw_tbl_progress_quiz_overall wpcw_question_yesno_status wpcw_question_yes">%s%% %s</span>', number_format($results->quiz_grade, 1), __('Passed', 'wp_courseware')); } else { $gradeData = sprintf('<span class="wpcw_tbl_progress_quiz_overall wpcw_question_yesno_status wpcw_question_no">%s%% %s</span>', number_format($results->quiz_grade, 1), __('Failed', 'wp_courseware')); } $summaryData[__('Overall Grade', 'wp_courseware')] = $gradeData; } } foreach ($summaryData as $label => $data) { $tbl->addRow(array('quiz_label' => $label . ':', 'quiz_detail' => $data)); } echo $tbl->toString(); // ### 4 - Form Code - to allow instructor to send data back to printf('<form method="POST" id="wpcw_tbl_progress_quiz_grading_form">'); printf('<input type="hidden" name="grade_answers_submitted" value="true">'); // ### 5 - Table 2 - Each Specific Quiz $questionNumber = 0; if ($results->quiz_data && count($results->quiz_data) > 0) { foreach ($results->quiz_data as $questionID => $answer) { $data = $answer; // Get the question type if (isset($quizDetails->questions[$questionID])) { // Store as object for easy reference. $quObj = $quizDetails->questions[$questionID]; // Render the question as a table. printf('<h3>%s #%d - %s</h3>', __('Question', 'wp_courseware'), ++$questionNumber, $quObj->question_question); $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_progress_quiz_info', 'class' => 'widefat wpcw_tbl wpcw_tbl_progress_quiz_answers_' . $quObj->question_type); $tblCol = new TableColumn(false, 'quiz_label'); $tblCol->cellClass = 'wpcw_tbl_label'; $tbl->addColumn($tblCol); $tblCol = new TableColumn(false, 'quiz_detail'); $tbl->addColumn($tblCol); $theirAnswer = false; switch ($quObj->question_type) { case 'truefalse': case 'multi': $theirAnswer = $answer['their_answer']; break; // File Upload - create a download link // File Upload - create a download link case 'upload': $theirAnswer = sprintf('<a href="%s%s" target="_blank" class="button-primary">%s .%s %s (%s)</a>', WP_CONTENT_URL, $answer['their_answer'], __('Open', 'wp_courseware'), pathinfo($answer['their_answer'], PATHINFO_EXTENSION), __('File', 'wp_courseware'), WPCW_files_getFileSize_human($answer['their_answer'])); break; // Open Ended - Wrap in span tags, to cap the size of the field, and format new lines. // Open Ended - Wrap in span tags, to cap the size of the field, and format new lines. case 'open': $theirAnswer = '<span class="wpcw_q_answer_open_wrap"><textarea readonly>' . $data['their_answer'] . '</textarea></span>'; break; } // end of $theirAnswer check $summaryData = array(__('Type', 'wp_courseware') => array('data' => WPCW_quizzes_getQuestionTypeName($quObj->question_type), 'cssclass' => ''), __('Their Answer', 'wp_courseware') => array('data' => $theirAnswer, 'cssclass' => '')); // Just for quizzes - show answers/grade if ('survey' != $quizDetails->quiz_type) { switch ($quObj->question_type) { case 'truefalse': case 'multi': // The right answer... $summaryData[__('Correct Answer', 'wp_courseware')] = array('data' => $answer['correct'], 'cssclass' => ''); // Did they get it right? $getItRight = sprintf('<span class="wpcw_question_yesno_status wpcw_question_%s">%s</span>', $answer['got_right'], 'yes' == $answer['got_right'] ? __('Yes', 'wp_courseware') : __('No', 'wp_courseware')); $summaryData[__('Did they get it right?', 'wp_courseware')] = array('data' => $getItRight, 'cssclass' => ''); break; case 'upload': case 'open': $gradeHTML = false; $theirGrade = WPCW_arrays_getValue($answer, 'their_grade'); // Not graded - show select box. if ($theirGrade == 0) { $cssClass = 'wpcw_grade_needs_grading'; } else { $cssClass = 'wpcw_grade_already_graded'; $gradeHTML = sprintf('<span class="wpcw_grade_view">%d%% <a href="#">(%s)</a></span>', $theirGrade, __('Click to edit', 'wp_courseware')); } // Not graded yet, allow admin to grade the quiz, or change // the grading later if they want to. $gradeHTML .= WPCW_forms_createDropdown('grade_quiz_' . $quObj->question_id, WPCW_quizzes_getPercentageList(__('-- Select a grade --', 'wp_courseware')), $theirGrade, false, 'wpcw_tbl_progress_quiz_answers_grade'); $summaryData[__('Their Grade', 'wp_courseware')] = array('data' => $gradeHTML, 'cssclass' => $cssClass); break; } } // Check of showing the right answer. foreach ($summaryData as $label => $data) { $tbl->addRow(array('quiz_label' => $label . ':', 'quiz_detail' => $data['data']), $data['cssclass']); } echo $tbl->toString(); } // end if (isset($quizDetails->questions[$questionID])) } // foreach ($results->quiz_data as $questionID => $answer) } printf('</form>'); // Shows a bar that pops up, allowing the user to easily save all grades that have changed. ?> <div id="wpcw_sticky_bar" style="display: none"> <div id="wpcw_sticky_bar_inner"> <a href="#" id="wpcw_tbl_progress_quiz_grading_updated" class="button-primary"><?php _e('Save Changes to Grades', 'wp_courseware'); ?> </a> <span id="wpcw_sticky_bar_status" title="<?php _e('Grades have been changed. Ready to save changes?', 'wp_courseware'); ?> "></span> </div> </div> <br/><br/><br/><br/> <?php $page->showPageFooter(); }
/** * Function that show a summary of the quizzes. */ function WPCW_showPage_QuizSummary_load() { global $wpcwdb, $wpdb; $wpdb->show_errors(); // Get the requested page number $paging_pageWanted = WPCW_arrays_getValue($_GET, 'pagenum') + 0; if ($paging_pageWanted == 0) { $paging_pageWanted = 1; } // Title for page with page number $titlePage = false; if ($paging_pageWanted > 1) { $titlePage = sprintf(' - %s %s', __('Page', 'wp_courseware'), $paging_pageWanted); } $page = new PageBuilder(false); $page->showPageHeader(__('Quiz & Survey Summary', 'wp_courseware') . $titlePage, '75%', WPCW_icon_getPageIconURL()); // Handle the quiz deletion before showing remaining quizzes... WPCW_quizzes_handleQuizDeletion($page); // Handle the sorting and filtering $orderBy = WPCW_arrays_getValue($_GET, 'orderby'); $ordering = WPCW_arrays_getValue($_GET, 'order'); // Validate ordering switch ($orderBy) { case 'quiz_title': case 'quiz_id': break; default: $orderBy = 'quiz_id'; break; } // Create opposite ordering for reversing it. $ordering_opposite = false; switch ($ordering) { case 'desc': $ordering_opposite = 'asc'; break; case 'asc': $ordering_opposite = 'desc'; break; default: $ordering = 'desc'; $ordering_opposite = 'asc'; break; } // Was a search string specified? Or a specific item? $searchString = WPCW_arrays_getValue($_GET, 's'); // Create WHERE string based search - Title or Description of Quiz $stringWHERE = false; if ($searchString) { $stringWHERE = $wpdb->prepare(" WHERE quiz_title LIKE %s OR quiz_desc LIKE %s ", '%' . $searchString . '%', '%' . $searchString . '%'); } $summaryPageURL = admin_url('admin.php?page=WPCW_showPage_QuizSummary'); // Show the form for searching ?> <form id="wpcw_quizzes_search_box" method="get" action="<?php echo $summaryPageURL; ?> "> <p class="search-box"> <label class="screen-reader-text" for="wpcw_quizzes_search_input"><?php _e('Search Quizzes', 'wp_courseware'); ?> </label> <input id="wpcw_quizzes_search_input" type="text" value="<?php echo $searchString; ?> " name="s"/> <input class="button" type="submit" value="<?php _e('Search Quizzes', 'wp_courseware'); ?> "/> <input type="hidden" name="page" value="WPCW_showPage_QuizSummary" /> </p> </form> <br/><br/> <?php $SQL_PAGING = "\n\t\t\tSELECT COUNT(*) as quiz_count \n\t\t\tFROM {$wpcwdb->quiz}\t\t\t\n\t\t\t{$stringWHERE}\n\t\t\tORDER BY quiz_id DESC \n\t\t"; $paging_resultsPerPage = 50; $paging_totalCount = $wpdb->get_var($SQL_PAGING); $paging_recordStart = ($paging_pageWanted - 1) * $paging_resultsPerPage + 1; $paging_recordEnd = $paging_pageWanted * $paging_resultsPerPage; $paging_pageCount = ceil($paging_totalCount / $paging_resultsPerPage); $paging_sqlStart = $paging_recordStart - 1; // Show search message - that a search has been tried. if ($searchString) { printf('<div class="wpcw_search_count">%s "%s" (%s %s) (<a href="%s">%s</a>)</div>', __('Search results for', 'wp_courseware'), htmlentities($searchString), $paging_totalCount, _n('result', 'results', $paging_totalCount, 'wp_courseware'), $summaryPageURL, __('reset', 'wp_courseware')); } // Do main query $SQL = "SELECT * \n\t\t\tFROM {$wpcwdb->quiz}\t\t\t\n\t\t\t{$stringWHERE}\n\t\t\tORDER BY {$orderBy} {$ordering}\n\t\t\tLIMIT {$paging_sqlStart}, {$paging_resultsPerPage}\t\t\t \n\t\t\t"; // These are already checked, so they are safe, hence no prepare() // Generate paging code $baseURL = WPCW_urls_getURLWithParams($summaryPageURL, 'pagenum') . "&pagenum="; $paging = WPCW_tables_showPagination($baseURL, $paging_pageWanted, $paging_pageCount, $paging_totalCount, $paging_recordStart, $paging_recordEnd); $quizzes = $wpdb->get_results($SQL); if ($quizzes) { $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_quiz_summary', 'class' => 'widefat wpcw_tbl'); // ID - sortable $sortableLink = sprintf('<a href="%s&order=%s&orderby=quiz_id"><span>%s</span><span class="sorting-indicator"></span></a>', $baseURL, 'quiz_id' == $orderBy ? $ordering_opposite : 'asc', __('ID', 'wp_courseware')); // ID - render $tblCol = new TableColumn($sortableLink, 'quiz_id'); $tblCol->headerClass = 'quiz_id' == $orderBy ? 'sorted ' . $ordering : 'sortable'; $tblCol->cellClass = "quiz_id"; $tbl->addColumn($tblCol); // Title - sortable $sortableLink = sprintf('<a href="%s&order=%s&orderby=quiz_title"><span>%s</span><span class="sorting-indicator"></span></a>', $baseURL, 'quiz_title' == $orderBy ? $ordering_opposite : 'asc', __('Quiz Title', 'wp_courseware')); // Title - render $tblCol = new TableColumn($sortableLink, 'quiz_title'); $tblCol->headerClass = 'quiz_title' == $orderBy ? 'sorted ' . $ordering : 'sortable'; $tblCol->cellClass = "quiz_title"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Associated Unit', 'wp_courseware'), 'associated_unit'); $tblCol->cellClass = "associated_unit"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Quiz Type', 'wp_courseware'), 'quiz_type'); $tblCol->cellClass = "quiz_type"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Show Answers', 'wp_courseware'), 'quiz_show_answers'); $tblCol->cellClass = "quiz_type wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Paging', 'wp_courseware'), 'quiz_use_paging'); $tblCol->cellClass = "quiz_type wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Questions', 'wp_courseware'), 'total_questions'); $tblCol->cellClass = "total_questions wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Actions', 'wp_courseware'), 'actions'); $tblCol->cellClass = "actions"; $tbl->addColumn($tblCol); // Stores course details in a mini cache to save lots of MySQL lookups. $miniCourseDetailCache = array(); // Format row data and show it. $odd = false; foreach ($quizzes as $quiz) { $data = array(); // URLs $editURL = admin_url('admin.php?page=WPCW_showPage_ModifyQuiz&quiz_id=' . $quiz->quiz_id); $surveyExportURL = admin_url('admin.php?page=WPCW_showPage_QuizSummary&wpcw_export=csv_export_survey_data&quiz_id=' . $quiz->quiz_id); // Maintain paging where possible. $deleteURL = $baseURL . '&action=delete&quiz_id=' . $quiz->quiz_id; // Basic Details $data['quiz_id'] = $quiz->quiz_id; // Quiz Title $data['quiz_title'] = sprintf('<b><a href="%s">%s</a></b>', $editURL, $quiz->quiz_title); if ($quiz->quiz_desc) { $data['quiz_title'] .= '<span class="wpcw_quiz_desc">' . $quiz->quiz_desc . '</span>'; } // Associated Unit if ($quiz->parent_unit_id > 0 && ($unitDetails = get_post($quiz->parent_unit_id))) { $data['associated_unit'] = sprintf('<span class="associated_unit_unit"><b>%s</b>: <a href="%s" target="_blank" title="%s \'%s\'...">%s</a></span>', __('Unit', 'wp_courseware'), get_permalink($unitDetails->ID), __('View ', 'wp_courseware'), $unitDetails->post_title, $unitDetails->post_title); // Also add associated course if (isset($miniCourseDetailCache[$quiz->parent_course_id])) { $courseDetails = $miniCourseDetailCache[$quiz->parent_course_id]; } else { // Save course details to cache (as likely to use it again). $courseDetails = $miniCourseDetailCache[$quiz->parent_course_id] = WPCW_courses_getCourseDetails($quiz->parent_course_id); } // Might not have course details. if ($courseDetails) { $data['associated_unit'] .= sprintf('<span class="associated_unit_course"><b>%s:</b> <a href="admin.php?page=WPCW_showPage_ModifyCourse&course_id=%d" title="%s \'%s\'...">%s</a></span>', __('Course', 'wp_courseware'), $courseDetails->course_id, __('Edit ', 'wp_courseware'), $courseDetails->course_title, $courseDetails->course_title); } } else { $data['associated_unit'] = 'n/a'; } // Showing Answers or paging? $data['quiz_show_answers'] = 'show_answers' == $quiz->quiz_show_answers ? '<span class="wpcw_tick"></span>' : '-'; $data['quiz_use_paging'] = 'use_paging' == $quiz->quiz_paginate_questions ? '<span class="wpcw_tick"></span>' : '-'; // Type of quiz $data['quiz_type'] = WPCW_quizzes_getQuizTypeName($quiz->quiz_type); // Show passmark for blocking quizzes. if ('quiz_block' == $quiz->quiz_type) { $data['quiz_type'] .= '<span class="wpcw_quiz_pass_info">' . sprintf(__('Min. Pass Mark of %d%%', 'wp_courseware'), $quiz->quiz_pass_mark) . '</span>'; } // Total number of questions $data['total_questions'] = WPCW_quizzes_calculateActualQuestionCount($quiz->quiz_id); // Actions $data['actions'] = '<ul class="wpcw_action_link_list">'; $data['actions'] .= sprintf('<li><a href="%s" class="button-primary">%s</a></li>', $editURL, __('Edit', 'wp_courseware')); $data['actions'] .= sprintf('<li><a href="%s" class="button-secondary wpcw_action_link_delete_quiz wpcw_action_link_delete" rel="%s">%s</a></li>', $deleteURL, __('Are you sure you wish to delete this quiz?', 'wp_courseware'), __('Delete', 'wp_courseware')); // Add export button for surveys if ('survey' == $quiz->quiz_type) { $data['actions'] .= sprintf('<li class="wpcw_action_item_newline"><a href="%s" class="button-secondary">%s</a></li>', $surveyExportURL, __('Export Responses', 'wp_courseware')); } $data['actions'] .= '</ul>'; // Odd/Even row colouring. $odd = !$odd; $tbl->addRow($data, $odd ? 'alternate' : ''); } // Finally show table echo $paging; echo $tbl->toString(); echo $paging; } else { printf('<p>%s</p>', __('There are currently no quizzes to show. Why not create one?', 'wp_courseware')); } $page->showPageFooter(); }