/** * Creates the column columns of data. * * @param String $colContent The content of the column. * @param String $column_name The name of the column we're changing. * @param Integer $user_id The ID of the user we're rendering. * * @return String The formatted HTML code for the table. */ function WPCW_users_addCustomColumnContent($colContent, $column_name, $user_id) { switch ($column_name) { // #### Basically condense user details. case 'wpcw_col_user_details': // Format nice details of name, email and role to save space. $userDetails = get_userdata($user_id); // Ensure role is valid and it exists. $roleName = false; if (!empty($userDetails->roles)) { $roleName = $userDetails->roles[0]; } $colContent = sprintf('<span class="wpcw_col_cell_name">%s</span>', $userDetails->data->display_name); $colContent .= sprintf('<span class="wpcw_col_cell_email"><a href="mailto:%s" target="_blank">%s</a></span>', $userDetails->data->user_email, $userDetails->data->user_email); $colContent .= sprintf('<span class="wpcw_col_cell_role">%s</span>', ucwords($roleName)); break; // ####ÊThe training course statuses. // ####ÊThe training course statuses. case 'wpcw_col_training_courses': // Got some associated courses, so render progress. $courseData = WPCW_users_getUserCourseList($user_id); if ($courseData) { foreach ($courseData as $courseDataItem) { $colContent .= WPCW_stats_convertPercentageToBar($courseDataItem->course_progress, $courseDataItem->course_title); } } else { $colContent = __('No associated courses', 'wp_courseware'); } break; // #### Links to change user access for courses. // #### Links to change user access for courses. case 'wpcw_col_training_courses_access': $colContent = sprintf('<span><a href="%s&user_id=%d" class="button-primary">%s</a></span>', admin_url('users.php?page=WPCW_showPage_UserProgess'), $user_id, __('View Detailed Progress', 'wp_courseware')); // View the full progress of the user. $colContent .= sprintf('<span><a href="%s&user_id=%d" class="button-secondary">%s</a></span>', admin_url('users.php?page=WPCW_showPage_UserCourseAccess'), $user_id, __('Update Course Access Permissions', 'wp_courseware')); break; } // return $colContent; }
/** * Gradebook View - show the grade details for the users of the system. */ function WPCW_showPage_GradeBook_load() { $page = new PageBuilder(false); $courseDetails = false; $courseID = false; // Trying to view a specific course $courseDetails = false; if (isset($_GET['course_id'])) { $courseID = $_GET['course_id'] + 0; $courseDetails = WPCW_courses_getCourseDetails($courseID); } // Abort if course not found. if (!$courseDetails) { $page->showPageHeader(__('GradeBook', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $page->showMessage(__('Sorry, but that course could not be found.', 'wp_courseware'), true); $page->showPageFooter(); return; } // Show title of this course $page->showPageHeader(__('GradeBook', 'wp_courseware') . ': ' . $courseDetails->course_title, '75%', WPCW_icon_getPageIconURL()); global $wpcwdb, $wpdb; $wpdb->show_errors(); // Need a list of all quizzes for this course, excluding surveys. $quizzesForCourse = WPCW_quizzes_getAllQuizzesForCourse($courseDetails->course_id); // Handle situation when there are no quizzes. if (!$quizzesForCourse) { $page->showMessage(__('There are no quizzes for this course, therefore no grade information to show.', 'wp_courseware'), true); $page->showPageFooter(); return; } // Create a simple list of IDs to use in SQL queries $quizIDList = array(); foreach ($quizzesForCourse as $singleQuiz) { $quizIDList[] = $singleQuiz->quiz_id; } // Convert list of IDs into an SQL list $quizIDListForSQL = '(' . implode(',', $quizIDList) . ')'; // Do we want certificates? $usingCertificates = 'use_certs' == $courseDetails->course_opt_use_certificate; // #### Handle checking if we're sending out any emails to users with their final grades // Called here so that any changes are reflected in the table using the code below. if ('email_grades' == WPCW_arrays_getValue($_GET, 'action')) { WPCW_showPage_GradeBook_handleFinalGradesEmail($courseDetails, $page); } // Get the requested page number $paging_pageWanted = WPCW_arrays_getValue($_GET, 'pagenum') + 0; if ($paging_pageWanted == 0) { $paging_pageWanted = 1; } // Need a count of how many there are to mark anyway, hence doing calculation. // Using COUNT DISTINCT so that we get a total of the different user IDs. // If we use GROUP BY, we end up with several rows of results. $userCount_toMark = $wpdb->get_var("\n\t\tSELECT COUNT(DISTINCT upq.user_id) AS user_count \n\t\tFROM {$wpcwdb->user_progress_quiz} upq\t\t\n\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = upq.user_id\t\t\t\t\t\t\t\t\t\t\t\n\t\tWHERE upq.quiz_id IN {$quizIDListForSQL}\n\t\t AND upq.quiz_needs_marking > 0\n\t\t AND u.ID IS NOT NULL\n\t\t AND quiz_is_latest = 'latest'\n\t\t"); // Count - all users for this course $userCount_all = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t", $courseDetails->course_id)); // Count - users who have completed the course. $userCount_completed = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t AND uc.course_progress = 100\n\t\t", $courseDetails->course_id)); // Count - all users that need their final grade. $userCount_needGrade = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t AND uc.course_progress = 100\n\t\t AND uc.course_final_grade_sent != 'sent'\n\t\t", $courseDetails->course_id)); // SQL Code used by filters below $coreSQL_allUsers = $wpdb->prepare("\n\t\t\tSELECT * \n\t\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\t\tWHERE uc.course_id = %d\n\t\t\t AND u.ID IS NOT NULL\t\t\t\n\t\t\t", $courseDetails->course_id); // The currently selected filter to determine what quizzes to show. $currentFilter = WPCW_arrays_getValue($_GET, 'filter'); switch ($currentFilter) { case 'to_mark': // Chooses all progress where there are questions that need grading. // Then group by user, so that we don't show the same user twice. // Not added join for certificates, since they can't be complete // if they've got stuff to be marked. $coreSQL = "\n\t\t\t\tSELECT * \n\t\t\t\tFROM {$wpcwdb->user_progress_quiz} upq\t\t\t\t\t\t\t\t\t\n\t\t\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = upq.user_id\t\t\t\t\t\n\t\t\t\t\tLEFT JOIN {$wpcwdb->user_courses} uc ON uc.user_id = upq.user_id\n\t\t\t\tWHERE upq.quiz_id IN {$quizIDListForSQL}\n\t\t\t\t AND upq.quiz_needs_marking > 0\n\t\t\t\t AND u.ID IS NOT NULL\n\t\t\t\t AND quiz_is_latest = 'latest'\n\t\t\t\tGROUP BY u.ID\t\t\t\t\t\t\t\t \n\t\t\t\t"; // No need to re-calculate, just re-use the number. $paging_totalCount = $userCount_toMark; break; // Completed the course // Completed the course case 'completed': // Same SQL as all users, but just filtering those with a progress of 100. $coreSQL = $coreSQL_allUsers . " \n\t\t\t\t\tAND uc.course_progress = 100\n\t\t\t\t"; // The total number of results to show - used for paging $paging_totalCount = $userCount_completed; break; // Completed the course // Completed the course case 'eligible_for_final_grade': // Same SQL as all users, but just filtering those with a progress of 100 AND // needing a final grade due to flag in course_progress. $coreSQL = $coreSQL_allUsers . " \n\t\t\t\t\tAND uc.course_progress = 100 \n\t\t\t\t\tAND course_final_grade_sent != 'sent'\n\t\t\t\t"; // The total number of results to show - used for paging $paging_totalCount = $userCount_needGrade; break; // Default to all users, regardless of what progress they've made // Default to all users, regardless of what progress they've made default: $currentFilter = 'all'; // Allow the query to be modified by other plugins $coreSQL_filteredUsers = apply_filters("wpcw_back_query_filter_gradebook_users", $coreSQL_allUsers, $courseDetails->course_id); // Select all users that exist for this course $coreSQL = $coreSQL_filteredUsers; // The total number of results to show - used for paging $paging_totalCount = $userCount_all; break; } // Generate page URL $summaryPageURL = admin_url('admin.php?page=WPCW_showPage_GradeBook&course_id=' . $courseDetails->course_id); $paging_resultsPerPage = 50; $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; // Use the main SQL from above, but limit it and order by user's name. $SQL = "{$coreSQL}\n\t\t\tORDER BY display_name ASC\n\t\t\tLIMIT {$paging_sqlStart}, {$paging_resultsPerPage}"; // 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); $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_quiz_gradebook', 'class' => 'widefat wpcw_tbl'); $tblCol = new TableColumn(__('Learner Details', 'wp_courseware'), 'learner_details'); $tblCol->cellClass = "wpcw_learner_details"; $tbl->addColumn($tblCol); // ### Add the quiz data if ($quizzesForCourse) { // Show the overall progress for the course. $tblCol = new TableColumn(__('Overall Progress', 'wp_courseware'), 'course_progress'); //$tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_course_progress"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. $tblCol = new TableColumn(__('Cumulative Grade', 'wp_courseware'), 'quiz_cumulative'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. $tblCol = new TableColumn(__('Grade Sent?', 'wp_courseware'), 'grade_sent'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. if ($usingCertificates) { $tblCol = new TableColumn(__('Certificate Available?', 'wp_courseware'), 'certificate_available'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); } // ### Add main quiz scores foreach ($quizzesForCourse as $singleQuiz) { $tblCol = new TableColumn($singleQuiz->quiz_title, 'quiz_' . $singleQuiz->quiz_id); $tblCol->cellClass = "wpcw_center wpcw_quiz_grade"; $tblCol->headerClass = "wpcw_center wpcw_quiz_grade"; $tbl->addColumn($tblCol); } } $urlForQuizResultDetails = admin_url('users.php?page=WPCW_showPage_UserProgess_quizAnswers'); $userList = $wpdb->get_results($SQL); if (!$userList) { switch ($currentFilter) { case 'to_mark': $msg = __('There are currently no quizzes that need a manual grade.', 'wp_courseware'); break; case 'eligible_for_final_grade': $msg = __('There are currently no users that are eligible to receive their final grade.', 'wp_courseware'); break; case 'completed': $msg = __('There are currently no users that have completed the course.', 'wp_courseware'); break; default: $msg = __('There are currently no learners allocated to this course.', 'wp_courseware'); break; } // Create spanning item with message - number of quizzes + fixed columns. $rowDataObj = new RowDataSimple('wpcw_no_users wpcw_center', $msg, count($quizIDList) + 5); $tbl->addRowObj($rowDataObj); } else { // ### Format main row data and show it. $odd = false; foreach ($userList as $singleUser) { $data = array(); // Basic Details with avatar $data['learner_details'] = sprintf(' %s <span class="wpcw_col_cell_name">%s</span> <span class="wpcw_col_cell_username">%s</span> <span class="wpcw_col_cell_email"><a href="mailto:%s" target="_blank">%s</a></span></span> ', get_avatar($singleUser->ID, 48), $singleUser->display_name, $singleUser->user_login, $singleUser->user_email, $singleUser->user_email); // Get the user's progress for the quizzes. if ($quizzesForCourse) { $quizResults = WPCW_quizzes_getQuizResultsForUser($singleUser->ID, $quizIDListForSQL); // Track cumulative data $quizScoresSoFar = 0; $quizScoresSoFar_count = 0; // ### Now render results for each quiz foreach ($quizIDList as $aQuizID) { // Got progress data, process the result if (isset($quizResults[$aQuizID])) { // Extract results and unserialise the data array. $theResults = $quizResults[$aQuizID]; $theResults->quiz_data = maybe_unserialize($theResults->quiz_data); $quizDetailURL = sprintf('%s&user_id=%d&quiz_id=%d&unit_id=%d', $urlForQuizResultDetails, $singleUser->ID, $theResults->quiz_id, $theResults->unit_id); // We've got something that needs grading. So render link to where the quiz can be graded. if ($theResults->quiz_needs_marking > 0) { $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_needs_grading"><a href="%s">%s</span>', $quizDetailURL, __('Manual Grade Required', 'wp_courseware')); } else { if ('quiz_fail_no_retakes' == $theResults->quiz_next_step_type) { $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_needs_grading"><a href="%s">%s</span>', $quizDetailURL, __('Quiz Retakes Exhausted', 'wp_courseware')); } else { if ('incomplete' == $theResults->quiz_paging_status) { $data['quiz_' . $aQuizID] = '<span class="wpcw_grade_not_taken">' . __('In Progress', 'wp_courseware') . '</span>'; } else { // Use grade for cumulative grade $score = number_format($quizResults[$aQuizID]->quiz_grade, 1); $quizScoresSoFar += $score; $quizScoresSoFar_count++; // Render score and link to the full test data. $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_valid"><a href="%s">%s%%</span>', $quizDetailURL, $score); } } } } else { $data['quiz_' . $aQuizID] = '<span class="wpcw_grade_not_taken">' . __('Not Taken', 'wp_courseware') . '</span>'; } } // #### Show the cumulative quiz results. $data['quiz_cumulative'] = '-'; if ($quizScoresSoFar_count > 0) { $data['quiz_cumulative'] = '<span class="wpcw_grade_valid">' . number_format($quizScoresSoFar / $quizScoresSoFar_count, 1) . '%</span>'; } } // ####ÊUser Progress $data['course_progress'] = WPCW_stats_convertPercentageToBar($singleUser->course_progress); // #### Grade Sent? $data['grade_sent'] = 'sent' == $singleUser->course_final_grade_sent ? __('Yes', 'wp_courseware') : '-'; // #### Certificate - Show if there's a certificate that can be downloaded. if ($usingCertificates && ($certDetails = WPCW_certificate_getCertificateDetails($singleUser->ID, $courseDetails->course_id, false))) { $data['certificate_available'] = sprintf('<a href="%s" title="%s">%s</a>', WPCW_certificate_generateLink($certDetails->cert_access_key), __('Download the certificate for this user.', 'wp_courseware'), __('Yes', 'wp_courseware')); } else { $data['certificate_available'] = '-'; } // Odd/Even row colouring. $odd = !$odd; $tbl->addRow($data, $odd ? 'alternate' : ''); } // single user } // Check we have some users. // Here are the action buttons for Gradebook. printf('<div class="wpcw_button_group">'); // Button to generate a CSV of the gradebook. printf('<a href="%s" class="button-primary">%s</a> ', admin_url('?wpcw_export=gradebook_csv&course_id=' . $courseDetails->course_id), __('Export Gradebook (CSV)', 'wp_courseware')); printf('<a href="%s" class="button-primary">%s</a> ', admin_url('admin.php?page=WPCW_showPage_GradeBook&action=email_grades&filter=all&course_id=' . $courseDetails->course_id), __('Email Final Grades', 'wp_courseware')); // URL that shows the eligible users who are next to get the email for the final grade. $eligibleURL = sprintf(admin_url('admin.php?page=WPCW_showPage_GradeBook&course_id=%d&filter=eligible_for_final_grade'), $courseDetails->course_id); // Create information about how people are chosen to send grades to. printf('<div id="wpcw_button_group_info_gradebook" class="wpcw_button_group_info">%s</div>', sprintf(__('Grades will only be emailed to students who have <b>completed the course</b> and who have <b>not yet received</b> their final grade. You can see the students who are <a href="%s">eligible to receive the final grade email</a> here.', 'wp_courseware'), $eligibleURL)); printf('</div>'); echo $paging; // Show the filtering to selectively show different quizzes // Filter list can be modified to indicate Group's name instead of 'all' $filters_list = array('all' => sprintf(__('All (%d)', 'wp_courseware'), $userCount_all), 'completed' => sprintf(__('Completed (%d)', 'wp_courseware'), $userCount_completed), 'eligible_for_final_grade' => sprintf(__('Eligible for Final Grade Email (%d)', 'wp_courseware'), $userCount_needGrade), 'to_mark' => sprintf(__('Just Quizzes that Need Marking (%d)', 'wp_courseware'), $userCount_toMark)); // Allow the filters to be customised $filters_list = apply_filters("wpcw_back_filters_gradebook_filters", $filters_list, $courseDetails->course_id); echo WPCW_table_showFilters($filters_list, WPCW_urls_getURLWithParams($summaryPageURL, 'filter') . "&filter=", $currentFilter); // Finally show table echo $tbl->toString(); echo $paging; $page->showPageFooter(); }
/** * Creates the column columns of data. * * @param String $colContent The content of the column. * @param String $column_name The name of the column we're changing. * @param Integer $user_id The ID of the user we're rendering. * * @return String The formatted HTML code for the table. */ function WPCW_users_addCustomColumnContent($colContent, $column_name, $user_id) { switch ($column_name) { // #### Basically condense user details. case 'wpcw_col_user_details': // Format nice details of name, email and role to save space. $userDetails = get_userdata($user_id); // Ensure role is valid and it exists. $roleName = false; if (!empty($userDetails->roles)) { $roleName = $userDetails->roles[0]; } $colContent = sprintf('<span class="wpcw_col_cell_name">%s</span>', $userDetails->data->display_name); $colContent .= sprintf('<span class="wpcw_col_cell_email"><a href="mailto:%s" target="_blank">%s</a></span>', $userDetails->data->user_email, $userDetails->data->user_email); $colContent .= sprintf('<span class="wpcw_col_cell_role">%s</span>', ucwords($roleName)); break; // ####ÊThe training course statuses. // ####ÊThe training course statuses. case 'wpcw_col_training_courses': // Got some associated courses, so render progress. $courseData = WPCW_users_getUserCourseList($user_id); if ($courseData) { foreach ($courseData as $courseDataItem) { $colContent .= WPCW_stats_convertPercentageToBar($courseDataItem->course_progress, $courseDataItem->course_title); } } else { $colContent = __('No associated courses', 'wp_courseware'); } break; // #### Links to change user access for courses. // #### Links to change user access for courses. case 'wpcw_col_training_courses_access': $colContent = sprintf('<span><a href="%s&user_id=%d" class="button-primary">%s</a></span>', admin_url('users.php?page=WPCW_showPage_UserProgess'), $user_id, __('View Detailed Progress', 'wp_courseware')); // View the full progress of the user. $colContent .= sprintf('<span><a href="%s&user_id=%d" class="button-secondary">%s</a></span>', admin_url('users.php?page=WPCW_showPage_UserCourseAccess'), $user_id, __('Update Course Access Permissions', 'wp_courseware')); // Allow the user progress to be reset $courseData = WPCW_users_getUserCourseList($user_id); $courseIDList = array(); if (!empty($courseData)) { // Construct a simple list of IDs that we can use for filtering. foreach ($courseData as $courseDetails) { $courseIDList[] = $courseDetails->course_id; } } // Construct the mini form for resetting the user progress. $colContent .= '<span>'; $colContent .= '<form method="get">'; // Using this method of the user ID automaticallyed added the first user to any bulk action, which is clearly a bug. // So the field had to be renamed. //$colContent .= sprintf('<input type="hidden" name="users[]" value="%d" >', $user_id); $colContent .= sprintf('<input type="hidden" name="wpcw_users_single" value="%d" >', $user_id); // The dropdown for this. $colContent .= WPCW_courses_getCourseResetDropdown('wpcw_user_progress_reset_point_single', $courseIDList, __('No associated courses.', 'wp_courseware'), __('Reset this user to beginning of...', 'wp_courseware'), '', 'wpcw_user_progress_reset_select wpcw_user_progress_reset_point_single'); $colContent .= '</form>'; $colContent .= '</span>'; break; } return $colContent; }