/**
 * Convert page/post to a course unit 
 */
function WPCW_showPage_ConvertPage_load()
{
    $page = new PageBuilder(false);
    $page->showPageHeader(__('Convert Page/Post to Course Unit', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
    // Future Feature - Check user can edit other people's pages - use edit_others_pages or custom capability.
    if (!current_user_can('manage_options')) {
        $page->showMessage(__('Sorry, but you are not allowed to edit this page/post.', 'wp_courseware'), true);
        $page->showPageFooter();
        return false;
    }
    // Check that post ID is valid
    $postID = WPCW_arrays_getValue($_GET, 'postid') + 0;
    $convertPost = get_post($postID);
    if (!$convertPost) {
        $page->showMessage(__('Sorry, but the specified page/post does not appear to exist.', 'wp_courseware'), true);
        $page->showPageFooter();
        return false;
    }
    // Check that post isn't already a course unit before trying change.
    // This is where the conversion takes place.
    if ('course_unit' != $convertPost->post_type) {
        // Confirm we want to do the conversion
        if (!isset($_GET['confirm'])) {
            $message = sprintf(__('Are you sure you wish to convert the <em>%s</em> to a course unit?', 'wp_courseware'), $convertPost->post_type);
            $message .= '<br/><br/>';
            // Yes Button
            $message .= sprintf('<a href="%s&postid=%d&confirm=yes" class="button-primary">%s</a>', admin_url('admin.php?page=WPCW_showPage_ConvertPage'), $postID, __('Yes, convert it', 'wp_courseware'));
            // Cancel
            $message .= sprintf('&nbsp;&nbsp;<a href="%s&postid=%d&confirm=no" class="button-secondary">%s</a>', admin_url('admin.php?page=WPCW_showPage_ConvertPage'), $postID, __('No, don\'t convert it', 'wp_courseware'));
            $page->showMessage($message);
            $page->showPageFooter();
            return false;
        } else {
            // Confirmed conversion
            if ($_GET['confirm'] == 'yes') {
                $postDetails = array();
                $postDetails['ID'] = $postID;
                $postDetails['post_type'] = 'course_unit';
                // Update the post into the database
                wp_update_post($postDetails);
            }
            // Cancelled conversion
            if ($_GET['confirm'] != 'yes') {
                $page->showMessage(__('Conversion to a course unit cancelled.', 'wp_courseware'), false);
                $page->showPageFooter();
                return false;
            }
        }
    }
    // Check conversion happened
    $convertedPost = get_post($postID);
    if ('course_unit' == $convertedPost->post_type) {
        $page->showMessage(sprintf(__('The page/post was successfully converted to a course unit. You can <a href="%s">now edit the course unit</a>.', 'wp_courseware'), admin_url(sprintf('post.php?post=%d&action=edit', $postID))));
    } else {
        $page->showMessage(__('Unfortunately, there was an error trying to convert the page/post to a course unit. Perhaps you could try again?', 'wp_courseware'), true);
    }
    $page->showPageFooter();
}
Example #2
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.
 }
/**
 * Shows the page to do with importing/exporting training courses.
 */
function WPCW_showPage_ImportExport_load()
{
    switch (WPCW_arrays_getValue($_GET, 'show')) {
        case 'import':
            WPCW_showPage_ImportExport_import();
            break;
        case 'import_users':
            WPCW_showPage_ImportExport_importUsers();
            break;
        default:
            WPCW_showPage_ImportExport_export();
            break;
    }
}
/**
 * Shows the documentation page for the plugin. 
 */
function WPCW_showPage_Documentation_load()
{
    $page = new PageBuilder();
    // List of tabs to show
    $docTabs = array('default' => array('flag' => false, 'fn' => 'WPCW_showPage_Documentation_shortcodes', 'label' => __('Shortcodes', 'wp_courseware')), 'howto' => array('flag' => 'howto', 'fn' => 'WPCW_showPage_Documentation_howto', 'label' => __('How-To Videos', 'wp_courseware')));
    // Allow modification of the documentation tabs.
    $docTabs = apply_filters('wpcw_back_documentation_tabs', $docTabs);
    printf('<div class="wrap">');
    $tabNames = array_keys($docTabs);
    // What tabs are active?
    $tabSel = WPCW_arrays_getValue($_GET, 'info');
    if (!in_array($tabSel, $tabNames)) {
        $tabSel = false;
    }
    // Create main settings tab URL
    $baseURL = admin_url('admin.php?page=WPCW_showPage_Documentation');
    // Header
    printf('<h2 class="nav-tab-wrapper">');
    // Icon
    printf('<div id="icon-pagebuilder" class="icon32" style="background-image: url(\'%s\'); margin: 0px 6px 0 6px;"><br></div>', WPCW_icon_getPageIconURL());
    foreach ($docTabs as $type => $tabDetails) {
        // Tabs
        $urlToUse = $baseURL;
        if ($tabDetails['flag']) {
            $urlToUse = $baseURL . '&info=' . $tabDetails['flag'];
        }
        printf('<a href="%s" class="nav-tab %s">%s</a>', $urlToUse, $tabDetails['flag'] == $tabSel ? 'nav-tab-active' : '', $tabDetails['label']);
    }
    printf('</h2>');
    // Create the doc header.
    $page->showPageHeader(false, '75%', false, true);
    // What settings do we show?
    if (in_array($tabSel, $tabNames)) {
        call_user_func($docTabs[$tabSel]['fn']);
    } else {
        call_user_func($docTabs['default']['fn']);
    }
    // Needed to show RHS section for panels
    $page->showPageMiddle('23%');
    // RHS Support Information
    WPCW_docs_showSupportInfo($page);
    WPCW_docs_showSupportInfo_News($page);
    WPCW_docs_showSupportInfo_Affiliate($page);
    $page->showPageFooter();
    // Final div closed by showPageFooter().
    //printf('</div>');
}
Example #5
0
/**
 * Function called when a user is submitting quiz answers via
 * the frontend form. 
 */
function WPCW_AJAX_units_handleQuizResponse()
{
    // Security check
    if (!wp_verify_nonce(WPCW_arrays_getValue($_POST, 'progress_nonce'), 'wpcw-progress-nonce')) {
        die(__('Security check failed!', 'wp_courseware'));
    }
    // Quiz ID and Unit ID are combined in the single CSS ID for validation.
    // So validate both are correct and that user is allowed to access quiz.
    $quizAndUnitID = WPCW_arrays_getValue($_POST, 'id');
    // e.g. quiz_complete_69_1 or quiz_complete_17_2 (first ID is unit, 2nd ID is quiz)
    if (!preg_match('/quiz_complete_(\\d+)_(\\d+)/', $quizAndUnitID, $matches)) {
        echo WPCW_units_getCompletionBox_error();
        die;
    }
    // Use the extracted data for further validation
    $unitID = $matches[1];
    $quizID = $matches[2];
    $user_id = get_current_user_id();
    // #### Get associated data for this unit. No course/module data, not a unit
    $parentData = WPCW_units_getAssociatedParentData($unitID);
    if (!$parentData) {
        // No error, as not a valid unit.
        die;
    }
    // #### User not allowed access to content, so certainly can't say they've done this unit.
    if (!WPCW_courses_canUserAccessCourse($parentData->course_id, $user_id)) {
        // No error, as not a valid unit.
        die;
    }
    // #### Check that the quiz is valid and belongs to this unit
    $quizDetails = WPCW_quizzes_getQuizDetails($quizID, true);
    if (!($quizDetails && $quizDetails->parent_unit_id == $unitID)) {
        die;
    }
    // Validate the quiz answers... which means we might have to
    // send back the form to be re-filled.
    $canContinue = WPCW_quizzes_handleQuizRendering_canUserContinueAfterQuiz($quizDetails, $_POST, $user_id);
    // Check that user is allowed to progress.
    if ($canContinue) {
        WPCW_units_saveUserProgress_Complete($user_id, $unitID, 'complete');
        // Unit complete, check if course/module is complete too.
        do_action('wpcw_user_completed_unit', $user_id, $unitID, $parentData);
        // Only complete if allowed to continue.
        echo WPCW_units_getCompletionBox_complete($parentData, $unitID, $user_id);
    }
    die;
}
 /**
  * Check if we need to show the answer later button.
  * @return Boolean True if yes, false otherwise.
  */
 function check_paging_shouldWeShowAnswerLaterButton()
 {
     if (!$this->unitQuizDetails) {
         return false;
     }
     // First check if settings allow it.
     $pagingSettings = maybe_unserialize($this->unitQuizDetails->quiz_paginate_questions_settings);
     $allowAnswerLater = 'on' == WPCW_arrays_getValue($pagingSettings, 'allow_students_to_answer_later');
     // True if settings allow it, and we're allowed to show it based on what question we're at.
     return $allowAnswerLater && (empty($this->unitQuizProgress) || !empty($this->unitQuizProgress) && $this->unitQuizProgress->quiz_paging_next_q < $this->unitQuizProgress->quiz_question_total);
 }
Example #7
0
/**
 * Calculates the grade for a set of results, taking into account the
 * different types of questions.
 * 
 * @param Array $quizData The list of quiz results data.
 * @param Integer $questionsThatNeedMarking How many questions need marking.
 * 
 * @return Integer The overall grade for the results.
 */
function WPCW_quizzes_calculateGradeForQuiz($quizData, $questionsThatNeedMarking = 0)
{
    if ($questionsThatNeedMarking > 0) {
        return '-1';
    }
    $questionTotal = 0;
    $gradeTotal = 0;
    foreach ($quizData as $questionID => $questionResults) {
        // It's a truefalse/multi question
        if ($questionResults['got_right']) {
            // Got it right, so add 100%.
            if ($questionResults['got_right'] == 'yes') {
                $gradeTotal += 100;
            }
        } else {
            // Making assumption that the grade number exists
            // Otherwise we'd never get this far as the question still needs marking.
            $gradeTotal += WPCW_arrays_getValue($questionResults, 'their_grade');
        }
        $questionTotal++;
    }
    // Simple calculation that averages the grade.
    $grade = 0;
    if ($questionTotal) {
        $grade = number_format($gradeTotal / $questionTotal, 1);
    }
    return $grade;
}
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();
}
/**
 * Handle saving a feedback message to the database.
 * 
 * @param Integer $quizID The quiz for which the questions apply to. 
 */
function WPCW_showPage_customFeedback_processSave($quizID)
{
    global $wpdb, $wpcwdb;
    $wpdb->show_errors();
    $msgToSave = array();
    $msgToSave_New = array();
    // Check $_POST data for the
    foreach ($_POST as $key => $value) {
        // ### 1) - Check if we're deleting a custom feedback message
        if (preg_match('/^delete_wpcw_qcfm_sgl_wrapper_([0-9]+)$/', $key, $matches)) {
            // Delete the message from the message table
            $SQL = $wpdb->prepare("\n\t\t\t\tDELETE FROM {$wpcwdb->quiz_feedback}\n\t\t\t\tWHERE qfeedback_id = %d\n\t\t\t", $matches[1]);
            $wpdb->query($SQL);
        }
        // #### 2 - See if we have a custom feedback message to add or update
        // Checking for wpcw_qcfm_sgl_wrapper_1 or wpcw_qcfm_sgl_wrapper_new_message_1
        if (preg_match('/^wpcw_qcfm_sgl_summary(_new_message)?_([0-9]+)$/', $key, $matches)) {
            // Got the ID of the message we're updating or adding.
            $messageID = $matches[2];
            // Store the extra string if we're adding a new message.
            $newMessagePrefix = $matches[1];
            $fieldSuffix = $newMessagePrefix . '_' . $messageID;
            // Fetch each field we need that will be saved
            $messageFields = array('qfeedback_quiz_id' => $quizID, 'qfeedback_summary' => stripslashes(WPCW_arrays_getValue($_POST, 'wpcw_qcfm_sgl_' . 'summary' . $fieldSuffix)), 'qfeedback_message' => stripslashes(WPCW_arrays_getValue($_POST, 'wpcw_qcfm_sgl_' . 'message' . $fieldSuffix)), 'qfeedback_tag_id' => intval(WPCW_arrays_getValue($_POST, 'wpcw_qcfm_sgl_' . 'tag' . $fieldSuffix)), 'qfeedback_score_grade' => intval(WPCW_arrays_getValue($_POST, 'wpcw_qcfm_sgl_' . 'score_grade' . $fieldSuffix)), 'qfeedback_score_type' => WPCW_arrays_getValue($_POST, 'wpcw_qcfm_sgl_' . 'score_type' . $fieldSuffix));
            // Check we have a valid score type.
            if ('below' != $messageFields['qfeedback_score_type'] && 'above' != $messageFields['qfeedback_score_type']) {
                $messageFields['qfeedback_score_type'] = 'below';
            }
            // #### 3) - Not a new message - so add to list of new messages to add.
            if ($newMessagePrefix) {
                $msgToSave_New[] = $messageFields;
            } else {
                $messageFields['qfeedback_id'] = $messageID;
                $msgToSave[] = $messageFields;
            }
        }
        // end of preg_match check
    }
    // each of $_POST foreach.
    // #### 4) Add new messages
    if (!empty($msgToSave_New)) {
        foreach ($msgToSave_New as $messageDetails) {
            $wpdb->query(arrayToSQLInsert($wpcwdb->quiz_feedback, $messageDetails));
        }
    }
    // #### 5) Update existing messages
    if (!empty($msgToSave)) {
        foreach ($msgToSave as $messageDetails) {
            $wpdb->query(arrayToSQLUpdate($wpcwdb->quiz_feedback, $messageDetails, 'qfeedback_id'));
        }
    }
}
Example #10
0
/**
 * Get the URL for the desired page, preserving any parameters.
 * @param String $pageBase The based page to fetch.
 * @param Mixed $ignoreFields The array or string of parameters not to include.
 * @return String The newly formed URL. 
 */
function WPCW_urls_getURLWithParams($pageBase, $ignoreFields = false)
{
    // Parameters to extract from URL to keep in the URL.
    $params = array('s' => false, 'pagenum' => false, 'filter' => false);
    // Got fields we don't want in the URL? Handle both a string and
    // arrays
    if ($ignoreFields) {
        if (is_array($ignoreFields)) {
            foreach ($ignoreFields as $field) {
                unset($params[$field]);
            }
        } else {
            unset($params[$ignoreFields]);
        }
    }
    foreach ($params as $paramName => $notused) {
        $value = WPCW_arrays_getValue($_GET, $paramName);
        if ($value) {
            $pageBase .= '&' . $paramName . '=' . $value;
        }
    }
    return $pageBase;
}
Example #11
0
/**
 * Function that handles the export of the survey responses for a specified survey.
 */
function WPCW_data_export_quizSurveyData()
{
    $quizID = trim(WPCW_arrays_getValue($_GET, 'quiz_id')) + 0;
    $quizDetails = WPCW_quizzes_getQuizDetails($quizID, true, false, false);
    // Check that we can find the survey.
    if (!$quizDetails) {
        printf('<div class="error updated"><p>%s</p></div>', __('Sorry, could not find that survey to export the response data.', 'wp_courseware'));
        return;
    }
    // Ensure it's a survey
    if ('survey' != $quizDetails->quiz_type) {
        printf('<div class="error updated"><p>%s</p></div>', __('Sorry, but the selected item is not a survey, it\'s a quiz.', 'wp_courseware'));
        return;
    }
    // Does this survey contain random questions? If so, then we need to get the full question data
    // of all possible questions
    if (WPCW_quizzes_doesQuizContainRandomQuestions($quizDetails)) {
        $quizDetails->questions = WPCW_quizzes_randomQuestions_fullyExpand($quizDetails);
    }
    global $wpcwdb, $wpdb;
    $wpdb->show_errors();
    // Create a URL-safe version of the filename.
    $csvFileName = WPCW_urls_createCleanURL('survey-' . $quizDetails->quiz_id . '-' . $quizDetails->quiz_title) . '.csv';
    WPCW_data_export_sendHeaders_CSV($csvFileName);
    // The headings
    $headings = array(__('Trainee WP ID', 'wp_courseware'), __('Trainee Name', 'wp_courseware'), __('Trainee Email Address', 'wp_courseware'));
    // Extract the questions to use as headings.
    $questionListForColumns = array();
    // See if we have any questions in the list.
    if (!empty($quizDetails->questions)) {
        foreach ($quizDetails->questions as $questionID => $questionDetails) {
            $questionListForColumns[$questionID] = $questionDetails->question_question;
            // Add this question to the headings.
            $headings[] = $questionDetails->question_question;
        }
    }
    // Start CSV
    $out = fopen('php://output', 'w');
    // Push out the question headings.
    fputcsv($out, $headings);
    // The responses to the questions
    $answers = $wpdb->get_results($wpdb->prepare("\n\t\tSELECT * \n\t\tFROM {$wpcwdb->user_progress_quiz}\n\t\tWHERE quiz_id = %d\n\t", $quizDetails->quiz_id));
    // Process eacy response from the user, extracting their details too.
    if (!empty($answers)) {
        foreach ($answers as $answerDetails) {
            $resultData = array();
            // We've definitely got the ID
            $resultData[] = $answerDetails->user_id;
            // See if we can get the name and email address.
            $userDetails = get_userdata($answerDetails->user_id);
            if ($userDetails) {
                $resultData[] = $userDetails->display_name;
                $resultData[] = $userDetails->user_email;
            } else {
                $resultData[] = __('User no longer on system.', 'wp_courseware');
                $resultData[] = __('n/a', 'wp_courseware');
            }
            // Extract their responses into an array
            $theirResponses = maybe_unserialize($answerDetails->quiz_data);
            // Go through answers logically now
            if (!empty($questionListForColumns)) {
                foreach ($questionListForColumns as $questionID => $questionTitle) {
                    if (isset($theirResponses[$questionID]) && isset($theirResponses[$questionID]['their_answer'])) {
                        $resultData[] = $theirResponses[$questionID]['their_answer'];
                    } else {
                        $resultData[] = __('No answer for this question.', 'wp_courseware');
                    }
                }
            }
            // end of !empty check
            fputcsv($out, $resultData);
        }
        // end foreach
    }
    // end of if (!empty($answers))
    // All done
    fclose($out);
    die;
}
/**
 * Function that allows a question to be edited.
 */
function WPCW_showPage_ModifyQuestion_load()
{
    $page = new PageBuilder(true);
    $page->showPageHeader(__('Edit Single Question', 'wp_courseware'), '70%', WPCW_icon_getPageIconURL());
    $questionID = false;
    // Check POST and GET
    if (isset($_GET['question_id'])) {
        $questionID = $_GET['question_id'] + 0;
    } else {
        if (isset($_POST['question_id'])) {
            $questionID = $_POST['question_id'] + 0;
        }
    }
    // Trying to edit a question
    $questionDetails = WPCW_questions_getQuestionDetails($questionID, true);
    // Abort if question not found.
    if (!$questionDetails) {
        $page->showMessage(__('Sorry, but that question could not be found.', 'wp_courseware'), true);
        $page->showPageFooter();
        return;
    }
    // See if the question has been submitted for saving.
    if ('true' == WPCW_arrays_getValue($_POST, 'question_save_mode')) {
        WPCW_handler_questions_processSave(false, true);
        $page->showMessage(__('Question successfully updated.', 'wp_courseware'));
        // Assume save has happened, so reload the settings.
        $questionDetails = WPCW_questions_getQuestionDetails($questionID, true);
    }
    // Manually set the order to zero, as not needed for ordering in this context.
    $questionDetails->question_order = 0;
    switch ($questionDetails->question_type) {
        case 'multi':
            $quizObj = new WPCW_quiz_MultipleChoice($questionDetails);
            break;
        case 'truefalse':
            $quizObj = new WPCW_quiz_TrueFalse($questionDetails);
            break;
        case 'open':
            $quizObj = new WPCW_quiz_OpenEntry($questionDetails);
            break;
        case 'upload':
            $quizObj = new WPCW_quiz_FileUpload($questionDetails);
            break;
        default:
            die(__('Unknown quiz type: ', 'wp_courseware') . $questionDetails->question_type);
            break;
    }
    $quizObj->showErrors = true;
    $quizObj->needCorrectAnswers = true;
    $quizObj->hideDragActions = true;
    // #wpcw_quiz_details_questions = needed for media uploader
    // .wpcw_question_holder_static = needed for wrapping the question using existing HTML.
    printf('<div id="wpcw_quiz_details_questions"><ul class="wpcw_question_holder_static">');
    // Create form wrapper, so that we can save this question.
    printf('<form method="POST" action="%s?page=WPCW_showPage_ModifyQuestion&question_id=%d" />', admin_url('admin.php'), $questionDetails->question_id);
    // Question hidden fields
    printf('<input name="question_id" type="hidden" value="%d" />', $questionDetails->question_id);
    printf('<input name="question_save_mode" type="hidden" value="true" />');
    // Show the quiz so that it can be edited. We're re-using the code we have for editing questions,
    // to save creating any special form edit code.
    echo $quizObj->editForm_toString();
    // Save and return buttons.
    printf('<div class="wpcw_button_group"><br/>');
    printf('<a href="%s?page=WPCW_showPage_QuestionPool" class="button-secondary">%s</a>&nbsp;&nbsp;', admin_url('admin.php'), __('&laquo; Return to Question Pool', 'wp_courseware'));
    printf('<input type="submit" class="button-primary" value="%s" />', __('Save Question Details', 'wp_courseware'));
    printf('</div>');
    printf('</form>');
    printf('</ul></div>');
    $page->showPageFooter();
}
/**
 * Function called when user starting a quiz and needs to kick off the timer.
 */
function WPCW_AJAX_units_handleQuizTimerBegin()
{
    // Security check
    if (!wp_verify_nonce(WPCW_arrays_getValue($_POST, 'progress_nonce'), 'wpcw-progress-nonce')) {
        die(__('Security check failed!', 'wp_courseware'));
    }
    // Get unit and quiz ID
    $unitID = intval(WPCW_arrays_getValue($_POST, 'unitid'));
    $quizID = intval(WPCW_arrays_getValue($_POST, 'quizid'));
    // Get the post object for this quiz item.
    $post = get_post($unitID);
    if (!$post) {
        echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('Could not find training unit.', 'wp_courseware'));
        die;
    }
    // Initalise the unit details
    $fe = new WPCW_UnitFrontend($post);
    // #### Get associated data for this unit. No course/module data, then it's not a unit
    if (!$fe->check_unit_doesUnitHaveParentData()) {
        echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('Could not find course details for unit.', 'wp_courseware'));
        die;
    }
    // #### User not allowed access to content
    if (!$fe->check_user_canUserAccessCourse()) {
        echo $fe->message_user_cannotAccessCourse();
        die;
    }
    // #### See if we're in a position to retake this quiz?
    if (!$fe->check_quizzes_canUserRequestRetake()) {
        echo WPCW_UnitFrontend::message_createMessage_error(__('Error - could not start the timer for the quiz.', 'wp_courseware') . ' ' . __('You are not permitted to retake this quiz.', 'wp_courseware'));
        die;
    }
    // Trigger the upgrade to progress so that we can start the quiz, and trigger the timer.
    $fe->update_quizzes_beginQuiz();
    // Only complete if allowed to continue.
    echo $fe->render_detailsForUnit(false, true);
    die;
}
Example #14
0
<?php

// Check that plugin is active (so that this cannot be accessed if plugin isn't).
require dirname(__FILE__) . '/../../../wp-config.php';
// Can't find active WP Courseware init function, so cannot be active.
if (!function_exists('WPCW_plugin_init')) {
    WPCW_export_results_notFound();
}
// Get unit and quiz ID
$unitID = intval(WPCW_arrays_getValue($_GET, 'unitid'));
$quizID = intval(WPCW_arrays_getValue($_GET, 'quizid'));
// Get the post object for this quiz item.
$post = get_post($unitID);
if (!$post) {
    WPCW_export_results_notFound(__('Could not find training unit.', 'wp_courseware'));
}
// Initalise the unit details
$fe = new WPCW_UnitFrontend($post);
// #### Get associated data for this unit. No course/module data, then it's not a unit
if (!$fe->check_unit_doesUnitHaveParentData()) {
    WPCW_export_results_notFound(__('Could not find course details for unit.', 'wp_courseware'));
}
// #### User not allowed access to content
if (!$fe->check_user_canUserAccessCourse()) {
    WPCW_export_results_notFound($fe->fetch_message_user_cannotAccessCourse());
}
include_once 'pdf/pdf_quizresults.inc.php';
$qrpdf = new WPCW_QuizResults();
$parentData = $fe->fetch_getUnitParentData();
$quizDetails = $fe->fetch_getUnitQuizDetails();
// Set values for use in the results
Example #15
0
 /**
  * Try to add this specific question to the database (to the pool).
  * @param Array $singleQuestionData Specific question data to add.
  * @return Integer The ID of the newly inserted question ID, or false if it wasn't added.
  */
 private function loadQuestionData_addQuestionToDatabase($singleQuestionData)
 {
     if (!$singleQuestionData || empty($singleQuestionData)) {
         return false;
     }
     global $wpdb, $wpcwdb;
     $wpdb->show_errors();
     // ### 1 - Initialise data to be added for question.
     $questionDetailsToAdd = $singleQuestionData;
     // ### 2 - Need to strip out question order, as there is no question_order field
     // in the database, so we need to use it in the mappings data.
     $question_order = WPCW_arrays_getValue($singleQuestionData, 'question_order');
     unset($questionDetailsToAdd['question_order']);
     // ### 3 - Handle the insert of the special arrays that need serialising. We know these exist
     // as we have specifically validated them.
     $questionDetailsToAdd['question_data_answers'] = false;
     if (!empty($singleQuestionData['question_data_answers'])) {
         $questionDetailsToAdd['question_data_answers'] = serialize($singleQuestionData['question_data_answers']);
     }
     // ### 4 - Extract tags from the question data so that we can insert the question into
     //		   the database without any errors.
     $tagList = array();
     if (isset($questionDetailsToAdd['tags'])) {
         $tagList = $questionDetailsToAdd['tags'];
     }
     unset($questionDetailsToAdd['tags']);
     // ### 5 - Insert details of this particular question into the database.
     $queryResult = $wpdb->query(arrayToSQLInsert($wpcwdb->quiz_qs, $questionDetailsToAdd));
     // ### 6 - Store the ID of the newly inserted ID, we'll need it for associating tags.
     $currentQuestionID = $wpdb->insert_id;
     // ### 7 - Check query succeeded.
     if ($queryResult === FALSE) {
         $this->errorList[] = __('There was a problem adding the question into the database.', 'wp_courseware');
         return false;
     }
     // ### 8 - Now we create the tag associations.
     WPCW_questions_tags_addTags($currentQuestionID, $tagList);
     return $currentQuestionID;
 }
Example #16
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 #17
0
/**
 * Handles saving what the admin wants to do for the user next.
 */
function WPCW_showPage_UserProgess_quizAnswers_whatsNext_savePreferences($quizDetails, $results, $page, $userID, $unitID)
{
    // Admin wants to save the next action to this progress.
    if (isset($_POST['failed_quiz_next_action']) && $_POST['failed_quiz_next_action']) {
        global $wpdb, $wpcwdb;
        $wpdb->show_errors();
        $userNextAction = WPCW_arrays_getValue($_POST, 'wpcw_user_continue_action');
        $userRetakeMsg = filter_var(WPCW_arrays_getValue($_POST, 'wpcw_user_progress_failed_reason'), FILTER_SANITIZE_STRING);
        // Check action is valid. Abort if not
        if (!in_array($userNextAction, array('retake_quiz', 'progress_anyway'))) {
            return $results;
        }
        //  ****** REDUNDANT SWITCH *******
        // Sort out the SQL statement for what to update
        // switch ($userNextAction)
        // {
        // 	// User needs to retake the course.
        // 	case 'retake_quiz':
        // 		break;
        // 	// User is allowed to progress
        // 	case 'progress_anyway':
        // 			$userRetakeMsg = false;
        // 			// Mark the unit as completed.
        // 			WPCW_units_saveUserProgress_Complete($userID, $unitID);
        // 			// Unit complete, check if course/module is complete too.
        // 			do_action('wpcw_user_completed_unit', $userID, $unitID, WPCW_units_getAssociatedParentData($unitID));
        // 		break;
        // }
        // Update the progress item
        $SQL = $wpdb->prepare("\n\t\t    \tUPDATE {$wpcwdb->user_progress_quiz}\n\t\t    \t  SET quiz_next_step_type = '%s', \n\t\t    \t      quiz_next_step_msg = %s  \n\t\t    \tWHERE user_id = %d \n\t\t    \t  AND unit_id = %d \n\t\t    \t  AND quiz_id = %d\n\t\t    \tORDER BY quiz_attempt_id DESC\n\t\t    \tLIMIT 1\n\t   \t\t", $userNextAction, $userRetakeMsg, $userID, $unitID, $quizDetails->quiz_id);
        $wpdb->query($SQL);
        // Need to update the results object for use later.
        $results->quiz_next_step_type = $userNextAction;
        $results->quiz_next_step_msg = $userRetakeMsg;
        switch ($userNextAction) {
            // User needs to retake the course.
            case 'retake_quiz':
                $results->extraEmailDetail = __('Since you didn\'t pass the quiz, the instructor has asked that you re-take this quiz.', 'wp_courseware');
                if ($userRetakeMsg) {
                    $results->extraEmailDetail .= "\n\n" . $userRetakeMsg;
                }
                break;
                // User is allowed to progress
            // User is allowed to progress
            case 'progress_anyway':
                $results->extraEmailDetail = __('Although you didn\'t pass the quiz, the instructor is allowing you to continue.', 'wp_courseware');
                // Mark the unit as completed.
                WPCW_units_saveUserProgress_Complete($userID, $unitID);
                // Unit complete, check if course/module is complete too.
                do_action('wpcw_user_completed_unit', $userID, $unitID, WPCW_units_getAssociatedParentData($unitID));
                break;
        }
        // Tell code to send out emails
        $results->sendOutEmails = true;
    }
    $results->quiz_has_just_been_graded = true;
    return $results;
}
Example #18
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;
}
Example #19
0
/**
 * Determine if we're on a page just related to this plugin in the admin area.
 * @return Boolean True if we're on an admin page, false otherwise.
 */
function WPCW_areWeOnPluginPage()
{
    // Checks for admin.php?page=
    if ($currentPage = WPCW_arrays_getValue($_GET, 'page')) {
        // This handles any admin page for our plugin.
        if (substr($currentPage, 0, 5) == 'WPCW_') {
            return true;
        }
    }
    return false;
}
Example #20
0
    /**
     * Output the form that allows questions to be configured.
     */
    function editForm_toString()
    {
        $answerList = false;
        if ($this->quizItem->question_data_answers) {
            $answerList = WPCW_quizzes_decodeAnswers($this->quizItem->question_data_answers);
        }
        $html = false;
        // Extra CSS for errors
        $errorClass_Question = false;
        $errorClass_CorAnswer = false;
        // Error Check - Have we got an issue with a lack of question?
        if ($this->showErrors) {
            if (!$this->quizItem->question_question) {
                $errorClass_Question = 'wpcw_quiz_missing';
                $this->gotError = true;
            }
            if ($this->needCorrectAnswers && !$this->quizItem->question_correct_answer) {
                $errorClass_CorAnswer = 'wpcw_quiz_missing';
                $this->gotError = true;
            }
        }
        // Track columns needed to show question details
        $columnCount = 4;
        // Render just the question area
        $html .= sprintf('<li id="wpcw_quiz_details_%s" class="%s"><table class="wpcw_quiz_details_questions_wrap" cellspacing="0">', $this->quizItem->question_id, $this->cssClasses);
        // Details of the question - top of the question details.
        $html .= $this->getSection_processHeader($columnCount);
        // Main question details here...
        $html .= sprintf('<tr class="wpcw_quiz_row_question %s">', $errorClass_Question);
        $html .= sprintf('<th>%s</th>', __('Question', 'wp_courseware'));
        $html .= sprintf('<td>');
        $html .= sprintf('<textarea name="question_question_%s">%s</textarea>', $this->quizItem->question_id, htmlspecialchars($this->quizItem->question_question));
        $html .= sprintf('<input type="hidden" name="question_type_%s" value="multi" />', $this->quizItem->question_id);
        // Field storing order of question among other questions
        $html .= sprintf('<input type="hidden" name="question_order_%s" value="%s" class="wpcw_question_hidden_order" />', $this->quizItem->question_id, $this->quizItem->question_order + 0);
        $html .= sprintf('</td>');
        // Only show column if need correct answers.
        $html .= sprintf('<td class="wpcw_quiz_details_tick_correct wpcw_quiz_only_td">%s</td>', __('Correct<br/>Answer?', 'wp_courseware'));
        // Column for add/remove buttons
        $html .= '<td>&nbsp;</td>';
        $html .= sprintf('</tr>');
        // Render the section that allows an image to be shown.
        $html .= $this->getSection_showImageField($columnCount);
        // Render the field that allows answers to be randomized
        $html .= $this->getSection_showRandomizeAnswersField($columnCount);
        // Render the list of answers if we have any.
        if ($answerList) {
            $count = 0;
            $odd = true;
            foreach ($answerList as $answerItem) {
                // Extract image if available
                $answerItemImageVal = WPCW_arrays_getValue($answerItem, 'image');
                // Exract the answer if available
                $answerItemVal = trim($answerItem['answer']);
                $count++;
                // Show an error if the field is still blank.
                $errorClass_Answer = false;
                if ($this->showErrors) {
                    // Check that answer contains some characters.
                    if (strlen($answerItemVal) == 0) {
                        $errorClass_Answer = 'wpcw_quiz_missing';
                        $this->gotError = true;
                    }
                }
                // Add 'data-answer-id' field to store the ID of this row, and other rows that match this.
                $html .= sprintf('<tr class="wpcw_quiz_row_answer %s %s" data-answer-id="%d">', $errorClass_Answer, $odd ? 'alternate' : '', $count);
                $html .= sprintf('<th>%s <span>%d</span></th>', __('Answer', 'wp_courseware'), $count);
                $html .= sprintf('<td><input type="text" name="question_answer_%s[%d]" value="%s" /></td>', $this->quizItem->question_id, $count, htmlspecialchars($answerItemVal));
                // Correct answer column
                $html .= sprintf('<td class="wpcw_quiz_details_tick_correct wpcw_quiz_only_td">
										<input type="radio" name="question_answer_sel_%s" value="%s" %s />
									  </td>', $this->quizItem->question_id, $count, $this->quizItem->question_correct_answer == $count ? 'checked="checked"' : false);
                // Buttons for add/remove questions
                $html .= sprintf('
					<td class="wpcw_quiz_add_rem">
						<a href="#" title="%s" class="wpcw_question_add"><img src="%simg/icon_add_32.png" /></a>
						<a href="#" title="%s" class="wpcw_question_remove"><img src="%simg/icon_remove_32.png" /></a>
					</td>', __('Add a new answer...', 'wp_courseware'), WPCW_plugin_getPluginPath(), __('Remove this answer...', 'wp_courseware'), WPCW_plugin_getPluginPath());
                $html .= sprintf('</tr>');
                // Add the image URL for this answer - added as a new row.
                $html .= sprintf('<tr class="wpcw_quiz_row_answer_image wpcw_quiz_row_answer_image_%d %s %s">', $count, $errorClass_Answer, $odd ? 'alternate' : '');
                $html .= sprintf('<th>%s <span class="wpcw_inner_hint">%s</span></th>', __('Answer Image URL', 'wp_courseware'), __('(Optional) ', 'wp_courseware'));
                $html .= '<td>';
                // Field name - needs to use underscore, as square brackets break the jQuery to find the target.
                $thisAnswerFieldName = 'question_answer_image_' . $this->quizItem->question_id . '_' . $count;
                // The URL field.
                $html .= sprintf('<input type="text" name="question_answer_image_%s[%d]" id="%s" value="%s" />', $this->quizItem->question_id, $count, $thisAnswerFieldName, $answerItemImageVal);
                // The insert button.
                $html .= sprintf('<span class="wpcw_insert_image_wrap"><a href="#" class="button wpcw_insert_image" data-uploader_title="%s" data-uploader_btn_text="%s" data-target="%s" title="%s"><span class="wpcw_insert_image_img"></span> %s</a></span>', __('Choose an image for this answer...', 'wp_courseware'), __('Select Image...', 'wp_courseware'), $thisAnswerFieldName, __('Select Image', 'wp_courseware'), __('Select Image', 'wp_courseware'));
                $html .= '</td>';
                // Filler for the remaining space
                $html .= '<td colspan="2"></td>';
                $html .= sprintf('</tr>');
                $odd = !$odd;
            }
        }
        // Extra fields at the bottom of a question.
        $html .= $this->getSection_processFooter($columnCount);
        // All done
        $html .= sprintf('</table></li>');
        return $html;
    }
Example #21
0
 /**
  * Renders the signature area for the certificate.
  */
 function render_handleSignature()
 {
     // Have we got a text or image signature?
     $signature = '';
     $signatureType = WPCW_arrays_getValue($this->settingsList, 'cert_signature_type', 'text');
     $signatureImg = WPCW_arrays_getValue($this->settingsList, 'cert_sig_image_url');
     // Get the text for the signature
     if ('text' == $signatureType) {
         $signature = WPCW_arrays_getValue($this->settingsList, 'cert_sig_text');
         // Nothing to do, signature is empty
         if (!$signature) {
             return;
         }
         // Create the signature
         $signature_len = $this->pdffile->GetStringWidth($signature);
         $this->pdffile->SetXY($this->signature_X + ($this->footer_line_length - $signature_len) / 2, $this->footer_Y);
         $this->pdffile->Cell(0, 0, $signature, false, false);
     } else {
         // No image to work with
         if (!$signatureImg) {
             return;
         }
         // Image is fetched using URL, and resized to match the space. We're using
         // an image that's twice the size to get it to scale nicely.
         $sigWidth = WPCW_Certificate::px2mm(WPCW_CERTIFICATE_SIGNATURE_WIDTH_PX);
         $sigHeight = WPCW_Certificate::px2mm(WPCW_CERTIFICATE_SIGNATURE_HEIGHT_PX);
         $this->pdffile->Image($signatureImg, $this->signature_X + ($this->footer_line_length - $sigWidth) / 2, $this->footer_Y - $sigHeight + 3, $sigWidth);
         // Only force width
     }
 }
Example #22
0
/**
 * Function that allows a module to be created or edited.
 */
function WPCW_showPage_ModifyModule_load()
{
    $page = new PageBuilder(true);
    $moduleDetails = false;
    $moduleID = false;
    $adding = false;
    // Trying to edit a course
    if (isset($_GET['module_id'])) {
        $moduleID = $_GET['module_id'] + 0;
        $moduleDetails = WPCW_modules_getModuleDetails($moduleID);
        // Abort if module not found.
        if (!$moduleDetails) {
            $page->showPageHeader(__('Edit Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
            $page->showMessage(__('Sorry, but that module could not be found.', 'wp_courseware'), true);
            $page->showPageFooter();
            return;
        } else {
            $page->showPageHeader(__('Edit Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
        }
    } else {
        $page->showPageHeader(__('Add Module', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
        $adding = true;
    }
    global $wpcwdb;
    $formDetails = array('module_title' => array('label' => __('Module Title', 'wp_courseware'), 'type' => 'text', 'required' => true, 'cssclass' => 'wpcw_module_title', 'desc' => __('The title of your module. You <b>do not need to number the modules</b> - this is done automatically based on the order that they are arranged.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 150, 'minlen' => 1, 'regexp' => '/^[^<>]+$/', 'error' => __('Please specify a name for your module, up to a maximum of 150 characters, just no angled brackets (&lt; or &gt;). Your trainees will be able to see this module title.', 'wp_courseware'))), 'parent_course_id' => array('label' => __('Associated Course', 'wp_courseware'), 'type' => 'select', 'required' => true, 'cssclass' => 'wpcw_associated_course', 'desc' => __('The associated training course that this module belongs to.', 'wp_courseware'), 'data' => WPCW_courses_getCourseList(__('-- Select a Training Course --', 'wp_courseware'))), 'module_desc' => array('label' => __('Module Description', 'wp_courseware'), 'type' => 'textarea', 'required' => true, 'cssclass' => 'wpcw_module_desc', 'desc' => __('The description of this module. Your trainees will be able to see this module description.', 'wp_courseware'), 'validate' => array('type' => 'string', 'maxlen' => 5000, 'minlen' => 1, 'error' => __('Please limit the description of your module to 5000 characters.', 'wp_courseware'))));
    $form = new RecordsForm($formDetails, $wpcwdb->modules, 'module_id');
    $form->customFormErrorMsg = __('Sorry, but unfortunately there were some errors saving the module details. Please fix the errors and try again.', 'wp_courseware');
    $form->setAllTranslationStrings(WPCW_forms_getTranslationStrings());
    // 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 = __('Module details successfully created.', 'wp_courseware') . $directionMsg;
    $form->msg_record_updated = __('Module details successfully updated.', 'wp_courseware') . $directionMsg;
    $form->setPrimaryKeyValue($moduleID);
    $form->setSaveButtonLabel(__('Save ALL Details', 'wp_courseware'));
    // See if we have a course ID to pre-set.
    if ($adding && ($courseID = WPCW_arrays_getValue($_GET, 'course_id'))) {
        $form->loadDefaults(array('parent_course_id' => $courseID));
    }
    // Call to re-order modules once they've been created
    $form->afterSaveFunction = 'WPCW_actions_modules_afterModuleSaved_formHook';
    $form->show();
    $page->showPageMiddle('20%');
    // Editing a module?
    if ($moduleDetails) {
        // ### Include a link to delete the module
        $page->openPane('wpcw-deletion-module', __('Delete Module?', 'wp_courseware'));
        printf('<a href="%s&action=delete_module&module_id=%d" class="wpcw_delete_item" title="%s">%s</a>', admin_url('admin.php?page=WPCW_wp_courseware'), $moduleID, __("Are you sure you want to delete the this module?\n\nThis CANNOT be undone!", 'wp_courseware'), __('Delete this Module', 'wp_courseware'));
        printf('<p>%s</p>', __('Units will <b>not</b> be deleted, they will <b>just be disassociated</b> from this module.', 'wp_courseware'));
        $page->closePane();
        // #### Show a list of all sub-units
        $page->openPane('wpcw-units-module', __('Units in this Module', 'wp_courseware'));
        $unitList = WPCW_units_getListOfUnits($moduleID);
        if ($unitList) {
            printf('<ul class="wpcw_unit_list">');
            foreach ($unitList as $unitID => $unitObj) {
                printf('<li>%s %d - %s</li>', __('Unit', 'wp_courseware'), $unitObj->unit_meta->unit_number, $unitObj->post_title);
            }
            printf('</ul>');
        } else {
            printf('<p>%s</p>', __('There are currently no units in this module.', 'wp_courseware'));
        }
    }
    $page->showPageFooter();
}
Example #23
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 #24
0
    /**
     * Shows the configuration form for the widget.
     */
    function form($instance)
    {
        // Create a default title if there is one.
        if ($instance) {
            $title = esc_attr($instance['title']);
        } else {
            $title = __('Current User Progress', 'wp_courseware');
        }
        $option_course = esc_attr(WPCW_arrays_getValue($instance, 'option_course'));
        $option_module = esc_attr(WPCW_arrays_getValue($instance, 'option_module'));
        $option_show_course_title = WPCW_arrays_getValue($instance, 'option_show_course_title') == 'on' ? 'checked="checked"' : '';
        $option_show_course_desc = WPCW_arrays_getValue($instance, 'option_show_course_desc') == 'on' ? 'checked="checked"' : '';
        $option_show_module_desc = WPCW_arrays_getValue($instance, 'option_show_module_desc') == 'on' ? 'checked="checked"' : '';
        $option_show_only_on_units = WPCW_arrays_getValue($instance, 'option_show_only_on_units') == 'on' ? 'checked="checked"' : '';
        // Module visibility Toggling
        $option_toggle_modules = esc_attr(WPCW_arrays_getValue($instance, 'option_toggle_modules'));
        $option_show_modules_previous = esc_attr(WPCW_arrays_getValue($instance, 'option_show_modules_previous'));
        $option_show_modules_next = esc_attr(WPCW_arrays_getValue($instance, 'option_show_modules_next'));
        // Generate dropdowns for the previous/next options
        $optionsList_previous = array('all' => __('All previous modules', 'wp_courseware'), 'none' => __('None', 'wp_courseware'));
        for ($i = 1; $i <= 20; $i++) {
            $optionsList_previous[$i] = sprintf(_n('Show just 1 previous module', 'Show %d previous modules', $i, 'wp_courseware'), $i);
        }
        $optionsList_next = array('all' => __('All subsequent modules', 'wp_courseware'), 'none' => __('None', 'wp_courseware'));
        for ($i = 1; $i <= 20; $i++) {
            $optionsList_next[$i] = sprintf(_n('Show just 1 subsequent module', 'Show %d subsequent modules', $i, 'wp_courseware'), $i);
        }
        ?>
		<p>
			<b><label for="<?php 
        echo $this->get_field_id('title');
        ?>
"><?php 
        _e('Title:', 'wp_courseware');
        ?>
</label></b> 
			<input class="widefat" id="<?php 
        echo $this->get_field_id('title');
        ?>
" name="<?php 
        echo $this->get_field_name('title');
        ?>
" type="text" value="<?php 
        echo $title;
        ?>
" />
			<small><?php 
        _e('(Optional) Leave blank for no title.', 'wp_courseware');
        ?>
</small>
		</p>
		
		<p>
			<b style="display: block; padding-bottom: 3px;"><label for="<?php 
        echo $this->get_field_id('option_course');
        ?>
"><?php 
        _e('Course To Show:', 'wp_courseware');
        ?>
</label></b>
			<?php 
        $courseList = array('' => __('-- Select a Training Course --', 'wp_courseware'), 'current' => __("Show User's Current Course", 'wp_courseware'));
        // Blend lists together
        $mainCourseList = WPCW_courses_getCourseList();
        if ($mainCourseList) {
            $courseList = $courseList + $mainCourseList;
        }
        echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_course'), $courseList, $option_course, $this->get_field_id('option_course'));
        ?>
			<br/><small><?php 
        _e('(Required) Choose whether to display a specific course to the user or to display the course associated with the unit that the user is currently viewing.', 'wp_courseware');
        ?>
</small>
		</p>
		
		<p>
			<b style="display: block; padding-bottom: 3px;"><label><?php 
        _e('Show/Hide Modules:', 'wp_courseware');
        ?>
</label></b>
			<small><?php 
        _e('Here you can control how many modules to show before and after the current module to save space.', 'wp_courseware');
        ?>
</small>
		</p>
		
		<table>
			<tr>
				<td><label for="<?php 
        echo $this->get_field_id('option_show_modules_previous');
        ?>
"><?php 
        _e('Previous modules to display:', 'wp_courseware');
        ?>
</label></td>
				<td><label for="<?php 
        echo $this->get_field_id('option_show_modules_next');
        ?>
"><?php 
        _e('Subsequent modules to display:', 'wp_courseware');
        ?>
</label></td>
			</tr>
			
			<tr>
				<td>
					<?php 
        echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_show_modules_previous'), $optionsList_previous, $option_show_modules_previous, $this->get_field_id('option_show_modules_previous'));
        ?>
				</td>
				
				<td>
					<?php 
        echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_show_modules_next'), $optionsList_next, $option_show_modules_next, $this->get_field_id('option_show_modules_next'));
        ?>
				</td>
			</tr>
		</table><br/>
		
		<p>
			<b style="display: block; padding-bottom: 3px;"><label for="<?php 
        echo $this->get_field_id('option_toggle_modules');
        ?>
"><?php 
        _e('Expand/Contract Modules:', 'wp_courseware');
        ?>
</label></b>
			<?php 
        echo WPCW_CourseProgress::createDropdown($this->get_field_name('option_toggle_modules'), array('expand_all' => __('Expand all modules', 'wp_courseware'), 'contract_all_but_current' => __('Contract all except current module', 'wp_courseware'), 'contract_all' => __('Contract all modules', 'wp_courseware')), $option_toggle_modules, $this->get_field_id('option_toggle_modules'));
        ?>
			<br/><small><?php 
        _e('You can save sidebar space by contracting  modules in the widget to just show the module title.', 'wp_courseware');
        ?>
</small>
		</p>
		
		<?php 
        /*
        // Likely to be deprecated.
        <p>
        	<b><label for="<?php echo $this->get_field_id('option_module'); ?>"><?php _e('Module:', 'wp_courseware'); ?></label></b> 
        	<input class="widefat" id="<?php echo $this->get_field_id('option_module'); ?>" name="<?php echo $this->get_field_name('option_module'); ?>" type="text" value="<?php echo $option_module; ?>" />
        	<small><?php _e('(Optional) The module number of a module in this course to show specifically (rather than all modules in the course).', 'wp_courseware'); ?></small>
        </p>
        */
        ?>
		
		<p>
			<b style="display: block; padding-bottom: 3px;"><label for="<?php 
        echo $this->get_field_id('option_show_module_desc');
        ?>
"><?php 
        _e('More Options:', 'wp_courseware');
        ?>
</label></b>
			<input id="<?php 
        echo $this->get_field_id('option_show_course_title');
        ?>
" name="<?php 
        echo $this->get_field_name('option_show_course_title');
        ?>
" type="checkbox" <?php 
        echo $option_show_course_title;
        ?>
 /> <?php 
        _e('Show Course Title', 'wp_courseware');
        ?>
<br/>
			<input id="<?php 
        echo $this->get_field_id('option_show_course_desc');
        ?>
" name="<?php 
        echo $this->get_field_name('option_show_course_desc');
        ?>
" type="checkbox" <?php 
        echo $option_show_course_desc;
        ?>
 /> <?php 
        _e('Show Course Description', 'wp_courseware');
        ?>
<br/>
			<input id="<?php 
        echo $this->get_field_id('option_show_module_desc');
        ?>
" name="<?php 
        echo $this->get_field_name('option_show_module_desc');
        ?>
" type="checkbox" <?php 
        echo $option_show_module_desc;
        ?>
 /> <?php 
        _e('Show Module Descriptions', 'wp_courseware');
        ?>
<br/>
			
			<input id="<?php 
        echo $this->get_field_id('option_show_only_on_units');
        ?>
" name="<?php 
        echo $this->get_field_name('option_show_only_on_units');
        ?>
" type="checkbox" <?php 
        echo $option_show_only_on_units;
        ?>
 /> <?php 
        _e('Only display this widget when showing a course unit', 'wp_courseware');
        ?>
		</p>
		<?php 
    }
/**
 * Handle any deletion if any has been requested.
 * @param Object $page The reference to the object showing the page content
 */
function WPCW_handler_processDeletion($page)
{
    // Check for deletion command
    if (!isset($_GET['action'])) {
        return;
    }
    $action = WPCW_arrays_getValue($_GET, 'action');
    switch ($action) {
        // ### Deleting a module
        case 'delete_module':
            $module_id = WPCW_arrays_getValue($_GET, 'module_id');
            $moduleDetails = WPCW_modules_getModuleDetails($module_id);
            if ($moduleDetails) {
                // Actually delete the module from the system
                WPCW_modules_deleteModule($moduleDetails);
                $page->showMessage(sprintf(__('Successfully deleted module "<em>%s</em>".', 'wp_courseware'), $moduleDetails->module_title));
            }
            break;
            // ### Deleting a course
        // ### Deleting a course
        case 'delete_course':
            $course_id = WPCW_arrays_getValue($_GET, 'course_id');
            $courseDetails = WPCW_courses_getCourseDetails($course_id);
            if ($courseDetails) {
                // What deletion method?
                $deleteMethod = 'complete';
                if ('course_and_module' == WPCW_arrays_getValue($_POST, 'delete_course_type')) {
                    $deleteMethod = 'course_and_module';
                }
                // Actually delete the course from the system
                WPCW_modules_deleteCourse($courseDetails, $deleteMethod);
                $page->showMessage(sprintf(__('Successfully deleted training course "<em>%s</em>".', 'wp_courseware'), $courseDetails->course_title));
            }
            break;
    }
}
Example #26
0
 /**
  * Generate the results PDF.
  * 
  * @param String $showMode What type of export to do. ('download' to force a download or 'browser' to do it inline.)
  */
 function generatePDF($showMode = 'download')
 {
     // Start with main content
     $this->pdffile->setY(25);
     $this->pdffile->SetFont('dejavusans', '', 11, '', true);
     // Do codepage conversions of text used in the certificate.
     $encoding = WPCW_arrays_getValue($this->settingsList, 'certificate_encoding', 'ISO-8859-1');
     //$this->data_traineeName    	= iconv('UTF-8', $encoding.'//TRANSLIT//IGNORE', $this->data_traineeName);
     //$this->data_courseName 		= iconv('UTF-8', $encoding.'//TRANSLIT//IGNORE', $this->data_courseName);
     //$this->data_quizName 		= iconv('UTF-8', $encoding.'//TRANSLIT//IGNORE', $this->data_quizName);
     // Work out the maximum width of labels to use so that the labels line up.
     $labelList = array('course' => __('Course Name:', 'wp_courseware'), 'quiz' => __('Quiz Title:', 'wp_courseware'), 'trainee' => __('Candidate Name:', 'wp_courseware'));
     $labelWidth = 20;
     foreach ($labelList as $key => $label) {
         $labelWidth = max($labelWidth, $this->pdffile->GetStringWidth($label));
     }
     $labelWidth += 4;
     $this->pdffile->SetLineWidth(0.25);
     $this->pdffile->SetDrawColor(0, 0, 0);
     $this->pdffile->Ln(2);
     $this->pdffile->Line(10, $this->pdffile->GetY(), 200, $this->pdffile->GetY());
     $this->pdffile->Ln(2);
     // Course Title
     $this->outputLabel($labelList['course'], $this->data_courseName, $labelWidth);
     //$this->outputLabel($labelList['course'], 'This is a reallly really long course title to test with to see if wrapping happens really nicely because this is really important and we want it to look good.', $labelWidth);
     // Quiz Title
     $this->outputLabel($labelList['quiz'], $this->data_quizName, $labelWidth);
     // Candidate Name
     $this->outputLabel($labelList['trainee'], $this->data_traineeName, $labelWidth);
     $this->pdffile->Ln(2);
     $this->pdffile->setImageScale(3);
     // Render the messages that we have.
     if (!empty($this->data_Messages)) {
         $messageToShow = false;
         // 1) Check for messages by row. If we've got a row, then render each item.
         //    There are a maximum of 5 rows.
         for ($idx = 0; $idx < 5; $idx++) {
             if (!empty($this->data_Messages[$idx])) {
                 // There may be multiple messages per row.
                 foreach ($this->data_Messages[$idx] as $keyName => $stringToShow) {
                     $messageToShow .= $stringToShow . ' ';
                 }
                 $messageToShow .= '<br><br>';
             }
         }
         // Render as a single box with padding
         if ($messageToShow) {
             $this->pdffile->SetFont('dejavusans', '', 11);
             // Set text colour based on pass or fail.
             if ($this->data_Messages['error_mode']) {
                 $this->pdffile->SetTextColor(255, 0, 0);
             } else {
                 $this->pdffile->SetTextColor(0, 128, 0);
             }
             // Need to remove the final <br><br>
             $messageToShow = substr($messageToShow, 0, -8);
             // 8 due to 8 chars in <br><br>
             $this->pdffile->writeHTML($messageToShow);
             $this->pdffile->Ln(4);
             // Restore colour
             $this->pdffile->SetTextColor(0, 0, 0);
         }
         // Line underneath the message summary
         $this->pdffile->Line(10, $this->pdffile->GetY(), 200, $this->pdffile->GetY());
         $this->pdffile->Ln(3);
         // Set new body size
         $this->pdffile->SetFont('dejavusans', '', 10);
         $showingTags = false;
         $showingTimer = false;
         // 2) Show the progress by tag if present.
         if (isset($this->data_Messages['msg_results_by_tag']) && !empty($this->data_Messages['msg_results_by_tag'])) {
             $showingTags = true;
             // Create Results breakdown label
             $this->pdffile->SetFont('', 'B', 11);
             $this->pdffile->WriteHTML(__('Results breakdown:', 'wp_courseware'));
             $this->pdffile->Ln(2);
             $this->pdffile->SetFont('', 'B', 10);
             // Add a wrapper per line for the tag results.
             foreach ($this->data_Messages['msg_results_by_tag'] as $tagMessage) {
                 $this->pdffile->WriteHTML('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' . $tagMessage);
                 $this->pdffile->Ln(1);
             }
             $this->pdffile->Ln(0);
         }
         // 2) Show the progress by timer if present.
         if (isset($this->data_Messages['msg_results_by_timer'])) {
             $showingTimer = false;
             if ($showingTags) {
                 $this->pdffile->Ln(3);
                 $this->pdffile->Line(10, $this->pdffile->GetY(), 200, $this->pdffile->GetY());
                 $this->pdffile->Ln(2);
             }
             $this->pdffile->WriteHTML($this->data_Messages['msg_results_by_timer']);
             $this->pdffile->Ln(1);
         }
         // 3) Show extra line for clarity
         if ($showingTags || $showingTimer) {
             $this->pdffile->Ln(2);
             $this->pdffile->Line(10, $this->pdffile->GetY(), 200, $this->pdffile->GetY());
             $this->pdffile->Ln(3);
         }
     }
     // 4) - Render the results data we have for this quiz
     if (!empty($this->data_Results)) {
         // Create Results breakdown label
         $this->pdffile->Ln(4);
         $this->pdffile->SetFont('dejavusansb', 'B', 14);
         $this->pdffile->Write(5, __('Your answer details:', 'wp_courseware'), false, false, 'C', true);
         $this->pdffile->Ln(5);
         // Set up text size and compact it
         $this->pdffile->SetFont('dejavusans', '', 10);
         $this->pdffile->setCellHeightRatio(0.9);
         foreach ($this->data_Results as $singleLineOfData) {
             // Set colours
             $this->pdffile->SetFillColor(239, 239, 239);
             $this->pdffile->SetDrawColor(200, 200, 200);
             // Render each results box
             $this->pdffile->SetCellPadding(5);
             $this->pdffile->WriteHTMLCell(0, 0, 10, $this->pdffile->GetY(), $singleLineOfData, 'TBLR', true, true);
             $this->pdffile->Ln(5);
         }
     }
     // 5) - Render the custom feedback messages
     if (!empty($this->data_Feedback)) {
         // Create Results breakdown label
         $this->pdffile->Ln(4);
         $this->pdffile->SetFont('dejavusansb', 'B', 14);
         $this->pdffile->Write(5, __('Instructor Feedback:', 'wp_courseware'), false, false, 'C', true);
         $this->pdffile->Ln(3);
         // Set up text size and compact it
         $this->pdffile->SetFont('dejavusans', '', 10);
         $this->pdffile->setCellHeightRatio(1);
         foreach ($this->data_Feedback as $singleLineOfData) {
             // Set colours
             $this->pdffile->SetFillColor(239, 239, 239);
             $this->pdffile->SetDrawColor(200, 200, 200);
             // Render each results box
             $this->pdffile->SetCellPadding(5);
             $this->pdffile->WriteHTMLCell(0, 0, 10, $this->pdffile->GetY(), wpautop($singleLineOfData), 'TBLR', true, true);
             $this->pdffile->Ln(5);
         }
     }
     // Change output based on what's been specified as a parameter.
     $exportFile = "quiz-results-" . sanitize_title($this->data_quizName) . '-' . date("Y-m-d") . ".pdf";
     if ('browser' == $showMode) {
         $this->pdffile->Output($exportFile, 'I');
     } else {
         $this->pdffile->Output($exportFile, 'D');
     }
 }
/** 
 * Page where the site owner can choose which courses a user is allowed to access.
 */
function WPCW_showPage_UserCourseAccess_load()
{
    global $wpcwdb, $wpdb;
    $wpdb->show_errors();
    $page = new PageBuilder(false);
    $page->showPageHeader(__('Update User Course Access Permissions', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL());
    // Check passed user ID is valid
    $userID = WPCW_arrays_getValue($_GET, 'user_id');
    $userDetails = get_userdata($userID);
    if (!$userDetails) {
        $page->showMessage(__('Sorry, but that user could not be found.', 'wp_courseware'), true);
        $page->showPageFooter();
        return false;
    }
    printf(__('<p>Here you can change which courses the user <b>%s</b> (Username: <b>%s</b>) can access.</p>', 'wp_courseware'), $userDetails->data->display_name, $userDetails->data->user_login);
    // Check to see if anything has been submitted?
    if (isset($_POST['wpcw_course_user_access'])) {
        $subUserID = WPCW_arrays_getValue($_POST, 'user_id') + 0;
        $userSubDetails = get_userdata($subUserID);
        // Check that user ID is valid, and that it matches user we're editing.
        if (!$userSubDetails || $subUserID != $userID) {
            $page->showMessage(__('Sorry, but that user could not be found. The changes were not saved.', 'wp_courseware'), true);
        } else {
            // Get list of courses that user is allowed to access from the submitted values.
            $courseAccessIDs = array();
            foreach ($_POST as $key => $value) {
                // Check for course ID selection
                if (preg_match('/^wpcw_course_(\\d+)$/', $key, $matches)) {
                    $courseAccessIDs[] = $matches[1];
                }
            }
            // Sync courses that the user is allowed to access
            WPCW_courses_syncUserAccess($subUserID, $courseAccessIDs, 'sync');
            // Final success message
            $message = sprintf(__('The courses for user <em>%s</em> have now been updated.', 'wp_courseware'), $userDetails->data->display_name);
            $page->showMessage($message, false);
        }
    }
    $SQL = "SELECT * \n\t\t\tFROM {$wpcwdb->courses}\n\t\t\tORDER BY course_title ASC \n\t\t\t";
    $courses = $wpdb->get_results($SQL);
    if ($courses) {
        $tbl = new TableBuilder();
        $tbl->attributes = array('id' => 'wpcw_tbl_course_access_summary', 'class' => 'widefat wpcw_tbl');
        $tblCol = new TableColumn(__('Allowed Access', 'wp_courseware'), 'allowed_access');
        $tblCol->cellClass = "allowed_access";
        $tbl->addColumn($tblCol);
        $tblCol = new TableColumn(__('Course Title', 'wp_courseware'), 'course_title');
        $tblCol->cellClass = "course_title";
        $tbl->addColumn($tblCol);
        $tblCol = new TableColumn(__('Description', 'wp_courseware'), 'course_desc');
        $tblCol->cellClass = "course_desc";
        $tbl->addColumn($tblCol);
        // Format row data and show it.
        $odd = false;
        foreach ($courses as $course) {
            $data = array();
            // Basic details
            $data['course_desc'] = $course->course_desc;
            $editURL = admin_url('admin.php?page=WPCW_showPage_ModifyCourse&course_id=' . $course->course_id);
            $data['course_title'] = sprintf('<a href="%s">%s</a>', $editURL, $course->course_title);
            // Checkbox if enabled or not
            $userAccess = WPCW_courses_canUserAccessCourse($course->course_id, $userID);
            $checkedHTML = $userAccess ? 'checked="checked"' : '';
            $data['allowed_access'] = sprintf('<input type="checkbox" name="wpcw_course_%d" %s/>', $course->course_id, $checkedHTML);
            // Odd/Even row colouring.
            $odd = !$odd;
            $tbl->addRow($data, $odd ? 'alternate' : '');
        }
        // Create a form so user can update access.
        ?>
		<form action="<?php 
        str_replace('%7E', '~', $_SERVER['REQUEST_URI']);
        ?>
" method="post">
			<?php 
        // Finally show table
        echo $tbl->toString();
        ?>
			<input type="hidden" name="user_id" value="<?php 
        echo $userID;
        ?>
"> 
			<input type="submit" class="button-primary" name="wpcw_course_user_access" value="<?php 
        _e('Save Changes', 'wp_courseware');
        ?>
" />
		</form>
		<?php 
    } else {
        printf('<p>%s</p>', __('There are currently no courses to show. Why not create one?', 'wp_courseware'));
    }
    $page->showPageFooter();
}
/**
 * Process the action form to change tags for the selected questions.
 */
function WPCW_showPage_QuestionPool_processActionForm($page)
{
    global $wpdb, $wpcwdb;
    $wpdb->show_errors();
    if (!isset($_POST['wpcw_bulk_action_actions'])) {
        return;
    }
    // #### #1 - Get a list of the questions to update
    $questionListToUpdate = array();
    foreach ($_POST as $key => $value) {
        // We're looking for these to get the question ID
        // 		[question_162] => on
        //		[question_149] => on
        if (preg_match('/^question_([0-9]+)$/', $key, $matches)) {
            $questionListToUpdate[] = $matches[1];
        }
    }
    // Appears there's nothing to do.
    if (empty($questionListToUpdate)) {
        $page->showMessage(__('Error. Please select some questions to update.', 'wp_courseware'), true);
        return;
    }
    // #### #2 - Validate that the questions do indeed exist
    // Direct SQL is ok here, as IDs have been validated with the regex previously.
    $questionListStr = implode(',', $questionListToUpdate);
    $validatedQuestions = $wpdb->get_col("\n\t\tSELECT * \n\t\tFROM {$wpcwdb->quiz_qs}\n\t\tWHERE question_id IN ({$questionListStr}) \n\t");
    // Appears there's nothing to do, as questions do not validate.
    if (empty($questionListToUpdate)) {
        $page->showMessage(__('Error. Those questions no longer exist. Please select some more questions to update.', 'wp_courseware'), true);
        return;
    }
    // #### #3 - Check that the action is what we're expecting.
    $actionToProcess = WPCW_arrays_getValue($_POST, 'wpcw_bulk_action_actions');
    switch ($actionToProcess) {
        case 'add_tag':
        case 'remove_tag':
        case 'replace_tag':
            break;
        default:
            $page->showMessage(__('Error. Did not recognise action to apply to selected questions.', 'wp_courseware'), true);
            return;
            break;
    }
    // #### #4 - Check that we have the tags that we're expecting.
    $tagID_first = WPCW_arrays_getValue($_POST, 'wpcw_bulk_action_select_tag_a', 0);
    $tagID_second = WPCW_arrays_getValue($_POST, 'wpcw_bulk_action_select_tag_b', 0);
    $tagDetails_first = false;
    $tagDetails_second = false;
    if (!($tagDetails_first = WPCW_questions_tags_getTagDetails($tagID_first))) {
        $page->showMessage(__('Error. The first tag does not exist. Please select another tag.', 'wp_courseware'), true);
        return;
    }
    // Check replace tag requirements
    if ('replace_tag' == $actionToProcess) {
        // No 2nd tag
        if (!($tagDetails_second = WPCW_questions_tags_getTagDetails($tagID_second))) {
            $page->showMessage(__('Error. The second tag does not exist. Please select another tag.', 'wp_courseware'), true);
            return;
        }
        // 1st and 2nd tags match
        if ($tagDetails_first->question_tag_id == $tagDetails_second->question_tag_id) {
            $page->showMessage(__('Error. The first and second tag should be different.', 'wp_courseware'), true);
            return;
        }
    }
    // #### #5 - By this point, everything is validated, so just execute the SQL.
    foreach ($validatedQuestions as $questionID) {
        switch ($actionToProcess) {
            case 'add_tag':
                $wpdb->query($wpdb->prepare("\n\t\t\t\t\tINSERT IGNORE {$wpcwdb->question_tag_mapping}\n\t\t\t\t\t(question_id, tag_id) \n\t\t\t\t\tVALUES (%d, %d) \n\t\t\t\t", $questionID, $tagDetails_first->question_tag_id));
                break;
            case 'remove_tag':
                $wpdb->query($wpdb->prepare("\n\t\t\t\t\tDELETE FROM {$wpcwdb->question_tag_mapping}\n\t\t\t\t\tWHERE question_id = %d\n\t\t\t\t\t  AND tag_id = %d \n\t\t\t\t", $questionID, $tagDetails_first->question_tag_id));
                break;
            case 'replace_tag':
                $wpdb->query($wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->question_tag_mapping}\n\t\t\t\t\t  SET tag_id = %d\n\t\t\t\t\tWHERE question_id = %d\n\t\t\t\t\t  AND tag_id = %d \n\t\t\t\t", $tagDetails_second->question_tag_id, $questionID, $tagDetails_first->question_tag_id));
                break;
        }
    }
    // Need to update tag counts
    WPCW_questions_tags_updatePopularity($tagDetails_first->question_tag_id);
    // 2nd is optional, so just need to check it exists first before trying update to prevent
    // an error message.
    if ($tagDetails_second) {
        WPCW_questions_tags_updatePopularity($tagDetails_second->question_tag_id);
    }
    // #### #6 Finally show message
    $page->showMessage(__('Questions successfully updated.', 'wp_courseware'));
}
<?php

// Check that plugin is active (so that this cannot be accessed if plugin isn't).
require dirname(__FILE__) . '/../../../wp-config.php';
// Can't find active WP Courseware init function, so cannot be active.
if (!function_exists('WPCW_plugin_init')) {
    WPCW_certificate_notFound();
}
// Certificate class
include_once 'pdf/pdf_certificates.inc.php';
// Grab the certificate from the parameter
$certificateID = WPCW_arrays_getValue($_GET, 'certificate');
// Nothing to see.
if (!$certificateID) {
    WPCW_certificate_notFound();
}
// #### PREVIEW - Has a preview been requested? Is the user logged in and is permitted to preview.
if ('preview' == $certificateID) {
    // User can change options - allow preview
    if (current_user_can('manage_options')) {
        // See if the provided ID is a valid ID
        $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
 /**
  * Renders the signature area for the certificate.
  */
 function render_handleSignature()
 {
     $topLineY = 257;
     // Have we got a text or image signature?
     $signature = '';
     $signatureType = WPCW_arrays_getValue($this->settingsList, 'cert_signature_type', 'text');
     $signatureImg = WPCW_arrays_getValue($this->settingsList, 'cert_sig_image_url');
     // Get the text for the signature
     if ('text' == $signatureType) {
         // Use codepage translation of signature text
         $encoding = WPCW_arrays_getValue($this->settingsList, 'certificate_encoding', 'ISO-8859-1');
         $signature = iconv('UTF-8', $encoding . '//TRANSLIT//IGNORE', WPCW_arrays_getValue($this->settingsList, 'cert_sig_text'));
         // Nothing to do, signature is empty
         if (!$signature) {
             return;
         }
         // Create the signature
         $signature_len = $this->pdffile->GetStringWidth($signature);
         $this->pdffile->SetXY($this->signature_X + ($this->footer_line_length - $signature_len) / 2, $topLineY);
         $this->pdffile->Cell(300, 150, $signature, false, false);
     } else {
         // No image to work with
         if (!$signatureImg) {
             return;
         }
         // Image is fetched using URL, and resized to match the space. We're using
         // an image that's twice the size to get it to scale nicely.
         $sigWidth = WPCW_Certificate::px2mm(WPCW_CERTIFICATE_SIGNATURE_WIDTH_PX);
         $sigHeight = WPCW_Certificate::px2mm(WPCW_CERTIFICATE_SIGNATURE_HEIGHT_PX);
         // Only force width
         $this->pdffile->Image($signatureImg, 122, 252, $sigWidth);
     }
 }