Version Description
29 April, 2020 =
Added: Course Completion Process. Flexible and Strict mode. in strict mode, students have to complete all lessons and pass all quizzes in order to complete any course.
Added: Quiz question validation, all type of quiz are now under validation except quiz ordering type
Added: hook,
tutor/course/enrol_status_change/after
Added: utils method,
get_course_by_enrol_id($enrol_id)
;Added utils method, `course_enrol_status_change($enrol_id
Download this release
Release Info
Developer | themeum |
Plugin | Tutor LMS – eLearning and online course solution |
Version | 1.6.1 |
Comparing to | |
See all releases |
Code changes from version 1.6.0 to 1.6.1
- assets/css/tutor-admin.css +6 -0
- assets/js/tutor-front.js +110 -0
- classes/Assets.php +1 -1
- classes/Course.php +77 -1
- classes/Options.php +11 -0
- classes/Quiz.php +1 -1
- classes/Utils.php +72 -3
- classes/WooCommerce.php +1 -1
- readme.txt +13 -1
- templates/single/lesson/sidebar_question_and_answer.php +1 -1
- templates/single/quiz/body.php +10 -2
- tutor.php +2 -2
- views/metabox/course-contents.php +7 -7
- views/options/field-types/radio.php +1 -1
assets/css/tutor-admin.css
CHANGED
@@ -214,6 +214,9 @@ Group Field Option
|
|
214 |
width: 100px;
|
215 |
margin-right: 5px;
|
216 |
}
|
|
|
|
|
|
|
217 |
|
218 |
/**
|
219 |
* Course adding page
|
@@ -1982,6 +1985,9 @@ Tutor Media Upload
|
|
1982 |
.tutor-add-quiz-button-wrap {
|
1983 |
margin: 20px 0;
|
1984 |
}
|
|
|
|
|
|
|
1985 |
.tutor-quiz-delete-btn{
|
1986 |
color: #FF0000;
|
1987 |
}
|
214 |
width: 100px;
|
215 |
margin-right: 5px;
|
216 |
}
|
217 |
+
.option-type-radio-wrap{
|
218 |
+
margin-top: 0;
|
219 |
+
}
|
220 |
|
221 |
/**
|
222 |
* Course adding page
|
1985 |
.tutor-add-quiz-button-wrap {
|
1986 |
margin: 20px 0;
|
1987 |
}
|
1988 |
+
.tutor-add-quiz-button-wrap a{
|
1989 |
+
color: #2756d1;
|
1990 |
+
}
|
1991 |
.tutor-quiz-delete-btn{
|
1992 |
color: #FF0000;
|
1993 |
}
|
assets/js/tutor-front.js
CHANGED
@@ -550,7 +550,21 @@ jQuery(document).ready(function($){
|
|
550 |
|
551 |
$(document).on('click', '.tutor-quiz-answer-next-btn', function (e) {
|
552 |
e.preventDefault();
|
|
|
553 |
var $that = $(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
554 |
var question_id = parseInt($that.closest('.quiz-attempt-single-question').attr('id').match(/\d+/)[0], 10);
|
555 |
|
556 |
var next_question_id = $that.closest('.quiz-attempt-single-question').attr('data-next-question-id');
|
@@ -573,6 +587,24 @@ jQuery(document).ready(function($){
|
|
573 |
}
|
574 |
}
|
575 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
576 |
$(document).on('click', '.tutor-quiz-question-paginate-item', function (e) {
|
577 |
e.preventDefault();
|
578 |
var $that = $(this);
|
@@ -620,6 +652,84 @@ jQuery(document).ready(function($){
|
|
620 |
});
|
621 |
}
|
622 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
623 |
/**
|
624 |
* Add to cart in guest mode, show login form
|
625 |
*
|
550 |
|
551 |
$(document).on('click', '.tutor-quiz-answer-next-btn', function (e) {
|
552 |
e.preventDefault();
|
553 |
+
|
554 |
var $that = $(this);
|
555 |
+
var $question_wrap = $that.closest('.quiz-attempt-single-question');
|
556 |
+
/**
|
557 |
+
* Validating required answer
|
558 |
+
* @type {jQuery}
|
559 |
+
*
|
560 |
+
* @since v.1.6.1
|
561 |
+
*/
|
562 |
+
|
563 |
+
var validated = tutor_quiz_validation($question_wrap);
|
564 |
+
if ( ! validated){
|
565 |
+
return;
|
566 |
+
}
|
567 |
+
|
568 |
var question_id = parseInt($that.closest('.quiz-attempt-single-question').attr('id').match(/\d+/)[0], 10);
|
569 |
|
570 |
var next_question_id = $that.closest('.quiz-attempt-single-question').attr('data-next-question-id');
|
587 |
}
|
588 |
}
|
589 |
});
|
590 |
+
|
591 |
+
|
592 |
+
$(document).on('submit', '#tutor-answering-quiz', function (e) {
|
593 |
+
var $questions_wrap = $('.quiz-attempt-single-question');
|
594 |
+
var validated = true;
|
595 |
+
if ($questions_wrap.length){
|
596 |
+
$questions_wrap.each(function(index, question){
|
597 |
+
validated = tutor_quiz_validation($(question));
|
598 |
+
});
|
599 |
+
}
|
600 |
+
|
601 |
+
if ( ! validated){
|
602 |
+
e.preventDefault();
|
603 |
+
}
|
604 |
+
|
605 |
+
});
|
606 |
+
|
607 |
+
|
608 |
$(document).on('click', '.tutor-quiz-question-paginate-item', function (e) {
|
609 |
e.preventDefault();
|
610 |
var $that = $(this);
|
652 |
});
|
653 |
}
|
654 |
|
655 |
+
|
656 |
+
/**
|
657 |
+
* Quiz Validation Helper
|
658 |
+
*
|
659 |
+
* @since v.1.6.1
|
660 |
+
*/
|
661 |
+
|
662 |
+
function tutor_quiz_validation($question_wrap){
|
663 |
+
var validated = true;
|
664 |
+
|
665 |
+
var $required_answer_wrap = $question_wrap.find('.quiz-answer-required');
|
666 |
+
|
667 |
+
|
668 |
+
if ($required_answer_wrap.length){
|
669 |
+
|
670 |
+
/**
|
671 |
+
* Radio field validation
|
672 |
+
*
|
673 |
+
* @type {jQuery}
|
674 |
+
*
|
675 |
+
* @since v.1.6.1
|
676 |
+
*/
|
677 |
+
var $inputs = $required_answer_wrap.find('input');
|
678 |
+
if ($inputs.length){
|
679 |
+
var $type = $inputs.attr('type');
|
680 |
+
if ($type === 'radio') {
|
681 |
+
if ($required_answer_wrap.find('input[type="radio"]:checked').length == 0) {
|
682 |
+
$question_wrap.find('.answer-help-block').html('<p style="color: #dc3545">Please select an option to answer</p>');
|
683 |
+
validated = false;
|
684 |
+
}
|
685 |
+
}else if ($type === 'checkbox'){
|
686 |
+
if ($required_answer_wrap.find('input[type="checkbox"]:checked').length == 0) {
|
687 |
+
$question_wrap.find('.answer-help-block').html('<p style="color: #dc3545">Please select at least one option to answer.</p>');
|
688 |
+
validated = false;
|
689 |
+
}
|
690 |
+
}else if($type === 'text'){
|
691 |
+
//Fill in the gaps if many, validation all
|
692 |
+
$inputs.each(function(index, input){
|
693 |
+
if ( ! $(input).val().trim().length){
|
694 |
+
$question_wrap.find('.answer-help-block').html('<p style="color: #dc3545">The answer for this question is required</p>');
|
695 |
+
validated = false;
|
696 |
+
}
|
697 |
+
});
|
698 |
+
}
|
699 |
+
|
700 |
+
}
|
701 |
+
if ($required_answer_wrap.find('textarea').length) {
|
702 |
+
if ($required_answer_wrap.find('textarea').val().trim().length < 1){
|
703 |
+
$question_wrap.find('.answer-help-block').html('<p style="color: #dc3545">The answer for this question is required</p>');
|
704 |
+
validated = false;
|
705 |
+
}
|
706 |
+
}
|
707 |
+
|
708 |
+
/**
|
709 |
+
* Matching Question
|
710 |
+
*/
|
711 |
+
var $matchingDropable = $required_answer_wrap.find('.quiz-answer-matching-droppable');
|
712 |
+
if ($matchingDropable.length){
|
713 |
+
|
714 |
+
$matchingDropable.each(function(index, matching){
|
715 |
+
if ( ! $(matching).find('.quiz-draggable-answer-item').length){
|
716 |
+
$question_wrap.find('.answer-help-block').html('<p style="color: #dc3545">Please match all the items</p>');
|
717 |
+
validated = false;
|
718 |
+
}
|
719 |
+
|
720 |
+
});
|
721 |
+
|
722 |
+
}
|
723 |
+
|
724 |
+
|
725 |
+
|
726 |
+
}
|
727 |
+
|
728 |
+
return validated;
|
729 |
+
}
|
730 |
+
|
731 |
+
|
732 |
+
|
733 |
/**
|
734 |
* Add to cart in guest mode, show login form
|
735 |
*
|
classes/Assets.php
CHANGED
@@ -90,7 +90,7 @@ class Assets{
|
|
90 |
);
|
91 |
|
92 |
if ( ! empty($post->post_type) && $post->post_type === 'tutor_quiz'){
|
93 |
-
$single_quiz_options = tutor_utils()->get_quiz_option($post->ID);
|
94 |
$saved_quiz_options = array(
|
95 |
'quiz_when_time_expires' => tutils()->get_option('quiz_when_time_expires'),
|
96 |
);
|
90 |
);
|
91 |
|
92 |
if ( ! empty($post->post_type) && $post->post_type === 'tutor_quiz'){
|
93 |
+
$single_quiz_options = (array) tutor_utils()->get_quiz_option($post->ID);
|
94 |
$saved_quiz_options = array(
|
95 |
'quiz_when_time_expires' => tutils()->get_option('quiz_when_time_expires'),
|
96 |
);
|
classes/Course.php
CHANGED
@@ -80,7 +80,15 @@ class Course extends Tutor_Base {
|
|
80 |
* @since 1.5.8
|
81 |
*/
|
82 |
add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
/**
|
86 |
* Registering metabox
|
@@ -1030,4 +1038,72 @@ class Course extends Tutor_Base {
|
|
1030 |
return $html;
|
1031 |
}
|
1032 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1033 |
}
|
80 |
* @since 1.5.8
|
81 |
*/
|
82 |
add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
|
83 |
+
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Remove course complete button if course completion is strict mode
|
87 |
+
* @since v.1.6.1
|
88 |
+
*/
|
89 |
+
add_filter('tutor_course/single/complete_form', array($this, 'tutor_lms_hide_course_complete_btn'));
|
90 |
+
add_filter('get_gradebook_generate_form_html', array($this, 'get_generate_greadbook'));
|
91 |
+
}
|
92 |
|
93 |
/**
|
94 |
* Registering metabox
|
1038 |
return $html;
|
1039 |
}
|
1040 |
|
1041 |
+
/**
|
1042 |
+
* @param $html
|
1043 |
+
* @return string
|
1044 |
+
*
|
1045 |
+
* Check if all lessons and quizzes done before mark course complete.
|
1046 |
+
*/
|
1047 |
+
function tutor_lms_hide_course_complete_btn($html){
|
1048 |
+
|
1049 |
+
$completion_mode = tutils()->get_option('course_completion_process');
|
1050 |
+
if ($completion_mode !== 'strict'){
|
1051 |
+
return $html;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
$completed_lesson = tutils()->get_completed_lesson_count_by_course();
|
1055 |
+
$lesson_count = tutils()->get_lesson_count_by_course();
|
1056 |
+
|
1057 |
+
if ($completed_lesson < $lesson_count){
|
1058 |
+
return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
|
1059 |
+
}
|
1060 |
+
|
1061 |
+
$quizzes = array();
|
1062 |
+
|
1063 |
+
$course_contents = tutils()->get_course_contents_by_id();
|
1064 |
+
if (tutils()->count($course_contents)){
|
1065 |
+
foreach ($course_contents as $content){
|
1066 |
+
if ($content->post_type === 'tutor_quiz'){
|
1067 |
+
$quizzes[] = $content;
|
1068 |
+
}
|
1069 |
+
}
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
$is_pass = true;
|
1073 |
+
$required_quiz_pass = 0;
|
1074 |
+
|
1075 |
+
if (tutils()->count($quizzes)){
|
1076 |
+
foreach ($quizzes as $quiz){
|
1077 |
+
|
1078 |
+
$attempt = tutils()->get_quiz_attempt($quiz->ID);
|
1079 |
+
if ($attempt) {
|
1080 |
+
$passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
|
1081 |
+
$earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
|
1082 |
+
|
1083 |
+
if ($earned_percentage < $passing_grade) {
|
1084 |
+
$required_quiz_pass++;
|
1085 |
+
$is_pass = false;
|
1086 |
+
}
|
1087 |
+
}else{
|
1088 |
+
$required_quiz_pass++;
|
1089 |
+
$is_pass = false;
|
1090 |
+
}
|
1091 |
+
}
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
if ( ! $is_pass){
|
1095 |
+
return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
return $html;
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
public function get_generate_greadbook($html){
|
1102 |
+
if ( ! tutils()->is_completed_course()){
|
1103 |
+
return '';
|
1104 |
+
}
|
1105 |
+
return $html;
|
1106 |
+
}
|
1107 |
+
|
1108 |
+
|
1109 |
}
|
classes/Options.php
CHANGED
@@ -186,6 +186,17 @@ class Options {
|
|
186 |
'label_title' => __('Hide course products from shop page', 'tutor'),
|
187 |
'desc' => __('Enabling this feature will be removed course products from the shop page.', 'tutor'),
|
188 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
),
|
190 |
),
|
191 |
'archive' => array(
|
186 |
'label_title' => __('Hide course products from shop page', 'tutor'),
|
187 |
'desc' => __('Enabling this feature will be removed course products from the shop page.', 'tutor'),
|
188 |
),
|
189 |
+
'course_completion_process' => array(
|
190 |
+
'type' => 'radio',
|
191 |
+
'label' => __('Course Completion Process', 'tutor'),
|
192 |
+
'default' => 'flexible',
|
193 |
+
'select_options' => false,
|
194 |
+
'options' => array(
|
195 |
+
'flexible' => __('Flexible', 'tutor'),
|
196 |
+
'strict' => __('Strict Mode', 'tutor'),
|
197 |
+
),
|
198 |
+
'desc' => __('Students can complete courses anytime in the Flexible mode. In the Strict mode, students have to complete, pass all the lessons and quizzes (if any) to mark a course as complete.', 'tutor'),
|
199 |
+
),
|
200 |
),
|
201 |
),
|
202 |
'archive' => array(
|
classes/Quiz.php
CHANGED
@@ -757,7 +757,7 @@ class Quiz {
|
|
757 |
'belongs_question_id' => $question_id,
|
758 |
'belongs_question_type' => $question_type,
|
759 |
'answer_title' => $answer['answer_title'],
|
760 |
-
'answer_two_gap_match'
|
761 |
);
|
762 |
$wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
|
763 |
}
|
757 |
'belongs_question_id' => $question_id,
|
758 |
'belongs_question_type' => $question_type,
|
759 |
'answer_title' => $answer['answer_title'],
|
760 |
+
'answer_two_gap_match' => isset($answer['answer_two_gap_match']) ? trim($answer['answer_two_gap_match']) : null,
|
761 |
);
|
762 |
$wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
|
763 |
}
|
classes/Utils.php
CHANGED
@@ -663,16 +663,38 @@ class Utils {
|
|
663 |
* @return float|int
|
664 |
*
|
665 |
* @since v.1.0.0
|
|
|
666 |
*/
|
667 |
public function get_course_completed_percent($course_id = 0, $user_id = 0){
|
668 |
$course_id = $this->get_post_id($course_id);
|
669 |
$user_id = $this->get_user_id($user_id);
|
670 |
|
671 |
-
$total_lesson = $this->get_lesson_count_by_course($course_id);
|
672 |
$completed_lesson = $this->get_completed_lesson_count_by_course($course_id, $user_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
673 |
|
674 |
-
if ($
|
675 |
-
return number_format(($
|
676 |
}
|
677 |
|
678 |
return 0;
|
@@ -968,6 +990,32 @@ class Utils {
|
|
968 |
return false;
|
969 |
}
|
970 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
971 |
/**
|
972 |
* @param int $lesson_id
|
973 |
* @param int $user_id
|
@@ -1908,6 +1956,27 @@ class Utils {
|
|
1908 |
return false;
|
1909 |
}
|
1910 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1911 |
|
1912 |
/**
|
1913 |
* @param int $course_id
|
663 |
* @return float|int
|
664 |
*
|
665 |
* @since v.1.0.0
|
666 |
+
* @updated v.1.6.1
|
667 |
*/
|
668 |
public function get_course_completed_percent($course_id = 0, $user_id = 0){
|
669 |
$course_id = $this->get_post_id($course_id);
|
670 |
$user_id = $this->get_user_id($user_id);
|
671 |
|
|
|
672 |
$completed_lesson = $this->get_completed_lesson_count_by_course($course_id, $user_id);
|
673 |
+
$course_contents = tutils()->get_course_contents_by_id($course_id);
|
674 |
+
|
675 |
+
$totalContents = $this->count($course_contents);
|
676 |
+
$totalContents = $totalContents ? $totalContents : 0;
|
677 |
+
|
678 |
+
$completedCount = $completed_lesson;
|
679 |
+
|
680 |
+
if (tutils()->count($course_contents)){
|
681 |
+
foreach ($course_contents as $content){
|
682 |
+
if ($content->post_type === 'tutor_quiz'){
|
683 |
+
$attempt = $this->get_quiz_attempt($content->ID);
|
684 |
+
if ($attempt){
|
685 |
+
$completedCount++;
|
686 |
+
}
|
687 |
+
}elseif ($content->post_type === 'tutor_assignments'){
|
688 |
+
$isSubmitted = $this->is_assignment_submitted($content->ID);
|
689 |
+
if ($isSubmitted){
|
690 |
+
$completedCount++;
|
691 |
+
}
|
692 |
+
}
|
693 |
+
}
|
694 |
+
}
|
695 |
|
696 |
+
if ($totalContents > 0 && $completedCount > 0){
|
697 |
+
return number_format(($completedCount * 100) / $totalContents);
|
698 |
}
|
699 |
|
700 |
return 0;
|
990 |
return false;
|
991 |
}
|
992 |
|
993 |
+
|
994 |
+
/**
|
995 |
+
* @param int $enrol_id
|
996 |
+
* @return array|bool|\WP_Post|null
|
997 |
+
*
|
998 |
+
* Get course by enrol id
|
999 |
+
*
|
1000 |
+
* @since v.1.6.1
|
1001 |
+
*/
|
1002 |
+
|
1003 |
+
public function get_course_by_enrol_id($enrol_id = 0){
|
1004 |
+
if ( ! $enrol_id){
|
1005 |
+
return false;
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
global $wpdb;
|
1009 |
+
|
1010 |
+
$course_id = (int) $wpdb->get_var( "select post_parent from {$wpdb->posts} WHERE post_type = 'tutor_enrolled' AND ID = {$enrol_id}" );
|
1011 |
+
|
1012 |
+
if ( $course_id ) {
|
1013 |
+
return get_post($course_id);
|
1014 |
+
}
|
1015 |
+
|
1016 |
+
return null;
|
1017 |
+
}
|
1018 |
+
|
1019 |
/**
|
1020 |
* @param int $lesson_id
|
1021 |
* @param int $user_id
|
1956 |
return false;
|
1957 |
}
|
1958 |
|
1959 |
+
/**
|
1960 |
+
* @param bool $enrol_id
|
1961 |
+
* @param string $new_status
|
1962 |
+
*
|
1963 |
+
* Enrol Status change
|
1964 |
+
*
|
1965 |
+
* @since v.1.6.1
|
1966 |
+
*/
|
1967 |
+
|
1968 |
+
public function course_enrol_status_change($enrol_id = false, $new_status = ''){
|
1969 |
+
if ( ! $enrol_id){
|
1970 |
+
return;
|
1971 |
+
}
|
1972 |
+
|
1973 |
+
global $wpdb;
|
1974 |
+
|
1975 |
+
do_action('tutor/course/enrol_status_change/before',$enrol_id, $new_status );
|
1976 |
+
$wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $enrol_id ) );
|
1977 |
+
do_action('tutor/course/enrol_status_change/after',$enrol_id, $new_status );
|
1978 |
+
}
|
1979 |
+
|
1980 |
|
1981 |
/**
|
1982 |
* @param int $course_id
|
classes/WooCommerce.php
CHANGED
@@ -210,7 +210,7 @@ class WooCommerce extends Tutor_Base {
|
|
210 |
|
211 |
if (is_array($enrolled_ids) && count($enrolled_ids)){
|
212 |
foreach ($enrolled_ids as $enrolled_id){
|
213 |
-
|
214 |
}
|
215 |
}
|
216 |
}
|
210 |
|
211 |
if (is_array($enrolled_ids) && count($enrolled_ids)){
|
212 |
foreach ($enrolled_ids as $enrolled_id){
|
213 |
+
tutils()->course_enrol_status_change($enrolled_id, $status_to);
|
214 |
}
|
215 |
}
|
216 |
}
|
readme.txt
CHANGED
@@ -5,7 +5,7 @@ Tags: lms, course, elearning, education, learning management system
|
|
5 |
Requires at least: 4.5
|
6 |
Tested up to: 5.4
|
7 |
Requires PHP: 5.4.0
|
8 |
-
Stable tag: 1.6.
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
11 |
|
@@ -241,6 +241,18 @@ Tutor enables you to use any third party plugins without facing any compatibilit
|
|
241 |
|
242 |
== Changelog ==
|
243 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
244 |
= 1.6.0 - 16 April, 2020 =
|
245 |
|
246 |
* New: Quiz Export/Import add-on (Pro)
|
5 |
Requires at least: 4.5
|
6 |
Tested up to: 5.4
|
7 |
Requires PHP: 5.4.0
|
8 |
+
Stable tag: 1.6.1
|
9 |
License: GPLv3
|
10 |
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
11 |
|
241 |
|
242 |
== Changelog ==
|
243 |
|
244 |
+
= 1.6.1 - 29 April, 2020 =
|
245 |
+
|
246 |
+
* Added: Course Completion Process. Flexible and Strict mode. in strict mode, students have to complete all lessons and pass all quizzes in order to complete any course.
|
247 |
+
* Added: Quiz question validation, all type of quiz are now under validation except quiz ordering type
|
248 |
+
* Added: hook, `tutor/course/enrol_status_change/after`
|
249 |
+
* Added: utils method, `get_course_by_enrol_id($enrol_id)`;
|
250 |
+
* Added utils method, `course_enrol_status_change($enrol_id = false, $new_status = '')`;
|
251 |
+
* Improved: curriculum content add button group design, now it's link style button.
|
252 |
+
* Improved: course completion progress bar, is now counting quiz attempts and assignment. It will show 100% progress when you done all lessons, quiz, and assignments.
|
253 |
+
* Fixed: Tutor is sending the Course Enrollment email to the instructor without completing the payment
|
254 |
+
* Fixed: quiz question description div print even if the description is not exist
|
255 |
+
|
256 |
= 1.6.0 - 16 April, 2020 =
|
257 |
|
258 |
* New: Quiz Export/Import add-on (Pro)
|
templates/single/lesson/sidebar_question_and_answer.php
CHANGED
@@ -49,7 +49,7 @@ $course_id = tutils()->get_course_id_by_content($post);
|
|
49 |
</div>
|
50 |
|
51 |
<div class="tutor_question_area">
|
52 |
-
<p><strong><?php echo $question->question_title; ?> </strong></p>
|
53 |
<?php echo wpautop(stripslashes($question->comment_content)); ?>
|
54 |
</div>
|
55 |
</div>
|
49 |
</div>
|
50 |
|
51 |
<div class="tutor_question_area">
|
52 |
+
<p><strong><?php echo stripslashes($question->question_title); ?> </strong></p>
|
53 |
<?php echo wpautop(stripslashes($question->comment_content)); ?>
|
54 |
</div>
|
55 |
</div>
|
templates/single/quiz/body.php
CHANGED
@@ -99,6 +99,7 @@ $attempt_remaining = $attempts_allowed - $attempted_count;
|
|
99 |
$question_type = $question->question_type;
|
100 |
$answers = tutor_utils()->get_answers_by_quiz_question($question->question_id);
|
101 |
$show_question_mark = (bool) tutor_utils()->avalue_dot('show_question_mark', $question_settings);
|
|
|
102 |
|
103 |
echo '<h4 class="question-text">';
|
104 |
if ( ! $hide_question_number_overview){
|
@@ -110,10 +111,14 @@ $attempt_remaining = $attempts_allowed - $attempted_count;
|
|
110 |
if ($show_question_mark){
|
111 |
echo '<p class="question-marks"> '.__('Marks : ', 'tutor').$question->question_mark.' </p>';
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
113 |
?>
|
114 |
-
<p class="question-description"><?php echo stripslashes($question->question_description); ?></p>
|
115 |
|
116 |
-
<div class="tutor-quiz-answers-wrap question-type-<?php echo $question_type; ?>">
|
117 |
<?php
|
118 |
if ( is_array($answers) && count($answers) ) {
|
119 |
foreach ($answers as $answer){
|
@@ -320,6 +325,9 @@ $attempt_remaining = $attempts_allowed - $attempted_count;
|
|
320 |
<?php
|
321 |
}
|
322 |
?>
|
|
|
|
|
|
|
323 |
</div>
|
324 |
|
325 |
<?php
|
99 |
$question_type = $question->question_type;
|
100 |
$answers = tutor_utils()->get_answers_by_quiz_question($question->question_id);
|
101 |
$show_question_mark = (bool) tutor_utils()->avalue_dot('show_question_mark', $question_settings);
|
102 |
+
$answer_required = (bool) tutils()->array_get('answer_required', $question_settings);
|
103 |
|
104 |
echo '<h4 class="question-text">';
|
105 |
if ( ! $hide_question_number_overview){
|
111 |
if ($show_question_mark){
|
112 |
echo '<p class="question-marks"> '.__('Marks : ', 'tutor').$question->question_mark.' </p>';
|
113 |
}
|
114 |
+
|
115 |
+
$question_description = stripslashes(esc_html($question->question_description));
|
116 |
+
if ($question_description){
|
117 |
+
echo "<p class='question-description'>{$question_description}</p>";
|
118 |
+
}
|
119 |
?>
|
|
|
120 |
|
121 |
+
<div class="tutor-quiz-answers-wrap question-type-<?php echo $question_type; ?> <?php echo $answer_required? 'quiz-answer-required':''; ?> ">
|
122 |
<?php
|
123 |
if ( is_array($answers) && count($answers) ) {
|
124 |
foreach ($answers as $answer){
|
325 |
<?php
|
326 |
}
|
327 |
?>
|
328 |
+
|
329 |
+
<div class="answer-help-block"></div>
|
330 |
+
|
331 |
</div>
|
332 |
|
333 |
<?php
|
tutor.php
CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Tutor LMS
|
|
4 |
Plugin URI: https://www.themeum.com/product/tutor-lms/
|
5 |
Description: Tutor is a complete solution for creating a Learning Management System in WordPress way. It can help you to create small to large scale online education site very conveniently. Power features like report, certificate, course preview, private file sharing make Tutor a robust plugin for any educational institutes.
|
6 |
Author: Themeum
|
7 |
-
Version: 1.6.
|
8 |
Author URI: https://themeum.com
|
9 |
Requires at least: 4.5
|
10 |
Tested up to: 5.3
|
@@ -17,7 +17,7 @@ if ( ! defined( 'ABSPATH' ) )
|
|
17 |
/**
|
18 |
* Defined the tutor main file
|
19 |
*/
|
20 |
-
define('TUTOR_VERSION', '1.6.
|
21 |
define('TUTOR_FILE', __FILE__);
|
22 |
|
23 |
/**
|
4 |
Plugin URI: https://www.themeum.com/product/tutor-lms/
|
5 |
Description: Tutor is a complete solution for creating a Learning Management System in WordPress way. It can help you to create small to large scale online education site very conveniently. Power features like report, certificate, course preview, private file sharing make Tutor a robust plugin for any educational institutes.
|
6 |
Author: Themeum
|
7 |
+
Version: 1.6.1
|
8 |
Author URI: https://themeum.com
|
9 |
Requires at least: 4.5
|
10 |
Tested up to: 5.3
|
17 |
/**
|
18 |
* Defined the tutor main file
|
19 |
*/
|
20 |
+
define('TUTOR_VERSION', '1.6.1');
|
21 |
define('TUTOR_FILE', __FILE__);
|
22 |
|
23 |
/**
|
views/metabox/course-contents.php
CHANGED
@@ -123,18 +123,18 @@
|
|
123 |
</div>
|
124 |
|
125 |
<div class="tutor_add_quiz_wrap" data-add-quiz-under="<?php echo $topic->ID; ?>">
|
126 |
-
<div class="tutor-add-quiz-button-wrap">
|
127 |
|
128 |
<?php do_action('tutor_course_builder_before_btn_group', $topic->ID); ?>
|
129 |
|
130 |
-
<a href="javascript:;" class="
|
131 |
<i class="tutor-icon-plus-square-button"></i>
|
132 |
-
<?php _e('
|
|
|
|
|
|
|
|
|
133 |
</a>
|
134 |
-
<button type="button" class="icon-bl tutor-add-quiz-btn tutor-btn default-btn">
|
135 |
-
<i class="tutor-icon-doubt"></i>
|
136 |
-
<?php _e('Add Topic Quiz', 'tutor'); ?>
|
137 |
-
</button>
|
138 |
<?php do_action('tutor_course_builder_after_btn_group', $topic->ID); ?>
|
139 |
</div>
|
140 |
</div>
|
123 |
</div>
|
124 |
|
125 |
<div class="tutor_add_quiz_wrap" data-add-quiz-under="<?php echo $topic->ID; ?>">
|
126 |
+
<div class="tutor-add-cotnents-btn-group tutor-add-quiz-button-wrap">
|
127 |
|
128 |
<?php do_action('tutor_course_builder_before_btn_group', $topic->ID); ?>
|
129 |
|
130 |
+
<a href="javascript:;" class="open-tutor-lesson-modal create-lesson-in-topic-btn" data-topic-id="<?php echo $topic->ID; ?>" data-lesson-id="0" >
|
131 |
<i class="tutor-icon-plus-square-button"></i>
|
132 |
+
<?php _e('Lesson', 'tutor'); ?>
|
133 |
+
</a>
|
134 |
+
<a href="javascript:;" class="tutor-add-quiz-btn">
|
135 |
+
<i class="tutor-icon-plus-square-button"></i>
|
136 |
+
<?php _e('Quiz', 'tutor'); ?>
|
137 |
</a>
|
|
|
|
|
|
|
|
|
138 |
<?php do_action('tutor_course_builder_after_btn_group', $topic->ID); ?>
|
139 |
</div>
|
140 |
</div>
|
views/options/field-types/radio.php
CHANGED
@@ -8,7 +8,7 @@ if ( ! empty($field['options'])){
|
|
8 |
foreach ($field['options'] as $optionKey => $option){
|
9 |
$option_value = $this->get($field['field_key'], tutils()->array_get('default', $field));
|
10 |
?>
|
11 |
-
<p>
|
12 |
<label>
|
13 |
<input type="radio" name="tutor_option[<?php echo $field['field_key']; ?>]" value="<?php echo $optionKey ?>" <?php checked($option_value, $optionKey) ?> /> <?php echo $option ?>
|
14 |
</label>
|
8 |
foreach ($field['options'] as $optionKey => $option){
|
9 |
$option_value = $this->get($field['field_key'], tutils()->array_get('default', $field));
|
10 |
?>
|
11 |
+
<p class="option-type-radio-wrap">
|
12 |
<label>
|
13 |
<input type="radio" name="tutor_option[<?php echo $field['field_key']; ?>]" value="<?php echo $optionKey ?>" <?php checked($option_value, $optionKey) ?> /> <?php echo $option ?>
|
14 |
</label>
|