/** * 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(' <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(); }
/** * 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>'); }
/** * 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); }
/** * 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; }
/** * Function that show a summary of the quizzes. */ function WPCW_showPage_QuizSummary_load() { global $wpcwdb, $wpdb; $wpdb->show_errors(); // Get the requested page number $paging_pageWanted = WPCW_arrays_getValue($_GET, 'pagenum') + 0; if ($paging_pageWanted == 0) { $paging_pageWanted = 1; } // Title for page with page number $titlePage = false; if ($paging_pageWanted > 1) { $titlePage = sprintf(' - %s %s', __('Page', 'wp_courseware'), $paging_pageWanted); } $page = new PageBuilder(false); $page->showPageHeader(__('Quiz & Survey Summary', 'wp_courseware') . $titlePage, '75%', WPCW_icon_getPageIconURL()); // Handle the quiz deletion before showing remaining quizzes... WPCW_quizzes_handleQuizDeletion($page); // Handle the sorting and filtering $orderBy = WPCW_arrays_getValue($_GET, 'orderby'); $ordering = WPCW_arrays_getValue($_GET, 'order'); // Validate ordering switch ($orderBy) { case 'quiz_title': case 'quiz_id': break; default: $orderBy = 'quiz_id'; break; } // Create opposite ordering for reversing it. $ordering_opposite = false; switch ($ordering) { case 'desc': $ordering_opposite = 'asc'; break; case 'asc': $ordering_opposite = 'desc'; break; default: $ordering = 'desc'; $ordering_opposite = 'asc'; break; } // Was a search string specified? Or a specific item? $searchString = WPCW_arrays_getValue($_GET, 's'); // Create WHERE string based search - Title or Description of Quiz $stringWHERE = false; if ($searchString) { $stringWHERE = $wpdb->prepare(" WHERE quiz_title LIKE %s OR quiz_desc LIKE %s ", '%' . $searchString . '%', '%' . $searchString . '%'); } $summaryPageURL = admin_url('admin.php?page=WPCW_showPage_QuizSummary'); // Show the form for searching ?> <form id="wpcw_quizzes_search_box" method="get" action="<?php echo $summaryPageURL; ?> "> <p class="search-box"> <label class="screen-reader-text" for="wpcw_quizzes_search_input"><?php _e('Search Quizzes', 'wp_courseware'); ?> </label> <input id="wpcw_quizzes_search_input" type="text" value="<?php echo $searchString; ?> " name="s"/> <input class="button" type="submit" value="<?php _e('Search Quizzes', 'wp_courseware'); ?> "/> <input type="hidden" name="page" value="WPCW_showPage_QuizSummary" /> </p> </form> <br/><br/> <?php $SQL_PAGING = "\n\t\t\tSELECT COUNT(*) as quiz_count \n\t\t\tFROM {$wpcwdb->quiz}\t\t\t\n\t\t\t{$stringWHERE}\n\t\t\tORDER BY quiz_id DESC \n\t\t"; $paging_resultsPerPage = 50; $paging_totalCount = $wpdb->get_var($SQL_PAGING); $paging_recordStart = ($paging_pageWanted - 1) * $paging_resultsPerPage + 1; $paging_recordEnd = $paging_pageWanted * $paging_resultsPerPage; $paging_pageCount = ceil($paging_totalCount / $paging_resultsPerPage); $paging_sqlStart = $paging_recordStart - 1; // Show search message - that a search has been tried. if ($searchString) { printf('<div class="wpcw_search_count">%s "%s" (%s %s) (<a href="%s">%s</a>)</div>', __('Search results for', 'wp_courseware'), htmlentities($searchString), $paging_totalCount, _n('result', 'results', $paging_totalCount, 'wp_courseware'), $summaryPageURL, __('reset', 'wp_courseware')); } // Do main query $SQL = "SELECT * \n\t\t\tFROM {$wpcwdb->quiz}\t\t\t\n\t\t\t{$stringWHERE}\n\t\t\tORDER BY {$orderBy} {$ordering}\n\t\t\tLIMIT {$paging_sqlStart}, {$paging_resultsPerPage}\t\t\t \n\t\t\t"; // These are already checked, so they are safe, hence no prepare() // Generate paging code $baseURL = WPCW_urls_getURLWithParams($summaryPageURL, 'pagenum') . "&pagenum="; $paging = WPCW_tables_showPagination($baseURL, $paging_pageWanted, $paging_pageCount, $paging_totalCount, $paging_recordStart, $paging_recordEnd); $quizzes = $wpdb->get_results($SQL); if ($quizzes) { $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_quiz_summary', 'class' => 'widefat wpcw_tbl'); // ID - sortable $sortableLink = sprintf('<a href="%s&order=%s&orderby=quiz_id"><span>%s</span><span class="sorting-indicator"></span></a>', $baseURL, 'quiz_id' == $orderBy ? $ordering_opposite : 'asc', __('ID', 'wp_courseware')); // ID - render $tblCol = new TableColumn($sortableLink, 'quiz_id'); $tblCol->headerClass = 'quiz_id' == $orderBy ? 'sorted ' . $ordering : 'sortable'; $tblCol->cellClass = "quiz_id"; $tbl->addColumn($tblCol); // Title - sortable $sortableLink = sprintf('<a href="%s&order=%s&orderby=quiz_title"><span>%s</span><span class="sorting-indicator"></span></a>', $baseURL, 'quiz_title' == $orderBy ? $ordering_opposite : 'asc', __('Quiz Title', 'wp_courseware')); // Title - render $tblCol = new TableColumn($sortableLink, 'quiz_title'); $tblCol->headerClass = 'quiz_title' == $orderBy ? 'sorted ' . $ordering : 'sortable'; $tblCol->cellClass = "quiz_title"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Associated Unit', 'wp_courseware'), 'associated_unit'); $tblCol->cellClass = "associated_unit"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Quiz Type', 'wp_courseware'), 'quiz_type'); $tblCol->cellClass = "quiz_type"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Show Answers', 'wp_courseware'), 'quiz_show_answers'); $tblCol->cellClass = "quiz_type wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Paging', 'wp_courseware'), 'quiz_use_paging'); $tblCol->cellClass = "quiz_type wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Questions', 'wp_courseware'), 'total_questions'); $tblCol->cellClass = "total_questions wpcw_center"; $tbl->addColumn($tblCol); $tblCol = new TableColumn(__('Actions', 'wp_courseware'), 'actions'); $tblCol->cellClass = "actions"; $tbl->addColumn($tblCol); // Stores course details in a mini cache to save lots of MySQL lookups. $miniCourseDetailCache = array(); // Format row data and show it. $odd = false; foreach ($quizzes as $quiz) { $data = array(); // URLs $editURL = admin_url('admin.php?page=WPCW_showPage_ModifyQuiz&quiz_id=' . $quiz->quiz_id); $surveyExportURL = admin_url('admin.php?page=WPCW_showPage_QuizSummary&wpcw_export=csv_export_survey_data&quiz_id=' . $quiz->quiz_id); // Maintain paging where possible. $deleteURL = $baseURL . '&action=delete&quiz_id=' . $quiz->quiz_id; // Basic Details $data['quiz_id'] = $quiz->quiz_id; // Quiz Title $data['quiz_title'] = sprintf('<b><a href="%s">%s</a></b>', $editURL, $quiz->quiz_title); if ($quiz->quiz_desc) { $data['quiz_title'] .= '<span class="wpcw_quiz_desc">' . $quiz->quiz_desc . '</span>'; } // Associated Unit if ($quiz->parent_unit_id > 0 && ($unitDetails = get_post($quiz->parent_unit_id))) { $data['associated_unit'] = sprintf('<span class="associated_unit_unit"><b>%s</b>: <a href="%s" target="_blank" title="%s \'%s\'...">%s</a></span>', __('Unit', 'wp_courseware'), get_permalink($unitDetails->ID), __('View ', 'wp_courseware'), $unitDetails->post_title, $unitDetails->post_title); // Also add associated course if (isset($miniCourseDetailCache[$quiz->parent_course_id])) { $courseDetails = $miniCourseDetailCache[$quiz->parent_course_id]; } else { // Save course details to cache (as likely to use it again). $courseDetails = $miniCourseDetailCache[$quiz->parent_course_id] = WPCW_courses_getCourseDetails($quiz->parent_course_id); } // Might not have course details. if ($courseDetails) { $data['associated_unit'] .= sprintf('<span class="associated_unit_course"><b>%s:</b> <a href="admin.php?page=WPCW_showPage_ModifyCourse&course_id=%d" title="%s \'%s\'...">%s</a></span>', __('Course', 'wp_courseware'), $courseDetails->course_id, __('Edit ', 'wp_courseware'), $courseDetails->course_title, $courseDetails->course_title); } } else { $data['associated_unit'] = 'n/a'; } // Showing Answers or paging? $data['quiz_show_answers'] = 'show_answers' == $quiz->quiz_show_answers ? '<span class="wpcw_tick"></span>' : '-'; $data['quiz_use_paging'] = 'use_paging' == $quiz->quiz_paginate_questions ? '<span class="wpcw_tick"></span>' : '-'; // Type of quiz $data['quiz_type'] = WPCW_quizzes_getQuizTypeName($quiz->quiz_type); // Show passmark for blocking quizzes. if ('quiz_block' == $quiz->quiz_type) { $data['quiz_type'] .= '<span class="wpcw_quiz_pass_info">' . sprintf(__('Min. Pass Mark of %d%%', 'wp_courseware'), $quiz->quiz_pass_mark) . '</span>'; } // Total number of questions $data['total_questions'] = WPCW_quizzes_calculateActualQuestionCount($quiz->quiz_id); // Actions $data['actions'] = '<ul class="wpcw_action_link_list">'; $data['actions'] .= sprintf('<li><a href="%s" class="button-primary">%s</a></li>', $editURL, __('Edit', 'wp_courseware')); $data['actions'] .= sprintf('<li><a href="%s" class="button-secondary wpcw_action_link_delete_quiz wpcw_action_link_delete" rel="%s">%s</a></li>', $deleteURL, __('Are you sure you wish to delete this quiz?', 'wp_courseware'), __('Delete', 'wp_courseware')); // Add export button for surveys if ('survey' == $quiz->quiz_type) { $data['actions'] .= sprintf('<li class="wpcw_action_item_newline"><a href="%s" class="button-secondary">%s</a></li>', $surveyExportURL, __('Export Responses', 'wp_courseware')); } $data['actions'] .= '</ul>'; // Odd/Even row colouring. $odd = !$odd; $tbl->addRow($data, $odd ? 'alternate' : ''); } // Finally show table echo $paging; echo $tbl->toString(); echo $paging; } else { printf('<p>%s</p>', __('There are currently no quizzes to show. Why not create one?', 'wp_courseware')); } $page->showPageFooter(); }
/** * 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')); } } }
/** * 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; }
/** * 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> ', admin_url('admin.php'), __('« 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; }
<?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
/** * 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; }
/** * Gradebook View - show the grade details for the users of the system. */ function WPCW_showPage_GradeBook_load() { $page = new PageBuilder(false); $courseDetails = false; $courseID = false; // Trying to view a specific course $courseDetails = false; if (isset($_GET['course_id'])) { $courseID = $_GET['course_id'] + 0; $courseDetails = WPCW_courses_getCourseDetails($courseID); } // Abort if course not found. if (!$courseDetails) { $page->showPageHeader(__('GradeBook', 'wp_courseware'), '75%', WPCW_icon_getPageIconURL()); $page->showMessage(__('Sorry, but that course could not be found.', 'wp_courseware'), true); $page->showPageFooter(); return; } // Show title of this course $page->showPageHeader(__('GradeBook', 'wp_courseware') . ': ' . $courseDetails->course_title, '75%', WPCW_icon_getPageIconURL()); global $wpcwdb, $wpdb; $wpdb->show_errors(); // Need a list of all quizzes for this course, excluding surveys. $quizzesForCourse = WPCW_quizzes_getAllQuizzesForCourse($courseDetails->course_id); // Handle situation when there are no quizzes. if (!$quizzesForCourse) { $page->showMessage(__('There are no quizzes for this course, therefore no grade information to show.', 'wp_courseware'), true); $page->showPageFooter(); return; } // Create a simple list of IDs to use in SQL queries $quizIDList = array(); foreach ($quizzesForCourse as $singleQuiz) { $quizIDList[] = $singleQuiz->quiz_id; } // Convert list of IDs into an SQL list $quizIDListForSQL = '(' . implode(',', $quizIDList) . ')'; // Do we want certificates? $usingCertificates = 'use_certs' == $courseDetails->course_opt_use_certificate; // #### Handle checking if we're sending out any emails to users with their final grades // Called here so that any changes are reflected in the table using the code below. if ('email_grades' == WPCW_arrays_getValue($_GET, 'action')) { WPCW_showPage_GradeBook_handleFinalGradesEmail($courseDetails, $page); } // Get the requested page number $paging_pageWanted = WPCW_arrays_getValue($_GET, 'pagenum') + 0; if ($paging_pageWanted == 0) { $paging_pageWanted = 1; } // Need a count of how many there are to mark anyway, hence doing calculation. // Using COUNT DISTINCT so that we get a total of the different user IDs. // If we use GROUP BY, we end up with several rows of results. $userCount_toMark = $wpdb->get_var("\n\t\tSELECT COUNT(DISTINCT upq.user_id) AS user_count \n\t\tFROM {$wpcwdb->user_progress_quiz} upq\t\t\n\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = upq.user_id\t\t\t\t\t\t\t\t\t\t\t\n\t\tWHERE upq.quiz_id IN {$quizIDListForSQL}\n\t\t AND upq.quiz_needs_marking > 0\n\t\t AND u.ID IS NOT NULL\n\t\t AND quiz_is_latest = 'latest'\n\t\t"); // Count - all users for this course $userCount_all = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t", $courseDetails->course_id)); // Count - users who have completed the course. $userCount_completed = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t AND uc.course_progress = 100\n\t\t", $courseDetails->course_id)); // Count - all users that need their final grade. $userCount_needGrade = $wpdb->get_var($wpdb->prepare("\n\t\tSELECT COUNT(*) AS user_count \n\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\tWHERE uc.course_id = %d\n\t\t AND u.ID IS NOT NULL\n\t\t AND uc.course_progress = 100\n\t\t AND uc.course_final_grade_sent != 'sent'\n\t\t", $courseDetails->course_id)); // SQL Code used by filters below $coreSQL_allUsers = $wpdb->prepare("\n\t\t\tSELECT * \n\t\t\tFROM {$wpcwdb->user_courses} uc\t\t\t\t\t\t\t\t\t\n\t\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = uc.user_id\n\t\t\tWHERE uc.course_id = %d\n\t\t\t AND u.ID IS NOT NULL\t\t\t\n\t\t\t", $courseDetails->course_id); // The currently selected filter to determine what quizzes to show. $currentFilter = WPCW_arrays_getValue($_GET, 'filter'); switch ($currentFilter) { case 'to_mark': // Chooses all progress where there are questions that need grading. // Then group by user, so that we don't show the same user twice. // Not added join for certificates, since they can't be complete // if they've got stuff to be marked. $coreSQL = "\n\t\t\t\tSELECT * \n\t\t\t\tFROM {$wpcwdb->user_progress_quiz} upq\t\t\t\t\t\t\t\t\t\n\t\t\t\t\tLEFT JOIN {$wpdb->users} u ON u.ID = upq.user_id\t\t\t\t\t\n\t\t\t\t\tLEFT JOIN {$wpcwdb->user_courses} uc ON uc.user_id = upq.user_id\n\t\t\t\tWHERE upq.quiz_id IN {$quizIDListForSQL}\n\t\t\t\t AND upq.quiz_needs_marking > 0\n\t\t\t\t AND u.ID IS NOT NULL\n\t\t\t\t AND quiz_is_latest = 'latest'\n\t\t\t\tGROUP BY u.ID\t\t\t\t\t\t\t\t \n\t\t\t\t"; // No need to re-calculate, just re-use the number. $paging_totalCount = $userCount_toMark; break; // Completed the course // Completed the course case 'completed': // Same SQL as all users, but just filtering those with a progress of 100. $coreSQL = $coreSQL_allUsers . " \n\t\t\t\t\tAND uc.course_progress = 100\n\t\t\t\t"; // The total number of results to show - used for paging $paging_totalCount = $userCount_completed; break; // Completed the course // Completed the course case 'eligible_for_final_grade': // Same SQL as all users, but just filtering those with a progress of 100 AND // needing a final grade due to flag in course_progress. $coreSQL = $coreSQL_allUsers . " \n\t\t\t\t\tAND uc.course_progress = 100 \n\t\t\t\t\tAND course_final_grade_sent != 'sent'\n\t\t\t\t"; // The total number of results to show - used for paging $paging_totalCount = $userCount_needGrade; break; // Default to all users, regardless of what progress they've made // Default to all users, regardless of what progress they've made default: $currentFilter = 'all'; // Allow the query to be modified by other plugins $coreSQL_filteredUsers = apply_filters("wpcw_back_query_filter_gradebook_users", $coreSQL_allUsers, $courseDetails->course_id); // Select all users that exist for this course $coreSQL = $coreSQL_filteredUsers; // The total number of results to show - used for paging $paging_totalCount = $userCount_all; break; } // Generate page URL $summaryPageURL = admin_url('admin.php?page=WPCW_showPage_GradeBook&course_id=' . $courseDetails->course_id); $paging_resultsPerPage = 50; $paging_recordStart = ($paging_pageWanted - 1) * $paging_resultsPerPage + 1; $paging_recordEnd = $paging_pageWanted * $paging_resultsPerPage; $paging_pageCount = ceil($paging_totalCount / $paging_resultsPerPage); $paging_sqlStart = $paging_recordStart - 1; // Use the main SQL from above, but limit it and order by user's name. $SQL = "{$coreSQL}\n\t\t\tORDER BY display_name ASC\n\t\t\tLIMIT {$paging_sqlStart}, {$paging_resultsPerPage}"; // Generate paging code $baseURL = WPCW_urls_getURLWithParams($summaryPageURL, 'pagenum') . "&pagenum="; $paging = WPCW_tables_showPagination($baseURL, $paging_pageWanted, $paging_pageCount, $paging_totalCount, $paging_recordStart, $paging_recordEnd); $tbl = new TableBuilder(); $tbl->attributes = array('id' => 'wpcw_tbl_quiz_gradebook', 'class' => 'widefat wpcw_tbl'); $tblCol = new TableColumn(__('Learner Details', 'wp_courseware'), 'learner_details'); $tblCol->cellClass = "wpcw_learner_details"; $tbl->addColumn($tblCol); // ### Add the quiz data if ($quizzesForCourse) { // Show the overall progress for the course. $tblCol = new TableColumn(__('Overall Progress', 'wp_courseware'), 'course_progress'); //$tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_course_progress"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. $tblCol = new TableColumn(__('Cumulative Grade', 'wp_courseware'), 'quiz_cumulative'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. $tblCol = new TableColumn(__('Grade Sent?', 'wp_courseware'), 'grade_sent'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); // ### Create heading for cumulative data. if ($usingCertificates) { $tblCol = new TableColumn(__('Certificate Available?', 'wp_courseware'), 'certificate_available'); $tblCol->headerClass = "wpcw_center"; $tblCol->cellClass = "wpcw_grade_summary wpcw_center"; $tbl->addColumn($tblCol); } // ### Add main quiz scores foreach ($quizzesForCourse as $singleQuiz) { $tblCol = new TableColumn($singleQuiz->quiz_title, 'quiz_' . $singleQuiz->quiz_id); $tblCol->cellClass = "wpcw_center wpcw_quiz_grade"; $tblCol->headerClass = "wpcw_center wpcw_quiz_grade"; $tbl->addColumn($tblCol); } } $urlForQuizResultDetails = admin_url('users.php?page=WPCW_showPage_UserProgess_quizAnswers'); $userList = $wpdb->get_results($SQL); if (!$userList) { switch ($currentFilter) { case 'to_mark': $msg = __('There are currently no quizzes that need a manual grade.', 'wp_courseware'); break; case 'eligible_for_final_grade': $msg = __('There are currently no users that are eligible to receive their final grade.', 'wp_courseware'); break; case 'completed': $msg = __('There are currently no users that have completed the course.', 'wp_courseware'); break; default: $msg = __('There are currently no learners allocated to this course.', 'wp_courseware'); break; } // Create spanning item with message - number of quizzes + fixed columns. $rowDataObj = new RowDataSimple('wpcw_no_users wpcw_center', $msg, count($quizIDList) + 5); $tbl->addRowObj($rowDataObj); } else { // ### Format main row data and show it. $odd = false; foreach ($userList as $singleUser) { $data = array(); // Basic Details with avatar $data['learner_details'] = sprintf(' %s <span class="wpcw_col_cell_name">%s</span> <span class="wpcw_col_cell_username">%s</span> <span class="wpcw_col_cell_email"><a href="mailto:%s" target="_blank">%s</a></span></span> ', get_avatar($singleUser->ID, 48), $singleUser->display_name, $singleUser->user_login, $singleUser->user_email, $singleUser->user_email); // Get the user's progress for the quizzes. if ($quizzesForCourse) { $quizResults = WPCW_quizzes_getQuizResultsForUser($singleUser->ID, $quizIDListForSQL); // Track cumulative data $quizScoresSoFar = 0; $quizScoresSoFar_count = 0; // ### Now render results for each quiz foreach ($quizIDList as $aQuizID) { // Got progress data, process the result if (isset($quizResults[$aQuizID])) { // Extract results and unserialise the data array. $theResults = $quizResults[$aQuizID]; $theResults->quiz_data = maybe_unserialize($theResults->quiz_data); $quizDetailURL = sprintf('%s&user_id=%d&quiz_id=%d&unit_id=%d', $urlForQuizResultDetails, $singleUser->ID, $theResults->quiz_id, $theResults->unit_id); // We've got something that needs grading. So render link to where the quiz can be graded. if ($theResults->quiz_needs_marking > 0) { $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_needs_grading"><a href="%s">%s</span>', $quizDetailURL, __('Manual Grade Required', 'wp_courseware')); } else { if ('quiz_fail_no_retakes' == $theResults->quiz_next_step_type) { $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_needs_grading"><a href="%s">%s</span>', $quizDetailURL, __('Quiz Retakes Exhausted', 'wp_courseware')); } else { if ('incomplete' == $theResults->quiz_paging_status) { $data['quiz_' . $aQuizID] = '<span class="wpcw_grade_not_taken">' . __('In Progress', 'wp_courseware') . '</span>'; } else { // Use grade for cumulative grade $score = number_format($quizResults[$aQuizID]->quiz_grade, 1); $quizScoresSoFar += $score; $quizScoresSoFar_count++; // Render score and link to the full test data. $data['quiz_' . $aQuizID] = sprintf('<span class="wpcw_grade_valid"><a href="%s">%s%%</span>', $quizDetailURL, $score); } } } } else { $data['quiz_' . $aQuizID] = '<span class="wpcw_grade_not_taken">' . __('Not Taken', 'wp_courseware') . '</span>'; } } // #### Show the cumulative quiz results. $data['quiz_cumulative'] = '-'; if ($quizScoresSoFar_count > 0) { $data['quiz_cumulative'] = '<span class="wpcw_grade_valid">' . number_format($quizScoresSoFar / $quizScoresSoFar_count, 1) . '%</span>'; } } // ####ÊUser Progress $data['course_progress'] = WPCW_stats_convertPercentageToBar($singleUser->course_progress); // #### Grade Sent? $data['grade_sent'] = 'sent' == $singleUser->course_final_grade_sent ? __('Yes', 'wp_courseware') : '-'; // #### Certificate - Show if there's a certificate that can be downloaded. if ($usingCertificates && ($certDetails = WPCW_certificate_getCertificateDetails($singleUser->ID, $courseDetails->course_id, false))) { $data['certificate_available'] = sprintf('<a href="%s" title="%s">%s</a>', WPCW_certificate_generateLink($certDetails->cert_access_key), __('Download the certificate for this user.', 'wp_courseware'), __('Yes', 'wp_courseware')); } else { $data['certificate_available'] = '-'; } // Odd/Even row colouring. $odd = !$odd; $tbl->addRow($data, $odd ? 'alternate' : ''); } // single user } // Check we have some users. // Here are the action buttons for Gradebook. printf('<div class="wpcw_button_group">'); // Button to generate a CSV of the gradebook. printf('<a href="%s" class="button-primary">%s</a> ', admin_url('?wpcw_export=gradebook_csv&course_id=' . $courseDetails->course_id), __('Export Gradebook (CSV)', 'wp_courseware')); printf('<a href="%s" class="button-primary">%s</a> ', admin_url('admin.php?page=WPCW_showPage_GradeBook&action=email_grades&filter=all&course_id=' . $courseDetails->course_id), __('Email Final Grades', 'wp_courseware')); // URL that shows the eligible users who are next to get the email for the final grade. $eligibleURL = sprintf(admin_url('admin.php?page=WPCW_showPage_GradeBook&course_id=%d&filter=eligible_for_final_grade'), $courseDetails->course_id); // Create information about how people are chosen to send grades to. printf('<div id="wpcw_button_group_info_gradebook" class="wpcw_button_group_info">%s</div>', sprintf(__('Grades will only be emailed to students who have <b>completed the course</b> and who have <b>not yet received</b> their final grade. You can see the students who are <a href="%s">eligible to receive the final grade email</a> here.', 'wp_courseware'), $eligibleURL)); printf('</div>'); echo $paging; // Show the filtering to selectively show different quizzes // Filter list can be modified to indicate Group's name instead of 'all' $filters_list = array('all' => sprintf(__('All (%d)', 'wp_courseware'), $userCount_all), 'completed' => sprintf(__('Completed (%d)', 'wp_courseware'), $userCount_completed), 'eligible_for_final_grade' => sprintf(__('Eligible for Final Grade Email (%d)', 'wp_courseware'), $userCount_needGrade), 'to_mark' => sprintf(__('Just Quizzes that Need Marking (%d)', 'wp_courseware'), $userCount_toMark)); // Allow the filters to be customised $filters_list = apply_filters("wpcw_back_filters_gradebook_filters", $filters_list, $courseDetails->course_id); echo WPCW_table_showFilters($filters_list, WPCW_urls_getURLWithParams($summaryPageURL, 'filter') . "&filter=", $currentFilter); // Finally show table echo $tbl->toString(); echo $paging; $page->showPageFooter(); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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> </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; }
/** * 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 } }
/** * 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 (< or >). 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(); }
/** * 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. }
/** * 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; } }
/** * 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(' ' . $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); } }