Example #1
0
/**
 * Generates a verbose output of the gradebook data for a specific course.
 */
function WPCW_data_export_gradebookData()
{
    global $wpcwdb, $wpdb;
    $wpdb->show_errors();
    // #### 1 - See if the course exists first.
    $courseDetails = false;
    if (isset($_GET['course_id']) && ($courseID = $_GET['course_id'])) {
        $courseDetails = WPCW_courses_getCourseDetails($courseID);
    }
    // Course does not exist, simply output an error using plain text.
    if (!$courseDetails) {
        header('Content-Type: text/plain');
        _e('Sorry, but that course could not be found.', 'wp_courseware');
        return;
    }
    // #### 2 - 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) {
        header('Content-Type: text/plain');
        _e('There are no quizzes for this course, therefore no grade information to show.', 'wp_courseware');
        return;
    }
    // Do we want certificates?
    $usingCertificates = 'use_certs' == $courseDetails->course_opt_use_certificate;
    // 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) . ')';
    // Course does exist, so now we really output the data
    WPCW_data_export_sendHeaders_CSV();
    // Start CSV
    $out = fopen('php://output', 'w');
    // #### 3 - The headings for the CSV data
    $headings = array(__('Name', 'wp_courseware'), __('Username', 'wp_courseware'), __('Email Address', 'wp_courseware'), __('Course Progress', 'wp_courseware'), __('Cumulative Grade', 'wp_courseware'), __('Has Grade Been Sent?', 'wp_courseware'));
    // Check if we're using certificates or not.
    if ($usingCertificates) {
        $headings[] = __('Is Certificate Available?', 'wp_courseware');
    }
    // #### 4 - Add the headings for the quiz titles.
    foreach ($quizzesForCourse as $singleQuiz) {
        $headings[] = sprintf('%s (quiz_%d)', $singleQuiz->quiz_title, $singleQuiz->quiz_id);
    }
    // #### 6 - Render the headings
    fputcsv($out, $headings);
    // #### 7 - Select all users that exist for this course
    $SQL = $wpdb->prepare("\n\t\tSELECT * \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\t\t\t\n\t\t", $courseDetails->course_id);
    $userData = $wpdb->get_results($SQL);
    if (!$userData) {
        // All done
        fclose($out);
        return;
    }
    // #### 8 - Render the specific user details.
    foreach ($userData as $userObj) {
        $quizResults = WPCW_quizzes_getQuizResultsForUser($userObj->ID, $quizIDListForSQL);
        // Track cumulative data
        $quizScoresSoFar = 0;
        $quizScoresSoFar_count = 0;
        // Track the quiz scores in order
        $thisUsersQuizData = array();
        // ### 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);
                // We've got something that needs grading.
                if ($theResults->quiz_needs_marking > 0) {
                    $thisUsersQuizData['quiz_' . $aQuizID] = __('Manual Grade Required', 'wp_courseware');
                } else {
                    // Calculate score, and use for cumulative.
                    $score = number_format($theResults->quiz_grade);
                    $quizScoresSoFar += $score;
                    $thisUsersQuizData['quiz_' . $aQuizID] = $score . '%';
                    $quizScoresSoFar_count++;
                }
            } else {
                $thisUsersQuizData['quiz_' . $aQuizID] = __('Not Taken', 'wp_courseware');
            }
        }
        $dataToOutput = array();
        // These must be in the order of the columns specified above for it all to match up.
        $dataToOutput['name'] = $userObj->display_name;
        $dataToOutput['username'] = $userObj->user_login;
        $dataToOutput['email_address'] = $userObj->user_email;
        // Progress Details
        $dataToOutput['course_progress'] = $userObj->course_progress . '%';
        $dataToOutput['cumulative_grade'] = $quizScoresSoFar_count > 0 ? number_format($quizScoresSoFar / $quizScoresSoFar_count, 1) . '%' : __('n/a', 'wp_courseware');
        $dataToOutput['has_grade_been_sent'] = 'sent' == $userObj->course_final_grade_sent ? __('Yes', 'wp_courseware') : __('No', 'wp_courseware');
        // Show if there's a certificate that can be downloaded.
        if ($usingCertificates) {
            $dataToOutput['is_certificate_available'] = __('No', 'wp_courseware');
            if (WPCW_certificate_getCertificateDetails($userObj->ID, $courseDetails->course_id, false)) {
                $dataToOutput['is_certificate_available'] = __('Yes', 'wp_courseware');
            }
        }
        // Output the quiz summary here..
        $dataToOutput += $thisUsersQuizData;
        fputcsv($out, $dataToOutput);
    }
    // All done
    fclose($out);
}
Example #2
0
/**
 * Replace all of the email tags with the actual details.
 * 
 * @param Object $unitParentData The parent data for a unit.
 * @param Object $userDetails The details of the user who's done the completing.
 * @param Array $tagList The list of tags found in the template. 
 * @param String $emailData The data to replace the strings with. 
 * 
 * @return The modified email data ready for sending. 
 */
function WPCW_email_replaceTags_generic($unitParentData, $userDetails, $tagList, $emailData)
{
    if (empty($tagList)) {
        return $emailData;
    }
    // Replace each tag for quiz-related data.
    foreach ($tagList as $tagToReplace) {
        switch ($tagToReplace) {
            case '{USER_NAME}':
                $emailData = str_replace('{USER_NAME}', $userDetails->display_name, $emailData);
                break;
            case '{SITE_NAME}':
                $emailData = str_replace('{SITE_NAME}', get_bloginfo('name'), $emailData);
                break;
            case '{SITE_URL}':
                $emailData = str_replace('{SITE_URL}', get_bloginfo('url'), $emailData);
                break;
            case '{COURSE_TITLE}':
                $emailData = str_replace('{COURSE_TITLE}', $unitParentData->course_title, $emailData);
                break;
            case '{MODULE_TITLE}':
                $moduleTitle = false;
                if (isset($unitParentData->module_title)) {
                    $moduleTitle = $unitParentData->module_title;
                }
                $emailData = str_replace('{MODULE_TITLE}', $moduleTitle, $emailData);
                break;
            case '{MODULE_NUMBER}':
                $moduleNumber = false;
                if (isset($unitParentData->module_number)) {
                    $moduleTitle = $unitParentData->module_number;
                }
                $emailData = str_replace('{MODULE_NUMBER}', $moduleNumber, $emailData);
                break;
            case '{UNIT_TITLE}':
                $emailData = str_replace('{UNIT_TITLE}', get_the_title($unitParentData->unit_id), $emailData);
                break;
            case '{UNIT_URL}':
                $emailData = str_replace('{UNIT_URL}', get_permalink($unitParentData->unit_id), $emailData);
                break;
            case '{CERTIFICATE_LINK}':
                // Certificates - generate a link if enabled.
                $certificateLink = false;
                if ('use_certs' == $unitParentData->course_opt_use_certificate) {
                    $certificateDetails = WPCW_certificate_getCertificateDetails($userDetails->ID, $unitParentData->course_id, false);
                    if ($certificateDetails) {
                        $certificateLink = WPCW_certificate_generateLink($certificateDetails->cert_access_key);
                    }
                }
                $emailData = str_ireplace('{CERTIFICATE_LINK}', $certificateLink, $emailData);
                break;
        }
    }
    return $emailData;
}
    /**
     * Creates a box to show that a unit has been completed.
     * 
     * @return String The HTML that renders this box.
     */
    function render_completionBox_complete()
    {
        $html = false;
        // Work out if course completed.
        // Unit and course is complete, so show course complete message.
        if ($this->userProgress->isCourseCompleted()) {
            $certHTML = false;
            $certificateDetails = WPCW_certificate_getCertificateDetails($this->currentUserID, $this->parentData->course_id);
            // Generate certificate button if enabled and a certificate exists for this user.
            if ('use_certs' == $this->parentData->course_opt_use_certificate && $certificateDetails) {
                $certHTML = sprintf('<div class="wpcw_fe_progress_box_download"><a href="%s" class="fe_btn fe_btn_download">%s</a></div>', WPCW_certificate_generateLink($certificateDetails->cert_access_key), __('Download Certificate', 'wp_courseware'));
            }
            // Course completion message
            $html .= sprintf('<div class="wpcw_fe_progress_box_wrap">
				<div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s%s</div>
			</div>', $certHTML, $this->parentData->course_message_course_complete);
        } else {
            $html = sprintf('<div class="wpcw_fe_progress_box_wrap"><div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s</div></div>', $this->parentData->course_message_unit_complete);
        }
        // Got any quiz status data to show?
        $quizMessageData = $this->render_completionBox_quizPassStatus();
        // Got any custom feedback data to show?
        $customFeedbackMessages = $this->render_customFeedbackMessage_showResults();
        $html .= $quizMessageData . $customFeedbackMessages;
        // Allow non-blocking Quiz Retakes - (as unit is always complete for non-blocking quizzes).
        if ($this->check_quizzes_NonBlockingQuizOffersRetakeButton()) {
            $remainingAttempts = $this->fetch_quizzes_getRemainingAttempts();
            if ($remainingAttempts != 0) {
                if ('quiz_noblock' == $this->unitQuizDetails->quiz_type) {
                    // Show a message about the recommended score.
                    $courseDetails = WPCW_courses_getCourseDetails($this->unitQuizDetails->parent_course_id);
                    if ($this->unitQuizProgress->quiz_needs_marking != 0) {
                        $messageToShow .= $courseDetails->course_message_quiz_open_grading_non_blocking;
                        $showRetakeButton = false;
                    } elseif ('retake_waiting' != $this->unitQuizProgress->quiz_next_step_type) {
                        $messageToShow .= wpautop(sprintf(__('The recommended grade for this quiz is <b>%d%%</b> (and your grade is <b>%d%%</b>). The course instructor has allowed you to retake this quiz if you wish to improve your grade.', 'wp_courseware'), $this->unitQuizDetails->show_recommended_percentage, $this->unitQuizProgress->quiz_grade));
                        $showRetakeButton = true;
                    }
                }
            } else {
                $showRetakeButton = false;
                $messageToShow .= wpautop(__('Unfortunately you have reached the maximum limit of attempts you are permitted for this quiz.', 'wp_courseware'));
            }
            // The retake button (if allowed)
            if ($showRetakeButton) {
                $messageToShow .= sprintf('<div class="wpcw_fe_quiz_retake">
				<div class="wpcw_fe_submit_loader wpcw_loader">
					<img src="%simg/ajax_loader.gif" />
				</div>
				
				<a href="#" class="fe_btn fe_btn_completion btn_completion" data-wpcw_quiz="%d" data-wpcw_unit="%d">%s</a>						
			</div>', WPCW_plugin_getPluginPath(), $this->unitQuizDetails->quiz_id, $this->unitPost->ID, __('Retake Quiz', 'wp_courseware'));
                $html .= WPCW_UnitFrontend::message_createMessage_warning($messageToShow);
            }
            // No quiz progress or we're ready for a retake, so show the quiz to be rendered for completion by the user.
            // Ensure that we render the quiz if we've not yet completed the quiz.
            if (!$this->check_quizzes_hasUserCompletedQuiz() || $this->check_quizzes_areWeWaitingForUserToRetakeQuiz()) {
                $html .= $this->render_quizzes_handleQuizRendering();
            }
        }
        //. $quizMessageData . $customFeedbackMessages . $retakeButtonData
        return $html;
    }
    /**
     * Creates a box to show that a unit has been completed.
     * 
     * @return String The HTML that renders this box.
     */
    function render_completionBox_complete()
    {
        $html = false;
        // Work out if course completed.
        // Unit and course is complete, so show course complete message.
        if ($this->userProgress->isCourseCompleted()) {
            $certHTML = false;
            $certificateDetails = WPCW_certificate_getCertificateDetails($this->currentUserID, $this->parentData->course_id);
            // Generate certificate button if enabled and a certificate exists for this user.
            if ('use_certs' == $this->parentData->course_opt_use_certificate && $certificateDetails) {
                $certHTML = sprintf('<div class="wpcw_fe_progress_box_download"><a href="%s" class="fe_btn fe_btn_download">%s</a></div>', WPCW_certificate_generateLink($certificateDetails->cert_access_key), __('Download Certificate', 'wp_courseware'));
            }
            // Course completion message
            $html .= sprintf('<div class="wpcw_fe_progress_box_wrap">
				<div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s%s</div>
			</div>', $certHTML, $this->parentData->course_message_course_complete);
        } else {
            $html = sprintf('<div class="wpcw_fe_progress_box_wrap"><div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s</div></div>', $this->parentData->course_message_unit_complete);
        }
        // Got any quiz status data to show?
        $quizMessageData = $this->render_completionBox_quizPassStatus();
        // Got any custom feedback data to show?
        $customFeedbackMessages = $this->render_customFeedbackMessage_showResults();
        return $html . $quizMessageData . $customFeedbackMessages;
    }
Example #5
0
/**
 * Replace all of the email tags with the actual details.
 * 
 * @param String $template The template to do the string replace for.
 * @param Object $unitParentData The parent data for a unit.
 * @param Object $userDetails The details of the user who's done the completing.
 */
function WPCW_email_replaceTags($template, $unitParentData, $userDetails)
{
    $message = $template;
    // User Details
    $message = str_ireplace('{USER_NAME}', $userDetails->display_name, $message);
    // Site Details
    $message = str_ireplace('{SITE_NAME}', get_bloginfo('name'), $message);
    $message = str_ireplace('{SITE_URL}', get_bloginfo('url'), $message);
    // Course Details
    $message = str_ireplace('{COURSE_TITLE}', $unitParentData->course_title, $message);
    // Module Details - may not exist.
    if (isset($unitParentData->module_title)) {
        $message = str_ireplace('{MODULE_TITLE}', $unitParentData->module_title, $message);
    }
    if (isset($unitParentData->module_number)) {
        $message = str_ireplace('{MODULE_NUMBER}', $unitParentData->module_number, $message);
    }
    // Certificates - generate a link if enabled.
    $certificateLink = false;
    if ('use_certs' == $unitParentData->course_opt_use_certificate) {
        $certificateDetails = WPCW_certificate_getCertificateDetails($userDetails->ID, $unitParentData->course_id, false);
        if ($certificateDetails) {
            $certificateLink = WPCW_certificate_generateLink($certificateDetails->cert_access_key);
        }
    }
    $message = str_ireplace('{CERTIFICATE_LINK}', $certificateLink, $message);
    return $message;
}
Example #6
0
/**
 * Creates a box to show that a unit has been completed.
 * 
 * @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 been completed.
 * @param Integer $user_id The ID of the user who has just completed the unit.
 */
function WPCW_units_getCompletionBox_complete($parentData, $unitID, $user_id)
{
    // Work out if course completed.
    $userProgress = new UserProgress($parentData->course_id, $user_id);
    $html = false;
    // Unit and course is complete, so show course complete message.
    if ($userProgress->isCourseCompleted()) {
        $certHTML = false;
        $certificateDetails = WPCW_certificate_getCertificateDetails($user_id, $parentData->course_id);
        // Generate certificate button if enabled and a certificate exists for this user.
        if ('use_certs' == $parentData->course_opt_use_certificate && $certificateDetails) {
            $certHTML = sprintf('<div class="wpcw_fe_progress_box_download"><a href="%s" class="fe_btn fe_btn_download">%s</a></div>', WPCW_certificate_generateLink($certificateDetails->cert_access_key), __('Download Certificate', 'wp_courseware'));
        }
        // Course completion message
        $html .= sprintf('<div class="wpcw_fe_progress_box_wrap">
			<div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s%s</div>
		</div>', $certHTML, $parentData->course_message_course_complete);
    } else {
        $html = sprintf('<div class="wpcw_fe_progress_box_wrap"><div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s</div></div>', $parentData->course_message_unit_complete);
    }
    return $html;
}
Example #7
0
/**
 * 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>&nbsp;&nbsp;', 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>&nbsp;&nbsp;', 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 a box to show that a unit has been completed.
     * 
     * @return String The HTML that renders this box.
     */
    function render_completionBox_complete()
    {
        $html = false;
        // Work out if course completed.
        // Unit and course is complete, so show course complete message.
        if ($this->userProgress->isCourseCompleted()) {
            $certHTML = false;
            // GW 150130 echo "Course ".$this->parentData->course_id." of User ".$this->currentUserID. " is complete/d";
            $certificateDetails = WPCW_certificate_getCertificateDetails($this->currentUserID, $this->parentData->course_id);
            // Generate certificate button if enabled and a certificate exists for this user.
            if ('use_certs' == $this->parentData->course_opt_use_certificate && $certificateDetails) {
                $certHTML = sprintf('<div class="wpcw_fe_progress_box_download"><a href="%s" class="fe_btn fe_btn_download">%s</a></div>', WPCW_certificate_generateLink($certificateDetails->cert_access_key), __('Download Certificate', 'wp_courseware'));
            }
            // Course completion message
            $html .= sprintf('<div class="wpcw_fe_progress_box_wrap">
				<div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s%s</div>
			</div>', $certHTML, $this->parentData->course_message_course_complete);
        } else {
            $html = sprintf('<div class="wpcw_fe_progress_box_wrap"><div class="wpcw_fe_progress_box wpcw_fe_progress_box_complete">%s</div></div>', $this->parentData->course_message_unit_complete);
        }
        // Got any quiz status data to show?
        $quizMessageData = $this->render_completionBox_quizPassStatus();
        // Got any custom feedback data to show?
        $customFeedbackMessages = $this->render_customFeedbackMessage_showResults();
        // TODO WORKING HERE #3 - retake button
        // Allow non-blocking Quiz Retakes - (as unit is always complete for non-blocking quizzes).
        /*
        		$messageToShow = false;
        		printf('ERJOASCNLASKNXLKASNCLKAMSD');
        		if ($this->check_quizzes_NonBlockingQuizOffersRetakeButton())
        		{
        			$messageToShow .= sprintf('<div class="wpcw_fe_quiz_retake">
        				<div class="wpcw_fe_submit_loader wpcw_loader">
        					<img src="%simg/ajax_loader.gif" />
        				</div>
        				
        				<a href="#" class="fe_btn fe_btn_completion btn_completion" data-wpcw_quiz="%d" data-wpcw_unit="%d">%s</a>						
        			</div>',
        				WPCW_plugin_getPluginPath(),
        				$this->unitQuizDetails->quiz_id,
        				$this->unitPost->ID,
        				__('Retake Quiz', 'wp_courseware'));
        		}
        
        		// Finally show the message to the user.
        		$retakeButtonData = WPCW_UnitFrontend::message_createMessage_warning($messageToShow);	*/
        return $html . $quizMessageData . $customFeedbackMessages . $retakeButtonData;
    }