Example #1
0
 /**
  * See if there's a course to export based on $_POST variables. If so, trigger the export and XML download.
  * @param Boolean $triggerFileDownload If true, trigger a file download rather than just XML output as a page.
  */
 public static function tryExportCourse($triggerFileDownload = true)
 {
     // See if course is being exported
     if (isset($_POST["update"]) && $_POST["update"] == 'wpcw_export' && current_user_can('manage_options')) {
         // Now check course is valid. If not, then don't do anything, and let
         // normal form handle the errors.
         $courseID = WPCW_arrays_getValue($_POST, 'export_course_id');
         $courseDetails = WPCW_courses_getCourseDetails($courseID);
         if ($courseDetails) {
             $moduleList = false;
             // Work out what details to fetch and then export
             $whatToExport = WPCW_arrays_getValue($_POST, 'what_to_export');
             switch ($whatToExport) {
                 // Just the course title, description and settings (no units or modules)
                 case 'just_course':
                     break;
                     // Just the course settings and module settings (no units)
                 // Just the course settings and module settings (no units)
                 case 'course_modules':
                     $moduleList = WPCW_courses_getModuleDetailsList($courseDetails->course_id);
                     break;
                     // Basically case 'whole_course' - The whole course, modules and units
                 // Basically case 'whole_course' - The whole course, modules and units
                 default:
                     $moduleList = WPCW_courses_getModuleDetailsList($courseDetails->course_id);
                     if ($moduleList) {
                         // Grab units for each module, in the right order, and associate with each module object.
                         foreach ($moduleList as $module) {
                             // This might return false, but that's OK. We'll check for it later.
                             $module->units = WPCW_units_getListOfUnits($module->module_id);
                         }
                     }
                     break;
             }
             // If true, trigger a file download of the XML file.
             if ($triggerFileDownload) {
                 $exportFile = "wp-courseware-export-" . date("Y-m-d") . ".xml";
                 header('Content-Description: File Transfer');
                 header("Content-Disposition: attachment; filename={$exportFile}");
             }
             header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
             // When debugging, comment out the line above, and use the following line so that you can see
             // any error messages.
             // header('Content-Type: text/plain');
             $export = new WPCW_Export();
             echo $export->exportCourseDetails($courseDetails, $moduleList);
             die;
         }
     }
     // If get here, then normal WPCW processing takes place.
 }
 /**
  * Create user progress object.
  * 
  * @param Integer $courseID The ID of the course that we're checking.
  * @param Integer $userID The ID of the user that we're checking.
  */
 function __construct($courseID, $userID)
 {
     $this->courseID = $courseID;
     $this->userID = $userID;
     // Work out if access allowed
     $this->canAccessCourse = WPCW_courses_canUserAccessCourse($this->courseID, $this->userID);
     // Work out if want walled access to units
     $this->userCanOnlyAccessNext = false;
     $courseDetails = WPCW_courses_getCourseDetails($this->courseID);
     // Completion wall is set, so need to stop access to all units.
     if ($courseDetails && 'completion_wall' == $courseDetails->course_opt_completion_wall) {
         $this->userCanOnlyAccessNext = true;
     }
     // Get the next item user is allowed to access
     $this->nextUnitLoaded = false;
     $this->nextUnit = false;
 }
/**
 * Delete a module and disassociating of the units that it contains.
 * 
 * @param Object $moduleDetails The details of the module to delete.
 */
function WPCW_modules_deleteModule($moduleDetails)
{
    if (!$moduleDetails) {
        return;
    }
    global $wpdb, $wpcwdb;
    $wpdb->show_errors();
    // Remove association with all units for this module
    $unitList = WPCW_units_getListOfUnits($moduleDetails->module_id);
    if ($unitList) {
        // Unassociate units from this module
        $SQL = $wpdb->prepare("\n\t\t\tUPDATE {$wpcwdb->units_meta}\n\t\t\t   SET unit_order = 0, parent_module_id = 0, parent_course_id = 0, unit_number = 0\n\t\t\tWHERE parent_module_id = %d\n\t\t", $moduleDetails->module_id);
        // Update database with new association and ordering.
        foreach ($unitList as $unitID => $unitObj) {
            $wpdb->query($SQL);
            // Update post meta to remove associated module detail
            update_post_meta($unitID, 'wpcw_associated_module', 0);
            // Remove progress for this unit, since unit is now unassociated.
            $SQL = $wpdb->prepare("\n\t\t\t\tDELETE FROM {$wpcwdb->user_progress}\n\t\t\t\tWHERE unit_id = %d\n\t\t\t", $unitID);
            $wpdb->query($SQL);
        }
    }
    // Perform module deletion here.
    $wpdb->query($SQL = $wpdb->prepare("\n\t\t\t\tDELETE FROM {$wpcwdb->modules}\n\t\t\t\tWHERE module_id = %d\n\t\t\t", $moduleDetails->module_id));
    // Modules have changed for this course, update numbering
    do_action('wpcw_modules_modified', $moduleDetails->parent_course_id);
    // Course has been updated, update the progress details
    $courseDetails = WPCW_courses_getCourseDetails($moduleDetails->parent_course_id);
    if ($courseDetails) {
        do_action('wpcw_course_details_updated', $courseDetails);
    }
    // Trigger event that module has been deleted
    do_action('wpcw_module_deleted', $moduleDetails);
}
Example #4
0
 /**
  * See if there's a course to export based on $_POST variables. If so, trigger the export and XML download.
  * @param Boolean $triggerFileDownload If true, trigger a file download rather than just XML output as a page.
  */
 public static function tryExportCourse($triggerFileDownload = true)
 {
     // See if course is being exported
     if (isset($_POST["update"]) && $_POST["update"] == 'wpcw_export' && current_user_can('manage_options')) {
         // Now check course is valid. If not, then don't do anything, and let
         // normal form handle the errors.
         $courseID = WPCW_arrays_getValue($_POST, 'export_course_id');
         $courseDetails = WPCW_courses_getCourseDetails($courseID);
         if ($courseDetails) {
             $moduleList = false;
             $questionList = false;
             // Work out what details to fetch and then export
             $whatToExport = WPCW_arrays_getValue($_POST, 'what_to_export');
             switch ($whatToExport) {
                 // Course Settings: Yes
                 // Module Settings: No
                 // 			 Units: No
                 // 	 	   Quizzes: No
                 case 'just_course':
                     break;
                     // Course Settings: Yes
                     // Module Settings: Yes
                     // 			 Units: No
                     // 	 	   Quizzes: No
                 // Course Settings: Yes
                 // Module Settings: Yes
                 // 			 Units: No
                 // 	 	   Quizzes: No
                 case 'course_modules':
                     $moduleList = WPCW_courses_getModuleDetailsList($courseDetails->course_id);
                     break;
                     // Course Settings: Yes
                     // Module Settings: Yes
                     // 			 Units: Yes
                     // 	 	   Quizzes: No
                 // Course Settings: Yes
                 // Module Settings: Yes
                 // 			 Units: Yes
                 // 	 	   Quizzes: No
                 case 'course_modules_and_units':
                     $moduleList = WPCW_courses_getModuleDetailsList($courseDetails->course_id);
                     if ($moduleList) {
                         // Grab units for each module, in the right order, and associate with each module object.
                         foreach ($moduleList as $module) {
                             // This might return false, but that's OK. We'll check for it later.
                             $module->units = WPCW_units_getListOfUnits($module->module_id);
                         }
                     }
                     break;
                     // Basically the whole course
                     // Course Settings: Yes
                     // Module Settings: Yes
                     // 			 Units: Yes
                     // 	 	   Quizzes: Yes
                 // Basically the whole course
                 // Course Settings: Yes
                 // Module Settings: Yes
                 // 			 Units: Yes
                 // 	 	   Quizzes: Yes
                 default:
                     $questionList = WPCW_questions_getAllQuestionsforCourse($courseDetails->course_id);
                     $moduleList = WPCW_courses_getModuleDetailsList($courseDetails->course_id);
                     if ($moduleList) {
                         // Grab units for each module, in the right order, and associate with each module object.
                         foreach ($moduleList as $module) {
                             // This might return false, but that's OK. We'll check for it later.
                             $module->units = WPCW_units_getListOfUnits($module->module_id);
                             // See if we have any units, and then check each for the associated quiz data.
                             // Update the unit objects with details of the quizzes
                             WPCW_Export::WPCW_quizzes_fetchQuizzesForUnits($module->units);
                         }
                     }
                     break;
             }
             // TODO ZZZ - DEBUG Tool - To enable debugging, comment this in so that the download is not triggered.
             $triggerFileDownload = true;
             // If true, trigger a file download of the XML file.
             if ($triggerFileDownload) {
                 $exportFile = "wp-courseware-export-" . sanitize_title($courseDetails->course_title) . '-' . date("Y-m-d") . ".xml";
                 header('Content-Description: File Transfer');
                 header("Content-Disposition: attachment; filename={$exportFile}");
                 header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
             } else {
                 // When debugging, comment out the line above, and use the following line so that you can see
                 // any error messages.
                 header('Content-Type: text/plain');
             }
             $export = new WPCW_Export();
             echo $export->exportCourseDetails($courseDetails, $moduleList, $questionList);
             die;
         }
     }
     // If get here, then normal WPCW processing takes place.
 }
Example #5
0
/**
 * Function called when the unit ordering is being saved via AJAX.
 * This function will save the order of the modules, units and any unassigned units.
 * 
 */
function WPCW_AJAX_handleUnitOrderingSaving()
{
    // Security check
    if (!wp_verify_nonce(WPCW_arrays_getValue($_POST, 'order_nonce'), 'wpcw-order-nonce')) {
        die(__('Security check failed!', 'wp_courseware'));
    }
    // Get list of modules to save, check IDs are what we expect, and abort if nothing to do.
    $moduleList = WPCW_arrays_getValue($_POST, 'moduleList');
    if (!$moduleList || count($moduleList) < 1) {
        die;
    }
    global $wpdb, $wpcwdb;
    $wpdb->show_errors();
    $parentCourseID = 0;
    // Save new module ordering to database
    $moduleOrderCount = 0;
    // Ordering of units is absolute to the whole course
    $unitOrderCount = 0;
    //error_log(print_r($_POST, true));
    // Need a course ID for resetting the ordering.
    foreach ($moduleList as $moduleID) {
        // Validate we have an actual module
        if (preg_match('/^wpcw_mod_(\\d+)$/', $moduleID, $matches)) {
            // Get course ID from module
            $moduleDetails = WPCW_modules_getModuleDetails($matches[1]);
            if ($moduleDetails) {
                $parentCourseID = $moduleDetails->parent_course_id;
                break;
            }
        }
    }
    // If there's no associated parent course, there's an issue.
    if (!$parentCourseID) {
        error_log('WPCW_AJAX_handleUnitOrderingSaving(). No associated parent course ID, so aborting.');
        die;
    }
    // 2013-05-01 - Bug with orphan modules being left in the units_meta
    // Fix - Clean out existing units in this course, resetting them.
    // Then update the ordering using the loops below.
    $SQL = $wpdb->prepare("\n\t\tUPDATE {$wpcwdb->units_meta}\n\t\t   SET unit_order = 0, parent_module_id = 0, \n\t\t   \t   parent_course_id = 0, unit_number = 0\n\t\tWHERE parent_course_id = %d\n\t", $parentCourseID);
    $wpdb->query($SQL);
    foreach ($moduleList as $moduleID) {
        // ### Check module name matches expected format.
        if (preg_match('/^wpcw_mod_(\\d+)$/', $moduleID, $matches)) {
            $moduleOrderCount++;
            $moduleIDClean = $matches[1];
            // Update module list with new ordering
            $SQL = $wpdb->prepare("\n\t\t\t\tUPDATE {$wpcwdb->modules}\n\t\t\t\t   SET module_order = %d, module_number = %d\n\t\t\t\tWHERE module_id = %d\n\t\t\t", $moduleOrderCount, $moduleOrderCount, $moduleIDClean);
            $wpdb->query($SQL);
            // ### Check units associated with this module
            $unitList = WPCW_arrays_getValue($_POST, $moduleID);
            if ($unitList && count($unitList) > 0) {
                $unitNumber = 0;
                foreach ($unitList as $unitID) {
                    $unitNumber++;
                    // Check unit name matches expected format.
                    if (preg_match('/^wpcw_unit_(\\d+)$/', $unitID, $matches)) {
                        $unitOrderCount += 10;
                        $unitIDClean = $matches[1];
                        // Update database with new association and ordering.
                        $SQL = $wpdb->prepare("\n\t\t\t\t\t\t\tUPDATE {$wpcwdb->units_meta}\n\t\t\t\t\t\t\t   SET unit_order = %d, parent_module_id = %d, \n\t\t\t\t\t\t\t   \t   parent_course_id = %d, unit_number = %d\n\t\t\t\t\t\t\tWHERE unit_id = %d\n\t\t\t\t\t\t", $unitOrderCount, $moduleIDClean, $parentCourseID, $unitNumber, $unitIDClean);
                        $wpdb->query($SQL);
                        // 2013-05-01 - Updated to use the module ID, rather than the module order.
                        update_post_meta($unitIDClean, 'wpcw_associated_module', $moduleIDClean);
                    }
                }
                // end foreach
            }
            // end of $unitList check
        }
    }
    // #### Check for any units that have associated quizzes
    foreach ($_POST as $key => $value) {
        // Check any post value that has a unit in it
        if (preg_match('/^wpcw_unit_(\\d+)$/', $key, $matches)) {
            $unitIDClean = $matches[1];
            // Try to extract the unit ID
            // [wpcw_unit_71] => Array
            // (
            //	[0] => wpcw_quiz_2
            //)
            $quizIDRaw = false;
            if ($value && is_array($value)) {
                $quizIDRaw = $value[0];
            }
            // Got a matching quiz ID
            if (preg_match('/^wpcw_quiz_(\\d+)$/', $quizIDRaw, $matches)) {
                $quizIDClean = $matches[1];
                // Grab parent course ID from unit. Can't assume all units are in same course.
                $parentData = WPCW_units_getAssociatedParentData($unitIDClean);
                $parentCourseID = $parentData->parent_course_id;
                // Update database with new association and ordering.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->quiz}\n\t\t\t\t\t   SET parent_unit_id = %d, parent_course_id = %d\n\t\t\t\t\tWHERE quiz_id = %d\n\t\t\t\t", $unitIDClean, $parentCourseID, $quizIDClean);
                $wpdb->query($SQL);
                // Add new associated unit information to the user quiz progress,
                // keeping any existing quiz results.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->user_progress_quiz}\n\t\t\t\t\t   SET unit_id = %d\n\t\t\t\t\tWHERE quiz_id = %d\n\t\t\t\t", $unitIDClean, $quizIDClean);
                $wpdb->query($SQL);
            }
        }
    }
    // #### Check for any unassigned units, and ensure they're de-associated from modules.
    $unitList = WPCW_arrays_getValue($_POST, 'unassunits');
    if ($unitList && count($unitList) > 0) {
        foreach ($unitList as $unitID) {
            // Check unit name matches expected format.
            if (preg_match('/^wpcw_unit_(\\d+)$/', $unitID, $matches)) {
                $unitIDClean = $matches[1];
                // Update database with new association and ordering.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->units_meta}\n\t\t\t\t\t   SET unit_order = 0, parent_module_id = 0, parent_course_id = 0, unit_number = 0\n\t\t\t\t\tWHERE unit_id = %d\n\t\t\t\t", $unitIDClean);
                $wpdb->query($SQL);
                // Update post meta to remove associated module detail
                update_post_meta($unitIDClean, 'wpcw_associated_module', 0);
                // Remove progress for this unit, as likely to be associated with something else.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tDELETE FROM {$wpcwdb->user_progress}\n\t\t\t\t\tWHERE unit_id = %d\n\t\t\t\t", $unitIDClean);
                $wpdb->query($SQL);
            }
        }
        // end foreach ($unitList as $unitID)
    }
    // #### Check for any unassigned quizzes, and ensure they're de-associated from units.
    $quizList = WPCW_arrays_getValue($_POST, 'unassquizzes');
    if ($quizList && count($quizList) > 0) {
        foreach ($quizList as $quizID) {
            // Check unit name matches expected format.
            if (preg_match('/^wpcw_quiz_(\\d+)$/', $quizID, $matches)) {
                $quizIDClean = $matches[1];
                // Update database with new association and ordering.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->quiz}\n\t\t\t\t\t   SET parent_unit_id = 0, parent_course_id = 0\n\t\t\t\t\tWHERE quiz_id = %d\n\t\t\t\t", $quizIDClean);
                $wpdb->query($SQL);
                // Remove the associated unit information from the user quiz progress.
                // But keep the quiz results for now.
                $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->user_progress_quiz}\n\t\t\t\t\t   SET unit_id = 0\n\t\t\t\t\tWHERE quiz_id = %d\n\t\t\t\t", $quizIDClean);
                $wpdb->query($SQL);
            }
        }
        // end foreach ($quizList as $quizID)
    }
    // Update course details
    $courseDetails = WPCW_courses_getCourseDetails($parentCourseID);
    if ($courseDetails) {
        do_action('wpcw_course_details_updated', $courseDetails);
    }
    //error_log(print_r($matches, true));
    die;
}
/**
 * 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>&nbsp;&nbsp;', admin_url('users.php'), __('&laquo; 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>&nbsp;&nbsp;', admin_url('users.php?page=WPCW_showPage_UserProgess'), $userDetails->ID, sprintf(__('&laquo; 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>&nbsp;&nbsp;', admin_url('admin.php?page=WPCW_showPage_GradeBook'), $quizDetails->parent_course_id, __("&laquo; 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();
}
 /**
  * Checks the supplied answers to see which questions are correct.
  * 
  * @return Boolean Returns true if the trainee can continue (either passed in blocking, or survey/non-blocking), false otherwise.
  */
 function check_quizzes_gradeQuestionsForQuiz()
 {
     // Use the quiz answers that need grading, stored in the local variable.
     $resultsList = $this->unchecked_QuizAnswersToGrade;
     $resultDetails = array('correct' => array(), 'wrong' => array());
     // Flag to indicate if grading is needed before the user continues.
     $gradingNeeded = false;
     $gradingNeededBeforeContinue = false;
     // If true, then we notify the user of the grade.
     $quizGradeNotificationNeeded = false;
     // ### 3 - Do we need to check for correct answers?
     if ('survey' == $this->unitQuizDetails->quiz_type) {
         // Show answers only if this is a survey where we want trainees to see the results.
         // @since V2.90
         $this->unitQuizDetails->quiz_show_answers = 'hide_answers';
         if ('show_responses' == $this->unitQuizDetails->quiz_show_survey_responses) {
             $this->unitQuizDetails->quiz_show_answers = 'show_answers';
         }
         // No answers to check. Say thanks
         echo WPCW_UnitFrontend::message_createMessage_success(__('Thank you for your responses. This unit is now complete.', 'wp_courseware'));
     } else {
         $resultDetails = $this->check_quizzes_checkForCorrectAnswers($resultsList['answer_list']);
         // #### Step A - have open-ended questions that need marking.
         if (!empty($resultDetails['needs_marking'])) {
             $gradingNeeded = true;
             $courseDetails = WPCW_courses_getCourseDetails($this->unitQuizDetails->parent_course_id);
             // Non-blocking quiz - so allowed to continue, but will be graded later.
             if ('quiz_block' == $this->unitQuizDetails->quiz_type) {
                 // Grading is needed before they continue, but don't want them to re-take the quiz.
                 $gradingNeededBeforeContinue = true;
             }
         } else {
             // Copy over the wrong answers.
             $resultsList['wrong_answer_list'] = $resultDetails['wrong'];
             // Some statistics
             $correctCount = count($resultDetails['correct']);
             $totalQuestions = count($this->unitQuizDetails->questions);
             $correctPercentage = number_format($correctCount / $totalQuestions * 100, 1);
             // Non-blocking quiz.
             if ('quiz_noblock' == $this->unitQuizDetails->quiz_type) {
                 // Store user quiz results
                 // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes.
                 /*
                 					echo WPCW_UnitFrontend::message_createMessage_success(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'),
                 							$correctCount, $totalQuestions, $correctPercentage
                 						))*/
                 // Notify the user of their grade.
                 $quizGradeNotificationNeeded = true;
             } else {
                 // 2014-01-15 - Added ceil() calculation to ensure calculation is consistent when showing the quiz title
                 // above around the .wpcw_fe_quiz_title div.
                 $minPassQuestions = ceil($this->unitQuizDetails->quiz_pass_mark / 100 * $totalQuestions);
                 // They've passed. Report how many they got right.
                 if ($correctPercentage >= $this->unitQuizDetails->quiz_pass_mark) {
                     // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes.
                     /*echo WPCW_UnitFrontend::message_createMessage_success(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'),
                     			$correctCount, $totalQuestions, $correctPercentage
                     		));*/
                     // Notify the user of their grade.
                     $quizGradeNotificationNeeded = true;
                 } else {
                     // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes.
                     // Show error that they've failed
                     /*echo WPCW_UnitFrontend::message_createMessage_error(
                     			sprintf(__('Unfortunately, you only got <b>%d out of %d (%d%%)</b> questions correct. You need to correctly answer <b>at least %d questions (%d%%)</b>.', 'wp_courseware'),
                     			$correctCount, $totalQuestions, $correctPercentage,
                     			$minPassQuestions, $this->unitQuizDetails->quiz_pass_mark
                     		));*/
                     // Save the user progress anyway, so that we can record attempts.
                     $this->update_quizzes_saveUserProgress_completeQuiz($resultDetails, $resultsList['answer_list']);
                     // Have they run out of quiz attempts? If so, we need to notify the admin and mark the latest attempt
                     // as being the the last blocked one they can use.
                     if (!$this->check_quizzes_canUserRequestRetake()) {
                         // Update progress in database with next new step.
                         $this->update_quizzes_setNextStepData('quiz_fail_no_retakes', false);
                         // Notify the admin that this user is blocked and needs unblocking
                         do_action('wpcw_quiz_user_needs_unblocking', $this->currentUserID, $this->unitQuizDetails);
                     }
                     // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes.
                     // How many attempts have they now had?
                     /*
                     						$attemptCount = $this->fetch_quizzes_getQuizAttemptCount();
                     						echo WPCW_UnitFrontend::message_createMessage_error(
                     							($attemptCount == 1 
                     									? __('You have already had 1 previous attempt at this quiz.', 'wp_courseware')  
                     									: sprintf(__('You have already had %d previous attempts at this quiz.', 'wp_courseware'), $attemptCount)
                     						));*/
                     // 2014-07-11 - Deprecated. Now being generated by the message summary for quizzes.
                     // If quiz is a no-answers quiz, show the form without the errors, so that the user cannot keep guesssing to pass.
                     //echo $this->render_quizzes_old_handleQuizRendering($resultsList, ('no_answers' != $this->unitQuizDetails->quiz_show_answers));
                     // Errors, so the user cannot progress yet.
                     return false;
                 }
             }
             // end of blocking quiz check
         }
     }
     // end of survey check
     // ### 4 - Save the user progress
     $this->update_quizzes_saveUserProgress_completeQuiz($resultDetails, $resultsList['answer_list']);
     // ### 5 - Notify the user of their grade.
     if ($quizGradeNotificationNeeded) {
         do_action('wpcw_quiz_graded', $this->currentUserID, $this->unitQuizDetails, false, false);
     }
     // Questions need grading, notify the admin
     if ($gradingNeeded) {
         // Notify the admin that questions need answering.
         do_action('wpcw_quiz_needs_grading', $this->currentUserID, $this->unitQuizDetails);
     }
     // Questions need grading, so don't allow user to continue
     if ($gradingNeededBeforeContinue) {
         return false;
     }
     // If we get this far, the user may progress to next unit
     return true;
 }
Example #8
0
/**
 * 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 &amp; 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();
}
Example #9
0
/**
 * Function that creates a list of units.
 * 
 * @param Integer $courseID The ID of the course to show.
 * @param Array $options The list of options to show.
 */
function WPCW_courses_renderCourseList($courseID, $options)
{
    extract(shortcode_atts(array('module' => 0, 'module_desc' => false, 'show_title' => false, 'show_desc' => false, 'widget_mode' => false, 'show_toggle_col' => false, 'show_modules_previous' => 'all', 'show_modules_next' => 'all', 'toggle_modules' => 'expand_all'), $options));
    // Check settings to to see if they are true
    $module_desc = $module_desc == 'true';
    $show_title = $show_title == 'true';
    $show_desc = $show_desc == 'true';
    $courseDetails = false;
    $parentData = false;
    global $post;
    // Show course based on current location for user. Use the currently shown post
    // to work out which course to show using the associated parent data.
    if ('current' == $courseID) {
        $parentData = WPCW_units_getAssociatedParentData($post->ID);
        if ($parentData) {
            $courseDetails = WPCW_courses_getCourseDetails($parentData->parent_course_id);
            $courseID = $parentData->parent_course_id;
        } else {
            return false;
        }
    } else {
        // Check course ID is valid
        $courseDetails = WPCW_courses_getCourseDetails($courseID);
        if (!$courseDetails) {
            return __('Unrecognised course ID.', 'wp_courseware');
        }
        // Course ID is fine, get associated parent data for
        // hiding aspects of the widget
        $parentData = WPCW_units_getAssociatedParentData($post->ID);
    }
    $moduleList = false;
    // Do we just want a single module?
    if ($module > 0) {
        // Get module by module number within course (not the module ID)
        $moduleDetailsSingle = WPCW_modules_getModuleDetails_byModuleNumber($courseDetails->course_id, $module);
        if (!$moduleDetailsSingle) {
            return __('Could not find module.', 'wp_courseware');
        }
        // Create module list of 1 using single module
        $moduleList[$moduleDetailsSingle->module_id] = $moduleDetailsSingle;
    } else {
        // Check there are modules
        $moduleList = WPCW_courses_getModuleDetailsList($courseID);
        if (!$moduleList) {
            return __('There are no modules in this training course.', 'wp_courseware');
        }
    }
    $html = false;
    // #### Show course title/description
    if ($show_title) {
        $html .= sprintf('<div class="wpcw_fe_course_title">%s</div>', $courseDetails->course_title);
    }
    if ($show_desc) {
        $html .= sprintf('<div class="wpcw_fe_course_desc">%s</div>', $courseDetails->course_desc);
    }
    $html .= '<table id="wpcw_fe_course" cellspacing="0" cellborder="0">';
    $showUnitLinks = false;
    // If true, show links to the units
    $colCount = 2;
    // Number of columns in the table
    // UP Object to determine what to show to the user.
    $userProgress = false;
    // Check user is logged in, and if they can access this course
    $user_id = get_current_user_id();
    if ($user_id != 0) {
        $userProgress = new UserProgress($courseID, $user_id);
        // Show links for user if they are allowed to access this course.
        if ($userProgress->canUserAccessCourse()) {
            // User is logged in and can do course, so show the stuff they can do.
            $showUnitLinks = true;
            // Got an extra column to show progress
            $colCount = 3;
        }
    }
    // If we're showing a widget, and we have the parent data based on the
    // currently viewed unit, then change what's in the widget in terms
    // of previous/next units.
    $hideList = array();
    if ($widget_mode && $module == 0 && $parentData) {
        // Build a list of the modules before and after the current
        // module, so that we can more easily control what's visible,
        // and what's not.
        $modulesBefore = array();
        $modulesAfter = array();
        $currentList =& $modulesBefore;
        foreach ($moduleList as $moduleID => $moduleObj) {
            // Switch lists, we've found the current module
            if ($moduleID == $parentData->parent_module_id) {
                $currentList =& $modulesAfter;
            } else {
                $currentList[] = $moduleID;
            }
        }
        // Handle showing previous modules
        switch ($show_modules_previous) {
            // All all items in the before list to be hidden
            case 'none':
                $hideList = array_merge($hideList, $modulesBefore);
                break;
            case 'all':
                break;
                // Keep a specific number of modules to show.
            // Keep a specific number of modules to show.
            default:
                $show_modules_previous += 0;
                $modulesToPickFrom = count($modulesBefore);
                // Remove the modules at the start of the list, leaving the right number of
                // $show_modules_previous modules in the list.
                if ($show_modules_previous > 0 && $modulesToPickFrom > $show_modules_previous) {
                    $hideList = array_merge($hideList, array_slice($modulesBefore, 0, $modulesToPickFrom - $show_modules_previous));
                }
                break;
        }
        // end switch
        // Handle showing the next modules.
        switch ($show_modules_next) {
            // All all items in the after list to be hidden
            case 'none':
                $hideList = array_merge($hideList, $modulesAfter);
                break;
            case 'all':
                break;
                // Keep a specific number of modules to show.
            // Keep a specific number of modules to show.
            default:
                $show_modules_next += 0;
                $modulesToPickFrom = count($modulesAfter);
                // Remove the modules at the start of the list, leaving the right number of
                // $show_modules_previous modules in the list.
                if ($show_modules_next > 0 && $modulesToPickFrom > $show_modules_next) {
                    $hideList = array_merge($hideList, array_slice($modulesAfter, $show_modules_next));
                }
                break;
        }
        // end switch
    }
    // Columns for marking item as being pending or complete.
    $progress_Complete = '<td class="wpcw_fe_unit_progress wpcw_fe_unit_progress_complete"><span>&nbsp;</span></td>';
    $progress_Pending = '<td class="wpcw_fe_unit_progress wpcw_fe_unit_progress_incomplete"><span>&nbsp;</span></td>';
    $progress_Blank = '<td class="wpcw_fe_unit_progress"><span>&nbsp;</span></td>';
    // Show modules
    foreach ($moduleList as $moduleID => $moduleObj) {
        // See if we're skipping this module
        if (in_array($moduleID, $hideList)) {
            continue;
        }
        // If $collapseTitleArea is set to true, then the module will be collapsed. So just check what to hide
        // based on the contents of $toggle_modules
        $collapseTitleArea = false;
        if ($widget_mode && $parentData) {
            switch ($toggle_modules) {
                case 'contract_all':
                    $collapseTitleArea = true;
                    break;
                    // See if the currently visible unit module is the one being rendered.
                // See if the currently visible unit module is the one being rendered.
                case 'contract_all_but_current':
                    $collapseTitleArea = $moduleID != $parentData->parent_module_id;
                    break;
                    // Default is not to collapse.
            }
        }
        // We're showing the toggle section, so add it.
        if ($show_toggle_col) {
            $moduleTitleArea = false;
            $moduleTitleArea = sprintf('<td>%s</td><td class="wpcw_fe_toggle">%s</td>', $moduleObj->module_title, $collapseTitleArea ? '+' : '-');
        } else {
            $moduleTitleArea = sprintf('<td colspan="%d">%s</td>', $colCount - 1, $moduleObj->module_title);
        }
        // Render final title bit
        $html .= sprintf('<tr class="wpcw_fe_module %s" id="wpcw_fe_module_group_%d">
							<td>%s %d</td>
							' . $moduleTitleArea . '			
						</tr>', $collapseTitleArea ? 'wpcw_fe_module_toggle_hide' : '', $moduleObj->module_number, __('Module', 'wp_courseware'), $moduleObj->module_number, $moduleTitleArea);
        // ### Showing the module descriptions?
        if ($module_desc) {
            $html .= sprintf('<tr class="wpcw_fe_module_des"><td colspan="%d">%s</td></tr>', $colCount, $moduleObj->module_desc);
        }
        // Add the class for the row that matches the parent module ID.
        $moduleRowClass = ' wpcw_fe_module_group_' . $moduleObj->module_number;
        // ### No Units Line
        $units = WPCW_units_getListOfUnits($moduleID);
        if (!$units) {
            $extraColSpan = 0;
            if ($show_toggle_col) {
                $extraColSpan = 1;
            }
            $html .= sprintf('<tr class="wpcw_fe_unit wpcw_fe_unit_none %s">
						<td colspan="%d">%s</td>
					  </tr>', $moduleRowClass, $colCount + $extraColSpan, __('There are no units in this module.', 'wp_courseware'));
        } else {
            // Render each unit
            foreach ($units as $unit) {
                $progressRow = false;
                $progressCol = false;
                // Show links for units
                if ($showUnitLinks) {
                    // Yes we are showing progress data... see what state we're at.
                    if ($userProgress) {
                        if ($userProgress->isUnitCompleted($unit->ID)) {
                            $progressCol = $progress_Complete;
                            $progressRow = 'wpcw_fe_unit_complete';
                        } else {
                            $progressCol = $progress_Pending;
                            $progressRow = 'wpcw_fe_unit_pending';
                        }
                        //$progressCol = ($userProgress->isUnitCompleted($unit->ID) ? $progress_Complete : $progress_Pending);
                    }
                    // See if the user is allowed to access this unit or not.
                    if ($userProgress->canUserAccessUnit($unit->ID)) {
                        // Main unit title, link and unit number
                        $html .= sprintf('
							<tr class="wpcw_fe_unit ' . $progressRow . $moduleRowClass . '">
								<td>%s %d</td>
								<td class="wpcw_fe_unit"><a href="%s">%s</a></td>
								' . $progressCol . '
							</tr>', __('Unit', 'wp_courseware'), $unit->unit_meta->unit_number, get_permalink($unit->ID), $unit->post_title);
                    } else {
                        // If we're not allowed to access the unit, then it's always marked as pending.
                        $html .= sprintf('
							<tr class="wpcw_fe_unit ' . $progressRow . $moduleRowClass . '">
								<td>%s %d</td>
								<td class="wpcw_fe_unit">%s</td>
								' . $progress_Pending . '
							</tr>', __('Unit', 'wp_courseware'), $unit->unit_meta->unit_number, $unit->post_title);
                    }
                } else {
                    $colspan = 1;
                    if ($show_toggle_col) {
                        $colspan = 2;
                    }
                    $html .= sprintf('
					<tr class="wpcw_fe_unit ' . $progressRow . $moduleRowClass . '">
						<td>%s %d</td>
						<td colspan="%d" class="wpcw_fe_unit">%s</td>
					</tr>', __('Unit', 'wp_courseware'), $unit->unit_meta->unit_number, $colspan, $unit->post_title);
                }
            }
        }
        // end show units
    }
    $html .= '</table>';
    // Add powered by link
    $settings = TidySettings_getSettings(WPCW_DATABASE_SETTINGS_KEY);
    $html .= WPCW_generatedPoweredByLink($settings);
    return $html;
}
Example #10
0
 /**
  * Try to load details using a single unit.
  * @param Integer $unitID The ID of the unit to use to load details for this course.
  */
 public function loadDetails_byUnitID($unitID)
 {
     global $wpcwdb, $wpdb;
     $wpdb->show_errors();
     // Get a list of all units for this course in absolute order
     $parentCourseID = $wpdb->get_var($wpdb->prepare("\n\t\t\tSELECT parent_course_id\n\t\t\tFROM {$wpcwdb->units_meta}\n\t\t\tWHERE unit_id = %d\t\t\t\n\t\t", $unitID));
     $this->courseDetails = WPCW_courses_getCourseDetails($parentCourseID);
     $this->loadUnitsForCourse();
 }
/**
 * Page where the modules of a course can be ordered.
 */
function WPCW_showPage_CourseOrdering_load()
{
    $page = new PageBuilder(false);
    $page->showPageHeader(__('Order Course Modules &amp; 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();
}
Example #12
0
 /**
  * Function that performs the actual course import.
  * @return Integer The ID of the newly imported course.
  */
 public function importCourseIntoDatabase()
 {
     if (!current_user_can('manage_options')) {
         return $this->returnErrorList(__('Sorry, you\'re not allowed to import courses into WordPress.', 'wp_courseware'));
     }
     // ### 1) Extract XML data into a clean array of information.
     // The functions below may handle detailed verification of data in
     // future releases.
     $courseData = $this->loadCourseData();
     $moduleData = $this->loadModuleData();
     // ### 2) Turn the course into an actual database entry
     if (count($courseData) == 0) {
         return $this->returnErrorList(__('There was no course data to import.', 'wp_courseware'));
     }
     global $wpdb, $wpcwdb;
     $wpdb->show_errors();
     $queryResult = $wpdb->query(arrayToSQLInsert($wpcwdb->courses, $courseData));
     // Check query succeeded.
     if ($queryResult === FALSE) {
         return $this->returnErrorList(__('Could not create course in database.', 'wp_courseware'));
     }
     $this->course_id = $wpdb->insert_id;
     // Track how many units we add
     $unitCount = 0;
     $this->unit_order = 0;
     // ### 3) Check for the module data, and then try to add this
     if ($moduleData) {
         $moduleCount = 0;
         foreach ($moduleData as $moduleItem) {
             // Extract Unit Data from module info, so it doesn't interfere with database add
             $unitData = $moduleItem['units'];
             unset($moduleItem['units']);
             $moduleCount++;
             // Add parent course details, plus order details.
             $moduleItem['parent_course_id'] = $this->course_id;
             $moduleItem['module_order'] = $moduleCount;
             $moduleItem['module_number'] = $moduleCount;
             $queryResult = $wpdb->query(arrayToSQLInsert($wpcwdb->modules, $moduleItem));
             // Check query succeeded.
             if ($queryResult === FALSE) {
                 return $this->returnErrorList(__('There was a problem inserting the module into the database.', 'wp_courseware'));
             }
             $currentModuleID = $wpdb->insert_id;
             // ### 4) Check for any units
             $unitCount += $this->addUnitsToDatabase($unitData, $currentModuleID);
         }
     }
     // end if $moduleData
     // Update unit counts
     // 31st May 2013 - V1.26 - Fix - Incorrectly referring to $course_id - which is empty.
     // Changed to $this->course_id to fix issue.
     $courseDetails = WPCW_courses_getCourseDetails($this->course_id);
     do_action('wpcw_course_details_updated', $courseDetails);
 }
Example #13
0
/**
 * Having entered some details into the quiz, may the user progress to the next unit? If
 * there are any problems with the quiz, then they are dealt with via AJAX.
 * 
 * @param Object $quizDetails The potential quiz details.
 * @param Array $potentialAnswers The potential answers that need checking. 
 * @param Integer $userID The ID of the user that we're saving progress for.
 * 
 * @return Boolean True if the user may progress, false otherwise.
 */
function WPCW_quizzes_handleQuizRendering_canUserContinueAfterQuiz($quizDetails, $potentialAnswers, $userID)
{
    $resultsList = array('answer_list' => array(), 'wrong_answer_list' => array(), 'error_answer_list' => array());
    $resultDetails = array('correct' => array(), 'wrong' => array());
    // #### 1A Extract a list of actual answers from the potential answers. There will
    // be some noise in that data.
    foreach ($potentialAnswers as $key => $value) {
        // Only considering answers to questions. Format of answer field is:
        // question_16_truefalse_48 (first ID is quiz, 2nd ID is question, middle string
        // is the question type.
        if (preg_match('/^question_(\\d+)_([a-z]+)_(\\d+)$/', $key, $matches)) {
            $quizID = $matches[1];
            $questionID = $matches[3];
            $questionType = $matches[2];
            // Again, check that answer matches quiz we're expecting.
            // Probably a little paranoid, but it's worth checking
            // to ensure there's nothing naughty going on.
            if ($quizID != $quizDetails->quiz_id) {
                continue;
            }
            // Clean up the submitted data based on the type of quiz using the static checks in each
            // of the questions (to save loading whole class). If the data is valid, add the valid
            // answer to the list of fully validate danswers.
            switch ($questionType) {
                case 'multi':
                    $resultsList['answer_list'][$questionID] = WPCW_quiz_MultipleChoice::sanitizeAnswerData($value);
                    break;
                case 'truefalse':
                    $resultsList['answer_list'][$questionID] = WPCW_quiz_TrueFalse::sanitizeAnswerData($value);
                    break;
                case 'open':
                    $resultsList['answer_list'][$questionID] = WPCW_quiz_OpenEntry::sanitizeAnswerData($value);
                    break;
                    // Ignore uploads as a $_POST field, simply because the files should be stored in $_FILES
                    // not in $_POST. So if we have a file in $_FILES, that's clearly an issue.
                // Ignore uploads as a $_POST field, simply because the files should be stored in $_FILES
                // not in $_POST. So if we have a file in $_FILES, that's clearly an issue.
                case 'upload':
                    break;
            }
        }
        // end of question check
    }
    // end of potential answers loop
    // ### 1B Check for file uploads if the quiz requires them. Only check for uploads
    // if the quiz details say there should be some uploads.
    if ($quizDetails->want_uploads) {
        $uploadResultList = WPCW_quiz_FileUpload::validateFiles($_FILES, $quizDetails);
        // Merge the valid results.
        // Basically if a file has been uploaded correctly, that answer is marked as being set.
        if (count($uploadResultList['upload_valid']) > 0) {
            $resultsList['answer_list'] = $resultsList['answer_list'] + $uploadResultList['upload_valid'];
        }
        // Merge the error results
        if (count($uploadResultList['upload_errors']) > 0) {
            $resultsList['error_answer_list'] = $resultsList['error_answer_list'] + $uploadResultList['upload_errors'];
        }
    }
    // ### 2 - Check that we have enough answers given how many questions there are.
    // If there are not enough answers, then re-render the form with the answered questions
    // marked, and highlight the fields that have errors.
    if ($quizDetails->questions && count($resultsList['answer_list']) < count($quizDetails->questions)) {
        // Error - not all questions are answered
        echo WPCW_units_createErrorMessage(__('Please provide an answer for all of the questions.', 'wp_courseware'));
        // Show the form with the questions that have been completed already.
        echo WPCW_quizzes_handleQuizRendering($quizDetails->parent_unit_id, $quizDetails, $resultsList);
        // User may not continue - as quiz is not complete.
        return false;
    }
    // Flag to indicate if grading is needed before the user continues.
    $gradingNeeded = false;
    $gradingNeededBeforeContinue = false;
    // ### 3 - Do we need to check for correct answers?
    if ('survey' == $quizDetails->quiz_type) {
        // Never try to show answers. There aren't any.
        $quizDetails->quiz_show_answers = 'hide_answers';
        // No answers to check. Say thanks
        echo WPCW_units_createSuccessMessage(__('Thank you for your responses. This unit is now complete.', 'wp_courseware'));
    } else {
        $resultDetails = WPCW_quizzes_checkForCorrectAnswers($quizDetails, $resultsList['answer_list']);
        // #### Step A - have open-ended questions that need marking.
        if (!empty($resultDetails['needs_marking'])) {
            $gradingNeeded = true;
            $courseDetails = WPCW_courses_getCourseDetails($quizDetails->parent_course_id);
            // Non-blocking quiz - so allowed to continue, but will be graded later.
            if ('quiz_noblock' == $quizDetails->quiz_type) {
                echo WPCW_units_createSuccessMessage($courseDetails->course_message_quiz_open_grading_non_blocking);
            } else {
                echo WPCW_units_createSuccessMessage($courseDetails->course_message_quiz_open_grading_blocking);
                // Grading is needed before they continue, but don't want them to re-take the quiz.
                $gradingNeededBeforeContinue = true;
            }
        } else {
            // Copy over the wrong answers.
            $resultsList['wrong_answer_list'] = $resultDetails['wrong'];
            // Some statistics
            $correctCount = count($resultDetails['correct']);
            $totalQuestions = count($quizDetails->questions);
            $correctPercentage = number_format($correctCount / $totalQuestions * 100, 1);
            // Non-blocking quiz.
            if ('quiz_noblock' == $quizDetails->quiz_type) {
                // Store user quiz results
                echo WPCW_units_createSuccessMessage(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage));
                // Notify the user of their grade.
                do_action('wpcw_quiz_graded', $userID, $quizDetails, $correctPercentage, false);
            } else {
                $minPassQuestions = $totalQuestions * ($quizDetails->quiz_pass_mark / 100);
                // They've passed. Report how many they got right.
                if ($correctPercentage >= $quizDetails->quiz_pass_mark) {
                    echo WPCW_units_createSuccessMessage(sprintf(__('You got <b>%d out of %d (%d%%)</b> questions correct! This unit is now complete.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage));
                    // Notify the user of their grade.
                    do_action('wpcw_quiz_graded', $userID, $quizDetails, $correctPercentage, false);
                } else {
                    echo WPCW_units_createErrorMessage(sprintf(__('Unfortunately, you only got <b>%d out of %d (%d%%)</b> questions correct. You need to correctly answer <b>at least %d questions (%d%%)</b>.', 'wp_courseware'), $correctCount, $totalQuestions, $correctPercentage, $minPassQuestions, $quizDetails->quiz_pass_mark));
                    // Show form with error answers.
                    echo WPCW_quizzes_handleQuizRendering($quizDetails->parent_unit_id, $quizDetails, $resultsList);
                    // Errors, so the user cannot progress yet.
                    return false;
                }
            }
            // end of blocking quiz check
        }
    }
    // end of survey check
    // ### 4 - Show the correct answers to the user?
    if ('show_answers' == $quizDetails->quiz_show_answers) {
        echo WPCW_quizzes_showAllCorrectAnswers($quizDetails);
    }
    // ### 5 - Save the user progress
    WPCW_quizzes_saveUserProgress($userID, $quizDetails, $resultDetails, $resultsList['answer_list']);
    // Questions need grading, notify the admin
    if ($gradingNeeded) {
        // Notify the admin that questions need answering.
        do_action('wpcw_quiz_needs_grading', $userID, $quizDetails);
    }
    // Questions need grading, so don't allow user to continue
    if ($gradingNeededBeforeContinue) {
        return false;
    }
    // If we get this far, the user may progress to next unit
    return true;
}
Example #14
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();
}
Example #15
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 #16
0
/**
 * Function to add the specified list of course IDs for the specified user.
 * 
 * @param Integer $user_id The ID of the user to update.
 * @param Mixed $courseIDs The ID or array of IDs of the course IDs to give the user access to.
 * @param Boolean $syncMode If 'sync', then remove access to any course IDs not mentioned in $courseIDs parameter. If 'add', then just add access for course IDs that have been specified.
 */
function WPCW_courses_syncUserAccess($user_id, $courseIDs, $syncMode = 'add')
{
    // Not a valid user
    if (!get_userdata($user_id)) {
        return;
    }
    global $wpdb, $wpcwdb;
    $wpdb->show_errors();
    // List of course IDs that actually exist.
    $courseList = array();
    // Got a list of IDs?
    if (is_array($courseIDs)) {
        // List is empty, save a query
        if (count($courseIDs) > 0) {
            // Yep, this course actually exists
            foreach ($courseIDs as $potentialCourseID) {
                if ($courseDetails = WPCW_courses_getCourseDetails($potentialCourseID)) {
                    $courseList[$potentialCourseID] = $courseDetails;
                }
            }
        }
    } else {
        if ($courseDetails = WPCW_courses_getCourseDetails($courseIDs)) {
            $courseList[$courseIDs] = $courseDetails;
        }
    }
    // Check if we want to remove access for courses that are not mentioned.
    // We'll add any they should have access to in a mo.
    if ($syncMode == 'sync') {
        $str_courseIDs = false;
        $courseIDCount = count(array_keys($courseList));
        // Actually got some IDs to remove, so create an SQL string with all IDs
        if ($courseIDCount > 0) {
            $str_courseIDs = implode(",", array_keys($courseList));
            // Remove meta for this user all previous courses.
            // Previous version deleteted all courses then re-created them. As a result, data was being lost about email being sent.
            $wpdb->query($wpdb->prepare("DELETE FROM {$wpcwdb->user_courses} WHERE user_id = %d AND course_id NOT IN ({$str_courseIDs})", $user_id));
        } else {
            $wpdb->query($wpdb->prepare("DELETE FROM {$wpcwdb->user_courses} WHERE user_id = %d", $user_id));
        }
    }
    // Only process valid course IDs
    if (count($courseList) > 0) {
        foreach ($courseList as $validCourseID => $courseDetails) {
            // See if this is already in the database.
            if (!$wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpcwdb->user_courses} WHERE user_id = %d AND course_id = %d", $user_id, $validCourseID))) {
                // Actually add reference in database as it doesn't exist.
                $wpdb->query($wpdb->prepare("INSERT INTO {$wpcwdb->user_courses} (user_id, course_id, course_progress) VALUES(%d, %d, 0)", $user_id, $validCourseID));
            }
            // Get a total count of units in this course
            $SQL = $wpdb->prepare("\n\t\t    \tSELECT COUNT(*) \n\t\t    \tFROM {$wpcwdb->units_meta} \n\t\t    \tWHERE parent_course_id = %d\n\t\t    ", $validCourseID);
            $totalUnitCount = $wpdb->get_var($SQL);
            // Calculate the user's progress, in case they've still got completed progress
            // in the database.
            WPCW_users_updateUserUnitProgress($validCourseID, $user_id, $totalUnitCount);
        }
    }
}
        $current_user = wp_get_current_user();
        // Generate certificate
        $cert = new WPCW_Certificate();
        $cert->generatePDF(WPCW_users_getUsersName($current_user), __('This is an example course...', 'wp_courseware'), false, 'browser');
        die;
    } else {
        WPCW_certificate_notFound();
    }
} else {
    // Check database for the certificate by the ID
    $certificateDetails = WPCW_certificate_getCertificateDetails_byAccessKey($certificateID);
    // Not a valid certificate, abort
    if (!$certificateDetails) {
        WPCW_certificate_notFound();
    }
    $courseDetails = WPCW_courses_getCourseDetails($certificateDetails->cert_course_id);
    $userInfo = get_userdata($certificateDetails->cert_user_id);
    // Not a valid course or user data
    if (!$certificateDetails || !$userInfo) {
        WPCW_certificate_notFound();
    }
    // Generate certificate to download
    $cert = new WPCW_Certificate();
    // GW 150114 Richtigen Usernamen (Vor- und Nachnamen) holen.
    $cert->generatePDF(WPCW_users_getUsersName($userInfo), $courseDetails->course_title, $certificateDetails, 'browser');
    // $cert->generatePDF(WPCW_users_getUsersName($current_user), $courseDetails->course_title, $certificateDetails, 'browser');
    die;
}
/**
 * Show a generic error, details not found.
 */
Example #18
0
/**
 * Function that allows a course to be created or edited.
 */
function WPCW_showPage_ModifyCourse_load()
{
    $page = new PageBuilder(true);
    $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->showPageHeader(__('Edit Course', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
            $page->showMessage(__('Sorry, but that course could not be found.', 'wp_courseware'), true);
            $page->showPageFooter();
            return;
        } else {
            $page->showPageHeader(__('Edit Course', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
            // Check user is allowed to edit this course.
            $canEditCourse = apply_filters('wpcw_back_permissions_user_can_edit_course', true, get_current_user_id(), $courseDetails);
            if (!$canEditCourse) {
                $page->showMessage(apply_filters('wpcw_back_msg_permissions_user_can_edit_course', __('You are currently not permitted to edit this course.', 'wp_courseware'), get_current_user_id(), $courseDetails), true);
                $page->showPageFooter();
                return;
            }
        }
    } else {
        $page->showPageHeader(__('Add Course', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
        // Check user is allowed to add another course.
        $canAddCourse = apply_filters('wpcw_back_permissions_user_can_add_course', true, get_current_user_id());
        if (!$canAddCourse) {
            $page->showMessage(apply_filters('wpcw_back_msg_permissions_user_can_add_course', __('You are currently not permitted to add a new course.', 'wp_courseware'), get_current_user_id()), true);
            $page->showPageFooter();
            return;
        }
    }
    // We've requested a course tool. Do the checks here...
    if ($courseDetails && ($action = WPCW_arrays_getValue($_GET, 'action'))) {
        switch ($action) {
            // Tool - reset progress for all users.
            case 'reset_course_progress':
                // Get a list of all users on this course.
                global $wpdb, $wpcwdb;
                $userList = $wpdb->get_col($wpdb->prepare("\n\t\t\t\t\t\tSELECT user_id \n\t\t\t\t\t\tFROM {$wpcwdb->user_courses}\n\t\t\t\t\t\tWHERE course_id = %d \n\t\t\t\t\t", $courseDetails->course_id));
                $unitList = false;
                // Get all units for a course
                $courseMap = new WPCW_CourseMap();
                $courseMap->loadDetails_byCourseID($courseDetails->course_id);
                $unitList = $courseMap->getUnitIDList_forCourse();
                // Reset all users for this course.
                WPCW_users_resetProgress($userList, $unitList, $courseDetails, $courseMap->getUnitCount());
                // Confirm it's complete.
                $page->showMessage(__('User progress for this course has been reset.', 'wp_courseware'));
                break;
                // Access changes
            // Access changes
            case 'grant_access_users_all':
            case 'grant_access_users_admins':
                WPCW_showPage_ModifyCourse_courseAccess_runAccessChanges($page, $action, $courseDetails);
                break;
        }
        // Add a link back to editing, as we've hidden that panel.
        printf('<p><a href="%s?page=WPCW_showPage_ModifyCourse&course_id=%d" class="button button-secondary">%s</a></p>', admin_url('admin.php'), $courseDetails->course_id, __('&laquo; Go back to editing the course settings', 'wp_courseware'));
    } else {
        global $wpcwdb;
        $formDetails = array('break_course_general' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab(false)), 'course_title' => array('label' => __('Course Title', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_course_title', 'desc' => __('The title of your course.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 150, 'minlen' => 1, 'regexp' => '/^[^<>]+$/', 'error' => __('Please specify a name for your course, up to a maximum of 150 characters, just no angled brackets (&lt; or &gt;). Your trainees will be able to see this course title.', 'wp_courseware'))), 'course_desc' => array('label' => __('Course Description', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_desc', 'desc' => __('The description of this course. Your trainees will be able to see this course description.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the description of your course to 5000 characters.', 'wp_courseware'))), 'course_opt_completion_wall' => array('label' => __('When do users see the next unit on the course?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'desc' => __('Can a user see all possible course units? Or must they complete previous units before seeing the next unit?', 'wp_courseware'), 'data' => array('all_visible' => __('<b>All Units Visible</b> - All units are visible regardless of completion progress.', 'wp_courseware'), 'completion_wall' => __('<b>Only Completed/Next Units Visible</b> - Only show units that have been completed, plus the next unit that the user can start.', 'wp_courseware'))), 'break_course_access' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'course_opt_user_access' => array('label' => __('Granting users access to this course', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'desc' => __('This setting allows you to set how users can access this course. They can either be given access automatically as soon as the user is created, or you can manually give them access. You can always manually remove access if you wish.', 'wp_courseware'), 'data' => array('default_show' => __('<b>Automatic</b> - All newly created users will be given access this course.', 'wp_courseware'), 'default_hide' => __('<b>Manual</b> - Users can only access course if you grant them access.', 'wp_courseware'))), 'break_course_messages' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'course_message_unit_complete' => array('label' => __('Message - Unit Complete', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee once they\'ve <b>completed a unit</b>, which is displayed at the bottom of the unit page. HTML is OK.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_course_complete' => array('label' => __('Message - Course Complete', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee once they\'ve <b>completed the whole course</b>, which is displayed at the bottom of the unit page. HTML is OK.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_unit_pending' => array('label' => __('Message - Unit Pending', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee when they\'ve <b>yet to complete a unit</b>. This message is displayed at the bottom of the unit page, along with a button that says "<b>Mark as completed</b>". HTML is OK.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_unit_no_access' => array('label' => __('Message - Access Denied', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee they are <b>not allowed to access a unit</b>, because they are not allowed to <b>access the whole course</b>.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_unit_not_yet' => array('label' => __('Message - Not Yet Available', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee they are <b>not allowed to access a unit yet</b>, because they need to complete a previous unit.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_unit_not_logged_in' => array('label' => __('Message - Not Logged In', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee they are <b>not logged in</b>, and therefore cannot access the unit.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_quiz_open_grading_blocking' => array('label' => __('Message - Open-Question Submitted - Blocking Mode', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee they have submitted an answer to an <b>open-ended or upload question</b>, and you need to grade their answer <b>before they continue</b>.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'course_message_quiz_open_grading_non_blocking' => array('label' => __('Message - Open-Question Submitted - Non-Blocking Mode', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_course_message', 'desc' => __('The message shown to a trainee they have submitted an answer to an <b>open-ended or upload question</b>, and you need to grade their answer, but they can <b>continue anyway</b>.', 'wp_courseware'), 'rows' => 2, 'validate' => array('type' => 'string', 'maxlen' => 500, 'minlen' => 1, 'error' => __('Please limit message to 500 characters.', 'wp_courseware'))), 'break_course_notifications_from_details' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'course_from_email' => array('label' => __('Email From Address', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_course_email', 'desc' => __('The email address that the email notifications should be from.<br/>Depending on your server\'s spam-protection set up, this may not appear in the outgoing emails.', 'wp_courseware'), 'validate' => array('type' => 'email', 'maxlen' => 150, 'minlen' => 1, 'error' => __('Please enter a valid email address.', 'wp_courseware'))), 'course_from_name' => array('label' => __('Email From Name', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_course_email', 'desc' => __('The name used on the email notifications, which are sent to you and your trainees. <br/>Depending on your server\'s spam-protection set up, this may not appear in the outgoing emails.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 150, 'minlen' => 1, 'regexp' => '/^[^<>]+$/', 'error' => __('Please specify a from name, up to a maximum of 150 characters, just no angled brackets (&lt; or &gt;).', 'wp_courseware'))), 'course_to_email' => array('label' => __('Admin Notify Email Address', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_course_email', 'desc' => __('The email address to send admin notifications to.', 'wp_courseware'), 'validate' => array('type' => 'email', 'maxlen' => 150, 'minlen' => 1, 'error' => __('Please enter a valid email address.', 'wp_courseware'))), 'break_course_notifications_user_module' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'email_complete_module_option_admin' => array('label' => __('Module Complete - Notify You?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'cssclass' => 'wpcw_course_email_template_option', 'data' => array('send_email' => __('<b>Send me an email</b> - when one of your trainees has completed a module.', 'wp_courseware'), 'no_email' => __('<b>Don\'t send me an email</b> - when one of your trainees has completed a module.', 'wp_courseware'))), 'email_complete_module_option' => array('label' => __('Module Complete - Notify User?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'cssclass' => 'wpcw_course_email_template_option', 'data' => array('send_email' => __('<b>Send Email</b> - to user when module has been completed.', 'wp_courseware'), 'no_email' => __('<b>Don\'t Send Email</b> - to user when module has been completed.', 'wp_courseware'))), 'email_complete_module_subject' => array('label' => __('Module Complete - Email Subject', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template_subject', 'rows' => 2, 'desc' => __('The <b>subject line</b> for the email sent to a user when they complete a <b>module</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 300, 'minlen' => 1, 'error' => __('Please limit the email subject to 300 characters.', 'wp_courseware'))), 'email_complete_module_body' => array('label' => __('Module Complete - Email Body', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template', 'desc' => __('The <b>template body</b> for the email sent to a user when they complete a <b>module</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the email body to 5000 characters.', 'wp_courseware'))), 'break_course_notifications_user_course' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'email_complete_course_option_admin' => array('label' => __('Course Complete - Notify You?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'cssclass' => 'wpcw_course_email_template_option', 'data' => array('send_email' => __('<b>Send me an email</b> - when one of your trainees has completed the whole course.', 'wp_courseware'), 'no_email' => __('<b>Don\'t send me an email</b> - when one of your trainees has completed the whole course.', 'wp_courseware'))), 'email_complete_course_option' => array('label' => __('Course Complete - Notify User?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'cssclass' => 'wpcw_course_email_template_option', 'data' => array('send_email' => __('<b>Send Email</b> - to user when the whole course has been completed.', 'wp_courseware'), 'no_email' => __('<b>Don\'t Send Email</b> - to user when the whole course has been completed.', 'wp_courseware'))), 'email_complete_course_subject' => array('label' => __('Course Complete - Email Subject', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template_subject', 'rows' => 2, 'desc' => __('The <b>subject line</b> for the email sent to a user when they complete <b>the whole course</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 300, 'minlen' => 1, 'error' => __('Please limit the email subject to 300 characters.', 'wp_courseware'))), 'email_complete_course_body' => array('label' => __('Course Complete - Email Body', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template', 'desc' => __('The <b>template body</b> for the email sent to a user when they complete <b>the whole course</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the email body to 5000 characters.', 'wp_courseware'))), 'break_course_notifications_user_grades' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'email_quiz_grade_option' => array('label' => __('Quiz Grade - Notify User?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'cssclass' => 'wpcw_course_email_template_option', 'data' => array('send_email' => __('<b>Send Email</b> - to user after a quiz is graded (automatically or by the instructor).', 'wp_courseware'), 'no_email' => __('<b>Don\'t Send Email</b> - to user when a quiz is graded.', 'wp_courseware'))), 'email_quiz_grade_subject' => array('label' => __('Quiz Graded - Email Subject', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template_subject', 'rows' => 2, 'desc' => __('The <b>subject line</b> for the email sent to a user when they receive a <b>grade for a quiz</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 300, 'minlen' => 1, 'error' => __('Please limit the email subject to 300 characters.', 'wp_courseware'))), 'email_quiz_grade_body' => array('label' => __('Quiz Graded - Email Body', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template', 'desc' => __('The <b>template body</b> for the email sent to a user when they receive a <b>grade for a quiz</b>.', 'wp_courseware'), 'rows' => 20, 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the email body to 5000 characters.', 'wp_courseware'))), 'break_course_notifications_user_final' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'email_complete_course_grade_summary_subject' => array('label' => __('Final Summary - Email Subject', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'cssclass' => 'wpcw_course_email_template_subject', 'rows' => 2, 'desc' => __('The <b>subject line</b> for the email sent to a user when they receive their <b>grade summary at the end of the course</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 300, 'minlen' => 1, 'error' => __('Please limit the email subject to 300 characters.', 'wp_courseware'))), 'email_complete_course_grade_summary_body' => array('label' => __('Final Summary - Email Body', 'wp_courseware'), 'type' => 'textarea', 'required' => false, 'rows' => 20, 'cssclass' => 'wpcw_course_email_template', 'desc' => __('The <b>template body</b> for the email sent to a user when they receive their <b>grade summary at the end of the course</b>.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the email body to 5000 characters.', 'wp_courseware'))), 'break_course_certificates_user_course' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'course_opt_use_certificate' => array('label' => __('Enable certificates?', 'wp_courseware'), 'type' => 'radio', 'required' => true, 'data' => array('use_certs' => __('<b>Yes</b> - generate a PDF certificate when user completes this course.', 'wp_courseware'), 'no_certs' => __('<b>No</b> - don\'t generate a PDF certificate when user completes this course.', 'wp_courseware'))), 'break_course_certificates_user_tools' => array('type' => 'break', 'html' => WPCW_forms_createBreakHTML_tab()), 'course_tools_reset_all_users' => array('label' => __('Reset User Progess for this Course?', 'wp_courseware'), 'type' => 'custom', 'html' => sprintf('<a href="%s?page=WPCW_showPage_ModifyCourse&course_id=%d&action=reset_course_progress" class="button-primary" id="wpcw_course_btn_progress_reset_whole_course">%s</a><p>%s</p>', admin_url('admin.php'), $courseID, __('Reset All Users on this Course to the start', 'wp_courseware'), __('This button will reset all users who can access this course back to the beginning of the course. This deletes all grade data too.', 'wp_courseware'))), 'course_tools_user_access' => array('label' => __('Bulk-grant access to this course?', 'wp_courseware'), 'type' => 'custom', 'html' => sprintf('<a href="%s?page=WPCW_showPage_ModifyCourse&course_id=%d&action=grant_access_users_all" class="button-primary" id="wpcw_course_btn_access_all_existing_users">%s</a>&nbsp;&nbsp;
										    <a href="%s?page=WPCW_showPage_ModifyCourse&course_id=%d&action=grant_access_users_admins" class="button-primary" id="wpcw_course_btn_access_all_existing_admins">%s</a> 
										    <p>%s</p>', admin_url('admin.php'), $courseID, __('All Existing Users (including Administrators)', 'wp_courseware'), admin_url('admin.php'), $courseID, __('Only All Existing Administrators', 'wp_courseware'), __('You can use the buttons above to grant all users access to this course. Depending on how many users you have, this may be a slow process.', 'wp_courseware'))));
        // Generate the tabs.
        $tabList = array('break_course_general' => array('label' => __('General Course Details', 'wp_courseware')), 'break_course_access' => array('label' => __('User Access', 'wp_courseware')), 'break_course_messages' => array('label' => __('User Messages', 'wp_courseware')), 'break_course_notifications_from_details' => array('label' => __('Email Address Details', 'wp_courseware')), 'break_course_notifications_user_module' => array('label' => __('Email Notifications - Module', 'wp_courseware')), 'break_course_notifications_user_course' => array('label' => __('Email Notifications - Course', 'wp_courseware')), 'break_course_notifications_user_grades' => array('label' => __('Email Notifications - Quiz Grades', 'wp_courseware')), 'break_course_notifications_user_final' => array('label' => __('Email Notifications - Final Summary', 'wp_courseware')), 'break_course_certificates_user_course' => array('label' => __('Certificates', 'wp_courseware')), 'break_course_certificates_user_tools' => array('label' => __('Course Access Tools', 'wp_courseware')));
        // Remove reset fields if not appropriate.
        if (!$courseDetails) {
            // The tab
            unset($tabList['break_course_certificates_user_tools']);
            // The tool
            unset($formDetails['break_course_certificates_user_tools']);
            unset($formDetails['course_tools_reset_all_users']);
        }
        $form = new RecordsForm($formDetails, $wpcwdb->courses, 'course_id', false, 'wpcw_course_settings');
        $form->customFormErrorMsg = __('Sorry, but unfortunately there were some errors saving the course details. Please fix the errors and try again.', 'wp_courseware');
        $form->setAllTranslationStrings(WPCW_forms_getTranslationStrings());
        // Set defaults if adding a new course
        if (!$courseDetails) {
            $form->loadDefaults(array('email_complete_module_subject' => EMAIL_TEMPLATE_COMPLETE_MODULE_SUBJECT, 'email_complete_course_subject' => EMAIL_TEMPLATE_COMPLETE_COURSE_SUBJECT, 'email_quiz_grade_subject' => EMAIL_TEMPLATE_QUIZ_GRADE_SUBJECT, 'email_complete_course_grade_summary_subject' => EMAIL_TEMPLATE_COURSE_SUMMARY_WITH_GRADE_SUBJECT, 'email_complete_module_body' => EMAIL_TEMPLATE_COMPLETE_MODULE_BODY, 'email_complete_course_body' => EMAIL_TEMPLATE_COMPLETE_COURSE_BODY, 'email_quiz_grade_body' => EMAIL_TEMPLATE_QUIZ_GRADE_BODY, 'email_complete_course_grade_summary_body' => EMAIL_TEMPLATE_COURSE_SUMMARY_WITH_GRADE_BODY, 'course_from_name' => get_bloginfo('name'), 'course_from_email' => get_bloginfo('admin_email'), 'course_to_email' => get_bloginfo('admin_email'), 'course_opt_completion_wall' => 'completion_wall', 'course_opt_user_access' => 'default_show', 'email_complete_course_option_admin' => 'send_email', 'email_complete_course_option' => 'send_email', 'email_complete_module_option_admin' => 'send_email', 'email_complete_module_option' => 'send_email', 'email_quiz_grade_option' => 'send_email', 'course_opt_use_certificate' => 'no_certs', 'course_message_unit_not_yet' => __("You need to complete the previous unit first.", 'wp_courseware'), 'course_message_unit_pending' => __("Have you completed this unit? Then mark this unit as completed.", 'wp_courseware'), 'course_message_unit_complete' => __("You have now completed this unit.", 'wp_courseware'), 'course_message_course_complete' => __("You have now completed the whole course. Congratulations!", 'wp_courseware'), 'course_message_unit_no_access' => __("Sorry, but you're not allowed to access this course.", 'wp_courseware'), 'course_message_unit_not_logged_in' => __('You cannot view this unit as you\'re not logged in yet.', 'wp_courseware'), 'course_message_quiz_open_grading_blocking' => __('Your quiz has been submitted for grading by the course instructor. Once your grade has been entered, you will be able access the next unit.', 'wp_courseware'), 'course_message_quiz_open_grading_non_blocking' => __('Your quiz has been submitted for grading by the course instructor. You have now completed this unit.', 'wp_courseware')));
        }
        // Useful place to go
        $directionMsg = '<br/></br>' . sprintf(__('Do you want to return to the <a href="%s">course summary page</a>?', 'wp_courseware'), admin_url('admin.php?page=WPCW_wp_courseware'));
        // Override success messages
        $form->msg_record_created = __('Course details successfully created. ', 'wp_courseware') . $directionMsg;
        $form->msg_record_updated = __('Course details successfully updated. ', 'wp_courseware') . $directionMsg;
        $form->setPrimaryKeyValue($courseID);
        $form->setSaveButtonLabel(__('Save ALL Details', 'wp_courseware'));
        // Process form
        $formHTML = $form->getHTML();
        // Show message about this course having quizzes that require a pass mark.
        // Need updated details for this.
        $courseDetails = WPCW_courses_getCourseDetails($courseID);
        if ($courseDetails && $courseDetails->course_opt_completion_wall == 'all_visible') {
            $quizzes = WPCW_quizzes_getAllBlockingQuizzesForCourse($courseDetails->course_id);
            // Count how many blocking quizzes there are.
            if ($quizzes && count($quizzes) > 0) {
                $quizCountMessage = sprintf(__('Currently <b>%d of your quizzes</b> are blocking process based on a percentage score <b>in this course</b>.', 'wp_courseware'), count($quizzes));
            } else {
                $quizCountMessage = __('You do not currently have any blocking quizzes for this course.', 'wp_courseware');
            }
            printf('<div id="message" class="wpcw_msg_info wpcw_msg"><b>%s</b> - %s<br/><br/>
					%s				
					</div>', __('Important Note', 'wp_courseware'), __('You have selected <b>All Units Visible</b>. If you create a quiz blocking progress based on a percentage score, students will have access to the entire course regardless of quiz score.', 'wp_courseware'), $quizCountMessage);
        }
        // Generate the tabs
        echo WPCW_tabs_generateTabHeader($tabList, 'wpcw_courses_tabs', false);
        // Show the form
        echo $formHTML;
        echo '</div>';
        // .wpcw_tab_wrapper
    }
    // end if not doing a tool manipulation.
    $page->showPageMiddle('20%');
    // Include a link to delete the course
    if ($courseDetails) {
        $page->openPane('wpcw-deletion-course', __('Delete Course?', 'wp_courseware'));
        WPCW_showPage_ModifyCourse_deleteCourseButton($courseDetails);
        $page->closePane();
    }
    // Email template tags here...
    $page->openPane('wpcw_docs_email_tags', __('Email Template Tags', 'wp_courseware'));
    printf('<h4 class="wpcw_docs_side_mini_hdr">%s</h4>', __('All Email Notifications', 'wp_courseware'));
    printf('<dl class="wpcw_email_tags">');
    printf('<dt>{USER_NAME}</dt><dd>%s</dd>', __('The display name of the user.', 'wp_courseware'));
    printf('<dt>{SITE_NAME}</dt><dd>%s</dd>', __('The name of the website.', 'wp_courseware'));
    printf('<dt>{SITE_URL}</dt><dd>%s</dd>', __('The URL of the website.', 'wp_courseware'));
    printf('<dt>{COURSE_TITLE}</dt><dd>%s</dd>', __('The title of the course for the unit that\'s just been completed.', 'wp_courseware'));
    printf('<dt>{MODULE_TITLE}</dt><dd>%s</dd>', __('The title of the module for the unit that\'s just been completed.', 'wp_courseware'));
    printf('<dt>{MODULE_NUMBER}</dt><dd>%s</dd>', __('The number of the module for the unit that\'s just been completed.', 'wp_courseware'));
    printf('<dt>{CERTIFICATE_LINK}</dt><dd>%s</dd>', __('If the course has PDF certificates enabled, this is the link of the PDF certficate. (If there is no certificate or certificates are not enabled, this is simply blank)', 'wp_courseware'));
    printf('</dl>');
    printf('<h4 class="wpcw_docs_side_mini_hdr">%s</h4>', __('Quiz Email Notifications Only', 'wp_courseware'));
    printf('<dl class="wpcw_email_tags">');
    printf('<dt>{QUIZ_TITLE}</dt><dd>%s</dd>', __('The title of the quiz that has been graded.', 'wp_courseware'));
    printf('<dt>{QUIZ_GRADE}</dt><dd>%s</dd>', __('The overall percentage grade for a quiz.', 'wp_courseware'));
    printf('<dt>{QUIZ_GRADES_BY_TAG}</dt><dd>%s</dd>', __('Includes a breakdown of scores by tag if available.', 'wp_courseware'));
    printf('<dt>{QUIZ_TIME}</dt><dd>%s</dd>', __('If the quiz was timed, displays the time used to complete the quiz.', 'wp_courseware'));
    printf('<dt>{QUIZ_ATTEMPTS}</dt><dd>%s</dd>', __('Indicates the number of attempts for the quiz.', 'wp_courseware'));
    printf('<dt>{CUSTOM_FEEDBACK}</dt><dd>%s</dd>', __('Includes any custom feedback messages that have been triggered based on the user\'s specific results in the quiz.', 'wp_courseware'));
    printf('<dt>{QUIZ_RESULT_DETAIL}</dt><dd>%s</dd>', __('Any optional information relating to the result of the quiz, e.g. information about retaking the quiz.', 'wp_courseware'));
    printf('<dt>{UNIT_TITLE}</dt><dd>%s</dd>', __('The title of the unit that is associated with the quiz.', 'wp_courseware'));
    printf('<dt>{UNIT_URL}</dt><dd>%s</dd>', __('The URL of the unit that is associated with the quiz.', 'wp_courseware'));
    printf('</dl>');
    printf('<h4 class="wpcw_docs_side_mini_hdr">%s</h4>', __('Final Summary Notifications Only', 'wp_courseware'));
    printf('<dl class="wpcw_email_tags">');
    printf('<dt>{CUMULATIVE_GRADE}</dt><dd>%s</dd>', __('The overall cumulative grade that the user has scored from completing all quizzes on the course.', 'wp_courseware'));
    printf('<dt>{QUIZ_SUMMARY}</dt><dd>%s</dd>', __('The summary of each quiz, and what the user scored on each.', 'wp_courseware'));
    printf('</dl>');
    $page->showPageFooter();
}