Tutor LMS – eLearning and online course solution - Version 1.9.13

Version Description

  • January 10, 2022 =

Update: Security Update

Download this release

Release Info

Developer themeum
Plugin Icon wp plugin Tutor LMS – eLearning and online course solution
Version 1.9.13
Comparing to
See all releases

Code changes from version 1.9.12 to 1.9.13

classes/Addons.php CHANGED
@@ -11,144 +11,100 @@
11
 
12
  namespace TUTOR;
13
 
14
- if ( ! defined( 'ABSPATH' ) )
15
  exit;
 
16
 
17
  class Addons {
18
 
19
  public function __construct() {
20
- add_filter('tutor_pro_addons_lists_for_display', array($this, 'tutor_addons_lists_to_show'));
21
  }
22
 
23
- public function tutor_addons_lists_to_show(){
24
  $addons = array(
25
- 'buddypress' => array(
26
- 'name' => __('BuddyPress', 'tutor'),
27
- 'description' => 'Discuss about course and share your knowledge with your friends through BuddyPress',
28
  ),
29
- 'gradebook' => array(
30
- 'name' => __('Gradebook', 'tutor'),
31
- 'description' => 'Shows student progress from assignment and quiz',
32
  ),
33
- 'content-drip' => array(
34
- 'name' => __('Content Drip', 'tutor'),
35
- 'description' => 'Unlock lessons by schedule or when the student meets specific condition.',
36
  ),
37
- 'enrollments' => array(
38
- 'name' => __('Enrollments', 'tutor'),
39
- 'description' => 'Take advanced control on enrollments. Enroll the student manually.',
40
  ),
41
- 'wc-subscriptions' => array(
42
- 'name' => __('WooCommerce Subscriptions', 'tutor'),
43
- 'description' => 'Capture Residual Revenue with Recurring Payments.',
44
  ),
45
- 'pmpro' => array(
46
- 'name' => __('Paid Memberships Pro', 'tutor'),
47
- 'description' => 'Maximize revenue by selling membership access to all of your courses.',
48
  ),
49
- 'restrict-content-pro' => array(
50
- 'name' => __('Restrict Content Pro', 'tutor'),
51
- 'description' => 'Unlock Course depending on Restrict Content Pro Plugin Permission.',
52
  ),
53
- 'tutor-assignments' => array(
54
- 'name' => __('Tutor Assignments', 'tutor'),
55
- 'description' => 'Tutor assignments is a great way to assign tasks to students.',
56
  ),
57
- 'tutor-certificate' => array(
58
- 'name' => __('Tutor Certificate', 'tutor'),
59
- 'description' => 'Students will be able to download a certificate after course completion.',
60
  ),
61
  'tutor-course-attachments' => array(
62
- 'name' => __('Tutor Course Attachments', 'tutor'),
63
- 'description' => 'Add unlimited attachments/ private files to any Tutor course',
64
  ),
65
- 'tutor-course-preview' => array(
66
- 'name' => __('Tutor Course Preview', 'tutor'),
67
- 'description' => 'Unlock some lessons for students before enrollment.',
68
  ),
69
- 'tutor-email' => array(
70
- 'name' => __('Tutor E-Mail', 'tutor'),
71
- 'description' => 'Send email on various tutor events',
72
  ),
73
- 'tutor-multi-instructors' => array(
74
- 'name' => __('Tutor Multi Instructors', 'tutor'),
75
- 'description' => 'Start a course with multiple instructors by Tutor Multi Instructors',
76
  ),
77
- 'tutor-prerequisites' => array(
78
- 'name' => __('Tutor Prerequisites', 'tutor'),
79
- 'description' => 'Specific course you must complete before you can enroll new course by Tutor Prerequisites',
80
  ),
81
- 'tutor-report' => array(
82
- 'name' => __('Tutor Report', 'tutor'),
83
- 'description' => 'Check your course performance through Tutor Report stats.',
84
  ),
85
- 'quiz-import-export' => array(
86
- 'name' => __('Quiz Export/Import', 'tutor'),
87
- 'description' => __('Save time by exporting/importing quiz data with easy options.', 'tutor'),
88
  ),
89
- 'tutor-zoom' => array(
90
- 'name' => __('Tutor Zoom Integration', 'tutor'),
91
- 'description' => __('Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page.', 'tutor'),
92
  ),
93
- 'google-classroom' => array(
94
- 'name' => __('Google Classroom Integration', 'tutor'),
95
- 'description' => __('Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course.', 'tutor'),
96
  ),
97
- 'push-notification' => array(
98
- 'name' => 'Push Notification',
99
- 'description' => 'Users will get push notification on specified events.'
 
 
 
 
100
  ),
101
- 'tutor-wpml' => array(
102
- 'name' => __('WPML Multilingual CMS', 'tutor'),
103
- 'description' => __('Create multilingual courses, lessons, dashboard and more for a global audience.', 'tutor')
104
- )
105
  );
106
 
107
  return $addons;
108
  }
109
-
110
-
111
- /**
112
- * @deprecated from alpha version
113
- */
114
-
115
- public function addons_page(){
116
-
117
- if ( false === ( $addons_themes_data = get_transient( 'tutor_addons_themes_data' ) ) ) {
118
- //Request New
119
- $api_endpoint = 'https://www.themeum.com/wp-json/addon-serve/v2/get-products';
120
- $response = wp_remote_post( $api_endpoint, array(
121
- 'method' => 'POST',
122
- 'timeout' => 45,
123
- 'user-agent' => 'Tutor/'.TUTOR_VERSION.'; '.home_url( '/' ),
124
- 'headers' => array(
125
- 'wp_blog' => home_url( '/' )
126
- ),
127
- 'body' => array('plugin_slug' => 'tutor', 'wp_blog' => home_url( '/' )),
128
- )
129
- );
130
-
131
- if ( is_wp_error( $response ) ) {
132
- $error_message = $response->get_error_message();
133
- echo "Something went wrong: $error_message";
134
- } else {
135
- if (tutor_utils()->avalue_dot('body', $response) && tutor_utils()->avalue_dot('response.code', $response) == 200 ){
136
- $api_data = tutor_utils()->avalue_dot('body', $response);
137
-
138
- $addons_themes_data = array(
139
- 'last_checked_time' => tutor_time(),
140
- 'data' => $api_data,
141
- );
142
- }
143
- }
144
-
145
- //Save the Final api call result on the database
146
- set_transient( 'tutor_addons_themes_data', $addons_themes_data, 6 * HOUR_IN_SECONDS );
147
- }
148
-
149
-
150
- //Finally Show the View Page
151
- include tutor()->path.'views/pages/addons.php';
152
- }
153
-
154
- }
11
 
12
  namespace TUTOR;
13
 
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
  exit;
16
+ }
17
 
18
  class Addons {
19
 
20
  public function __construct() {
21
+ add_filter( 'tutor_pro_addons_lists_for_display', array( $this, 'tutor_addons_lists_to_show' ) );
22
  }
23
 
24
+ public function tutor_addons_lists_to_show() {
25
  $addons = array(
26
+ 'buddypress' => array(
27
+ 'name' => __( 'BuddyPress', 'tutor' ),
28
+ 'description' => 'Discuss about course and share your knowledge with your friends through BuddyPress',
29
  ),
30
+ 'gradebook' => array(
31
+ 'name' => __( 'Gradebook', 'tutor' ),
32
+ 'description' => 'Shows student progress from assignment and quiz',
33
  ),
34
+ 'content-drip' => array(
35
+ 'name' => __( 'Content Drip', 'tutor' ),
36
+ 'description' => 'Unlock lessons by schedule or when the student meets specific condition.',
37
  ),
38
+ 'enrollments' => array(
39
+ 'name' => __( 'Enrollments', 'tutor' ),
40
+ 'description' => 'Take advanced control on enrollments. Enroll the student manually.',
41
  ),
42
+ 'wc-subscriptions' => array(
43
+ 'name' => __( 'WooCommerce Subscriptions', 'tutor' ),
44
+ 'description' => 'Capture Residual Revenue with Recurring Payments.',
45
  ),
46
+ 'pmpro' => array(
47
+ 'name' => __( 'Paid Memberships Pro', 'tutor' ),
48
+ 'description' => 'Maximize revenue by selling membership access to all of your courses.',
49
  ),
50
+ 'restrict-content-pro' => array(
51
+ 'name' => __( 'Restrict Content Pro', 'tutor' ),
52
+ 'description' => 'Unlock Course depending on Restrict Content Pro Plugin Permission.',
53
  ),
54
+ 'tutor-assignments' => array(
55
+ 'name' => __( 'Tutor Assignments', 'tutor' ),
56
+ 'description' => 'Tutor assignments is a great way to assign tasks to students.',
57
  ),
58
+ 'tutor-certificate' => array(
59
+ 'name' => __( 'Tutor Certificate', 'tutor' ),
60
+ 'description' => 'Students will be able to download a certificate after course completion.',
61
  ),
62
  'tutor-course-attachments' => array(
63
+ 'name' => __( 'Tutor Course Attachments', 'tutor' ),
64
+ 'description' => 'Add unlimited attachments/ private files to any Tutor course',
65
  ),
66
+ 'tutor-course-preview' => array(
67
+ 'name' => __( 'Tutor Course Preview', 'tutor' ),
68
+ 'description' => 'Unlock some lessons for students before enrollment.',
69
  ),
70
+ 'tutor-email' => array(
71
+ 'name' => __( 'Tutor E-Mail', 'tutor' ),
72
+ 'description' => 'Send email on various tutor events',
73
  ),
74
+ 'tutor-multi-instructors' => array(
75
+ 'name' => __( 'Tutor Multi Instructors', 'tutor' ),
76
+ 'description' => 'Start a course with multiple instructors by Tutor Multi Instructors',
77
  ),
78
+ 'tutor-prerequisites' => array(
79
+ 'name' => __( 'Tutor Prerequisites', 'tutor' ),
80
+ 'description' => 'Specific course you must complete before you can enroll new course by Tutor Prerequisites',
81
  ),
82
+ 'tutor-report' => array(
83
+ 'name' => __( 'Tutor Report', 'tutor' ),
84
+ 'description' => 'Check your course performance through Tutor Report stats.',
85
  ),
86
+ 'quiz-import-export' => array(
87
+ 'name' => __( 'Quiz Export/Import', 'tutor' ),
88
+ 'description' => __( 'Save time by exporting/importing quiz data with easy options.', 'tutor' ),
89
  ),
90
+ 'tutor-zoom' => array(
91
+ 'name' => __( 'Tutor Zoom Integration', 'tutor' ),
92
+ 'description' => __( 'Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page.', 'tutor' ),
93
  ),
94
+ 'google-classroom' => array(
95
+ 'name' => __( 'Google Classroom Integration', 'tutor' ),
96
+ 'description' => __( 'Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course.', 'tutor' ),
97
  ),
98
+ 'push-notification' => array(
99
+ 'name' => 'Push Notification',
100
+ 'description' => 'Users will get push notification on specified events.',
101
+ ),
102
+ 'tutor-wpml' => array(
103
+ 'name' => __( 'WPML Multilingual CMS', 'tutor' ),
104
+ 'description' => __( 'Create multilingual courses, lessons, dashboard and more for a global audience.', 'tutor' ),
105
  ),
 
 
 
 
106
  );
107
 
108
  return $addons;
109
  }
110
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/Admin.php CHANGED
@@ -62,7 +62,7 @@ class Admin{
62
  if ($enable_course_marketplace) {
63
  add_submenu_page('tutor', __('Instructors', 'tutor'), __('Instructors', 'tutor'), 'manage_tutor', Instructors_List::INSTRUCTOR_LIST_PAGE, array($this, 'tutor_instructors'));
64
  }
65
-
66
  add_submenu_page('tutor', __('Announcements', 'tutor'), __('Announcements', 'tutor'), 'manage_tutor_instructor', 'tutor_announcements', array($this, 'tutor_announcements'));
67
 
68
  add_submenu_page('tutor', __('Q & A', 'tutor'), __('Q & A ', 'tutor').$unanswered_bubble, 'manage_tutor_instructor', Question_Answers_List::Question_Answer_PAGE, array($this, 'question_answer') );
@@ -130,7 +130,7 @@ class Admin{
130
  }
131
 
132
  public function tutor_tools(){
133
- $tutor_admin_tools_page = tutils()->array_get('tutor_admin_tools_page', $_GET);
134
  if ($tutor_admin_tools_page){
135
  include apply_filters('tutor_admin_tools_page', tutor()->path."views/pages/{$tutor_admin_tools_page}.php", $tutor_admin_tools_page);
136
  }else{
@@ -159,7 +159,7 @@ class Admin{
159
  }
160
 
161
  public function parent_menu_active( $parent_file ){
162
- $taxonomy = tutor_utils()->avalue_dot('taxonomy', $_GET);
163
  if ($taxonomy === 'course-category' || $taxonomy === 'course-tag'){
164
  return 'tutor';
165
  }
@@ -168,7 +168,7 @@ class Admin{
168
  }
169
 
170
  public function submenu_file_active($submenu_file, $parent_file){
171
- $taxonomy = tutor_utils()->avalue_dot('taxonomy', $_GET);
172
  $course_post_type = tutor()->course_post_type;
173
 
174
  if ($taxonomy === 'course-category'){
@@ -193,7 +193,7 @@ class Admin{
193
  }
194
 
195
  public function posts_clauses_request($clauses){
196
-
197
  if(!is_admin() || (!isset($_GET['post_type']) || $_GET['post_type']!='courses') || tutor_utils()->has_user_role(array('administrator', 'editor'))) {
198
  return $clauses;
199
  }
@@ -205,14 +205,14 @@ class Admin{
205
 
206
  $get_assigned_courses_ids = $wpdb->get_col($wpdb->prepare("SELECT meta_value from {$wpdb->usermeta} WHERE meta_key = '_tutor_instructor_course_id' AND user_id = %d", $user_id));
207
  $own_courses = is_array($get_assigned_courses_ids) ? $get_assigned_courses_ids : array();
208
-
209
  $in_query_pre = count($own_courses) ? implode(',', $own_courses) : null;
210
  $in_query_where = $in_query_pre ? " OR {$wpdb->posts}.ID IN({$in_query_pre})" : '';
211
 
212
  $custom_author_query = " AND ({$wpdb->posts}.post_type!='courses' OR {$wpdb->posts}.post_author = {$user_id}) {$in_query_where}";
213
-
214
  $clauses['where'] .= $custom_author_query;
215
-
216
  return $clauses;
217
  }
218
 
@@ -237,8 +237,8 @@ class Admin{
237
  global $wpdb;
238
 
239
  $get_assigned_courses_ids = (int) $wpdb->get_var($wpdb->prepare(
240
- "SELECT user_id
241
- from {$wpdb->usermeta}
242
  WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ", $current_user, $get_post_id));
243
 
244
  if ( ! $get_assigned_courses_ids){
62
  if ($enable_course_marketplace) {
63
  add_submenu_page('tutor', __('Instructors', 'tutor'), __('Instructors', 'tutor'), 'manage_tutor', Instructors_List::INSTRUCTOR_LIST_PAGE, array($this, 'tutor_instructors'));
64
  }
65
+
66
  add_submenu_page('tutor', __('Announcements', 'tutor'), __('Announcements', 'tutor'), 'manage_tutor_instructor', 'tutor_announcements', array($this, 'tutor_announcements'));
67
 
68
  add_submenu_page('tutor', __('Q & A', 'tutor'), __('Q & A ', 'tutor').$unanswered_bubble, 'manage_tutor_instructor', Question_Answers_List::Question_Answer_PAGE, array($this, 'question_answer') );
130
  }
131
 
132
  public function tutor_tools(){
133
+ $tutor_admin_tools_page = tutils()->array_get('tutor_admin_tools_page', tutor_sanitize_data($_GET));
134
  if ($tutor_admin_tools_page){
135
  include apply_filters('tutor_admin_tools_page', tutor()->path."views/pages/{$tutor_admin_tools_page}.php", $tutor_admin_tools_page);
136
  }else{
159
  }
160
 
161
  public function parent_menu_active( $parent_file ){
162
+ $taxonomy = tutor_utils()->avalue_dot('taxonomy', tutor_sanitize_data($_GET));
163
  if ($taxonomy === 'course-category' || $taxonomy === 'course-tag'){
164
  return 'tutor';
165
  }
168
  }
169
 
170
  public function submenu_file_active($submenu_file, $parent_file){
171
+ $taxonomy = tutor_utils()->avalue_dot('taxonomy', tutor_sanitize_data($_GET));
172
  $course_post_type = tutor()->course_post_type;
173
 
174
  if ($taxonomy === 'course-category'){
193
  }
194
 
195
  public function posts_clauses_request($clauses){
196
+
197
  if(!is_admin() || (!isset($_GET['post_type']) || $_GET['post_type']!='courses') || tutor_utils()->has_user_role(array('administrator', 'editor'))) {
198
  return $clauses;
199
  }
205
 
206
  $get_assigned_courses_ids = $wpdb->get_col($wpdb->prepare("SELECT meta_value from {$wpdb->usermeta} WHERE meta_key = '_tutor_instructor_course_id' AND user_id = %d", $user_id));
207
  $own_courses = is_array($get_assigned_courses_ids) ? $get_assigned_courses_ids : array();
208
+
209
  $in_query_pre = count($own_courses) ? implode(',', $own_courses) : null;
210
  $in_query_where = $in_query_pre ? " OR {$wpdb->posts}.ID IN({$in_query_pre})" : '';
211
 
212
  $custom_author_query = " AND ({$wpdb->posts}.post_type!='courses' OR {$wpdb->posts}.post_author = {$user_id}) {$in_query_where}";
213
+
214
  $clauses['where'] .= $custom_author_query;
215
+
216
  return $clauses;
217
  }
218
 
237
  global $wpdb;
238
 
239
  $get_assigned_courses_ids = (int) $wpdb->get_var($wpdb->prepare(
240
+ "SELECT user_id
241
+ from {$wpdb->usermeta}
242
  WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ", $current_user, $get_post_id));
243
 
244
  if ( ! $get_assigned_courses_ids){
classes/Ajax.php CHANGED
@@ -1,46 +1,50 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- class Ajax{
8
  public function __construct() {
9
 
10
- add_action('wp_ajax_sync_video_playback', array($this, 'sync_video_playback'));
11
- add_action('wp_ajax_nopriv_sync_video_playback', array($this, 'sync_video_playback_noprev'));
12
- add_action('wp_ajax_tutor_place_rating', array($this, 'tutor_place_rating'));
13
 
14
- add_action('wp_ajax_tutor_ask_question', array($this, 'tutor_ask_question'));
15
- add_action('wp_ajax_tutor_add_answer', array($this, 'tutor_add_answer'));
16
 
17
- add_action('wp_ajax_tutor_course_add_to_wishlist', array($this, 'tutor_course_add_to_wishlist'));
18
- add_action('wp_ajax_nopriv_tutor_course_add_to_wishlist', array($this, 'tutor_course_add_to_wishlist'));
19
 
20
  /**
21
  * Addon Enable Disable Control
22
  */
23
- add_action('wp_ajax_addon_enable_disable', array($this, 'addon_enable_disable'));
24
 
25
  /**
26
  * Update Rating/review
 
27
  * @since v.1.4.0
28
  */
29
- add_action('wp_ajax_tutor_load_edit_review_modal', array($this, 'tutor_load_edit_review_modal'));
30
- add_action('wp_ajax_tutor_update_review_modal', array($this, 'tutor_update_review_modal'));
31
 
32
  /**
33
  * Ajax login
 
34
  * @since v.1.6.3
35
  */
36
- add_action('wp_ajax_nopriv_tutor_user_login', array($this, 'process_ajax_login'));
37
 
38
  /**
39
  * Announcement
 
40
  * @since v.1.7.9
41
  */
42
- add_action("wp_ajax_tutor_announcement_create", array($this,'create_or_update_annoucement'));
43
- add_action("wp_ajax_tutor_announcement_delete", array($this,'delete_annoucement'));
44
  }
45
 
46
 
@@ -50,321 +54,384 @@ class Ajax{
50
  *
51
  * @since v.1.0.0
52
  */
53
- public function sync_video_playback(){
54
  tutor_utils()->checking_nonce();
55
 
56
- $user_id = get_current_user_id();
57
- $post_id = isset($_POST['post_id']) ? sanitize_text_field($_POST['post_id']) : 0;
58
- $duration = sanitize_text_field($_POST['duration']);
59
- $currentTime = sanitize_text_field($_POST['currentTime']);
60
 
61
- if(!tutils()->has_enrolled_content_access('lesson', $post_id)) {
62
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
63
  exit;
64
  }
65
 
66
  /**
67
  * Update posts attached video
68
  */
69
- $video = tutor_utils()->get_video($post_id);
70
 
71
- if ($duration) {
72
- $video['duration_sec'] = $duration; //secs
73
  $video['playtime'] = tutor_utils()->playtime_string( $duration );
74
  $video['runtime'] = tutor_utils()->playtime_array( $duration );
75
  }
76
- tutor_utils()->update_video($post_id, $video);
77
 
78
  /**
79
  * Sync Lesson Reading Info by Users
80
  */
81
 
82
- $best_watch_time = tutor_utils()->get_lesson_reading_info($post_id, $user_id, 'video_best_watched_time');
83
- if ($best_watch_time < $currentTime){
84
- tutor_utils()->update_lesson_reading_info($post_id, $user_id, 'video_best_watched_time', $currentTime);
85
  }
86
 
87
- if (tutor_utils()->avalue_dot('is_ended', $_POST)){
88
- tutor_utils()->mark_lesson_complete($post_id);
89
  }
90
  exit();
91
  }
92
 
93
- public function sync_video_playback_noprev(){
94
 
95
  }
96
 
97
 
98
- public function tutor_place_rating(){
99
  global $wpdb;
100
 
101
  tutils()->checking_nonce();
102
 
103
- $rating = sanitize_text_field(tutor_utils()->avalue_dot('rating', $_POST));
104
- $course_id = sanitize_text_field(tutor_utils()->avalue_dot('course_id', $_POST));
105
- $review = sanitize_textarea_field(tutor_utils()->avalue_dot('review', $_POST));
106
 
107
- !$rating ? $rating = 0 : 0;
108
- $rating>5 ? $rating = 5 : 0;
109
 
110
  $user_id = get_current_user_id();
111
- $user = get_userdata($user_id);
112
- $date = date("Y-m-d H:i:s", tutor_time());
113
 
114
- if(!tutils()->has_enrolled_content_access('course', $course_id)) {
115
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
116
  exit;
117
  }
118
 
119
- do_action('tutor_before_rating_placed');
120
 
121
- $previous_rating_id = $wpdb->get_var($wpdb->prepare("select comment_ID from {$wpdb->comments} WHERE comment_post_ID = %d AND user_id = %d AND comment_type = 'tutor_course_rating' LIMIT 1;", $course_id, $user_id));
122
 
123
  $review_ID = $previous_rating_id;
124
- if ( $previous_rating_id){
125
- $wpdb->update( $wpdb->comments, array('comment_content' => $review ),
126
- array('comment_ID' => $previous_rating_id)
 
 
127
  );
128
 
129
- $rating_info = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->commentmeta} WHERE comment_id = %d AND meta_key = 'tutor_rating'; ", $previous_rating_id));
130
- if ($rating_info){
131
- $wpdb->update( $wpdb->commentmeta, array('meta_value' => $rating), array('comment_id' => $previous_rating_id, 'meta_key' => 'tutor_rating') );
132
- }else{
133
- $wpdb->insert( $wpdb->commentmeta, array('comment_id' => $previous_rating_id, 'meta_key' => 'tutor_rating', 'meta_value' => $rating) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  }
135
- }else{
136
  $data = array(
137
- 'comment_post_ID' => esc_sql( $course_id ) ,
138
- 'comment_approved' => 'approved',
139
- 'comment_type' => 'tutor_course_rating',
140
- 'comment_date' => $date,
141
- 'comment_date_gmt' => get_gmt_from_date($date),
142
- 'user_id' => $user_id,
143
- 'comment_author' => $user->user_login,
144
- 'comment_agent' => 'TutorLMSPlugin',
145
  );
146
- if ($review){
147
  $data['comment_content'] = $review;
148
  }
149
 
150
- $wpdb->insert($wpdb->comments, $data);
151
  $comment_id = (int) $wpdb->insert_id;
152
- $review_ID = $comment_id;
153
-
154
- if ($comment_id){
155
- $result = $wpdb->insert( $wpdb->commentmeta, array(
156
- 'comment_id' => $comment_id,
157
- 'meta_key' => 'tutor_rating',
158
- 'meta_value' => $rating
159
- ) );
160
-
161
- do_action('tutor_after_rating_placed', $comment_id);
 
 
 
162
  }
163
  }
164
 
165
- $data = array('msg' => __('Rating placed success', 'tutor'), 'review_id' => $review_ID, 'review' => $review);
166
- wp_send_json_success($data);
 
 
 
 
167
  }
168
 
169
- public function tutor_ask_question(){
170
  tutor_utils()->checking_nonce();
171
 
172
  global $wpdb;
173
 
174
- $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
175
- $question_title = sanitize_text_field($_POST['question_title']);
176
- $question = wp_kses_post($_POST['question']);
177
 
178
- if(!tutils()->has_enrolled_content_access('course', $course_id)) {
179
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
180
  exit;
181
  }
182
 
183
- if (empty($question) || empty($question_title)){
184
- wp_send_json_error(__('Empty question title or body', 'tutor'));
185
  }
186
 
187
  $user_id = get_current_user_id();
188
- $user = get_userdata($user_id);
189
- $date = date("Y-m-d H:i:s", tutor_time());
190
-
191
- do_action('tutor_before_add_question', $course_id);
192
- $data = apply_filters('tutor_add_question_data', array(
193
- 'comment_post_ID' => $course_id,
194
- 'comment_author' => $user->user_login,
195
- 'comment_date' => $date,
196
- 'comment_date_gmt' => get_gmt_from_date($date),
197
- 'comment_content' => $question,
198
- 'comment_approved' => 'waiting_for_answer',
199
- 'comment_agent' => 'TutorLMSPlugin',
200
- 'comment_type' => 'tutor_q_and_a',
201
- 'user_id' => $user_id,
202
- ));
203
-
204
- $wpdb->insert($wpdb->comments, $data);
 
 
 
205
  $comment_id = (int) $wpdb->insert_id;
206
 
207
- if ($comment_id){
208
- $result = $wpdb->insert( $wpdb->commentmeta, array(
209
- 'comment_id' => $comment_id,
210
- 'meta_key' => 'tutor_question_title',
211
- 'meta_value' => $question_title
212
- ) );
 
 
 
213
  }
214
- do_action('tutor_after_add_question', $course_id, $comment_id);
215
 
216
- wp_send_json_success(__('Question has been added successfully', 'tutor'));
217
  }
218
 
219
 
220
- public function tutor_add_answer(){
221
  tutor_utils()->checking_nonce();
222
  global $wpdb;
223
 
224
- $answer = wp_kses_post($_POST['answer']);
225
- if ( ! $answer){
226
- wp_send_json_error(__('Please write answer', 'tutor'));
227
  }
228
 
229
- $question_id = (int) sanitize_text_field($_POST['question_id']);
230
- $question = tutor_utils()->get_qa_question($question_id);
231
 
232
  $user_id = get_current_user_id();
233
- $user = get_userdata($user_id);
234
- $date = date("Y-m-d H:i:s", tutor_time());
235
 
236
- if(!tutils()->has_enrolled_content_access('qa_question', $question_id)) {
237
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
238
  exit;
239
  }
240
 
241
- do_action('tutor_before_answer_to_question');
242
- $data = apply_filters('tutor_add_answer_data', array(
243
- 'comment_post_ID' => $question->comment_post_ID,
244
- 'comment_author' => $user->user_login,
245
- 'comment_date' => $date,
246
- 'comment_date_gmt' => get_gmt_from_date($date),
247
- 'comment_content' => $answer,
248
- 'comment_approved' => 'approved',
249
- 'comment_agent' => 'TutorLMSPlugin',
250
- 'comment_type' => 'tutor_q_and_a',
251
- 'comment_parent' => $question_id,
252
- 'user_id' => $user_id,
253
- ));
254
-
255
- $wpdb->insert($wpdb->comments, $data);
 
 
 
256
  $comment_id = (int) $wpdb->insert_id;
257
- do_action('tutor_after_answer_to_question', $comment_id);
258
 
259
- wp_send_json_success(__('Answer has been added successfully', 'tutor'));
260
  }
261
 
262
 
263
- public function tutor_course_add_to_wishlist(){
264
  tutils()->checking_nonce();
265
 
266
- $course_id = (int) sanitize_text_field($_POST['course_id']);
267
- if ( ! is_user_logged_in()){
268
- wp_send_json_error(array('redirect_to' => wp_login_url( wp_get_referer() ) ) );
269
  }
270
  global $wpdb;
271
 
272
- $user_id = get_current_user_id();
273
- $if_added_to_list = $wpdb->get_row($wpdb->prepare("SELECT * from {$wpdb->usermeta} WHERE user_id = %d AND meta_key = '_tutor_course_wishlist' AND meta_value = %d;", $user_id, $course_id));
274
-
275
- if ( $if_added_to_list){
276
- $wpdb->delete($wpdb->usermeta, array('user_id' => $user_id, 'meta_key' => '_tutor_course_wishlist', 'meta_value' => $course_id ));
277
- wp_send_json_success(array('status' => 'removed', 'msg' => __('Course removed from wish list', 'tutor')));
278
- }else{
279
- add_user_meta($user_id, '_tutor_course_wishlist', $course_id);
280
- wp_send_json_success(array('status' => 'added', 'msg' => __('Course added to wish list', 'tutor')));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  }
282
  }
283
 
284
  /**
285
  * Method for enable / disable addons
286
  */
287
- public function addon_enable_disable(){
288
 
289
- if(!current_user_can( 'manage_options' )) {
290
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
291
  }
292
 
293
- $addonsConfig = maybe_unserialize(get_option('tutor_addons_config'));
294
 
295
- $isEnable = (bool) sanitize_text_field(tutor_utils()->avalue_dot('isEnable', $_POST));
296
- $addonFieldName = sanitize_text_field(tutor_utils()->avalue_dot('addonFieldName', $_POST));
297
 
298
- do_action('tutor_addon_before_enable_disable');
299
- if ($isEnable){
300
- do_action("tutor_addon_before_enable_{$addonFieldName}");
301
- do_action('tutor_addon_before_enable', $addonFieldName);
302
- $addonsConfig[$addonFieldName]['is_enable'] = 1;
303
- update_option('tutor_addons_config', $addonsConfig);
304
 
305
- do_action('tutor_addon_after_enable', $addonFieldName);
306
- do_action("tutor_addon_after_enable_{$addonFieldName}");
307
- }else{
308
- do_action("tutor_addon_before_disable_{$addonFieldName}");
309
- do_action('tutor_addon_before_disable', $addonFieldName);
310
- $addonsConfig[$addonFieldName]['is_enable'] = 0;
311
- update_option('tutor_addons_config', $addonsConfig);
312
 
313
- do_action('tutor_addon_after_disable', $addonFieldName);
314
- do_action("tutor_addon_after_disable_{$addonFieldName}");
315
  }
316
 
317
- do_action('tutor_addon_after_enable_disable');
318
  wp_send_json_success();
319
  }
320
 
321
  /**
322
  * Load review edit form
 
323
  * @since v.1.4.0
324
  */
325
- public function tutor_load_edit_review_modal(){
326
  tutor_utils()->checking_nonce();
327
 
328
- $review_id = (int) sanitize_text_field(tutils()->array_get('review_id', $_POST));
329
- $rating = tutils()->get_rating_by_id($review_id);
330
 
331
- if(!tutils()->has_enrolled_content_access('review', $review_id)) {
332
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
333
  exit;
334
  }
335
 
336
  ob_start();
337
- tutor_load_template('dashboard.reviews.edit-review-form', array('rating' => $rating));
338
  $output = ob_get_clean();
339
 
340
- wp_send_json_success(array('output' => $output));
341
  }
342
 
343
- public function tutor_update_review_modal(){
344
  global $wpdb;
345
 
346
  tutor_utils()->checking_nonce();
347
 
348
- $review_id = (int) sanitize_text_field(tutils()->array_get('review_id', $_POST));
349
- $rating = sanitize_text_field(tutor_utils()->avalue_dot('rating', $_POST));
350
- $review = wp_kses_post(tutor_utils()->avalue_dot('review', $_POST));
351
 
352
- if(!tutils()->has_enrolled_content_access('review', $review_id)) {
353
- wp_send_json_error(array('message'=>__('Access Denied', 'tutor')));
354
  exit;
355
  }
356
 
357
- $is_exists = $wpdb->get_var($wpdb->prepare("SELECT comment_ID from {$wpdb->comments} WHERE comment_ID=%d AND comment_type = 'tutor_course_rating' ;", $review_id));
358
 
359
- if ( $is_exists) {
360
- $wpdb->update( $wpdb->comments, array( 'comment_content' => $review ),
 
 
361
  array( 'comment_ID' => $review_id )
362
  );
363
- $wpdb->update( $wpdb->commentmeta, array( 'meta_value' => $rating ),
364
- array( 'comment_id' => $review_id, 'meta_key' => 'tutor_rating' )
 
 
 
 
 
365
  );
366
 
367
- do_action('tutor_after_review_update', $review_id, $is_exists);
368
 
369
  wp_send_json_success();
370
  }
@@ -373,14 +440,15 @@ class Ajax{
373
 
374
  /**
375
  * Process ajax login
 
376
  * @since v.1.6.3
377
  */
378
- public function process_ajax_login(){
379
  tutils()->checking_nonce();
380
 
381
- $username = tutils()->array_get('log', $_POST);
382
- $password = tutils()->array_get('pwd', $_POST);
383
- $redirect_to = tutils()->array_get('redirect_to', $_POST);
384
 
385
  try {
386
  $creds = array(
@@ -415,131 +483,134 @@ class Ajax{
415
  if ( is_wp_error( $user ) ) {
416
  $message = $user->get_error_message();
417
  $message = str_replace( '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', $message );
418
-
419
  wp_send_json_error( $message );
420
  } else {
421
- //since 1.9.8 do enroll if guest attempt to enroll
422
  do_action( 'tutor_do_enroll_after_login_if_attempt', $_POST['tutor_course_enroll_attempt'] );
423
-
424
- wp_send_json_success([
425
- 'redirect' => apply_filters('tutor_login_redirect_url', $redirect_to)
426
- ]);
427
 
 
 
 
 
 
428
 
429
  }
430
  } catch ( \Exception $e ) {
431
- wp_send_json_error( apply_filters( 'login_errors', $e->getMessage()) );
432
  do_action( 'tutor_login_failed' );
433
  }
434
  }
435
 
436
  /**
437
  * Create/Update announcement
 
438
  * @since v.1.7.9
439
  */
440
- public function create_or_update_annoucement() {
441
- //prepare alert message
442
- $create_success_msg = __("Announcement created successfully",'tutor');
443
- $update_success_msg = __("Announcement updated successfully",'tutor');
444
- $create_fail_msg = __("Announcement creation failed",'tutor');
445
- $update_fail_msg = __("Announcement update failed",'tutor');
446
-
447
- $error = array();
448
- $response = array();
449
  tutils()->checking_nonce();
450
 
451
- $course_id = sanitize_text_field($_POST['tutor_announcement_course']);
452
- $announcement_title = sanitize_text_field($_POST['tutor_announcement_title']);
453
- $announcement_summary = sanitize_textarea_field($_POST['tutor_announcement_summary']);
454
-
455
- if(!tutils()->can_user_manage('course', $course_id)) {
456
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
457
  }
458
-
459
- //set data and sanitize it
460
- $form_data = array(
461
- 'post_type' => 'tutor_announcements',
462
- 'post_title' => $announcement_title,
463
  'post_content' => $announcement_summary,
464
- 'post_parent' => $course_id,
465
- 'post_status' => 'publish'
466
- );
467
 
468
- if (isset($_POST['announcement_id'])) {
469
- $form_data['ID'] = sanitize_text_field($_POST['announcement_id']);
470
- }
 
 
 
 
471
 
472
- //validation message set
473
- if (empty($form_data['post_parent'])) {
474
- $error['post_parent'] = __('Course name required','tutor');
475
 
 
 
476
  }
477
-
478
- if (empty($form_data['post_title'])) {
479
- $error['post_title'] = __('Announcement title required','tutor');
 
480
  }
481
-
482
- if (empty($form_data['post_content'])) {
483
- $error['post_content'] = __('Announcement summary required','tutor');
484
-
485
- }
486
-
487
- if (count($error)>0) {
488
- $response['status'] = 'validation_error';
489
- $response['message'] = $error;
490
- wp_send_json($response);
491
- } else {
492
- //insert or update post
493
- $post_id = wp_insert_post($form_data);
494
- if ($post_id > 0) {
495
- $announcement = get_post($post_id);
496
- $action_type = sanitize_textarea_field($_POST['action_type']);
497
- $response['status'] = 'success';
498
- //set reponse message as per action type
499
- $response['message'] = ($action_type == 'create') ? $create_success_msg : $update_success_msg;
500
-
501
- do_action('tutor_announcements/after/save', $post_id, $announcement, $action_type );
502
-
503
- wp_send_json($response);
504
- } else {
505
- //failure message
506
- $response['status'] = 'fail';
507
- if($_POST['action_type'] == 'create'){
508
- $response['message'] = $create_fail_msg;
509
- }
510
- if($_POST['action_type'] == 'update'){
511
- $response['message'] = $update_fail_msg;
512
- }
513
- wp_send_json($response);
514
- }
515
- }
516
- }
517
 
518
  /**
519
  * Delete announcement
 
520
  * @since v.1.7.9
521
  */
522
- public function delete_annoucement() {
523
- $announcement_id = sanitize_text_field($_POST['announcement_id']);
524
  tutils()->checking_nonce();
525
 
526
- if(!tutils()->can_user_manage('announcement', $announcement_id)) {
527
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
528
  }
529
 
530
- $delete = wp_delete_post($announcement_id);
531
- if ($delete) {
532
- $response = array(
533
- 'status' => 'success',
534
- 'message' => __('Announcement deleted successfully','tutor')
535
- );
536
- wp_send_json($response);
537
- } else {
538
- $response = array(
539
- 'status' => 'fail',
540
- 'message' => __('Announcement delete failed','tutor')
541
- );
542
- wp_send_json($response);
543
- }
544
- }
545
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ class Ajax {
9
  public function __construct() {
10
 
11
+ add_action( 'wp_ajax_sync_video_playback', array( $this, 'sync_video_playback' ) );
12
+ add_action( 'wp_ajax_nopriv_sync_video_playback', array( $this, 'sync_video_playback_noprev' ) );
13
+ add_action( 'wp_ajax_tutor_place_rating', array( $this, 'tutor_place_rating' ) );
14
 
15
+ add_action( 'wp_ajax_tutor_ask_question', array( $this, 'tutor_ask_question' ) );
16
+ add_action( 'wp_ajax_tutor_add_answer', array( $this, 'tutor_add_answer' ) );
17
 
18
+ add_action( 'wp_ajax_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
19
+ add_action( 'wp_ajax_nopriv_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
20
 
21
  /**
22
  * Addon Enable Disable Control
23
  */
24
+ add_action( 'wp_ajax_addon_enable_disable', array( $this, 'addon_enable_disable' ) );
25
 
26
  /**
27
  * Update Rating/review
28
+ *
29
  * @since v.1.4.0
30
  */
31
+ add_action( 'wp_ajax_tutor_load_edit_review_modal', array( $this, 'tutor_load_edit_review_modal' ) );
32
+ add_action( 'wp_ajax_tutor_update_review_modal', array( $this, 'tutor_update_review_modal' ) );
33
 
34
  /**
35
  * Ajax login
36
+ *
37
  * @since v.1.6.3
38
  */
39
+ add_action( 'wp_ajax_nopriv_tutor_user_login', array( $this, 'process_ajax_login' ) );
40
 
41
  /**
42
  * Announcement
43
+ *
44
  * @since v.1.7.9
45
  */
46
+ add_action( 'wp_ajax_tutor_announcement_create', array( $this, 'create_or_update_annoucement' ) );
47
+ add_action( 'wp_ajax_tutor_announcement_delete', array( $this, 'delete_annoucement' ) );
48
  }
49
 
50
 
54
  *
55
  * @since v.1.0.0
56
  */
57
+ public function sync_video_playback() {
58
  tutor_utils()->checking_nonce();
59
 
60
+ $user_id = get_current_user_id();
61
+ $post_id = isset( $_POST['post_id'] ) ? sanitize_text_field( $_POST['post_id'] ) : 0;
62
+ $duration = sanitize_text_field( $_POST['duration'] );
63
+ $currentTime = sanitize_text_field( $_POST['currentTime'] );
64
 
65
+ if ( ! tutils()->has_enrolled_content_access( 'lesson', $post_id ) ) {
66
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
67
  exit;
68
  }
69
 
70
  /**
71
  * Update posts attached video
72
  */
73
+ $video = tutor_utils()->get_video( $post_id );
74
 
75
+ if ( $duration ) {
76
+ $video['duration_sec'] = $duration; // secs
77
  $video['playtime'] = tutor_utils()->playtime_string( $duration );
78
  $video['runtime'] = tutor_utils()->playtime_array( $duration );
79
  }
80
+ tutor_utils()->update_video( $post_id, $video );
81
 
82
  /**
83
  * Sync Lesson Reading Info by Users
84
  */
85
 
86
+ $best_watch_time = tutor_utils()->get_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time' );
87
+ if ( $best_watch_time < $currentTime ) {
88
+ tutor_utils()->update_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time', $currentTime );
89
  }
90
 
91
+ if ( tutor_utils()->avalue_dot( 'is_ended', $_POST ) ) {
92
+ tutor_utils()->mark_lesson_complete( $post_id );
93
  }
94
  exit();
95
  }
96
 
97
+ public function sync_video_playback_noprev() {
98
 
99
  }
100
 
101
 
102
+ public function tutor_place_rating() {
103
  global $wpdb;
104
 
105
  tutils()->checking_nonce();
106
 
107
+ $rating = sanitize_text_field( tutor_utils()->avalue_dot( 'rating', $_POST ) );
108
+ $course_id = sanitize_text_field( tutor_utils()->avalue_dot( 'course_id', $_POST ) );
109
+ $review = sanitize_textarea_field( tutor_utils()->avalue_dot( 'review', $_POST ) );
110
 
111
+ ! $rating ? $rating = 0 : 0;
112
+ $rating > 5 ? $rating = 5 : 0;
113
 
114
  $user_id = get_current_user_id();
115
+ $user = get_userdata( $user_id );
116
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
117
 
118
+ if ( ! tutils()->has_enrolled_content_access( 'course', $course_id ) ) {
119
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
120
  exit;
121
  }
122
 
123
+ do_action( 'tutor_before_rating_placed' );
124
 
125
+ $previous_rating_id = $wpdb->get_var( $wpdb->prepare( "select comment_ID from {$wpdb->comments} WHERE comment_post_ID = %d AND user_id = %d AND comment_type = 'tutor_course_rating' LIMIT 1;", $course_id, $user_id ) );
126
 
127
  $review_ID = $previous_rating_id;
128
+ if ( $previous_rating_id ) {
129
+ $wpdb->update(
130
+ $wpdb->comments,
131
+ array( 'comment_content' => $review ),
132
+ array( 'comment_ID' => $previous_rating_id )
133
  );
134
 
135
+ $rating_info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->commentmeta} WHERE comment_id = %d AND meta_key = 'tutor_rating'; ", $previous_rating_id ) );
136
+ if ( $rating_info ) {
137
+ $wpdb->update(
138
+ $wpdb->commentmeta,
139
+ array( 'meta_value' => $rating ),
140
+ array(
141
+ 'comment_id' => $previous_rating_id,
142
+ 'meta_key' => 'tutor_rating',
143
+ )
144
+ );
145
+ } else {
146
+ $wpdb->insert(
147
+ $wpdb->commentmeta,
148
+ array(
149
+ 'comment_id' => $previous_rating_id,
150
+ 'meta_key' => 'tutor_rating',
151
+ 'meta_value' => $rating,
152
+ )
153
+ );
154
  }
155
+ } else {
156
  $data = array(
157
+ 'comment_post_ID' => esc_sql( $course_id ),
158
+ 'comment_approved' => 'approved',
159
+ 'comment_type' => 'tutor_course_rating',
160
+ 'comment_date' => $date,
161
+ 'comment_date_gmt' => get_gmt_from_date( $date ),
162
+ 'user_id' => $user_id,
163
+ 'comment_author' => $user->user_login,
164
+ 'comment_agent' => 'TutorLMSPlugin',
165
  );
166
+ if ( $review ) {
167
  $data['comment_content'] = $review;
168
  }
169
 
170
+ $wpdb->insert( $wpdb->comments, $data );
171
  $comment_id = (int) $wpdb->insert_id;
172
+ $review_ID = $comment_id;
173
+
174
+ if ( $comment_id ) {
175
+ $result = $wpdb->insert(
176
+ $wpdb->commentmeta,
177
+ array(
178
+ 'comment_id' => $comment_id,
179
+ 'meta_key' => 'tutor_rating',
180
+ 'meta_value' => $rating,
181
+ )
182
+ );
183
+
184
+ do_action( 'tutor_after_rating_placed', $comment_id );
185
  }
186
  }
187
 
188
+ $data = array(
189
+ 'msg' => __( 'Rating placed success', 'tutor' ),
190
+ 'review_id' => $review_ID,
191
+ 'review' => $review,
192
+ );
193
+ wp_send_json_success( $data );
194
  }
195
 
196
+ public function tutor_ask_question() {
197
  tutor_utils()->checking_nonce();
198
 
199
  global $wpdb;
200
 
201
+ $course_id = (int) sanitize_text_field( $_POST['tutor_course_id'] );
202
+ $question_title = sanitize_text_field( $_POST['question_title'] );
203
+ $question = wp_kses_post( $_POST['question'] );
204
 
205
+ if ( ! tutils()->has_enrolled_content_access( 'course', $course_id ) ) {
206
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
207
  exit;
208
  }
209
 
210
+ if ( empty( $question ) || empty( $question_title ) ) {
211
+ wp_send_json_error( __( 'Empty question title or body', 'tutor' ) );
212
  }
213
 
214
  $user_id = get_current_user_id();
215
+ $user = get_userdata( $user_id );
216
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
217
+
218
+ do_action( 'tutor_before_add_question', $course_id );
219
+ $data = apply_filters(
220
+ 'tutor_add_question_data',
221
+ array(
222
+ 'comment_post_ID' => $course_id,
223
+ 'comment_author' => $user->user_login,
224
+ 'comment_date' => $date,
225
+ 'comment_date_gmt' => get_gmt_from_date( $date ),
226
+ 'comment_content' => $question,
227
+ 'comment_approved' => 'waiting_for_answer',
228
+ 'comment_agent' => 'TutorLMSPlugin',
229
+ 'comment_type' => 'tutor_q_and_a',
230
+ 'user_id' => $user_id,
231
+ )
232
+ );
233
+
234
+ $wpdb->insert( $wpdb->comments, $data );
235
  $comment_id = (int) $wpdb->insert_id;
236
 
237
+ if ( $comment_id ) {
238
+ $result = $wpdb->insert(
239
+ $wpdb->commentmeta,
240
+ array(
241
+ 'comment_id' => $comment_id,
242
+ 'meta_key' => 'tutor_question_title',
243
+ 'meta_value' => $question_title,
244
+ )
245
+ );
246
  }
247
+ do_action( 'tutor_after_add_question', $course_id, $comment_id );
248
 
249
+ wp_send_json_success( __( 'Question has been added successfully', 'tutor' ) );
250
  }
251
 
252
 
253
+ public function tutor_add_answer() {
254
  tutor_utils()->checking_nonce();
255
  global $wpdb;
256
 
257
+ $answer = wp_kses_post( $_POST['answer'] );
258
+ if ( ! $answer ) {
259
+ wp_send_json_error( __( 'Please write answer', 'tutor' ) );
260
  }
261
 
262
+ $question_id = (int) sanitize_text_field( $_POST['question_id'] );
263
+ $question = tutor_utils()->get_qa_question( $question_id );
264
 
265
  $user_id = get_current_user_id();
266
+ $user = get_userdata( $user_id );
267
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
268
 
269
+ if ( ! tutils()->has_enrolled_content_access( 'qa_question', $question_id ) ) {
270
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
271
  exit;
272
  }
273
 
274
+ do_action( 'tutor_before_answer_to_question' );
275
+ $data = apply_filters(
276
+ 'tutor_add_answer_data',
277
+ array(
278
+ 'comment_post_ID' => $question->comment_post_ID,
279
+ 'comment_author' => $user->user_login,
280
+ 'comment_date' => $date,
281
+ 'comment_date_gmt' => get_gmt_from_date( $date ),
282
+ 'comment_content' => $answer,
283
+ 'comment_approved' => 'approved',
284
+ 'comment_agent' => 'TutorLMSPlugin',
285
+ 'comment_type' => 'tutor_q_and_a',
286
+ 'comment_parent' => $question_id,
287
+ 'user_id' => $user_id,
288
+ )
289
+ );
290
+
291
+ $wpdb->insert( $wpdb->comments, $data );
292
  $comment_id = (int) $wpdb->insert_id;
293
+ do_action( 'tutor_after_answer_to_question', $comment_id );
294
 
295
+ wp_send_json_success( __( 'Answer has been added successfully', 'tutor' ) );
296
  }
297
 
298
 
299
+ public function tutor_course_add_to_wishlist() {
300
  tutils()->checking_nonce();
301
 
302
+ $course_id = (int) sanitize_text_field( $_POST['course_id'] );
303
+ if ( ! is_user_logged_in() ) {
304
+ wp_send_json_error( array( 'redirect_to' => wp_login_url( wp_get_referer() ) ) );
305
  }
306
  global $wpdb;
307
 
308
+ $user_id = get_current_user_id();
309
+ $if_added_to_list = $wpdb->get_row( $wpdb->prepare( "SELECT * from {$wpdb->usermeta} WHERE user_id = %d AND meta_key = '_tutor_course_wishlist' AND meta_value = %d;", $user_id, $course_id ) );
310
+
311
+ if ( $if_added_to_list ) {
312
+ $wpdb->delete(
313
+ $wpdb->usermeta,
314
+ array(
315
+ 'user_id' => $user_id,
316
+ 'meta_key' => '_tutor_course_wishlist',
317
+ 'meta_value' => $course_id,
318
+ )
319
+ );
320
+ wp_send_json_success(
321
+ array(
322
+ 'status' => 'removed',
323
+ 'msg' => __(
324
+ 'Course removed from wish list',
325
+ 'tutor'
326
+ ),
327
+ )
328
+ );
329
+ } else {
330
+ add_user_meta( $user_id, '_tutor_course_wishlist', $course_id );
331
+ wp_send_json_success(
332
+ array(
333
+ 'status' => 'added',
334
+ 'msg' => __(
335
+ 'Course added to wish list',
336
+ 'tutor'
337
+ ),
338
+ )
339
+ );
340
  }
341
  }
342
 
343
  /**
344
  * Method for enable / disable addons
345
  */
346
+ public function addon_enable_disable() {
347
 
348
+ if ( ! current_user_can( 'manage_options' ) ) {
349
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
350
  }
351
 
352
+ $addonsConfig = maybe_unserialize( get_option( 'tutor_addons_config' ) );
353
 
354
+ $isEnable = (bool) sanitize_text_field( tutor_utils()->avalue_dot( 'isEnable', $_POST ) );
355
+ $addonFieldName = sanitize_text_field( tutor_utils()->avalue_dot( 'addonFieldName', $_POST ) );
356
 
357
+ do_action( 'tutor_addon_before_enable_disable' );
358
+ if ( $isEnable ) {
359
+ do_action( "tutor_addon_before_enable_{$addonFieldName}" );
360
+ do_action( 'tutor_addon_before_enable', $addonFieldName );
361
+ $addonsConfig[ $addonFieldName ]['is_enable'] = 1;
362
+ update_option( 'tutor_addons_config', $addonsConfig );
363
 
364
+ do_action( 'tutor_addon_after_enable', $addonFieldName );
365
+ do_action( "tutor_addon_after_enable_{$addonFieldName}" );
366
+ } else {
367
+ do_action( "tutor_addon_before_disable_{$addonFieldName}" );
368
+ do_action( 'tutor_addon_before_disable', $addonFieldName );
369
+ $addonsConfig[ $addonFieldName ]['is_enable'] = 0;
370
+ update_option( 'tutor_addons_config', $addonsConfig );
371
 
372
+ do_action( 'tutor_addon_after_disable', $addonFieldName );
373
+ do_action( "tutor_addon_after_disable_{$addonFieldName}" );
374
  }
375
 
376
+ do_action( 'tutor_addon_after_enable_disable' );
377
  wp_send_json_success();
378
  }
379
 
380
  /**
381
  * Load review edit form
382
+ *
383
  * @since v.1.4.0
384
  */
385
+ public function tutor_load_edit_review_modal() {
386
  tutor_utils()->checking_nonce();
387
 
388
+ $review_id = (int) sanitize_text_field( tutils()->array_get( 'review_id', $_POST ) );
389
+ $rating = tutils()->get_rating_by_id( $review_id );
390
 
391
+ if ( ! tutils()->has_enrolled_content_access( 'review', $review_id ) ) {
392
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
393
  exit;
394
  }
395
 
396
  ob_start();
397
+ tutor_load_template( 'dashboard.reviews.edit-review-form', array( 'rating' => $rating ) );
398
  $output = ob_get_clean();
399
 
400
+ wp_send_json_success( array( 'output' => $output ) );
401
  }
402
 
403
+ public function tutor_update_review_modal() {
404
  global $wpdb;
405
 
406
  tutor_utils()->checking_nonce();
407
 
408
+ $review_id = (int) sanitize_text_field( tutils()->array_get( 'review_id', $_POST ) );
409
+ $rating = sanitize_text_field( tutor_utils()->avalue_dot( 'rating', $_POST ) );
410
+ $review = wp_kses_post( tutor_utils()->avalue_dot( 'review', $_POST ) );
411
 
412
+ if ( ! tutils()->has_enrolled_content_access( 'review', $review_id ) ) {
413
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
414
  exit;
415
  }
416
 
417
+ $is_exists = $wpdb->get_var( $wpdb->prepare( "SELECT comment_ID from {$wpdb->comments} WHERE comment_ID=%d AND comment_type = 'tutor_course_rating' ;", $review_id ) );
418
 
419
+ if ( $is_exists ) {
420
+ $wpdb->update(
421
+ $wpdb->comments,
422
+ array( 'comment_content' => $review ),
423
  array( 'comment_ID' => $review_id )
424
  );
425
+ $wpdb->update(
426
+ $wpdb->commentmeta,
427
+ array( 'meta_value' => $rating ),
428
+ array(
429
+ 'comment_id' => $review_id,
430
+ 'meta_key' => 'tutor_rating',
431
+ )
432
  );
433
 
434
+ do_action( 'tutor_after_review_update', $review_id, $is_exists );
435
 
436
  wp_send_json_success();
437
  }
440
 
441
  /**
442
  * Process ajax login
443
+ *
444
  * @since v.1.6.3
445
  */
446
+ public function process_ajax_login() {
447
  tutils()->checking_nonce();
448
 
449
+ $username = sanitize_text_field( tutils()->array_get( 'log', $_POST ) );
450
+ $password = tutils()->array_get( 'pwd', $_POST ); // Password can not be sanitized because users might use special characters including quotes etc.
451
+ $redirect_to = esc_url( tutils()->array_get( 'redirect_to', $_POST ) );
452
 
453
  try {
454
  $creds = array(
483
  if ( is_wp_error( $user ) ) {
484
  $message = $user->get_error_message();
485
  $message = str_replace( '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', $message );
486
+
487
  wp_send_json_error( $message );
488
  } else {
489
+ // since 1.9.8 do enroll if guest attempt to enroll
490
  do_action( 'tutor_do_enroll_after_login_if_attempt', $_POST['tutor_course_enroll_attempt'] );
 
 
 
 
491
 
492
+ wp_send_json_success(
493
+ array(
494
+ 'redirect' => apply_filters( 'tutor_login_redirect_url', $redirect_to ),
495
+ )
496
+ );
497
 
498
  }
499
  } catch ( \Exception $e ) {
500
+ wp_send_json_error( apply_filters( 'login_errors', $e->getMessage() ) );
501
  do_action( 'tutor_login_failed' );
502
  }
503
  }
504
 
505
  /**
506
  * Create/Update announcement
507
+ *
508
  * @since v.1.7.9
509
  */
510
+ public function create_or_update_annoucement() {
511
+ // prepare alert message
512
+ $create_success_msg = __( 'Announcement created successfully', 'tutor' );
513
+ $update_success_msg = __( 'Announcement updated successfully', 'tutor' );
514
+ $create_fail_msg = __( 'Announcement creation failed', 'tutor' );
515
+ $update_fail_msg = __( 'Announcement update failed', 'tutor' );
516
+
517
+ $error = array();
518
+ $response = array();
519
  tutils()->checking_nonce();
520
 
521
+ $course_id = sanitize_text_field( $_POST['tutor_announcement_course'] );
522
+ $announcement_title = sanitize_text_field( $_POST['tutor_announcement_title'] );
523
+ $announcement_summary = sanitize_textarea_field( $_POST['tutor_announcement_summary'] );
524
+
525
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
526
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
527
  }
528
+
529
+ // set data and sanitize it
530
+ $form_data = array(
531
+ 'post_type' => 'tutor_announcements',
532
+ 'post_title' => $announcement_title,
533
  'post_content' => $announcement_summary,
534
+ 'post_parent' => $course_id,
535
+ 'post_status' => 'publish',
536
+ );
537
 
538
+ if ( isset( $_POST['announcement_id'] ) ) {
539
+ $form_data['ID'] = sanitize_text_field( $_POST['announcement_id'] );
540
+ }
541
+
542
+ // validation message set
543
+ if ( empty( $form_data['post_parent'] ) ) {
544
+ $error['post_parent'] = __( 'Course name required', 'tutor' );
545
 
546
+ }
 
 
547
 
548
+ if ( empty( $form_data['post_title'] ) ) {
549
+ $error['post_title'] = __( 'Announcement title required', 'tutor' );
550
  }
551
+
552
+ if ( empty( $form_data['post_content'] ) ) {
553
+ $error['post_content'] = __( 'Announcement summary required', 'tutor' );
554
+
555
  }
556
+
557
+ if ( count( $error ) > 0 ) {
558
+ $response['status'] = 'validation_error';
559
+ $response['message'] = $error;
560
+ wp_send_json( $response );
561
+ } else {
562
+ // insert or update post
563
+ $post_id = wp_insert_post( $form_data );
564
+ if ( $post_id > 0 ) {
565
+ $announcement = get_post( $post_id );
566
+ $action_type = sanitize_textarea_field( $_POST['action_type'] );
567
+ $response['status'] = 'success';
568
+ // set reponse message as per action type
569
+ $response['message'] = ( $action_type == 'create' ) ? $create_success_msg : $update_success_msg;
570
+
571
+ do_action( 'tutor_announcements/after/save', $post_id, $announcement, $action_type );
572
+
573
+ wp_send_json( $response );
574
+ } else {
575
+ // failure message
576
+ $response['status'] = 'fail';
577
+ if ( $_POST['action_type'] == 'create' ) {
578
+ $response['message'] = $create_fail_msg;
579
+ }
580
+ if ( $_POST['action_type'] == 'update' ) {
581
+ $response['message'] = $update_fail_msg;
582
+ }
583
+ wp_send_json( $response );
584
+ }
585
+ }
586
+ }
 
 
 
 
 
587
 
588
  /**
589
  * Delete announcement
590
+ *
591
  * @since v.1.7.9
592
  */
593
+ public function delete_annoucement() {
594
+ $announcement_id = sanitize_text_field( $_POST['announcement_id'] );
595
  tutils()->checking_nonce();
596
 
597
+ if ( ! tutils()->can_user_manage( 'announcement', $announcement_id ) ) {
598
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
599
  }
600
 
601
+ $delete = wp_delete_post( $announcement_id );
602
+ if ( $delete ) {
603
+ $response = array(
604
+ 'status' => 'success',
605
+ 'message' => __( 'Announcement deleted successfully', 'tutor' ),
606
+ );
607
+ wp_send_json( $response );
608
+ } else {
609
+ $response = array(
610
+ 'status' => 'fail',
611
+ 'message' => __( 'Announcement delete failed', 'tutor' ),
612
+ );
613
+ wp_send_json( $response );
614
+ }
615
+ }
616
+ }
classes/Assets.php CHANGED
@@ -1,79 +1,81 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- class Assets{
8
 
9
  public function __construct() {
10
  /**
11
  * Front and backend script enqueue
12
  */
13
- add_action('admin_enqueue_scripts', array($this, 'admin_scripts'));
14
- add_action('wp_enqueue_scripts', array($this, 'frontend_scripts'));
15
 
16
  /**
17
  * Common scripts loading
18
  */
19
- add_action('admin_enqueue_scripts', array($this, 'common_scripts'));
20
- add_action('wp_enqueue_scripts', array($this, 'common_scripts'));
21
 
22
  /**
23
  * Text domain loading
24
  */
25
- add_action('admin_enqueue_scripts', array($this, 'tutor_script_text_domain'), 100);
26
- add_action('wp_enqueue_scripts', array($this, 'tutor_script_text_domain'), 100);
27
- add_filter('tutor_localize_data', array($this, 'modify_localize_data') );
28
 
29
  /**
30
  * register translateable function to load
31
  * handled script with text domain attached to
 
32
  * @since 1.9.0
33
  */
34
- add_action( 'admin_head', array($this, 'tutor_add_mce_button'));
35
- add_filter( 'get_the_generator_html', array($this, 'tutor_generator_tag'), 10, 2 );
36
- add_filter( 'get_the_generator_xhtml', array($this, 'tutor_generator_tag'), 10, 2 );
37
 
38
  /**
39
  * Add translation support for external tinyMCE button
40
- *
41
  * @since 1.9.7
42
  */
43
  add_filter( 'mce_external_languages', array( $this, 'tutor_tinymce_translate' ) );
44
 
45
  /**
46
  * Identifier class to body tag
47
- *
48
  * @since v1.9.9
49
  */
50
- add_filter( 'body_class', array($this, 'add_identifier_class_to_body') );
51
- add_filter( 'admin_body_class', array($this, 'add_identifier_class_to_body') );
52
  }
53
 
54
  private function get_default_localized_data() {
55
  return array(
56
- 'ajaxurl' => admin_url('admin-ajax.php'),
57
- 'home_url' => get_home_url(),
58
- 'base_path' => tutor()->basepath,
59
- 'tutor_url' => tutor()->url,
60
- 'tutor_pro_url' => function_exists('tutor_pro') ? tutor_pro()->url : null,
61
- 'nonce_key' => tutor()->nonce,
62
- tutor()->nonce => wp_create_nonce( tutor()->nonce_action ),
63
- 'loading_icon_url' => get_admin_url() . 'images/wpspin_light.gif',
64
- 'placeholder_img_src' => tutor_placeholder_img_src(),
65
- 'enable_lesson_classic_editor' => get_tutor_option('enable_lesson_classic_editor'),
66
- 'tutor_frontend_dashboard_url' => tutor_utils()->get_tutor_dashboard_page_permalink(),
67
- 'wp_date_format' => tutor_js_date_format_against_wp(),
68
- 'is_admin' => is_admin(),
69
- 'is_admin_bar_showing' => is_admin_bar_showing()
70
  );
71
  }
72
 
73
- public function admin_scripts(){
74
- wp_enqueue_style('tutor-select2', tutor()->url.'assets/packages/select2/select2.min.css', array(), tutor()->version);
75
- wp_enqueue_style('tutor-admin', tutor()->url.'assets/css/tutor-admin.min.css', array(), tutor()->version);
76
- wp_enqueue_style('tutor-icon', tutor()->url.'assets/icons/css/tutor-icon.css', array(), tutor()->version);
77
 
78
  /**
79
  * Scripts
@@ -83,31 +85,31 @@ class Assets{
83
  wp_enqueue_script( 'wp-color-picker' );
84
  wp_enqueue_style( 'wp-color-picker' );
85
 
86
- wp_enqueue_script('jquery-ui-slider');
87
- wp_enqueue_script('jquery-ui-datepicker');
88
 
89
- wp_enqueue_script('tutor-select2', tutor()->url.'assets/packages/select2/select2.full.min.js', array('jquery'), tutor()->version, true );
90
- wp_enqueue_script('tutor-admin', tutor()->url.'assets/js/tutor-admin.js', array('jquery', 'wp-color-picker', 'wp-i18n'), tutor()->version, true );
91
  }
92
 
93
  /**
94
  * Load frontend scripts
95
  */
96
- public function frontend_scripts(){
97
  global $post, $wp_query;
98
 
99
  $is_script_debug = tutor_utils()->is_script_debug();
100
- $suffix = $is_script_debug ? '' : '.min';
101
 
102
  /**
103
  * We checked wp_enqueue_editor() in condition because it conflicting with Divi Builder
104
  * condition updated @since v.1.7.4
105
  */
106
 
107
- if (is_single()){
108
- if (function_exists('et_pb_is_pagebuilder_used')) {
109
- $is_page_builder_used = et_pb_is_pagebuilder_used(get_the_ID());
110
- if (!$is_page_builder_used) {
111
  wp_enqueue_editor();
112
  }
113
  } else {
@@ -118,102 +120,102 @@ class Assets{
118
  /**
119
  * Initializing quicktags script to use in wp_editor();
120
  */
121
- wp_enqueue_script( 'quicktags');
122
 
123
- $tutor_dashboard_page_id = (int) tutor_utils()->get_option('tutor_dashboard_page_id');
124
- if ($tutor_dashboard_page_id === get_the_ID()){
125
  wp_enqueue_media();
126
  }
127
 
128
  /**
129
  * Enabling Sorting, draggable, droppable...
130
  */
131
- wp_enqueue_script('jquery-ui-sortable');
132
  /**
133
  * Tutor Icon
134
  */
135
- wp_enqueue_style('tutor-icon', tutor()->url.'assets/icons/css/tutor-icon.css', array(), tutor()->version);
136
 
137
-
138
- //Plyr
139
  wp_enqueue_style( 'tutor-plyr', tutor()->url . 'assets/packages/plyr/plyr.css', array(), tutor()->version );
140
  wp_enqueue_script( 'tutor-plyr', tutor()->url . 'assets/packages/plyr/plyr.polyfilled.min.js', array( 'jquery' ), tutor()->version, true );
141
 
142
- //Social Share
143
- wp_enqueue_script( 'tutor-social-share', tutor()->url . 'assets/packages/SocialShare/SocialShare.min.js', array( 'jquery' ), tutor()->version, true );
144
 
145
  /**
146
  * Chart Data
147
  */
148
- if ( ! empty($wp_query->query_vars['tutor_dashboard_page']) ) {
149
- wp_enqueue_script('jquery-ui-slider');
150
 
151
- wp_enqueue_style('tutor-select2', tutor()->url.'assets/packages/select2/select2.min.css', array(), tutor()->version);
152
- wp_enqueue_script('tutor-select2', tutor()->url.'assets/packages/select2/select2.full.min.js', array('jquery'), tutor()->version, true );
153
 
154
- if ($wp_query->query_vars['tutor_dashboard_page'] === 'earning'){
155
  wp_enqueue_script( 'tutor-front-chart-js', tutor()->url . 'assets/js/Chart.bundle.min.js', array(), tutor()->version );
156
  wp_enqueue_script( 'jquery-ui-datepicker' );
157
  }
158
  }
159
- //End: chart data
160
-
161
- wp_enqueue_style('tutor-frontend', tutor()->url."assets/css/tutor-front{$suffix}.css", array(), tutor()->version);
162
-
163
  /**
164
- * dependency wp-i18n added for
165
  * translate js file
 
166
  * @since 1.9.0
167
  */
168
- wp_enqueue_script( 'tutor-frontend', tutor()->url . 'assets/js/tutor-front.js', array( 'jquery', 'wp-i18n'), tutor()->version, true );
169
-
170
 
171
  /**
172
  * Load frontend dashboard style
 
173
  * @since v1.9.8
174
  */
175
- if(tutor_utils()->is_tutor_frontend_dashboard()) {
176
- wp_enqueue_style('tutor-frontend-dashboard-css', tutor()->url . 'assets/css/tutor-frontend-dashboard.min.css', tutor()->version);
177
  }
178
 
179
  // Load date picker for announcement at frontend
180
- wp_enqueue_script('jquery-ui-datepicker');
181
  }
182
 
183
  public function modify_localize_data( $localize_data ) {
184
  global $post;
185
-
186
  if ( is_admin() ) {
187
- if ( ! empty($_GET['taxonomy']) && ( $_GET['taxonomy'] === 'course-category' || $_GET['taxonomy'] === 'course-tag') ){
188
  $localize_data['open_tutor_admin_menu'] = true;
189
  }
190
  } else {
191
 
192
  // Assign quiz option
193
- if ( ! empty($post->post_type) && $post->post_type === 'tutor_quiz'){
194
- $single_quiz_options = (array) tutor_utils()->get_quiz_option($post->ID);
195
- $saved_quiz_options = array(
196
- 'quiz_when_time_expires' => tutils()->get_option('quiz_when_time_expires'),
197
  );
198
-
199
- $quiz_options = array_merge($single_quiz_options, $saved_quiz_options);
200
-
201
  $previous_attempts = tutor_utils()->quiz_attempts();
202
-
203
- if ($previous_attempts && count($previous_attempts)) {
204
  $quiz_options['quiz_auto_start'] = 0;
205
  }
206
-
207
  $localize_data['quiz_options'] = $quiz_options;
208
  }
209
 
210
- //Including player assets if video exists
211
- if (tutor_utils()->has_video_in_single()) {
212
- $localize_data['post_id'] = get_the_ID();
213
  $localize_data['best_watch_time'] = 0;
214
 
215
- $best_watch_time = tutor_utils()->get_lesson_reading_info(get_the_ID(), 0, 'video_best_watched_time');
216
- if ($best_watch_time > 0){
217
  $localize_data['best_watch_time'] = $best_watch_time;
218
  }
219
  }
@@ -224,20 +226,20 @@ class Assets{
224
 
225
  public function common_scripts() {
226
  // Load course builder resources
227
- if($this->get_course_builder_screen()) {
228
- wp_enqueue_script( 'tutor-course-builder', tutor()->url . 'assets/js/tutor-course-builder.js', array( 'jquery', 'wp-i18n'), tutor()->version, true );
229
  wp_enqueue_style( 'tutor-course-builder-css', tutor()->url . 'assets/css/tutor-course-builder.css', array(), tutor()->version );
230
  }
231
 
232
  // Localize scripts
233
  $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
234
- wp_localize_script('tutor-frontend', '_tutorobject', $localize_data);
235
- wp_localize_script('tutor-admin', '_tutorobject', $localize_data);
236
- wp_localize_script('tutor-course-builder', '_tutorobject', $localize_data);
237
 
238
  // Inline styles
239
- wp_add_inline_style('tutor-frontend', $this->load_color_palette() );
240
- wp_add_inline_style('tutor-admin', $this->load_color_palette() );
241
  }
242
 
243
  private function load_color_palette() {
@@ -245,50 +247,50 @@ class Assets{
245
  /**
246
  * Default Color
247
  */
248
- $tutor_css = ":root{";
249
- $tutor_primary_color = tutor_utils()->get_option('tutor_primary_color');
250
- $tutor_primary_hover_color = tutor_utils()->get_option('tutor_primary_hover_color');
251
- $tutor_text_color = tutor_utils()->get_option('tutor_text_color');
252
- $tutor_light_color = tutor_utils()->get_option('tutor_light_color');
253
 
254
  /**
255
  * tutor buttons style
256
  */
257
- $tutor_button_primary = tutor_utils()->get_option('tutor_button_primary');
258
- $tutor_button_danger = tutor_utils()->get_option('tutor_button_danger');
259
- $tutor_button_success = tutor_utils()->get_option('tutor_button_success');
260
- $tutor_button_warning = tutor_utils()->get_option('tutor_button_warning');
261
 
262
- if ($tutor_primary_color){
263
  $tutor_css .= " --tutor-primary-color: {$tutor_primary_color};";
264
  }
265
- if ($tutor_primary_hover_color){
266
  $tutor_css .= " --tutor-primary-hover-color: {$tutor_primary_hover_color};";
267
  }
268
- if ($tutor_text_color){
269
  $tutor_css .= " --tutor-text-color: {$tutor_text_color};";
270
  }
271
- if ($tutor_light_color){
272
  $tutor_css .= " --tutor-light-color: {$tutor_light_color};";
273
  }
274
 
275
  /**
276
  * check if button style setup
277
  */
278
- if($tutor_button_primary){
279
  $tutor_css .= " --tutor-primary-button-color: {$tutor_button_primary}; ";
280
  }
281
- if($tutor_button_danger){
282
  $tutor_css .= " --tutor-danger-button-color: {$tutor_button_danger}; ";
283
  }
284
- if($tutor_button_success){
285
  $tutor_css .= " --tutor-success-button-color: {$tutor_button_success}; ";
286
  }
287
- if($tutor_button_warning){
288
  $tutor_css .= " --tutor-warning-button-color: {$tutor_button_warning}; ";
289
  }
290
 
291
- $tutor_css .= "}";
292
 
293
  return $tutor_css;
294
  }
@@ -298,18 +300,18 @@ class Assets{
298
  */
299
  function tutor_add_mce_button() {
300
  // check user permissions
301
- if ( !current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) ) {
302
  return;
303
  }
304
  // check if WYSIWYG is enabled
305
  if ( 'true' == get_user_option( 'rich_editing' ) ) {
306
- add_filter( 'mce_external_plugins', array($this, 'tutor_add_tinymce_js') );
307
- add_filter( 'mce_buttons', array($this, 'tutor_register_mce_button') );
308
  }
309
  }
310
  // Declare script for new button
311
  function tutor_add_tinymce_js( $plugin_array ) {
312
- $plugin_array['tutor_button'] = tutor()->url .'assets/js/mce-button.js';
313
  return $plugin_array;
314
  }
315
  // Register new button in the editor
@@ -328,62 +330,63 @@ class Assets{
328
  function tutor_generator_tag( $gen, $type ) {
329
  switch ( $type ) {
330
  case 'html':
331
- $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . esc_attr( TUTOR_VERSION ) . '">';
332
  break;
333
  case 'xhtml':
334
- $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . esc_attr( TUTOR_VERSION ) . '" />';
335
  break;
336
  }
337
  return $gen;
338
  }
339
 
340
  /**
341
- * load text domain handled script after all enqueue_scripts
342
  * registered functions
 
343
  * @since 1.9.0
344
- */
345
  function tutor_script_text_domain() {
346
- wp_set_script_translations( 'tutor-frontend', 'tutor', tutor()->path.'languages/' );
347
- wp_set_script_translations( 'tutor-admin', 'tutor', tutor()->path.'languages/' );
348
- wp_set_script_translations( 'tutor-course-builder', 'tutor', tutor()->path.'languages/' );
349
  }
350
 
351
  /**
352
  * Add translation support for external tinyMCE button
353
- *
354
  * @since 1.9.7
355
  */
356
  function tutor_tinymce_translate() {
357
- $locales['tutor_button'] = tutor()->path.'includes/tinymce_translate.php';
358
  return $locales;
359
  }
360
 
361
  private function get_course_builder_screen() {
362
 
363
  // Add course editor identifier class
364
- if(is_admin()) {
365
  $screen = get_current_screen();
366
- if(is_object($screen) && $screen->base=='post' && $screen->id=='courses') {
367
  return $screen->is_block_editor ? 'gutenberg' : 'classic';
368
  }
369
- } else if(tutor_utils()->is_tutor_frontend_dashboard('create-course')) {
370
  return 'frontend';
371
  }
372
 
373
  return null;
374
  }
375
-
376
- public function add_identifier_class_to_body($classes) {
377
  $course_builder_screen = $this->get_course_builder_screen();
378
- $to_add = array();
379
 
380
  // Add course editor identifier class
381
- if($course_builder_screen) {
382
  $to_add[] = ' tutor-screen-course-builder tutor-screen-course-builder-' . $course_builder_screen . ' ';
383
  }
384
 
385
- is_array($classes) ? $classes=array_merge($classes, $to_add) : $classes.=implode('', $to_add);
386
 
387
  return $classes;
388
  }
389
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ class Assets {
9
 
10
  public function __construct() {
11
  /**
12
  * Front and backend script enqueue
13
  */
14
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
15
+ add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
16
 
17
  /**
18
  * Common scripts loading
19
  */
20
+ add_action( 'admin_enqueue_scripts', array( $this, 'common_scripts' ) );
21
+ add_action( 'wp_enqueue_scripts', array( $this, 'common_scripts' ) );
22
 
23
  /**
24
  * Text domain loading
25
  */
26
+ add_action( 'admin_enqueue_scripts', array( $this, 'tutor_script_text_domain' ), 100 );
27
+ add_action( 'wp_enqueue_scripts', array( $this, 'tutor_script_text_domain' ), 100 );
28
+ add_filter( 'tutor_localize_data', array( $this, 'modify_localize_data' ) );
29
 
30
  /**
31
  * register translateable function to load
32
  * handled script with text domain attached to
33
+ *
34
  * @since 1.9.0
35
  */
36
+ add_action( 'admin_head', array( $this, 'tutor_add_mce_button' ) );
37
+ add_filter( 'get_the_generator_html', array( $this, 'tutor_generator_tag' ), 10, 2 );
38
+ add_filter( 'get_the_generator_xhtml', array( $this, 'tutor_generator_tag' ), 10, 2 );
39
 
40
  /**
41
  * Add translation support for external tinyMCE button
42
+ *
43
  * @since 1.9.7
44
  */
45
  add_filter( 'mce_external_languages', array( $this, 'tutor_tinymce_translate' ) );
46
 
47
  /**
48
  * Identifier class to body tag
49
+ *
50
  * @since v1.9.9
51
  */
52
+ add_filter( 'body_class', array( $this, 'add_identifier_class_to_body' ) );
53
+ add_filter( 'admin_body_class', array( $this, 'add_identifier_class_to_body' ) );
54
  }
55
 
56
  private function get_default_localized_data() {
57
  return array(
58
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
59
+ 'home_url' => get_home_url(),
60
+ 'base_path' => tutor()->basepath,
61
+ 'tutor_url' => tutor()->url,
62
+ 'tutor_pro_url' => function_exists( 'tutor_pro' ) ? tutor_pro()->url : null,
63
+ 'nonce_key' => tutor()->nonce,
64
+ tutor()->nonce => wp_create_nonce( tutor()->nonce_action ),
65
+ 'loading_icon_url' => get_admin_url() . 'images/wpspin_light.gif',
66
+ 'placeholder_img_src' => tutor_placeholder_img_src(),
67
+ 'enable_lesson_classic_editor' => get_tutor_option( 'enable_lesson_classic_editor' ),
68
+ 'tutor_frontend_dashboard_url' => tutor_utils()->get_tutor_dashboard_page_permalink(),
69
+ 'wp_date_format' => tutor_js_date_format_against_wp(),
70
+ 'is_admin' => is_admin(),
71
+ 'is_admin_bar_showing' => is_admin_bar_showing(),
72
  );
73
  }
74
 
75
+ public function admin_scripts() {
76
+ wp_enqueue_style( 'tutor-select2', tutor()->url . 'assets/packages/select2/select2.min.css', array(), tutor()->version );
77
+ wp_enqueue_style( 'tutor-admin', tutor()->url . 'assets/css/tutor-admin.min.css', array(), tutor()->version );
78
+ wp_enqueue_style( 'tutor-icon', tutor()->url . 'assets/icons/css/tutor-icon.css', array(), tutor()->version );
79
 
80
  /**
81
  * Scripts
85
  wp_enqueue_script( 'wp-color-picker' );
86
  wp_enqueue_style( 'wp-color-picker' );
87
 
88
+ wp_enqueue_script( 'jquery-ui-slider' );
89
+ wp_enqueue_script( 'jquery-ui-datepicker' );
90
 
91
+ wp_enqueue_script( 'tutor-select2', tutor()->url . 'assets/packages/select2/select2.full.min.js', array( 'jquery' ), tutor()->version, true );
92
+ wp_enqueue_script( 'tutor-admin', tutor()->url . 'assets/js/tutor-admin.js', array( 'jquery', 'wp-color-picker', 'wp-i18n' ), tutor()->version, true );
93
  }
94
 
95
  /**
96
  * Load frontend scripts
97
  */
98
+ public function frontend_scripts() {
99
  global $post, $wp_query;
100
 
101
  $is_script_debug = tutor_utils()->is_script_debug();
102
+ $suffix = $is_script_debug ? '' : '.min';
103
 
104
  /**
105
  * We checked wp_enqueue_editor() in condition because it conflicting with Divi Builder
106
  * condition updated @since v.1.7.4
107
  */
108
 
109
+ if ( is_single() ) {
110
+ if ( function_exists( 'et_pb_is_pagebuilder_used' ) ) {
111
+ $is_page_builder_used = et_pb_is_pagebuilder_used( get_the_ID() );
112
+ if ( ! $is_page_builder_used ) {
113
  wp_enqueue_editor();
114
  }
115
  } else {
120
  /**
121
  * Initializing quicktags script to use in wp_editor();
122
  */
123
+ wp_enqueue_script( 'quicktags' );
124
 
125
+ $tutor_dashboard_page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
126
+ if ( $tutor_dashboard_page_id === get_the_ID() ) {
127
  wp_enqueue_media();
128
  }
129
 
130
  /**
131
  * Enabling Sorting, draggable, droppable...
132
  */
133
+ wp_enqueue_script( 'jquery-ui-sortable' );
134
  /**
135
  * Tutor Icon
136
  */
137
+ wp_enqueue_style( 'tutor-icon', tutor()->url . 'assets/icons/css/tutor-icon.css', array(), tutor()->version );
138
 
139
+ // Plyr
 
140
  wp_enqueue_style( 'tutor-plyr', tutor()->url . 'assets/packages/plyr/plyr.css', array(), tutor()->version );
141
  wp_enqueue_script( 'tutor-plyr', tutor()->url . 'assets/packages/plyr/plyr.polyfilled.min.js', array( 'jquery' ), tutor()->version, true );
142
 
143
+ // Social Share
144
+ wp_enqueue_script( 'tutor-social-share', tutor()->url . 'assets/packages/SocialShare/SocialShare.min.js', array( 'jquery' ), tutor()->version, true );
145
 
146
  /**
147
  * Chart Data
148
  */
149
+ if ( ! empty( $wp_query->query_vars['tutor_dashboard_page'] ) ) {
150
+ wp_enqueue_script( 'jquery-ui-slider' );
151
 
152
+ wp_enqueue_style( 'tutor-select2', tutor()->url . 'assets/packages/select2/select2.min.css', array(), tutor()->version );
153
+ wp_enqueue_script( 'tutor-select2', tutor()->url . 'assets/packages/select2/select2.full.min.js', array( 'jquery' ), tutor()->version, true );
154
 
155
+ if ( $wp_query->query_vars['tutor_dashboard_page'] === 'earning' ) {
156
  wp_enqueue_script( 'tutor-front-chart-js', tutor()->url . 'assets/js/Chart.bundle.min.js', array(), tutor()->version );
157
  wp_enqueue_script( 'jquery-ui-datepicker' );
158
  }
159
  }
160
+ // End: chart data
161
+
162
+ wp_enqueue_style( 'tutor-frontend', tutor()->url . "assets/css/tutor-front{$suffix}.css", array(), tutor()->version );
163
+
164
  /**
165
+ * dependency wp-i18n added for
166
  * translate js file
167
+ *
168
  * @since 1.9.0
169
  */
170
+ wp_enqueue_script( 'tutor-frontend', tutor()->url . 'assets/js/tutor-front.js', array( 'jquery', 'wp-i18n' ), tutor()->version, true );
 
171
 
172
  /**
173
  * Load frontend dashboard style
174
+ *
175
  * @since v1.9.8
176
  */
177
+ if ( tutor_utils()->is_tutor_frontend_dashboard() ) {
178
+ wp_enqueue_style( 'tutor-frontend-dashboard-css', tutor()->url . 'assets/css/tutor-frontend-dashboard.min.css', tutor()->version );
179
  }
180
 
181
  // Load date picker for announcement at frontend
182
+ wp_enqueue_script( 'jquery-ui-datepicker' );
183
  }
184
 
185
  public function modify_localize_data( $localize_data ) {
186
  global $post;
187
+
188
  if ( is_admin() ) {
189
+ if ( ! empty( $_GET['taxonomy'] ) && ( $_GET['taxonomy'] === 'course-category' || $_GET['taxonomy'] === 'course-tag' ) ) {
190
  $localize_data['open_tutor_admin_menu'] = true;
191
  }
192
  } else {
193
 
194
  // Assign quiz option
195
+ if ( ! empty( $post->post_type ) && $post->post_type === 'tutor_quiz' ) {
196
+ $single_quiz_options = (array) tutor_utils()->get_quiz_option( $post->ID );
197
+ $saved_quiz_options = array(
198
+ 'quiz_when_time_expires' => tutils()->get_option( 'quiz_when_time_expires' ),
199
  );
200
+
201
+ $quiz_options = array_merge( $single_quiz_options, $saved_quiz_options );
202
+
203
  $previous_attempts = tutor_utils()->quiz_attempts();
204
+
205
+ if ( $previous_attempts && count( $previous_attempts ) ) {
206
  $quiz_options['quiz_auto_start'] = 0;
207
  }
208
+
209
  $localize_data['quiz_options'] = $quiz_options;
210
  }
211
 
212
+ // Including player assets if video exists
213
+ if ( tutor_utils()->has_video_in_single() ) {
214
+ $localize_data['post_id'] = get_the_ID();
215
  $localize_data['best_watch_time'] = 0;
216
 
217
+ $best_watch_time = tutor_utils()->get_lesson_reading_info( get_the_ID(), 0, 'video_best_watched_time' );
218
+ if ( $best_watch_time > 0 ) {
219
  $localize_data['best_watch_time'] = $best_watch_time;
220
  }
221
  }
226
 
227
  public function common_scripts() {
228
  // Load course builder resources
229
+ if ( $this->get_course_builder_screen() ) {
230
+ wp_enqueue_script( 'tutor-course-builder', tutor()->url . 'assets/js/tutor-course-builder.js', array( 'jquery', 'wp-i18n' ), tutor()->version, true );
231
  wp_enqueue_style( 'tutor-course-builder-css', tutor()->url . 'assets/css/tutor-course-builder.css', array(), tutor()->version );
232
  }
233
 
234
  // Localize scripts
235
  $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
236
+ wp_localize_script( 'tutor-frontend', '_tutorobject', $localize_data );
237
+ wp_localize_script( 'tutor-admin', '_tutorobject', $localize_data );
238
+ wp_localize_script( 'tutor-course-builder', '_tutorobject', $localize_data );
239
 
240
  // Inline styles
241
+ wp_add_inline_style( 'tutor-frontend', $this->load_color_palette() );
242
+ wp_add_inline_style( 'tutor-admin', $this->load_color_palette() );
243
  }
244
 
245
  private function load_color_palette() {
247
  /**
248
  * Default Color
249
  */
250
+ $tutor_css = ':root{';
251
+ $tutor_primary_color = tutor_utils()->get_option( 'tutor_primary_color' );
252
+ $tutor_primary_hover_color = tutor_utils()->get_option( 'tutor_primary_hover_color' );
253
+ $tutor_text_color = tutor_utils()->get_option( 'tutor_text_color' );
254
+ $tutor_light_color = tutor_utils()->get_option( 'tutor_light_color' );
255
 
256
  /**
257
  * tutor buttons style
258
  */
259
+ $tutor_button_primary = tutor_utils()->get_option( 'tutor_button_primary' );
260
+ $tutor_button_danger = tutor_utils()->get_option( 'tutor_button_danger' );
261
+ $tutor_button_success = tutor_utils()->get_option( 'tutor_button_success' );
262
+ $tutor_button_warning = tutor_utils()->get_option( 'tutor_button_warning' );
263
 
264
+ if ( $tutor_primary_color ) {
265
  $tutor_css .= " --tutor-primary-color: {$tutor_primary_color};";
266
  }
267
+ if ( $tutor_primary_hover_color ) {
268
  $tutor_css .= " --tutor-primary-hover-color: {$tutor_primary_hover_color};";
269
  }
270
+ if ( $tutor_text_color ) {
271
  $tutor_css .= " --tutor-text-color: {$tutor_text_color};";
272
  }
273
+ if ( $tutor_light_color ) {
274
  $tutor_css .= " --tutor-light-color: {$tutor_light_color};";
275
  }
276
 
277
  /**
278
  * check if button style setup
279
  */
280
+ if ( $tutor_button_primary ) {
281
  $tutor_css .= " --tutor-primary-button-color: {$tutor_button_primary}; ";
282
  }
283
+ if ( $tutor_button_danger ) {
284
  $tutor_css .= " --tutor-danger-button-color: {$tutor_button_danger}; ";
285
  }
286
+ if ( $tutor_button_success ) {
287
  $tutor_css .= " --tutor-success-button-color: {$tutor_button_success}; ";
288
  }
289
+ if ( $tutor_button_warning ) {
290
  $tutor_css .= " --tutor-warning-button-color: {$tutor_button_warning}; ";
291
  }
292
 
293
+ $tutor_css .= '}';
294
 
295
  return $tutor_css;
296
  }
300
  */
301
  function tutor_add_mce_button() {
302
  // check user permissions
303
+ if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) ) {
304
  return;
305
  }
306
  // check if WYSIWYG is enabled
307
  if ( 'true' == get_user_option( 'rich_editing' ) ) {
308
+ add_filter( 'mce_external_plugins', array( $this, 'tutor_add_tinymce_js' ) );
309
+ add_filter( 'mce_buttons', array( $this, 'tutor_register_mce_button' ) );
310
  }
311
  }
312
  // Declare script for new button
313
  function tutor_add_tinymce_js( $plugin_array ) {
314
+ $plugin_array['tutor_button'] = tutor()->url . 'assets/js/mce-button.js';
315
  return $plugin_array;
316
  }
317
  // Register new button in the editor
330
  function tutor_generator_tag( $gen, $type ) {
331
  switch ( $type ) {
332
  case 'html':
333
+ $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '">';
334
  break;
335
  case 'xhtml':
336
+ $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '" />';
337
  break;
338
  }
339
  return $gen;
340
  }
341
 
342
  /**
343
+ * load text domain handled script after all enqueue_scripts
344
  * registered functions
345
+ *
346
  * @since 1.9.0
347
+ */
348
  function tutor_script_text_domain() {
349
+ wp_set_script_translations( 'tutor-frontend', 'tutor', tutor()->path . 'languages/' );
350
+ wp_set_script_translations( 'tutor-admin', 'tutor', tutor()->path . 'languages/' );
351
+ wp_set_script_translations( 'tutor-course-builder', 'tutor', tutor()->path . 'languages/' );
352
  }
353
 
354
  /**
355
  * Add translation support for external tinyMCE button
356
+ *
357
  * @since 1.9.7
358
  */
359
  function tutor_tinymce_translate() {
360
+ $locales['tutor_button'] = tutor()->path . 'includes/tinymce_translate.php';
361
  return $locales;
362
  }
363
 
364
  private function get_course_builder_screen() {
365
 
366
  // Add course editor identifier class
367
+ if ( is_admin() ) {
368
  $screen = get_current_screen();
369
+ if ( is_object( $screen ) && $screen->base == 'post' && $screen->id == 'courses' ) {
370
  return $screen->is_block_editor ? 'gutenberg' : 'classic';
371
  }
372
+ } elseif ( tutor_utils()->is_tutor_frontend_dashboard( 'create-course' ) ) {
373
  return 'frontend';
374
  }
375
 
376
  return null;
377
  }
378
+
379
+ public function add_identifier_class_to_body( $classes ) {
380
  $course_builder_screen = $this->get_course_builder_screen();
381
+ $to_add = array();
382
 
383
  // Add course editor identifier class
384
+ if ( $course_builder_screen ) {
385
  $to_add[] = ' tutor-screen-course-builder tutor-screen-course-builder-' . $course_builder_screen . ' ';
386
  }
387
 
388
+ is_array( $classes ) ? $classes = array_merge( $classes, $to_add ) : $classes .= implode( '', $to_add );
389
 
390
  return $classes;
391
  }
392
+ }
classes/Course.php CHANGED
@@ -1,69 +1,73 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
  class Course extends Tutor_Base {
8
-
9
- private $additional_meta=array(
10
  '_tutor_disable_qa',
11
- '_tutor_is_public_course'
12
  );
13
 
14
  public function __construct() {
15
  parent::__construct();
16
-
17
- add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
18
- add_action('save_post_'.$this->course_post_type, array($this, 'save_course_meta'), 10, 2);
19
- add_action('wp_ajax_tutor_add_course_topic', array($this, 'tutor_add_course_topic'));
20
- add_action('wp_ajax_tutor_update_topic', array($this, 'tutor_update_topic'));
21
 
22
- //Add Column
23
- add_filter( "manage_{$this->course_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
24
- add_action( "manage_{$this->course_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
 
 
 
 
 
25
 
26
- add_action('admin_action_tutor_delete_topic', array($this, 'tutor_delete_topic'));
27
- add_action('admin_action_tutor_delete_announcement', array($this, 'tutor_delete_announcement'));
28
 
29
- //Frontend Action
30
- add_action('template_redirect', array($this, 'enroll_now'));
31
- add_action('init', array($this, 'mark_course_complete'));
32
 
33
- //Modal Perform
34
- add_action('wp_ajax_tutor_load_instructors_modal', array($this, 'tutor_load_instructors_modal'));
35
- add_action('wp_ajax_tutor_add_instructors_to_course', array($this, 'tutor_add_instructors_to_course'));
36
- add_action('wp_ajax_detach_instructor_from_course', array($this, 'detach_instructor_from_course'));
37
 
38
  /**
39
  * Frontend Dashboard
40
  */
41
- add_action('wp_ajax_tutor_delete_dashboard_course', array($this, 'tutor_delete_dashboard_course'));
42
 
43
  /**
44
  * Gutenberg author support
45
  */
46
- add_filter('wp_insert_post_data', array($this, 'tutor_add_gutenberg_author'), '99', 2);
47
 
48
  /**
49
  * Frontend metabox supports for course builder
 
50
  * @since v.1.3.4
51
  */
52
- add_action('tutor/dashboard_course_builder_form_field_after', array($this, 'register_meta_box_in_frontend'));
53
 
54
  /**
55
  * Do Stuff for the course save from frontend
56
  */
57
- add_action('save_tutor_course', array($this, 'attach_product_with_course'), 10, 2);
58
 
59
  /**
60
  * Add course level to course settings
 
61
  * @since v.1.4.1
62
  */
63
- add_action('tutor_course/settings_tab_content/after/general', array($this, 'add_course_level_to_settings'));
64
 
65
  /**
66
  * Enable Disable Course Details Page Feature
 
67
  * @since v.1.4.8
68
  */
69
  $this->course_elements_enable_disable();
@@ -72,7 +76,7 @@ class Course extends Tutor_Base {
72
  * @since v.1.4.8
73
  * Check if course starting, set meta if starting
74
  */
75
- add_action('tutor_lesson_load_before', array($this, 'tutor_lesson_load_before'));
76
 
77
  /**
78
  * @since v.1.4.9
@@ -80,187 +84,198 @@ class Course extends Tutor_Base {
80
  */
81
  $this->filter_product_in_shop_page();
82
 
83
- /**
84
- * Remove the course price if enrolled
85
- * @since 1.5.8
86
- */
87
- add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
88
-
89
- /**
90
- * Remove course complete button if course completion is strict mode
91
- * @since v.1.6.1
92
- */
93
- add_filter('tutor_course/single/complete_form', array($this, 'tutor_lms_hide_course_complete_btn'));
94
- add_filter('get_gradebook_generate_form_html', array($this, 'get_generate_greadbook'));
95
-
96
- /**
97
- * Add social share content in header
98
- * @since v.1.6.3
99
- */
100
- add_action('wp_head', array($this, 'social_share_content'));
101
-
102
- /**
103
- * Delete course data after deleted course
104
- * @since v.1.6.6
105
- */
106
- add_action('deleted_post', array($this, 'delete_tutor_course_data'));
107
- add_action('tutor/dashboard_course_builder_form_field_after', array($this, 'tutor_course_setting_metabox_frontend'));
 
 
 
 
108
 
109
  /**
110
- * Delete course data after deleted course
111
- * @since v.1.8.2
112
- */
113
- add_action('before_delete_post', array($this, 'delete_associated_enrollment'));
 
114
 
115
  /**
116
  * Show only own uploads in media library if user is instructor
 
117
  * @since v1.8.9
118
  */
119
- add_filter('posts_where', array($this, 'restrict_media' ) );
120
 
121
  /**
122
  * Restrict new enrol/purchase button if course member limit reached
 
123
  * @since v1.9.0
124
  */
125
- add_filter('tutor_course_restrict_new_entry', array($this, 'restrict_new_student_entry'));
126
 
127
  /**
128
  * Reset course progress on retake
 
129
  * @since v1.9.5
130
  */
131
- add_action( 'wp_ajax_tutor_reset_course_progress', array($this, 'tutor_reset_course_progress') );
132
-
133
  /**
134
  * Popup for review
 
135
  * @since v1.9.7
136
  */
137
- add_action( 'wp_footer', array($this, 'popup_review_form') );
138
 
139
  /**
140
  * Do enroll after login if guest take enroll attempt
141
- *
142
  * @since 1.9.8
143
  */
144
- add_action( 'tutor_do_enroll_after_login_if_attempt', array( $this, 'enroll_after_login_if_attempt' ), 10, 1 );
145
  }
146
 
147
- public function restrict_new_student_entry($content) {
148
 
149
- if(!tutils()->is_course_fully_booked()) {
150
  // No restriction if not fully booked
151
  return $content;
152
  }
153
-
154
  return '<span class="tutor-course-booked-fully">
155
- <img src="' . tutor()->url . '/assets/images/icon-warning-info.svg"/>
156
- <span>' . __('Fully booked', 'tutor') . '</span>
157
  </span>';
158
  }
159
 
160
- function restrict_media( $where ){
161
-
162
- if( isset( $_POST['action'] ) && $_POST['action'] == 'query-attachments' && tutor_utils()->is_instructor()){
163
- if(!tutor_utils()->has_user_role(array('administrator', 'editor'))) {
164
  $where .= ' AND post_author=' . get_current_user_id();
165
  }
166
  }
167
-
168
  return $where;
169
  }
170
 
171
  /**
172
  * Registering metabox
173
  */
174
- public function register_meta_box(){
175
- $coursePostType = tutor()->course_post_type;
176
- $course_marketplace = tutor_utils()->get_option('enable_course_marketplace');
177
- //add_meta_box( 'tutor-course-levels', __( 'Course Level', 'tutor' ), array($this, 'course_level_metabox'), $coursePostType );
178
- add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
179
- add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
180
- add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
181
- if ($course_marketplace) {
182
  add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
183
  }
184
 
185
  /**
186
- * Tutor course sidebar settings metabox
187
- * @since v.1.7.0
188
- */
189
- add_meta_box( 'tutor-course-sidebar-settings', __( 'Tutor Settings', 'tutor' ), array($this, 'tutor_course_setting_metabox'), $coursePostType, 'side' );
 
190
  }
191
 
192
- public function course_meta_box($echo = true){
193
  ob_start();
194
- include tutor()->path.'views/metabox/course-topics.php';
195
  $content = ob_get_clean();
196
 
197
- if ($echo){
198
- echo $content;
199
- }else{
200
  return $content;
201
  }
202
  }
203
 
204
- public function course_additional_data_meta_box($echo = true){
205
 
206
  ob_start();
207
- include tutor()->path.'views/metabox/course-additional-data.php';
208
  $content = ob_get_clean();
209
 
210
- if ($echo){
211
- echo $content;
212
- }else{
213
  return $content;
214
  }
215
  }
216
 
217
- public function video_metabox($echo = true){
218
  ob_start();
219
- include tutor()->path.'views/metabox/video-metabox.php';
220
  $content = ob_get_clean();
221
 
222
- if ($echo){
223
- echo $content;
224
- }else{
225
  return $content;
226
  }
227
  }
228
 
229
- public function course_level_metabox($echo = true){
230
  ob_start();
231
- include tutor()->path.'views/metabox/course-level-metabox.php';
232
  $content = ob_get_clean();
233
 
234
- if ($echo){
235
- echo $content;
236
- }else{
237
  return $content;
238
  }
239
  }
240
 
241
- public function instructors_metabox($echo = true){
242
  ob_start();
243
  include tutor()->path . 'views/metabox/instructors-metabox.php';
244
  $content = ob_get_clean();
245
 
246
- if ($echo){
247
- echo $content;
248
- }else{
249
  return $content;
250
  }
251
  }
252
 
253
  /**
254
  * Register metabox in course builder tutor
 
255
  * @since v.1.3.4
256
  */
257
- public function register_meta_box_in_frontend(){
258
- do_action('tutor_course_builder_metabox_before', get_the_ID());
259
- course_builder_section_wrap($this->video_metabox($echo = false), __( 'Video', 'tutor' ) );
260
- course_builder_section_wrap($this->course_meta_box($echo = false), __( 'Course Builder', 'tutor' ) );
261
- course_builder_section_wrap($this->instructors_metabox($echo = false), __( 'Instructors', 'tutor' ) );
262
- course_builder_section_wrap($this->course_additional_data_meta_box($echo = false), __( 'Additional Data', 'tutor' ) );
263
- do_action('tutor_course_builder_metabox_after', get_the_ID());
264
  }
265
 
266
  /**
@@ -268,77 +283,76 @@ class Course extends Tutor_Base {
268
  *
269
  * Insert Topic and attached it with Course
270
  */
271
- public function save_course_meta($post_ID, $post){
272
  global $wpdb;
273
 
274
- do_action( "tutor_save_course", $post_ID, $post);
275
-
276
  /**
277
  * Save course price type
278
  */
279
- $price_type = tutils()->array_get('tutor_course_price_type', $_POST);
280
- if ($price_type){
281
- update_post_meta($post_ID, '_tutor_course_price_type', $price_type);
282
  }
283
 
284
- //Course Duration
285
- if ( ! empty($_POST['course_duration'])){
286
- $video = tutils()->sanitize_array($_POST['course_duration']);
287
- update_post_meta($post_ID, '_course_duration', $video);
288
  }
289
 
290
- if ( ! empty($_POST['course_level'])){
291
- $course_level = sanitize_text_field($_POST['course_level']);
292
- update_post_meta($post_ID, '_tutor_course_level', $course_level);
293
  }
294
 
295
- $additional_data_edit = tutils()->avalue_dot('_tutor_course_additional_data_edit', $_POST);
296
- if ($additional_data_edit) {
297
- if (!empty($_POST['course_benefits'])) {
298
- $course_benefits = wp_kses_post($_POST['course_benefits']);
299
- update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
300
  } else {
301
- delete_post_meta($post_ID, '_tutor_course_benefits');
302
  }
303
 
304
- if (!empty($_POST['course_requirements'])) {
305
- $requirements = wp_kses_post($_POST['course_requirements']);
306
- update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
307
  } else {
308
- delete_post_meta($post_ID, '_tutor_course_requirements');
309
  }
310
 
311
- if (!empty($_POST['course_target_audience'])) {
312
- $target_audience = wp_kses_post($_POST['course_target_audience']);
313
- update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
314
  } else {
315
- delete_post_meta($post_ID, '_tutor_course_target_audience');
316
  }
317
 
318
- if (!empty($_POST['course_material_includes'])) {
319
- $material_includes = wp_kses_post($_POST['course_material_includes']);
320
- update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
321
  } else {
322
- delete_post_meta($post_ID, '_tutor_course_material_includes');
323
  }
324
  }
325
 
326
-
327
  /**
328
  * Sorting Topics and lesson
329
  */
330
- if ( ! empty($_POST['tutor_topics_lessons_sorting'])){
331
- $new_order = sanitize_text_field(stripslashes($_POST['tutor_topics_lessons_sorting']));
332
- $order = json_decode($new_order, true);
333
 
334
- if (is_array($order) && count($order)){
335
  $i = 0;
336
- foreach ($order as $topic ){
337
  $i++;
338
  $wpdb->update(
339
  $wpdb->posts,
340
- array('menu_order' => $i),
341
- array('ID' => $topic['topic_id'])
342
  );
343
 
344
  /**
@@ -347,38 +361,41 @@ class Course extends Tutor_Base {
347
 
348
  $wpdb->update(
349
  $wpdb->posts,
350
- array('post_parent' => 0),
351
- array('post_parent' => $topic['topic_id'])
352
  );
353
 
354
  /**
355
  * Lesson Attaching with topic ID
356
  * sorting lesson
357
  */
358
- if (isset($topic['lesson_ids'])){
359
  $lesson_ids = $topic['lesson_ids'];
360
- }else{
361
  $lesson_ids = array();
362
  }
363
- if (count($lesson_ids)){
364
- foreach ($lesson_ids as $lesson_key => $lesson_id ){
365
  $wpdb->update(
366
  $wpdb->posts,
367
- array('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
368
- array('ID' => $lesson_id)
 
 
 
369
  );
370
  }
371
  }
372
  }
373
  }
374
  }
375
-
376
- if ($additional_data_edit) {
377
- if ( ! empty($_POST['video']['source'])) { //Video
378
- $video = tutor_utils()->array_get('video', $_POST);
379
- update_post_meta($post_ID, '_video', $video);
380
- }else{
381
- delete_post_meta($post_ID, '_video');
382
  }
383
  }
384
 
@@ -387,76 +404,82 @@ class Course extends Tutor_Base {
387
  */
388
 
389
  $author_id = $post->post_author;
390
- $attached = (int) $wpdb->get_var($wpdb->prepare(
391
- "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta}
392
- WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ", $author_id, $post_ID));
 
 
 
 
 
393
 
394
- if ( ! $attached){
395
- add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
396
  }
397
 
398
  /**
399
  * Disable question and answer for this course
 
400
  * @since 1.7.0
401
  */
402
- if ($additional_data_edit) {
403
- foreach($this->additional_meta as $key){
404
- update_post_meta($post_ID, $key, (isset($_POST[$key]) ? 'yes' : 'no'));
405
  }
406
  }
407
 
408
- do_action( "tutor_save_course_after", $post_ID, $post);
409
  }
410
 
411
  /**
412
  * Tutor add course topic
413
  */
414
- public function tutor_add_course_topic(){
415
  tutils()->checking_nonce();
416
 
417
- if (empty($_POST['topic_title']) ) {
418
  wp_send_json_error();
419
  }
420
- $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
421
- $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
422
-
423
- if(!tutils()->can_user_manage('course', $course_id)) {
424
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
425
  }
426
 
427
  $topic_title = sanitize_text_field( $_POST['topic_title'] );
428
  $topic_summery = wp_kses_post( $_POST['topic_summery'] );
429
 
430
- $post_arr = array(
431
  'post_type' => 'topics',
432
  'post_title' => $topic_title,
433
  'post_content' => $topic_summery,
434
  'post_status' => 'publish',
435
  'post_author' => get_current_user_id(),
436
  'post_parent' => $course_id,
437
- 'menu_order' => $next_topic_order_id,
438
  );
439
  $current_topic_id = wp_insert_post( $post_arr );
440
 
441
  ob_start();
442
- include tutor()->path.'views/metabox/course-contents.php';
443
  $course_contents = ob_get_clean();
444
 
445
- wp_send_json_success(array('course_contents' => $course_contents));
446
  }
447
 
448
  /**
449
  * Update the topic
450
  */
451
- public function tutor_update_topic(){
452
  tutils()->checking_nonce();
453
 
454
- $topic_id = (int) sanitize_text_field($_POST['topic_id']);
455
- $topic_title = sanitize_text_field($_POST['topic_title']);
456
- $topic_summery = wp_kses_post($_POST['topic_summery']);
457
 
458
- if(!tutils()->can_user_manage('topic', $topic_id)) {
459
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
460
  }
461
 
462
  $topic_attr = array(
@@ -466,7 +489,7 @@ class Course extends Tutor_Base {
466
  );
467
  wp_update_post( $topic_attr );
468
 
469
- wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
470
  }
471
 
472
 
@@ -477,13 +500,13 @@ class Course extends Tutor_Base {
477
  *
478
  * Add Lesson column
479
  */
480
- public function add_column($columns){
481
  $date_col = $columns['date'];
482
- unset($columns['date']);
483
- $columns['lessons'] = __('Lessons', 'tutor');
484
- $columns['students'] = __('Students', 'tutor');
485
- $columns['price'] = __('Price', 'tutor');
486
- $columns['date'] = $date_col;
487
 
488
  return $columns;
489
  }
@@ -491,88 +514,87 @@ class Course extends Tutor_Base {
491
  /**
492
  * @param $column
493
  * @param $post_id
494
- *
495
  */
496
- public function custom_lesson_column($column, $post_id ){
497
- if ($column === 'lessons'){
498
- echo tutor_utils()->get_lesson_count_by_course($post_id);
499
  }
500
 
501
- if ($column === 'students'){
502
- echo tutor_utils()->count_enrolled_users_by_course($post_id);
503
  }
504
 
505
- if ($column === 'price'){
506
- $price = tutor_utils()->get_course_price($post_id);
507
- if ($price){
508
- $monetize_by = tutils()->get_option('monetize_by');
509
- if (function_exists('wc_price') && $monetize_by === 'wc'){
510
- echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
511
- }else{
512
- echo '<span class="tutor-label-success">'.$price.'</span>';
513
  }
514
- }else{
515
- echo apply_filters('tutor-loop-default-price', __( 'free', 'tutor' ));
516
  }
517
  }
518
  }
519
 
520
 
521
- public function tutor_delete_topic(){
522
 
523
- tutils()->checking_nonce('get');
524
-
525
- !isset($_GET['topic_id']) ? exit() : 0;
526
 
527
  global $wpdb;
528
 
529
- $topic_id = (int) sanitize_text_field($_GET['topic_id']);
530
  $wpdb->update(
531
  $wpdb->posts,
532
- array('post_parent' => 0),
533
- array('post_parent' => $topic_id)
534
  );
535
 
536
  $wpdb->delete(
537
  $wpdb->postmeta,
538
- array('post_id' => $topic_id)
539
  );
540
 
541
- wp_delete_post($topic_id);
542
- wp_safe_redirect(wp_get_referer());
543
  }
544
 
545
- public function tutor_delete_announcement(){
546
- tutor_utils()->checking_nonce('get');
547
 
548
- $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
549
 
550
- wp_delete_post($announcement_id);
551
- wp_safe_redirect(wp_get_referer());
552
  }
553
 
554
- public function enroll_now(){
555
 
556
- //Checking if action comes from Enroll form
557
- if (tutor_utils()->array_get('tutor_course_action', $_POST) !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
558
  return;
559
  }
560
- //Checking Nonce
561
  tutor_utils()->checking_nonce();
562
 
563
  $user_id = get_current_user_id();
564
- if ( ! $user_id){
565
- exit(__('Please Sign In first', 'tutor'));
566
  }
567
 
568
- $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
569
- $user_id = get_current_user_id();
570
 
571
  /**
572
  * TODO: need to check purchase information
573
  */
574
 
575
- $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
576
 
577
  /**
578
  * If is is not purchasable, it's free, and enroll right now
@@ -581,16 +603,16 @@ class Course extends Tutor_Base {
581
  *
582
  * @since: v.1.0.0
583
  */
584
- if ($is_purchasable){
585
- //process purchase
586
 
587
- }else{
588
- //Free enroll
589
- tutor_utils()->do_enroll($course_id);
590
  }
591
 
592
  $referer_url = wp_get_referer();
593
- wp_redirect($referer_url);
594
  }
595
 
596
  /**
@@ -599,169 +621,178 @@ class Course extends Tutor_Base {
599
  *
600
  * @since v.1.0.0
601
  */
602
- public function mark_course_complete(){
603
- if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
604
  return;
605
  }
606
- //Checking nonce
607
  tutor_utils()->checking_nonce();
608
 
609
  $user_id = get_current_user_id();
610
 
611
- //TODO: need to show view if not signed_in
612
- if ( ! $user_id){
613
- die(__('Please Sign-In', 'tutor'));
614
  }
615
 
616
- $course_id = (int) sanitize_text_field($_POST['course_id']);
617
 
618
- do_action('tutor_course_complete_before', $course_id);
619
  /**
620
  * Marking course completed at Comment
621
  */
622
 
623
  global $wpdb;
624
 
625
- $date = date("Y-m-d H:i:s", tutor_time());
626
 
627
- //Making sure that, hash is unique
628
- do{
629
- $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
630
- $hasHash = (int) $wpdb->get_var($wpdb->prepare(
631
- "SELECT COUNT(comment_ID) from {$wpdb->comments}
632
- WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ", $hash));
 
 
 
 
633
 
634
- }while($hasHash > 0);
635
 
636
  $data = array(
637
- 'comment_post_ID' => $course_id,
638
- 'comment_author' => $user_id,
639
- 'comment_date' => $date,
640
- 'comment_date_gmt' => get_gmt_from_date($date),
641
- 'comment_content' => $hash, //Identification Hash
642
- 'comment_approved' => 'approved',
643
- 'comment_agent' => 'TutorLMSPlugin',
644
- 'comment_type' => 'course_completed',
645
- 'user_id' => $user_id,
646
  );
647
 
648
- $wpdb->insert($wpdb->comments, $data);
649
 
650
- do_action('tutor_course_complete_after', $course_id, $user_id);
651
 
652
- $permalink = get_the_permalink($course_id);
653
 
654
  // Set temporary identifier to show review pop up
655
- if(!get_tutor_option( 'disable_course_review' )) {
656
- $rating = tutor_utils()->get_course_rating_by_user($course_id, $user_id);
657
- if(!$rating || (empty($rating->rating) && empty($rating->review))) {
658
- update_option( 'tutor_course_complete_popup_'.$user_id, array(
659
- 'course_id' => $course_id,
660
- 'course_url' => $permalink,
661
- 'expires' => time()+10
662
- ));
 
 
 
663
  }
664
  }
665
-
666
- wp_redirect($permalink);
667
  exit;
668
  }
669
 
670
  public function popup_review_form() {
671
- if(is_user_logged_in()) {
672
- $key = 'tutor_course_complete_popup_' . get_current_user_id();
673
  $popup = get_option( $key );
674
 
675
- if(is_array($popup)) {
676
 
677
- if($popup['expires']>time()) {
678
  $course_id = $popup['course_id'];
679
- include tutor()->path.'views/modal/review.php';
680
  }
681
 
682
- delete_option($key);
683
  }
684
  }
685
  }
686
-
687
- public function tutor_load_instructors_modal(){
688
  tutils()->checking_nonce();
689
-
690
  global $wpdb;
691
 
692
- $course_id = (int) sanitize_text_field($_POST['course_id']);
693
- $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
694
 
695
- if(!tutils()->can_user_manage('course', $course_id)) {
696
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
697
  }
698
-
699
- $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
700
- $instructors = array();
701
 
702
- $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
 
 
 
703
 
704
- if ($saved_instructors){
705
- $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
706
- $instructor_not_in_ids = implode(',', $saved_instructors_ids);
707
- $not_in_sql .= "AND user.ID NOT IN($instructor_not_in_ids) ";
708
  }
709
 
710
  $search_sql = '';
711
- if ($search_terms){
712
  $search_sql = "AND (user.user_login like '%{$search_terms}%' or user.user_nicename like '%{$search_terms}%' or user.display_name like '%{$search_terms}%') ";
713
  }
714
 
715
- $instructors = $wpdb->get_results("SELECT user.ID, user.display_name from {$wpdb->users} user
 
716
  INNER JOIN {$wpdb->usermeta} meta ON user.ID = meta.user_id AND meta.meta_key = '_tutor_instructor_status' AND meta.meta_value = 'approved'
717
- WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
 
718
 
719
  $output = '';
720
- if (is_array($instructors) && count($instructors)){
721
  $instructor_output = '';
722
- foreach ($instructors as $instructor){
723
- $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
724
  }
725
 
726
- $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
727
 
728
- }else{
729
- $output .= __('<p>No instructor available or you have already added maximum instructors</p>', 'tutor');
 
730
  }
731
 
732
-
733
- if ( ! defined('TUTOR_MT_VERSION')){
734
- $output .= '<p class="tutor-notice-warning" style="margin-top: 50px; font-size: 14px;">'. sprintf( __('To add unlimited multiple instructors in your course, get %sTutor LMS Pro%s', 'tutor'), '<a href="https://www.themeum.com/product/tutor-lms" target="_blank">', "</a>" ) .'</p>';
735
  }
736
 
737
- wp_send_json_success(array('output' => $output));
738
  }
739
 
740
- public function tutor_add_instructors_to_course(){
741
  tutils()->checking_nonce();
742
 
743
- $course_id = (int) sanitize_text_field($_POST['course_id']);
744
- $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
745
-
746
- if(!tutils()->can_user_manage('course', $course_id)) {
747
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
748
  }
749
 
750
- if (is_array($instructor_ids) && count($instructor_ids)){
751
- foreach ($instructor_ids as $instructor_id){
752
- add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
753
  }
754
  }
755
 
756
- $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
757
- $output = '';
758
 
759
- if ($saved_instructors){
760
- foreach ($saved_instructors as $t){
761
 
762
- $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
763
- <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
764
- <span class="instructor-name"> '.$t->display_name.' </span>
765
  <span class="instructor-control">
766
  <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
767
  </span>
@@ -769,55 +800,62 @@ class Course extends Tutor_Base {
769
  }
770
  }
771
 
772
- wp_send_json_success(array('output' => $output));
773
  }
774
 
775
- public function detach_instructor_from_course(){
776
  tutils()->checking_nonce();
777
 
778
  global $wpdb;
779
 
780
- $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
781
- $course_id = (int) sanitize_text_field($_POST['course_id']);
782
 
783
- if(!tutils()->can_user_manage('course', $course_id)) {
784
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
785
  }
786
-
787
- $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
 
 
 
 
 
 
 
788
  wp_send_json_success();
789
  }
790
 
791
- public function tutor_delete_dashboard_course(){
792
  tutils()->checking_nonce();
793
 
794
- $course_id = intval(sanitize_text_field($_POST['course_id']));
795
 
796
- if(!tutils()->can_user_manage('course', $course_id)) {
797
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
798
  }
799
 
800
- wp_trash_post($course_id);
801
- wp_send_json_success(['element'=>'course']);
802
  }
803
 
804
 
805
- public function tutor_add_gutenberg_author($data , $postarr){
806
  global $wpdb;
807
 
808
  $courses_post_type = tutor()->course_post_type;
809
- $post_type = tutils()->array_get('post_type', $postarr);
810
 
811
- if ($courses_post_type === $post_type){
812
- $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
813
- $post_author = (int) $wpdb->get_var($wpdb->prepare("SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID));
814
 
815
- if ($post_author > 0){
816
- $data['post_author'] = $post_author;
817
- }else{
818
- $data['post_author'] = get_current_user_id();
819
- }
820
- }
821
 
822
  return $data;
823
  }
@@ -828,53 +866,53 @@ class Course extends Tutor_Base {
828
  * @param $postData
829
  *
830
  * Attach product during save course from the frontend course dashboard.
831
- *
832
  * @return string
833
  *
834
  * @since v.1.3.4
835
  */
836
- public function attach_product_with_course($post_ID, $postData){
837
- $attached_product_id = tutor_utils()->get_course_product_id($post_ID);
838
- $course_price = sanitize_text_field(tutor_utils()->array_get('course_price', $_POST));
839
 
840
- if ( ! $course_price){
841
  return;
842
  }
843
 
844
- $monetize_by = tutor_utils()->get_option('monetize_by');
845
- $course = get_post($post_ID);
846
 
847
- if ($monetize_by === 'wc'){
848
 
849
  $is_update = false;
850
- if ($attached_product_id){
851
- $wc_product = get_post_meta($attached_product_id, '_product_version', true);
852
- if ($wc_product){
853
  $is_update = true;
854
  }
855
  }
856
 
857
- if ($is_update) {
858
- $productObj = wc_get_product($attached_product_id);
859
- $productObj->set_price($course_price); // set product price
860
- $productObj->set_regular_price($course_price); // set product regular price
861
- $productObj->set_sold_individually(true);
862
  $product_id = $productObj->save();
863
- if($productObj->is_type('subscription')) {
864
  update_post_meta( $attached_product_id, '_subscription_price', $course_price );
865
  }
866
  } else {
867
  $productObj = new \WC_Product();
868
- $productObj->set_name($course->post_title);
869
- $productObj->set_status('publish');
870
- $productObj->set_price($course_price); // set product price
871
- $productObj->set_regular_price($course_price); // set product regular price
872
- $productObj->set_sold_individually(true);
873
 
874
  $product_id = $productObj->save();
875
- if ($product_id) {
876
  update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
877
- //Mark product for woocommerce
878
  update_post_meta( $product_id, '_virtual', 'yes' );
879
  update_post_meta( $product_id, '_tutor_product', 'yes' );
880
 
@@ -884,49 +922,44 @@ class Course extends Tutor_Base {
884
  }
885
  }
886
  }
887
-
888
- }elseif ($monetize_by === 'edd'){
889
 
890
  $is_update = false;
891
-
892
- if ($attached_product_id){
893
- $edd_price = get_post_meta($attached_product_id, 'edd_price', true);
894
- if ($edd_price){
895
  $is_update = true;
896
  }
897
  }
898
 
899
- if ($is_update){
900
- //Update the product
901
  update_post_meta( $attached_product_id, 'edd_price', $course_price );
902
- }else{
903
- //Create new product
904
-
905
- $post_arr = array(
906
- 'post_type' => 'download',
907
- 'post_title' => $course->post_title,
908
- 'post_status' => 'publish',
909
- 'post_author' => get_current_user_id(),
910
  );
911
  $download_id = wp_insert_post( $post_arr );
912
- if ($download_id ) {
913
- //edd_price
914
  update_post_meta( $download_id, 'edd_price', $course_price );
915
 
916
  update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
917
- //Mark product for EDD
918
  update_post_meta( $download_id, '_tutor_product', 'yes' );
919
 
920
  $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
921
  if ( $coursePostThumbnail ) {
922
  set_post_thumbnail( $download_id, $coursePostThumbnail );
923
  }
924
-
925
  }
926
-
927
  }
928
-
929
-
930
  }
931
 
932
  }
@@ -934,10 +967,11 @@ class Course extends Tutor_Base {
934
 
935
  /**
936
  * Add Course level to course settings
 
937
  * @since v.1.4.1
938
  */
939
- public function add_course_level_to_settings(){
940
- include tutor()->path.'views/metabox/course-level-metabox.php';
941
  }
942
 
943
  /**
@@ -945,39 +979,41 @@ class Course extends Tutor_Base {
945
  *
946
  * @since v.1.4.8
947
  */
948
- public function tutor_lesson_load_before(){
949
- $course_id = tutils()->get_course_id_by_content(get_the_ID());
950
- $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
951
- if (is_user_logged_in()){
952
- $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
953
- if ( ! $completed_lessons && ! $is_course_started){
954
- update_post_meta($course_id, '_tutor_course_started', tutor_time());
955
- do_action('tutor/course/started', $course_id);
956
  }
957
  }
958
  }
959
 
960
  /**
961
  * Add Course level to course settings
 
962
  * @since v.1.4.8
963
  */
964
- public function course_elements_enable_disable(){
965
- add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
966
- add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
967
- add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
968
- add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
969
- add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
970
- add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
971
- add_filter('tutor_course/single/enrolled/nav_items', array($this, 'enable_disable_course_nav_items') );
972
  }
973
 
974
  /**
975
  * Enable disable course progress bar
 
976
  * @since v.1.4.8
977
  */
978
- public function enable_disable_course_progress_bar($html){
979
- $disable_option = (bool) get_tutor_option('disable_course_progress_bar');
980
- if($disable_option){
981
  return '';
982
  }
983
  return $html;
@@ -985,11 +1021,12 @@ class Course extends Tutor_Base {
985
 
986
  /**
987
  * Enable disable material includes
 
988
  * @since v.1.4.8
989
  */
990
- public function enable_disable_material_includes($html){
991
- $disable_option = (bool) get_tutor_option('disable_course_material');
992
- if($disable_option){
993
  return '';
994
  }
995
  return $html;
@@ -997,11 +1034,12 @@ class Course extends Tutor_Base {
997
 
998
  /**
999
  * Enable disable course content
 
1000
  * @since v.1.4.8
1001
  */
1002
- public function enable_disable_course_content($html){
1003
- $disable_option = (bool) get_tutor_option('disable_course_description');
1004
- if($disable_option){
1005
  return '';
1006
  }
1007
  return $html;
@@ -1009,11 +1047,12 @@ class Course extends Tutor_Base {
1009
 
1010
  /**
1011
  * Enable disable course benefits
 
1012
  * @since v.1.4.8
1013
  */
1014
- public function enable_disable_course_benefits($html){
1015
- $disable_option = (bool) get_tutor_option('disable_course_benefits');
1016
- if($disable_option){
1017
  return '';
1018
  }
1019
  return $html;
@@ -1021,11 +1060,12 @@ class Course extends Tutor_Base {
1021
 
1022
  /**
1023
  * Enable disable course requirements
 
1024
  * @since v.1.4.8
1025
  */
1026
- public function enable_disable_course_requirements($html){
1027
- $disable_option = (bool) get_tutor_option('disable_course_requirements');
1028
- if($disable_option){
1029
  return '';
1030
  }
1031
  return $html;
@@ -1033,35 +1073,37 @@ class Course extends Tutor_Base {
1033
 
1034
  /**
1035
  * Enable disable course target audience
 
1036
  * @since v.1.4.8
1037
  */
1038
- public function enable_disable_course_target_audience($html){
1039
- $disable_option = (bool) get_tutor_option('disable_course_target_audience');
1040
- if($disable_option){
1041
  return '';
1042
  }
1043
  return $html;
1044
  }
1045
-
1046
  /**
1047
  * Enable disable course nav items
 
1048
  * @since v.1.4.8
1049
  */
1050
- public function enable_disable_course_nav_items($items){
1051
  global $wp_query, $post;
1052
- $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
1053
- $disable_course_announcements = (bool) get_tutor_option('disable_course_announcements');
1054
 
1055
- $disable_qa_for_this_course = ($wp_query->is_single && !empty($post)) ? get_post_meta($post->ID, '_tutor_disable_qa', true) : '';
1056
 
1057
- if(!$enable_q_and_a_on_course || $disable_qa_for_this_course == 'yes') {
1058
- if(tutils()->array_get('questions', $items)) {
1059
- unset($items['questions']);
1060
  }
1061
  }
1062
- if($disable_course_announcements){
1063
- if(tutils()->array_get('announcements', $items)) {
1064
- unset($items['announcements']);
1065
  }
1066
  }
1067
  return $items;
@@ -1069,219 +1111,228 @@ class Course extends Tutor_Base {
1069
 
1070
  /**
1071
  * Filter product in shop page
 
1072
  * @since v.1.4.9
1073
  */
1074
- public function filter_product_in_shop_page(){
1075
- $hide_course_from_shop_page = (bool) get_tutor_option('hide_course_from_shop_page');
1076
- if(!$hide_course_from_shop_page){
1077
  return;
1078
  }
1079
- add_action('woocommerce_product_query', array($this, 'filter_woocommerce_product_query'));
1080
- add_filter('edd_downloads_query', array($this, 'filter_edd_downloads_query'), 10, 2);
1081
- add_action('pre_get_posts', array($this, 'filter_archive_meta_query'), 1);
1082
  }
1083
 
1084
  /**
1085
  * Tutor product meta query
 
1086
  * @since v.1.4.9
1087
  */
1088
- public function tutor_product_meta_query(){
1089
  $meta_query = array(
1090
- 'key' => '_tutor_product',
1091
- 'compare' => 'NOT EXISTS'
1092
  );
1093
  return $meta_query;
1094
  }
1095
 
1096
  /**
1097
  * Filter product in woocommerce shop page
 
1098
  * @since v.1.4.9
1099
  */
1100
- public function filter_woocommerce_product_query($wp_query){
1101
- $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1102
  return $wp_query;
1103
  }
1104
 
1105
  /**
1106
  * Filter product in edd downloads shortcode page
 
1107
  * @since v.1.4.9
1108
  */
1109
- public function filter_edd_downloads_query($query){
1110
  $query['meta_query'][] = $this->tutor_product_meta_query();
1111
  return $query;
1112
  }
1113
 
1114
  /**
1115
  * Filter product in edd downloads archive page
 
1116
  * @since v.1.4.9
1117
  */
1118
- public function filter_archive_meta_query($wp_query){
1119
- if(!is_admin() && $wp_query->is_archive && $wp_query->get('post_type') === 'download'){
1120
- $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1121
  }
1122
  return $wp_query;
1123
  }
1124
 
1125
- /**
1126
- * @param $html
1127
- * @return string
1128
- *
1129
- * Removed course price if already enrolled at single course
1130
- *
1131
- * @since v.1.5.8
1132
- */
1133
- public function remove_price_if_enrolled($html){
1134
- $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1135
-
1136
- if ($should_removed){
1137
- $course_id = get_the_ID();
1138
- $enrolled = tutils()->is_enrolled($course_id);
1139
- if ($enrolled){
1140
- $html = '';
1141
- }
1142
- }
1143
- return $html;
1144
- }
1145
-
1146
- /**
1147
- * @param $html
1148
- * @return string
1149
- *
1150
- * Check if all lessons and quizzes done before mark course complete.
1151
- */
1152
- function tutor_lms_hide_course_complete_btn($html){
1153
-
1154
- $completion_mode = tutils()->get_option('course_completion_process');
1155
- if ($completion_mode !== 'strict'){
1156
- return $html;
1157
- }
1158
-
1159
- $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1160
- $lesson_count = tutils()->get_lesson_count_by_course();
1161
-
1162
- if ($completed_lesson < $lesson_count){
1163
- return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
1164
- }
1165
-
1166
- $quizzes = array();
1167
-
1168
- $course_contents = tutils()->get_course_contents_by_id();
1169
- if (tutils()->count($course_contents)){
1170
- foreach ($course_contents as $content){
1171
- if ($content->post_type === 'tutor_quiz'){
1172
- $quizzes[] = $content;
1173
- }
1174
- }
1175
- }
1176
-
1177
- $is_pass = true;
1178
- $required_quiz_pass = 0;
1179
-
1180
- if (tutils()->count($quizzes)){
1181
- foreach ($quizzes as $quiz){
1182
-
1183
- $attempt = tutils()->get_quiz_attempt($quiz->ID);
1184
- if ($attempt) {
1185
- $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1186
- $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1187
-
1188
- if ($earned_percentage < $passing_grade) {
1189
- $required_quiz_pass++;
1190
- $is_pass = false;
1191
- }
1192
- }else{
1193
- $required_quiz_pass++;
1194
- $is_pass = false;
1195
- }
1196
- }
1197
- }
1198
-
1199
- if ( ! $is_pass){
1200
- return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
1201
- }
1202
-
1203
- return $html;
1204
- }
1205
-
1206
- public function get_generate_greadbook($html){
1207
- if ( ! tutils()->is_completed_course()){
1208
- return '';
1209
- }
1210
- return $html;
1211
  }
1212
 
1213
  /**
1214
  * Add social share content in header
 
1215
  * @since v.1.6.3
1216
  */
1217
- public function social_share_content(){
1218
  global $wp_query, $post;
1219
- if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type) { ?>
1220
  <!--Facebook-->
1221
  <meta property="og:type" content="website"/>
1222
- <meta property="og:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>" />
1223
- <meta property="og:description" content="<?php echo esc_html($post->post_content); ?>" />
1224
  <!--Twitter-->
1225
- <meta name="twitter:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1226
- <meta name="twitter:description" content="<?php echo esc_html($post->post_content); ?>">
1227
  <!--Google+-->
1228
- <meta itemprop="image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1229
- <meta itemprop="description" content="<?php echo esc_html($post->post_content); ?>"> <?php
 
1230
  }
1231
  }
1232
 
1233
  /**
1234
  * Get posts by type and parent
 
1235
  * @since v.1.6.6
1236
  */
1237
- public function tutor_get_post_ids($post_type, $post_parent) {
1238
  $args = array(
1239
- 'fields' => 'ids',
1240
  'post_type' => $post_type,
1241
  'post_parent' => $post_parent,
1242
  'post_status' => 'any',
1243
  'posts_per_page' => -1,
1244
  );
1245
- return get_posts($args);
1246
  }
1247
-
1248
  /**
1249
  * Delete course data when permanently deleting a course.
 
1250
  * @since v.1.6.6
1251
  */
1252
  function delete_tutor_course_data( $post_id ) {
1253
  $course_post_type = tutor()->course_post_type;
1254
  $lesson_post_type = tutor()->lesson_post_type;
1255
 
1256
- if (get_post_type($post_id) == $course_post_type) {
1257
  global $wpdb;
1258
- $topic_ids = $this->tutor_get_post_ids('topics', $post_id);
1259
- if ( !empty($topic_ids) ) {
1260
- foreach ($topic_ids as $topic_id) {
1261
- $content_post_type = apply_filters('tutor_course_contents_post_types', array($lesson_post_type, 'tutor_quiz'));
1262
- $topic_content_ids = $this->tutor_get_post_ids($content_post_type, $topic_id);
1263
-
1264
- foreach ($topic_content_ids as $content_id) {
1265
- if( get_post_type($content_id) == 'tutor_quiz') {
1266
- $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $content_id));
1267
- $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $content_id));
1268
-
1269
- $questions_ids = $wpdb->get_col($wpdb->prepare("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id));
1270
- if (is_array($questions_ids) && count($questions_ids)){
1271
- $in_question_ids = "'".implode("','", $questions_ids)."'";
1272
- $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
1273
  }
1274
- $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $content_id));
1275
  }
1276
- wp_delete_post($content_id, true);
1277
  }
1278
- wp_delete_post($topic_id, true);
1279
  }
1280
  }
1281
- $child_post_ids = $this->tutor_get_post_ids(array('tutor_announcements', 'tutor_enrolled'), $post_id);
1282
- if ( !empty($child_post_ids) ) {
1283
- foreach ($child_post_ids as $child_post_id) {
1284
- wp_delete_post($child_post_id, true);
1285
  }
1286
  }
1287
  }
@@ -1289,48 +1340,49 @@ class Course extends Tutor_Base {
1289
 
1290
  /**
1291
  * tutor course setting metabox
 
1292
  * @since v.1.7.0
1293
  */
1294
  function tutor_course_setting_metabox( $post ) {
1295
-
1296
  $disable_qa = $this->additional_meta[0];
1297
- $is_public = $this->additional_meta[1];
1298
 
1299
- $disable_qa_checked = get_post_meta($post->ID, $disable_qa, true)=='yes' ? 'checked="checked"' : '';
1300
- $is_public_checked = get_post_meta($post->ID, $is_public, true)=='yes' ? 'checked="checked"' : '';
1301
 
1302
- do_action('tutor_before_course_sidebar_settings_metabox', $post);
1303
  ?>
1304
  <div class="tutor-course-sidebar-settings-item" id="_tutor_is_course_public_meta_checkbox" style="display:none">
1305
- <label for="<?php echo $is_public; ?>">
1306
- <input id="<?php echo $is_public; ?>" type="checkbox" name="<?php echo $is_public; ?>" value="yes" <?php echo $is_public_checked; ?> />
1307
- <?php _e('Make This Course Public', 'tutor'); ?>
1308
  <small style="display:block;padding-left:24px">
1309
- <?php _e('No enrollment required.', 'tutor'); ?>
1310
  </small>
1311
  </label>
1312
  </div>
1313
  <div class="tutor-course-sidebar-settings-item">
1314
- <label for="<?php echo $disable_qa; ?>">
1315
  <input type="hidden" name="_tutor_course_additional_data_edit" value="true" />
1316
- <input id="<?php echo $disable_qa; ?>" type="checkbox" name="<?php echo $disable_qa; ?>" value="yes" <?php echo $disable_qa_checked; ?> />
1317
- <?php _e('Disable Q&A', 'tutor'); ?>
1318
  </label>
1319
  </div>
1320
  <?php
1321
- do_action('tutor_after_course_sidebar_settings_metabox', $post);
1322
  }
1323
 
1324
- function tutor_course_setting_metabox_frontend( $post ){
1325
- ?>
1326
  <div class="tutor-course-builder-section tutor-course-builder-info">
1327
  <div class="tutor-course-builder-section-title">
1328
- <h3><i class="tutor-icon-down"></i><span><?php esc_html_e('Tutor Settings', 'tutor'); ?></span></h3>
1329
  </div>
1330
  <div class="tutor-course-builder-section-content">
1331
  <div class="tutor-frontend-builder-item-scope">
1332
  <div class="tutor-form-group">
1333
- <?php $this->tutor_course_setting_metabox($post); ?>
1334
  </div>
1335
  </div>
1336
  </div>
@@ -1340,60 +1392,63 @@ class Course extends Tutor_Base {
1340
 
1341
  /**
1342
  * Delete associated enrollment
 
1343
  * @since v.1.8.2
1344
  */
1345
- public function delete_associated_enrollment($post_id) {
1346
- global $wpdb;
1347
 
1348
- $enroll_id = $wpdb->get_var( $wpdb->prepare(
1349
- "SELECT
1350
- post_id
1351
- FROM
 
1352
  {$wpdb->postmeta}
1353
- WHERE
1354
- meta_key='_tutor_enrolled_by_order_id'
1355
  AND meta_value = %d
1356
- ",
1357
- $post_id
1358
- ) );
1359
-
1360
- if(is_numeric($enroll_id) && $enroll_id>0) {
 
1361
 
1362
- $course_id = get_post_field('post_parent', $enroll_id);
1363
- $user_id = get_post_field('post_author', $enroll_id);
1364
 
1365
- tutils()->cancel_course_enrol($course_id, $user_id);
1366
- }
1367
- }
1368
 
1369
  public function tutor_reset_course_progress() {
1370
  tutils()->checking_nonce();
1371
- $course_id = tutor_utils()->array_get('course_id', $_POST);
1372
 
1373
- if(!$course_id || !is_numeric($course_id) || !tutor_utils()->is_enrolled( $course_id )) {
1374
- wp_send_json_error(array('message' => __('Invalid Course ID or Access Denied.', 'tutor')));
1375
  return;
1376
  }
1377
 
1378
- tutor_utils()->delete_course_progress($course_id);
1379
- wp_send_json_success(array('redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ));
1380
  }
1381
 
1382
  /**
1383
  * Do enroll if guest attempt to enroll and course is free
1384
- *
1385
  * @param $course_id
1386
- *
1387
  * @since 1.9.8
1388
  */
1389
  public function enroll_after_login_if_attempt( $course_id ) {
1390
  $course_id = sanitize_text_field( $course_id );
1391
  if ( $course_id ) {
1392
- $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
1393
- if ( !$is_purchasable ) {
1394
- tutor_utils()->do_enroll($course_id);
1395
  do_action( 'guest_attempt_after_enrollment', $course_id );
1396
  }
1397
  }
1398
  }
1399
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
  class Course extends Tutor_Base {
9
+
10
+ private $additional_meta = array(
11
  '_tutor_disable_qa',
12
+ '_tutor_is_public_course',
13
  );
14
 
15
  public function __construct() {
16
  parent::__construct();
 
 
 
 
 
17
 
18
+ add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ) );
19
+ add_action( 'save_post_' . $this->course_post_type, array( $this, 'save_course_meta' ), 10, 2 );
20
+ add_action( 'wp_ajax_tutor_add_course_topic', array( $this, 'tutor_add_course_topic' ) );
21
+ add_action( 'wp_ajax_tutor_update_topic', array( $this, 'tutor_update_topic' ) );
22
+
23
+ // Add Column
24
+ add_filter( "manage_{$this->course_post_type}_posts_columns", array( $this, 'add_column' ), 10, 1 );
25
+ add_action( "manage_{$this->course_post_type}_posts_custom_column", array( $this, 'custom_lesson_column' ), 10, 2 );
26
 
27
+ add_action( 'admin_action_tutor_delete_topic', array( $this, 'tutor_delete_topic' ) );
28
+ add_action( 'admin_action_tutor_delete_announcement', array( $this, 'tutor_delete_announcement' ) );
29
 
30
+ // Frontend Action
31
+ add_action( 'template_redirect', array( $this, 'enroll_now' ) );
32
+ add_action( 'init', array( $this, 'mark_course_complete' ) );
33
 
34
+ // Modal Perform
35
+ add_action( 'wp_ajax_tutor_load_instructors_modal', array( $this, 'tutor_load_instructors_modal' ) );
36
+ add_action( 'wp_ajax_tutor_add_instructors_to_course', array( $this, 'tutor_add_instructors_to_course' ) );
37
+ add_action( 'wp_ajax_detach_instructor_from_course', array( $this, 'detach_instructor_from_course' ) );
38
 
39
  /**
40
  * Frontend Dashboard
41
  */
42
+ add_action( 'wp_ajax_tutor_delete_dashboard_course', array( $this, 'tutor_delete_dashboard_course' ) );
43
 
44
  /**
45
  * Gutenberg author support
46
  */
47
+ add_filter( 'wp_insert_post_data', array( $this, 'tutor_add_gutenberg_author' ), '99', 2 );
48
 
49
  /**
50
  * Frontend metabox supports for course builder
51
+ *
52
  * @since v.1.3.4
53
  */
54
+ add_action( 'tutor/dashboard_course_builder_form_field_after', array( $this, 'register_meta_box_in_frontend' ) );
55
 
56
  /**
57
  * Do Stuff for the course save from frontend
58
  */
59
+ add_action( 'save_tutor_course', array( $this, 'attach_product_with_course' ), 10, 2 );
60
 
61
  /**
62
  * Add course level to course settings
63
+ *
64
  * @since v.1.4.1
65
  */
66
+ add_action( 'tutor_course/settings_tab_content/after/general', array( $this, 'add_course_level_to_settings' ) );
67
 
68
  /**
69
  * Enable Disable Course Details Page Feature
70
+ *
71
  * @since v.1.4.8
72
  */
73
  $this->course_elements_enable_disable();
76
  * @since v.1.4.8
77
  * Check if course starting, set meta if starting
78
  */
79
+ add_action( 'tutor_lesson_load_before', array( $this, 'tutor_lesson_load_before' ) );
80
 
81
  /**
82
  * @since v.1.4.9
84
  */
85
  $this->filter_product_in_shop_page();
86
 
87
+ /**
88
+ * Remove the course price if enrolled
89
+ *
90
+ * @since 1.5.8
91
+ */
92
+ add_filter( 'tutor_course_price', array( $this, 'remove_price_if_enrolled' ) );
93
+
94
+ /**
95
+ * Remove course complete button if course completion is strict mode
96
+ *
97
+ * @since v.1.6.1
98
+ */
99
+ add_filter( 'tutor_course/single/complete_form', array( $this, 'tutor_lms_hide_course_complete_btn' ) );
100
+ add_filter( 'get_gradebook_generate_form_html', array( $this, 'get_generate_greadbook' ) );
101
+
102
+ /**
103
+ * Add social share content in header
104
+ *
105
+ * @since v.1.6.3
106
+ */
107
+ add_action( 'wp_head', array( $this, 'social_share_content' ) );
108
+
109
+ /**
110
+ * Delete course data after deleted course
111
+ *
112
+ * @since v.1.6.6
113
+ */
114
+ add_action( 'deleted_post', array( $this, 'delete_tutor_course_data' ) );
115
+ add_action( 'tutor/dashboard_course_builder_form_field_after', array( $this, 'tutor_course_setting_metabox_frontend' ) );
116
 
117
  /**
118
+ * Delete course data after deleted course
119
+ *
120
+ * @since v.1.8.2
121
+ */
122
+ add_action( 'before_delete_post', array( $this, 'delete_associated_enrollment' ) );
123
 
124
  /**
125
  * Show only own uploads in media library if user is instructor
126
+ *
127
  * @since v1.8.9
128
  */
129
+ add_filter( 'posts_where', array( $this, 'restrict_media' ) );
130
 
131
  /**
132
  * Restrict new enrol/purchase button if course member limit reached
133
+ *
134
  * @since v1.9.0
135
  */
136
+ add_filter( 'tutor_course_restrict_new_entry', array( $this, 'restrict_new_student_entry' ) );
137
 
138
  /**
139
  * Reset course progress on retake
140
+ *
141
  * @since v1.9.5
142
  */
143
+ add_action( 'wp_ajax_tutor_reset_course_progress', array( $this, 'tutor_reset_course_progress' ) );
144
+
145
  /**
146
  * Popup for review
147
+ *
148
  * @since v1.9.7
149
  */
150
+ add_action( 'wp_footer', array( $this, 'popup_review_form' ) );
151
 
152
  /**
153
  * Do enroll after login if guest take enroll attempt
154
+ *
155
  * @since 1.9.8
156
  */
157
+ add_action( 'tutor_do_enroll_after_login_if_attempt', array( $this, 'enroll_after_login_if_attempt' ), 10, 1 );
158
  }
159
 
160
+ public function restrict_new_student_entry( $content ) {
161
 
162
+ if ( ! tutils()->is_course_fully_booked() ) {
163
  // No restriction if not fully booked
164
  return $content;
165
  }
166
+
167
  return '<span class="tutor-course-booked-fully">
168
+ <img src="' . esc_url( tutor()->url . '/assets/images/icon-warning-info.svg' ) . '"/>
169
+ <span>' . __( 'Fully booked', 'tutor' ) . '</span>
170
  </span>';
171
  }
172
 
173
+ function restrict_media( $where ) {
174
+
175
+ if ( isset( $_POST['action'] ) && $_POST['action'] == 'query-attachments' && tutor_utils()->is_instructor() ) {
176
+ if ( ! tutor_utils()->has_user_role( array( 'administrator', 'editor' ) ) ) {
177
  $where .= ' AND post_author=' . get_current_user_id();
178
  }
179
  }
180
+
181
  return $where;
182
  }
183
 
184
  /**
185
  * Registering metabox
186
  */
187
+ public function register_meta_box() {
188
+ $coursePostType = tutor()->course_post_type;
189
+ $course_marketplace = tutor_utils()->get_option( 'enable_course_marketplace' );
190
+ // add_meta_box( 'tutor-course-levels', __( 'Course Level', 'tutor' ), array($this, 'course_level_metabox'), $coursePostType );
191
+ add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array( $this, 'course_meta_box' ), $coursePostType );
192
+ add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array( $this, 'course_additional_data_meta_box' ), $coursePostType );
193
+ add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array( $this, 'video_metabox' ), $coursePostType );
194
+ if ( $course_marketplace ) {
195
  add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
196
  }
197
 
198
  /**
199
+ * Tutor course sidebar settings metabox
200
+ *
201
+ * @since v.1.7.0
202
+ */
203
+ add_meta_box( 'tutor-course-sidebar-settings', __( 'Tutor Settings', 'tutor' ), array( $this, 'tutor_course_setting_metabox' ), $coursePostType, 'side' );
204
  }
205
 
206
+ public function course_meta_box( $echo = true ) {
207
  ob_start();
208
+ include tutor()->path . 'views/metabox/course-topics.php';
209
  $content = ob_get_clean();
210
 
211
+ if ( $echo ) {
212
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
213
+ } else {
214
  return $content;
215
  }
216
  }
217
 
218
+ public function course_additional_data_meta_box( $echo = true ) {
219
 
220
  ob_start();
221
+ include tutor()->path . 'views/metabox/course-additional-data.php';
222
  $content = ob_get_clean();
223
 
224
+ if ( $echo ) {
225
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
226
+ } else {
227
  return $content;
228
  }
229
  }
230
 
231
+ public function video_metabox( $echo = true ) {
232
  ob_start();
233
+ include tutor()->path . 'views/metabox/video-metabox.php';
234
  $content = ob_get_clean();
235
 
236
+ if ( $echo ) {
237
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
238
+ } else {
239
  return $content;
240
  }
241
  }
242
 
243
+ public function course_level_metabox( $echo = true ) {
244
  ob_start();
245
+ include tutor()->path . 'views/metabox/course-level-metabox.php';
246
  $content = ob_get_clean();
247
 
248
+ if ( $echo ) {
249
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
250
+ } else {
251
  return $content;
252
  }
253
  }
254
 
255
+ public function instructors_metabox( $echo = true ) {
256
  ob_start();
257
  include tutor()->path . 'views/metabox/instructors-metabox.php';
258
  $content = ob_get_clean();
259
 
260
+ if ( $echo ) {
261
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
262
+ } else {
263
  return $content;
264
  }
265
  }
266
 
267
  /**
268
  * Register metabox in course builder tutor
269
+ *
270
  * @since v.1.3.4
271
  */
272
+ public function register_meta_box_in_frontend() {
273
+ do_action( 'tutor_course_builder_metabox_before', get_the_ID() );
274
+ course_builder_section_wrap( $this->video_metabox( $echo = false ), __( 'Video', 'tutor' ) );
275
+ course_builder_section_wrap( $this->course_meta_box( $echo = false ), __( 'Course Builder', 'tutor' ) );
276
+ course_builder_section_wrap( $this->instructors_metabox( $echo = false ), __( 'Instructors', 'tutor' ) );
277
+ course_builder_section_wrap( $this->course_additional_data_meta_box( $echo = false ), __( 'Additional Data', 'tutor' ) );
278
+ do_action( 'tutor_course_builder_metabox_after', get_the_ID() );
279
  }
280
 
281
  /**
283
  *
284
  * Insert Topic and attached it with Course
285
  */
286
+ public function save_course_meta( $post_ID, $post ) {
287
  global $wpdb;
288
 
289
+ do_action( 'tutor_save_course', $post_ID, $post );
290
+
291
  /**
292
  * Save course price type
293
  */
294
+ $price_type = tutils()->array_get( 'tutor_course_price_type', tutor_sanitize_data($_POST) );
295
+ if ( $price_type ) {
296
+ update_post_meta( $post_ID, '_tutor_course_price_type', $price_type );
297
  }
298
 
299
+ // Course Duration
300
+ if ( ! empty( $_POST['course_duration'] ) ) {
301
+ $video = tutils()->sanitize_array( $_POST['course_duration'] );
302
+ update_post_meta( $post_ID, '_course_duration', $video );
303
  }
304
 
305
+ if ( ! empty( $_POST['course_level'] ) ) {
306
+ $course_level = sanitize_text_field( $_POST['course_level'] );
307
+ update_post_meta( $post_ID, '_tutor_course_level', $course_level );
308
  }
309
 
310
+ $additional_data_edit = tutils()->avalue_dot( '_tutor_course_additional_data_edit', tutor_sanitize_data($_POST) );
311
+ if ( $additional_data_edit ) {
312
+ if ( ! empty( $_POST['course_benefits'] ) ) {
313
+ $course_benefits = wp_kses_post( $_POST['course_benefits'] );
314
+ update_post_meta( $post_ID, '_tutor_course_benefits', $course_benefits );
315
  } else {
316
+ delete_post_meta( $post_ID, '_tutor_course_benefits' );
317
  }
318
 
319
+ if ( ! empty( $_POST['course_requirements'] ) ) {
320
+ $requirements = wp_kses_post( $_POST['course_requirements'] );
321
+ update_post_meta( $post_ID, '_tutor_course_requirements', $requirements );
322
  } else {
323
+ delete_post_meta( $post_ID, '_tutor_course_requirements' );
324
  }
325
 
326
+ if ( ! empty( $_POST['course_target_audience'] ) ) {
327
+ $target_audience = wp_kses_post( $_POST['course_target_audience'] );
328
+ update_post_meta( $post_ID, '_tutor_course_target_audience', $target_audience );
329
  } else {
330
+ delete_post_meta( $post_ID, '_tutor_course_target_audience' );
331
  }
332
 
333
+ if ( ! empty( $_POST['course_material_includes'] ) ) {
334
+ $material_includes = wp_kses_post( $_POST['course_material_includes'] );
335
+ update_post_meta( $post_ID, '_tutor_course_material_includes', $material_includes );
336
  } else {
337
+ delete_post_meta( $post_ID, '_tutor_course_material_includes' );
338
  }
339
  }
340
 
 
341
  /**
342
  * Sorting Topics and lesson
343
  */
344
+ if ( ! empty( $_POST['tutor_topics_lessons_sorting'] ) ) {
345
+ $new_order = sanitize_text_field( stripslashes( $_POST['tutor_topics_lessons_sorting'] ) );
346
+ $order = json_decode( $new_order, true );
347
 
348
+ if ( is_array( $order ) && count( $order ) ) {
349
  $i = 0;
350
+ foreach ( $order as $topic ) {
351
  $i++;
352
  $wpdb->update(
353
  $wpdb->posts,
354
+ array( 'menu_order' => $i ),
355
+ array( 'ID' => $topic['topic_id'] )
356
  );
357
 
358
  /**
361
 
362
  $wpdb->update(
363
  $wpdb->posts,
364
+ array( 'post_parent' => 0 ),
365
+ array( 'post_parent' => $topic['topic_id'] )
366
  );
367
 
368
  /**
369
  * Lesson Attaching with topic ID
370
  * sorting lesson
371
  */
372
+ if ( isset( $topic['lesson_ids'] ) ) {
373
  $lesson_ids = $topic['lesson_ids'];
374
+ } else {
375
  $lesson_ids = array();
376
  }
377
+ if ( count( $lesson_ids ) ) {
378
+ foreach ( $lesson_ids as $lesson_key => $lesson_id ) {
379
  $wpdb->update(
380
  $wpdb->posts,
381
+ array(
382
+ 'post_parent' => $topic['topic_id'],
383
+ 'menu_order' => $lesson_key,
384
+ ),
385
+ array( 'ID' => $lesson_id )
386
  );
387
  }
388
  }
389
  }
390
  }
391
  }
392
+
393
+ if ( $additional_data_edit ) {
394
+ if ( ! empty( $_POST['video']['source'] ) ) { // Video
395
+ $video = tutor_utils()->array_get( 'video', tutor_sanitize_data($_POST) );
396
+ update_post_meta( $post_ID, '_video', $video );
397
+ } else {
398
+ delete_post_meta( $post_ID, '_video' );
399
  }
400
  }
401
 
404
  */
405
 
406
  $author_id = $post->post_author;
407
+ $attached = (int) $wpdb->get_var(
408
+ $wpdb->prepare(
409
+ "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta}
410
+ WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ",
411
+ $author_id,
412
+ $post_ID
413
+ )
414
+ );
415
 
416
+ if ( ! $attached ) {
417
+ add_user_meta( $author_id, '_tutor_instructor_course_id', $post_ID );
418
  }
419
 
420
  /**
421
  * Disable question and answer for this course
422
+ *
423
  * @since 1.7.0
424
  */
425
+ if ( $additional_data_edit ) {
426
+ foreach ( $this->additional_meta as $key ) {
427
+ update_post_meta( $post_ID, $key, ( isset( $_POST[ $key ] ) ? 'yes' : 'no' ) );
428
  }
429
  }
430
 
431
+ do_action( 'tutor_save_course_after', $post_ID, $post );
432
  }
433
 
434
  /**
435
  * Tutor add course topic
436
  */
437
+ public function tutor_add_course_topic() {
438
  tutils()->checking_nonce();
439
 
440
+ if ( empty( $_POST['topic_title'] ) ) {
441
  wp_send_json_error();
442
  }
443
+ $course_id = (int) tutor_utils()->avalue_dot( 'tutor_topic_course_ID', tutor_sanitize_data($_POST) );
444
+ $next_topic_order_id = tutor_utils()->get_next_topic_order_id( $course_id );
445
+
446
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
447
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
448
  }
449
 
450
  $topic_title = sanitize_text_field( $_POST['topic_title'] );
451
  $topic_summery = wp_kses_post( $_POST['topic_summery'] );
452
 
453
+ $post_arr = array(
454
  'post_type' => 'topics',
455
  'post_title' => $topic_title,
456
  'post_content' => $topic_summery,
457
  'post_status' => 'publish',
458
  'post_author' => get_current_user_id(),
459
  'post_parent' => $course_id,
460
+ 'menu_order' => $next_topic_order_id,
461
  );
462
  $current_topic_id = wp_insert_post( $post_arr );
463
 
464
  ob_start();
465
+ include tutor()->path . 'views/metabox/course-contents.php';
466
  $course_contents = ob_get_clean();
467
 
468
+ wp_send_json_success( array( 'course_contents' => $course_contents ) );
469
  }
470
 
471
  /**
472
  * Update the topic
473
  */
474
+ public function tutor_update_topic() {
475
  tutils()->checking_nonce();
476
 
477
+ $topic_id = (int) sanitize_text_field( $_POST['topic_id'] );
478
+ $topic_title = sanitize_text_field( $_POST['topic_title'] );
479
+ $topic_summery = wp_kses_post( $_POST['topic_summery'] );
480
 
481
+ if ( ! tutils()->can_user_manage( 'topic', $topic_id ) ) {
482
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
483
  }
484
 
485
  $topic_attr = array(
489
  );
490
  wp_update_post( $topic_attr );
491
 
492
+ wp_send_json_success( array( 'msg' => __( 'Topic has been updated', 'tutor' ) ) );
493
  }
494
 
495
 
500
  *
501
  * Add Lesson column
502
  */
503
+ public function add_column( $columns ) {
504
  $date_col = $columns['date'];
505
+ unset( $columns['date'] );
506
+ $columns['lessons'] = __( 'Lessons', 'tutor' );
507
+ $columns['students'] = __( 'Students', 'tutor' );
508
+ $columns['price'] = __( 'Price', 'tutor' );
509
+ $columns['date'] = $date_col;
510
 
511
  return $columns;
512
  }
514
  /**
515
  * @param $column
516
  * @param $post_id
 
517
  */
518
+ public function custom_lesson_column( $column, $post_id ) {
519
+ if ( $column === 'lessons' ) {
520
+ echo tutor_utils()->get_lesson_count_by_course( $post_id );
521
  }
522
 
523
+ if ( $column === 'students' ) {
524
+ echo tutor_utils()->count_enrolled_users_by_course( $post_id );
525
  }
526
 
527
+ if ( $column === 'price' ) {
528
+ $price = tutor_utils()->get_course_price( $post_id );
529
+ if ( $price ) {
530
+ $monetize_by = tutils()->get_option( 'monetize_by' );
531
+ if ( function_exists( 'wc_price' ) && $monetize_by === 'wc' ) {
532
+ echo '<span class="tutor-label-success">' . wc_price( $price ) . '</span>';
533
+ } else {
534
+ echo '<span class="tutor-label-success">' . $price . '</span>';
535
  }
536
+ } else {
537
+ echo apply_filters( 'tutor-loop-default-price', __( 'free', 'tutor' ) );
538
  }
539
  }
540
  }
541
 
542
 
543
+ public function tutor_delete_topic() {
544
 
545
+ tutils()->checking_nonce( 'get' );
546
+
547
+ ! isset( $_GET['topic_id'] ) ? exit() : 0;
548
 
549
  global $wpdb;
550
 
551
+ $topic_id = (int) sanitize_text_field( $_GET['topic_id'] );
552
  $wpdb->update(
553
  $wpdb->posts,
554
+ array( 'post_parent' => 0 ),
555
+ array( 'post_parent' => $topic_id )
556
  );
557
 
558
  $wpdb->delete(
559
  $wpdb->postmeta,
560
+ array( 'post_id' => $topic_id )
561
  );
562
 
563
+ wp_delete_post( $topic_id );
564
+ wp_safe_redirect( wp_get_referer() );
565
  }
566
 
567
+ public function tutor_delete_announcement() {
568
+ tutor_utils()->checking_nonce( 'get' );
569
 
570
+ $announcement_id = (int) sanitize_text_field( $_GET['topic_id'] );
571
 
572
+ wp_delete_post( $announcement_id );
573
+ wp_safe_redirect( wp_get_referer() );
574
  }
575
 
576
+ public function enroll_now() {
577
 
578
+ // Checking if action comes from Enroll form
579
+ if ( tutor_utils()->array_get( 'tutor_course_action', tutor_sanitize_data($_POST) ) !== '_tutor_course_enroll_now' || ! isset( $_POST['tutor_course_id'] ) ) {
580
  return;
581
  }
582
+ // Checking Nonce
583
  tutor_utils()->checking_nonce();
584
 
585
  $user_id = get_current_user_id();
586
+ if ( ! $user_id ) {
587
+ exit( __( 'Please Sign In first', 'tutor' ) );
588
  }
589
 
590
+ $course_id = (int) sanitize_text_field( $_POST['tutor_course_id'] );
591
+ $user_id = get_current_user_id();
592
 
593
  /**
594
  * TODO: need to check purchase information
595
  */
596
 
597
+ $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
598
 
599
  /**
600
  * If is is not purchasable, it's free, and enroll right now
603
  *
604
  * @since: v.1.0.0
605
  */
606
+ if ( $is_purchasable ) {
607
+ // process purchase
608
 
609
+ } else {
610
+ // Free enroll
611
+ tutor_utils()->do_enroll( $course_id );
612
  }
613
 
614
  $referer_url = wp_get_referer();
615
+ wp_redirect( $referer_url );
616
  }
617
 
618
  /**
621
  *
622
  * @since v.1.0.0
623
  */
624
+ public function mark_course_complete() {
625
+ if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_complete_course' ) {
626
  return;
627
  }
628
+ // Checking nonce
629
  tutor_utils()->checking_nonce();
630
 
631
  $user_id = get_current_user_id();
632
 
633
+ // TODO: need to show view if not signed_in
634
+ if ( ! $user_id ) {
635
+ die( __( 'Please Sign-In', 'tutor' ) );
636
  }
637
 
638
+ $course_id = (int) sanitize_text_field( $_POST['course_id'] );
639
 
640
+ do_action( 'tutor_course_complete_before', $course_id );
641
  /**
642
  * Marking course completed at Comment
643
  */
644
 
645
  global $wpdb;
646
 
647
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
648
 
649
+ // Making sure that, hash is unique
650
+ do {
651
+ $hash = substr( md5( wp_generate_password( 32 ) . $date . $course_id . $user_id ), 0, 16 );
652
+ $hasHash = (int) $wpdb->get_var(
653
+ $wpdb->prepare(
654
+ "SELECT COUNT(comment_ID) from {$wpdb->comments}
655
+ WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ",
656
+ $hash
657
+ )
658
+ );
659
 
660
+ } while ( $hasHash > 0 );
661
 
662
  $data = array(
663
+ 'comment_post_ID' => $course_id,
664
+ 'comment_author' => $user_id,
665
+ 'comment_date' => $date,
666
+ 'comment_date_gmt' => get_gmt_from_date( $date ),
667
+ 'comment_content' => $hash, // Identification Hash
668
+ 'comment_approved' => 'approved',
669
+ 'comment_agent' => 'TutorLMSPlugin',
670
+ 'comment_type' => 'course_completed',
671
+ 'user_id' => $user_id,
672
  );
673
 
674
+ $wpdb->insert( $wpdb->comments, $data );
675
 
676
+ do_action( 'tutor_course_complete_after', $course_id, $user_id );
677
 
678
+ $permalink = get_the_permalink( $course_id );
679
 
680
  // Set temporary identifier to show review pop up
681
+ if ( ! get_tutor_option( 'disable_course_review' ) ) {
682
+ $rating = tutor_utils()->get_course_rating_by_user( $course_id, $user_id );
683
+ if ( ! $rating || ( empty( $rating->rating ) && empty( $rating->review ) ) ) {
684
+ update_option(
685
+ 'tutor_course_complete_popup_' . $user_id,
686
+ array(
687
+ 'course_id' => $course_id,
688
+ 'course_url' => $permalink,
689
+ 'expires' => time() + 10,
690
+ )
691
+ );
692
  }
693
  }
694
+
695
+ wp_redirect( $permalink );
696
  exit;
697
  }
698
 
699
  public function popup_review_form() {
700
+ if ( is_user_logged_in() ) {
701
+ $key = 'tutor_course_complete_popup_' . get_current_user_id();
702
  $popup = get_option( $key );
703
 
704
+ if ( is_array( $popup ) ) {
705
 
706
+ if ( $popup['expires'] > time() ) {
707
  $course_id = $popup['course_id'];
708
+ include tutor()->path . 'views/modal/review.php';
709
  }
710
 
711
+ delete_option( $key );
712
  }
713
  }
714
  }
715
+
716
+ public function tutor_load_instructors_modal() {
717
  tutils()->checking_nonce();
718
+
719
  global $wpdb;
720
 
721
+ $course_id = (int) sanitize_text_field( $_POST['course_id'] );
722
+ $search_terms = sanitize_text_field( tutor_utils()->avalue_dot( 'search_terms', tutor_sanitize_data($_POST) ) );
723
 
724
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
725
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
726
  }
 
 
 
727
 
728
+ $saved_instructors = tutor_utils()->get_instructors_by_course( $course_id );
729
+ $instructors = array();
730
+
731
+ $not_in_sql = apply_filters( 'tutor_instructor_query_when_exists', ' AND ID <1 ' );
732
 
733
+ if ( $saved_instructors ) {
734
+ $saved_instructors_ids = wp_list_pluck( $saved_instructors, 'ID' );
735
+ $instructor_not_in_ids = implode( ',', $saved_instructors_ids );
736
+ $not_in_sql .= "AND user.ID NOT IN($instructor_not_in_ids) ";
737
  }
738
 
739
  $search_sql = '';
740
+ if ( $search_terms ) {
741
  $search_sql = "AND (user.user_login like '%{$search_terms}%' or user.user_nicename like '%{$search_terms}%' or user.display_name like '%{$search_terms}%') ";
742
  }
743
 
744
+ $instructors = $wpdb->get_results(
745
+ "SELECT user.ID, user.display_name from {$wpdb->users} user
746
  INNER JOIN {$wpdb->usermeta} meta ON user.ID = meta.user_id AND meta.meta_key = '_tutor_instructor_status' AND meta.meta_value = 'approved'
747
+ WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 "
748
+ );
749
 
750
  $output = '';
751
+ if ( is_array( $instructors ) && count( $instructors ) ) {
752
  $instructor_output = '';
753
+ foreach ( $instructors as $instructor ) {
754
+ $instructor_output .= '<p><label><input type="radio" name="tutor_instructor_ids[]" value="' . $instructor->ID . '" > ' . $instructor->display_name . ' </label></p>';
755
  }
756
 
757
+ $output .= apply_filters( 'tutor_course_instructors_html', $instructor_output, $instructors );
758
 
759
+ } else {
760
+ $output .= '<p>' . __( 'No instructor available or you have already added maximum instructors' ) . '</p>';
761
+ $output .= '<p>' . __( 'No instructor available or you have already added maximum instructors', 'tutor' ) . '</p>';
762
  }
763
 
764
+ if ( ! defined( 'TUTOR_MT_VERSION' ) ) {
765
+ $output .= '<p class="tutor-notice-warning" style="margin-top: 50px; font-size: 14px;">' . sprintf( __( 'To add unlimited multiple instructors in your course, get %1$sTutor LMS Pro%2$s', 'tutor' ), '<a href="https://www.themeum.com/product/tutor-lms" target="_blank">', '</a>' ) . '</p>';
 
766
  }
767
 
768
+ wp_send_json_success( array( 'output' => $output ) );
769
  }
770
 
771
+ public function tutor_add_instructors_to_course() {
772
  tutils()->checking_nonce();
773
 
774
+ $course_id = (int) sanitize_text_field( $_POST['course_id'] );
775
+ $instructor_ids = tutor_utils()->avalue_dot( 'tutor_instructor_ids', tutor_sanitize_data($_POST) );
776
+
777
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
778
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
779
  }
780
 
781
+ if ( is_array( $instructor_ids ) && count( $instructor_ids ) ) {
782
+ foreach ( $instructor_ids as $instructor_id ) {
783
+ add_user_meta( $instructor_id, '_tutor_instructor_course_id', $course_id );
784
  }
785
  }
786
 
787
+ $saved_instructors = tutor_utils()->get_instructors_by_course( $course_id );
788
+ $output = '';
789
 
790
+ if ( $saved_instructors ) {
791
+ foreach ( $saved_instructors as $t ) {
792
 
793
+ $output .= '<div id="added-instructor-id-' . $t->ID . '" class="added-instructor-item added-instructor-item-' . $t->ID . '" data-instructor-id="' . $t->ID . '">
794
+ <span class="instructor-icon">' . str_replace( "'", '"', get_avatar( $t->ID, 30 ) ) . '</span>
795
+ <span class="instructor-name"> ' . $t->display_name . ' </span>
796
  <span class="instructor-control">
797
  <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
798
  </span>
800
  }
801
  }
802
 
803
+ wp_send_json_success( array( 'output' => $output ) );
804
  }
805
 
806
+ public function detach_instructor_from_course() {
807
  tutils()->checking_nonce();
808
 
809
  global $wpdb;
810
 
811
+ $instructor_id = (int) sanitize_text_field( $_POST['instructor_id'] );
812
+ $course_id = (int) sanitize_text_field( $_POST['course_id'] );
813
 
814
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
815
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
816
  }
817
+
818
+ $wpdb->delete(
819
+ $wpdb->usermeta,
820
+ array(
821
+ 'user_id' => $instructor_id,
822
+ 'meta_key' => '_tutor_instructor_course_id',
823
+ 'meta_value' => $course_id,
824
+ )
825
+ );
826
  wp_send_json_success();
827
  }
828
 
829
+ public function tutor_delete_dashboard_course() {
830
  tutils()->checking_nonce();
831
 
832
+ $course_id = intval( sanitize_text_field( $_POST['course_id'] ) );
833
 
834
+ if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
835
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
836
  }
837
 
838
+ wp_trash_post( $course_id );
839
+ wp_send_json_success( array( 'element' => 'course' ) );
840
  }
841
 
842
 
843
+ public function tutor_add_gutenberg_author( $data, $postarr ) {
844
  global $wpdb;
845
 
846
  $courses_post_type = tutor()->course_post_type;
847
+ $post_type = tutils()->array_get( 'post_type', $postarr );
848
 
849
+ if ( $courses_post_type === $post_type ) {
850
+ $post_ID = (int) tutor_utils()->avalue_dot( 'ID', $postarr );
851
+ $post_author = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID ) );
852
 
853
+ if ( $post_author > 0 ) {
854
+ $data['post_author'] = $post_author;
855
+ } else {
856
+ $data['post_author'] = get_current_user_id();
857
+ }
858
+ }
859
 
860
  return $data;
861
  }
866
  * @param $postData
867
  *
868
  * Attach product during save course from the frontend course dashboard.
869
+ *
870
  * @return string
871
  *
872
  * @since v.1.3.4
873
  */
874
+ public function attach_product_with_course( $post_ID, $postData ) {
875
+ $attached_product_id = tutor_utils()->get_course_product_id( $post_ID );
876
+ $course_price = sanitize_text_field( tutor_utils()->array_get( 'course_price', $_POST ) );
877
 
878
+ if ( ! $course_price ) {
879
  return;
880
  }
881
 
882
+ $monetize_by = tutor_utils()->get_option( 'monetize_by' );
883
+ $course = get_post( $post_ID );
884
 
885
+ if ( $monetize_by === 'wc' ) {
886
 
887
  $is_update = false;
888
+ if ( $attached_product_id ) {
889
+ $wc_product = get_post_meta( $attached_product_id, '_product_version', true );
890
+ if ( $wc_product ) {
891
  $is_update = true;
892
  }
893
  }
894
 
895
+ if ( $is_update ) {
896
+ $productObj = wc_get_product( $attached_product_id );
897
+ $productObj->set_price( $course_price ); // set product price
898
+ $productObj->set_regular_price( $course_price ); // set product regular price
899
+ $productObj->set_sold_individually( true );
900
  $product_id = $productObj->save();
901
+ if ( $productObj->is_type( 'subscription' ) ) {
902
  update_post_meta( $attached_product_id, '_subscription_price', $course_price );
903
  }
904
  } else {
905
  $productObj = new \WC_Product();
906
+ $productObj->set_name( $course->post_title );
907
+ $productObj->set_status( 'publish' );
908
+ $productObj->set_price( $course_price ); // set product price
909
+ $productObj->set_regular_price( $course_price ); // set product regular price
910
+ $productObj->set_sold_individually( true );
911
 
912
  $product_id = $productObj->save();
913
+ if ( $product_id ) {
914
  update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
915
+ // Mark product for woocommerce
916
  update_post_meta( $product_id, '_virtual', 'yes' );
917
  update_post_meta( $product_id, '_tutor_product', 'yes' );
918
 
922
  }
923
  }
924
  }
925
+ } elseif ( $monetize_by === 'edd' ) {
 
926
 
927
  $is_update = false;
928
+
929
+ if ( $attached_product_id ) {
930
+ $edd_price = get_post_meta( $attached_product_id, 'edd_price', true );
931
+ if ( $edd_price ) {
932
  $is_update = true;
933
  }
934
  }
935
 
936
+ if ( $is_update ) {
937
+ // Update the product
938
  update_post_meta( $attached_product_id, 'edd_price', $course_price );
939
+ } else {
940
+ // Create new product
941
+
942
+ $post_arr = array(
943
+ 'post_type' => 'download',
944
+ 'post_title' => $course->post_title,
945
+ 'post_status' => 'publish',
946
+ 'post_author' => get_current_user_id(),
947
  );
948
  $download_id = wp_insert_post( $post_arr );
949
+ if ( $download_id ) {
950
+ // edd_price
951
  update_post_meta( $download_id, 'edd_price', $course_price );
952
 
953
  update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
954
+ // Mark product for EDD
955
  update_post_meta( $download_id, '_tutor_product', 'yes' );
956
 
957
  $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
958
  if ( $coursePostThumbnail ) {
959
  set_post_thumbnail( $download_id, $coursePostThumbnail );
960
  }
 
961
  }
 
962
  }
 
 
963
  }
964
 
965
  }
967
 
968
  /**
969
  * Add Course level to course settings
970
+ *
971
  * @since v.1.4.1
972
  */
973
+ public function add_course_level_to_settings() {
974
+ include tutor()->path . 'views/metabox/course-level-metabox.php';
975
  }
976
 
977
  /**
979
  *
980
  * @since v.1.4.8
981
  */
982
+ public function tutor_lesson_load_before() {
983
+ $course_id = tutils()->get_course_id_by_content( get_the_ID() );
984
+ $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course( $course_id );
985
+ if ( is_user_logged_in() ) {
986
+ $is_course_started = get_post_meta( $course_id, '_tutor_course_started', true );
987
+ if ( ! $completed_lessons && ! $is_course_started ) {
988
+ update_post_meta( $course_id, '_tutor_course_started', tutor_time() );
989
+ do_action( 'tutor/course/started', $course_id );
990
  }
991
  }
992
  }
993
 
994
  /**
995
  * Add Course level to course settings
996
+ *
997
  * @since v.1.4.8
998
  */
999
+ public function course_elements_enable_disable() {
1000
+ add_filter( 'tutor_course/single/completing-progress-bar', array( $this, 'enable_disable_course_progress_bar' ) );
1001
+ add_filter( 'tutor_course/single/material_includes', array( $this, 'enable_disable_material_includes' ) );
1002
+ add_filter( 'tutor_course/single/content', array( $this, 'enable_disable_course_content' ) );
1003
+ add_filter( 'tutor_course/single/benefits_html', array( $this, 'enable_disable_course_benefits' ) );
1004
+ add_filter( 'tutor_course/single/requirements_html', array( $this, 'enable_disable_course_requirements' ) );
1005
+ add_filter( 'tutor_course/single/audience_html', array( $this, 'enable_disable_course_target_audience' ) );
1006
+ add_filter( 'tutor_course/single/enrolled/nav_items', array( $this, 'enable_disable_course_nav_items' ) );
1007
  }
1008
 
1009
  /**
1010
  * Enable disable course progress bar
1011
+ *
1012
  * @since v.1.4.8
1013
  */
1014
+ public function enable_disable_course_progress_bar( $html ) {
1015
+ $disable_option = (bool) get_tutor_option( 'disable_course_progress_bar' );
1016
+ if ( $disable_option ) {
1017
  return '';
1018
  }
1019
  return $html;
1021
 
1022
  /**
1023
  * Enable disable material includes
1024
+ *
1025
  * @since v.1.4.8
1026
  */
1027
+ public function enable_disable_material_includes( $html ) {
1028
+ $disable_option = (bool) get_tutor_option( 'disable_course_material' );
1029
+ if ( $disable_option ) {
1030
  return '';
1031
  }
1032
  return $html;
1034
 
1035
  /**
1036
  * Enable disable course content
1037
+ *
1038
  * @since v.1.4.8
1039
  */
1040
+ public function enable_disable_course_content( $html ) {
1041
+ $disable_option = (bool) get_tutor_option( 'disable_course_description' );
1042
+ if ( $disable_option ) {
1043
  return '';
1044
  }
1045
  return $html;
1047
 
1048
  /**
1049
  * Enable disable course benefits
1050
+ *
1051
  * @since v.1.4.8
1052
  */
1053
+ public function enable_disable_course_benefits( $html ) {
1054
+ $disable_option = (bool) get_tutor_option( 'disable_course_benefits' );
1055
+ if ( $disable_option ) {
1056
  return '';
1057
  }
1058
  return $html;
1060
 
1061
  /**
1062
  * Enable disable course requirements
1063
+ *
1064
  * @since v.1.4.8
1065
  */
1066
+ public function enable_disable_course_requirements( $html ) {
1067
+ $disable_option = (bool) get_tutor_option( 'disable_course_requirements' );
1068
+ if ( $disable_option ) {
1069
  return '';
1070
  }
1071
  return $html;
1073
 
1074
  /**
1075
  * Enable disable course target audience
1076
+ *
1077
  * @since v.1.4.8
1078
  */
1079
+ public function enable_disable_course_target_audience( $html ) {
1080
+ $disable_option = (bool) get_tutor_option( 'disable_course_target_audience' );
1081
+ if ( $disable_option ) {
1082
  return '';
1083
  }
1084
  return $html;
1085
  }
1086
+
1087
  /**
1088
  * Enable disable course nav items
1089
+ *
1090
  * @since v.1.4.8
1091
  */
1092
+ public function enable_disable_course_nav_items( $items ) {
1093
  global $wp_query, $post;
1094
+ $enable_q_and_a_on_course = (bool) get_tutor_option( 'enable_q_and_a_on_course' );
1095
+ $disable_course_announcements = (bool) get_tutor_option( 'disable_course_announcements' );
1096
 
1097
+ $disable_qa_for_this_course = ( $wp_query->is_single && ! empty( $post ) ) ? get_post_meta( $post->ID, '_tutor_disable_qa', true ) : '';
1098
 
1099
+ if ( ! $enable_q_and_a_on_course || $disable_qa_for_this_course == 'yes' ) {
1100
+ if ( tutils()->array_get( 'questions', $items ) ) {
1101
+ unset( $items['questions'] );
1102
  }
1103
  }
1104
+ if ( $disable_course_announcements ) {
1105
+ if ( tutils()->array_get( 'announcements', $items ) ) {
1106
+ unset( $items['announcements'] );
1107
  }
1108
  }
1109
  return $items;
1111
 
1112
  /**
1113
  * Filter product in shop page
1114
+ *
1115
  * @since v.1.4.9
1116
  */
1117
+ public function filter_product_in_shop_page() {
1118
+ $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' );
1119
+ if ( ! $hide_course_from_shop_page ) {
1120
  return;
1121
  }
1122
+ add_action( 'woocommerce_product_query', array( $this, 'filter_woocommerce_product_query' ) );
1123
+ add_filter( 'edd_downloads_query', array( $this, 'filter_edd_downloads_query' ), 10, 2 );
1124
+ add_action( 'pre_get_posts', array( $this, 'filter_archive_meta_query' ), 1 );
1125
  }
1126
 
1127
  /**
1128
  * Tutor product meta query
1129
+ *
1130
  * @since v.1.4.9
1131
  */
1132
+ public function tutor_product_meta_query() {
1133
  $meta_query = array(
1134
+ 'key' => '_tutor_product',
1135
+ 'compare' => 'NOT EXISTS',
1136
  );
1137
  return $meta_query;
1138
  }
1139
 
1140
  /**
1141
  * Filter product in woocommerce shop page
1142
+ *
1143
  * @since v.1.4.9
1144
  */
1145
+ public function filter_woocommerce_product_query( $wp_query ) {
1146
+ $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1147
  return $wp_query;
1148
  }
1149
 
1150
  /**
1151
  * Filter product in edd downloads shortcode page
1152
+ *
1153
  * @since v.1.4.9
1154
  */
1155
+ public function filter_edd_downloads_query( $query ) {
1156
  $query['meta_query'][] = $this->tutor_product_meta_query();
1157
  return $query;
1158
  }
1159
 
1160
  /**
1161
  * Filter product in edd downloads archive page
1162
+ *
1163
  * @since v.1.4.9
1164
  */
1165
+ public function filter_archive_meta_query( $wp_query ) {
1166
+ if ( ! is_admin() && $wp_query->is_archive && $wp_query->get( 'post_type' ) === 'download' ) {
1167
+ $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1168
  }
1169
  return $wp_query;
1170
  }
1171
 
1172
+ /**
1173
+ * @param $html
1174
+ * @return string
1175
+ *
1176
+ * Removed course price if already enrolled at single course
1177
+ *
1178
+ * @since v.1.5.8
1179
+ */
1180
+ public function remove_price_if_enrolled( $html ) {
1181
+ $should_removed = apply_filters( 'should_remove_price_if_enrolled', true );
1182
+
1183
+ if ( $should_removed ) {
1184
+ $course_id = get_the_ID();
1185
+ $enrolled = tutils()->is_enrolled( $course_id );
1186
+ if ( $enrolled ) {
1187
+ $html = '';
1188
+ }
1189
+ }
1190
+ return $html;
1191
+ }
1192
+
1193
+ /**
1194
+ * @param $html
1195
+ * @return string
1196
+ *
1197
+ * Check if all lessons and quizzes done before mark course complete.
1198
+ */
1199
+ function tutor_lms_hide_course_complete_btn( $html ) {
1200
+
1201
+ $completion_mode = tutils()->get_option( 'course_completion_process' );
1202
+ if ( $completion_mode !== 'strict' ) {
1203
+ return $html;
1204
+ }
1205
+
1206
+ $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1207
+ $lesson_count = tutils()->get_lesson_count_by_course();
1208
+
1209
+ if ( $completed_lesson < $lesson_count ) {
1210
+ return '<p class="suggestion-before-course-complete">' . __( 'complete all lessons to mark this course as complete', 'tutor' ) . '</p>';
1211
+ }
1212
+
1213
+ $quizzes = array();
1214
+
1215
+ $course_contents = tutils()->get_course_contents_by_id();
1216
+ if ( tutils()->count( $course_contents ) ) {
1217
+ foreach ( $course_contents as $content ) {
1218
+ if ( $content->post_type === 'tutor_quiz' ) {
1219
+ $quizzes[] = $content;
1220
+ }
1221
+ }
1222
+ }
1223
+
1224
+ $is_pass = true;
1225
+ $required_quiz_pass = 0;
1226
+
1227
+ if ( tutils()->count( $quizzes ) ) {
1228
+ foreach ( $quizzes as $quiz ) {
1229
+
1230
+ $attempt = tutils()->get_quiz_attempt( $quiz->ID );
1231
+ if ( $attempt ) {
1232
+ $passing_grade = tutor_utils()->get_quiz_option( $quiz->ID, 'passing_grade', 0 );
1233
+ $earned_percentage = $attempt->earned_marks > 0 ? ( number_format( ( $attempt->earned_marks * 100 ) / $attempt->total_marks ) ) : 0;
1234
+
1235
+ if ( $earned_percentage < $passing_grade ) {
1236
+ $required_quiz_pass++;
1237
+ $is_pass = false;
1238
+ }
1239
+ } else {
1240
+ $required_quiz_pass++;
1241
+ $is_pass = false;
1242
+ }
1243
+ }
1244
+ }
1245
+
1246
+ if ( ! $is_pass ) {
1247
+ return '<p class="suggestion-before-course-complete">' . sprintf( __( 'You have to pass %s quizzes to complete this course.', 'tutor' ), $required_quiz_pass ) . '</p>';
1248
+ }
1249
+
1250
+ return $html;
1251
+ }
1252
+
1253
+ public function get_generate_greadbook( $html ) {
1254
+ if ( ! tutils()->is_completed_course() ) {
1255
+ return '';
1256
+ }
1257
+ return $html;
1258
  }
1259
 
1260
  /**
1261
  * Add social share content in header
1262
+ *
1263
  * @since v.1.6.3
1264
  */
1265
+ public function social_share_content() {
1266
  global $wp_query, $post;
1267
+ if ( $wp_query->is_single && ! empty( $wp_query->query_vars['post_type'] ) && $wp_query->query_vars['post_type'] === $this->course_post_type ) { ?>
1268
  <!--Facebook-->
1269
  <meta property="og:type" content="website"/>
1270
+ <meta property="og:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>" />
1271
+ <meta property="og:description" content="<?php echo esc_html( $post->post_content ); ?>" />
1272
  <!--Twitter-->
1273
+ <meta name="twitter:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1274
+ <meta name="twitter:description" content="<?php echo esc_html( $post->post_content ); ?>">
1275
  <!--Google+-->
1276
+ <meta itemprop="image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1277
+ <meta itemprop="description" content="<?php echo esc_html( $post->post_content ); ?>">
1278
+ <?php
1279
  }
1280
  }
1281
 
1282
  /**
1283
  * Get posts by type and parent
1284
+ *
1285
  * @since v.1.6.6
1286
  */
1287
+ public function tutor_get_post_ids( $post_type, $post_parent ) {
1288
  $args = array(
1289
+ 'fields' => 'ids',
1290
  'post_type' => $post_type,
1291
  'post_parent' => $post_parent,
1292
  'post_status' => 'any',
1293
  'posts_per_page' => -1,
1294
  );
1295
+ return get_posts( $args );
1296
  }
1297
+
1298
  /**
1299
  * Delete course data when permanently deleting a course.
1300
+ *
1301
  * @since v.1.6.6
1302
  */
1303
  function delete_tutor_course_data( $post_id ) {
1304
  $course_post_type = tutor()->course_post_type;
1305
  $lesson_post_type = tutor()->lesson_post_type;
1306
 
1307
+ if ( get_post_type( $post_id ) == $course_post_type ) {
1308
  global $wpdb;
1309
+ $topic_ids = $this->tutor_get_post_ids( 'topics', $post_id );
1310
+ if ( ! empty( $topic_ids ) ) {
1311
+ foreach ( $topic_ids as $topic_id ) {
1312
+ $content_post_type = apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) );
1313
+ $topic_content_ids = $this->tutor_get_post_ids( $content_post_type, $topic_id );
1314
+
1315
+ foreach ( $topic_content_ids as $content_id ) {
1316
+ if ( get_post_type( $content_id ) == 'tutor_quiz' ) {
1317
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempts', array( 'quiz_id' => $content_id ) );
1318
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempt_answers', array( 'quiz_id' => $content_id ) );
1319
+
1320
+ $questions_ids = $wpdb->get_col( $wpdb->prepare( "SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id ) );
1321
+ if ( is_array( $questions_ids ) && count( $questions_ids ) ) {
1322
+ $in_question_ids = "'" . implode( "','", $questions_ids ) . "'";
1323
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) " );
1324
  }
1325
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'quiz_id' => $content_id ) );
1326
  }
1327
+ wp_delete_post( $content_id, true );
1328
  }
1329
+ wp_delete_post( $topic_id, true );
1330
  }
1331
  }
1332
+ $child_post_ids = $this->tutor_get_post_ids( array( 'tutor_announcements', 'tutor_enrolled' ), $post_id );
1333
+ if ( ! empty( $child_post_ids ) ) {
1334
+ foreach ( $child_post_ids as $child_post_id ) {
1335
+ wp_delete_post( $child_post_id, true );
1336
  }
1337
  }
1338
  }
1340
 
1341
  /**
1342
  * tutor course setting metabox
1343
+ *
1344
  * @since v.1.7.0
1345
  */
1346
  function tutor_course_setting_metabox( $post ) {
1347
+
1348
  $disable_qa = $this->additional_meta[0];
1349
+ $is_public = $this->additional_meta[1];
1350
 
1351
+ $disable_qa_checked = get_post_meta( $post->ID, $disable_qa, true ) == 'yes' ? 'checked="checked"' : '';
1352
+ $is_public_checked = get_post_meta( $post->ID, $is_public, true ) == 'yes' ? 'checked="checked"' : '';
1353
 
1354
+ do_action( 'tutor_before_course_sidebar_settings_metabox', $post );
1355
  ?>
1356
  <div class="tutor-course-sidebar-settings-item" id="_tutor_is_course_public_meta_checkbox" style="display:none">
1357
+ <label for="<?php echo esc_attr( $is_public ); ?>">
1358
+ <input id="<?php echo esc_attr( $is_public ); ?>" type="checkbox" name="<?php echo esc_attr( $is_public ); ?>" value="yes" <?php echo $is_public_checked; ?> />
1359
+ <?php _e( 'Make This Course Public', 'tutor' ); ?>
1360
  <small style="display:block;padding-left:24px">
1361
+ <?php _e( 'No enrollment required.', 'tutor' ); ?>
1362
  </small>
1363
  </label>
1364
  </div>
1365
  <div class="tutor-course-sidebar-settings-item">
1366
+ <label for="<?php echo esc_attr( $disable_qa ); ?>">
1367
  <input type="hidden" name="_tutor_course_additional_data_edit" value="true" />
1368
+ <input id="<?php echo esc_attr( $disable_qa ); ?>" type="checkbox" name="<?php echo esc_attr( $disable_qa ); ?>" value="yes" <?php echo $disable_qa_checked; ?> />
1369
+ <?php _e( 'Disable Q&A', 'tutor' ); ?>
1370
  </label>
1371
  </div>
1372
  <?php
1373
+ do_action( 'tutor_after_course_sidebar_settings_metabox', $post );
1374
  }
1375
 
1376
+ function tutor_course_setting_metabox_frontend( $post ) {
1377
+ ?>
1378
  <div class="tutor-course-builder-section tutor-course-builder-info">
1379
  <div class="tutor-course-builder-section-title">
1380
+ <h3><i class="tutor-icon-down"></i><span><?php esc_html_e( 'Tutor Settings', 'tutor' ); ?></span></h3>
1381
  </div>
1382
  <div class="tutor-course-builder-section-content">
1383
  <div class="tutor-frontend-builder-item-scope">
1384
  <div class="tutor-form-group">
1385
+ <?php $this->tutor_course_setting_metabox( $post ); ?>
1386
  </div>
1387
  </div>
1388
  </div>
1392
 
1393
  /**
1394
  * Delete associated enrollment
1395
+ *
1396
  * @since v.1.8.2
1397
  */
1398
+ public function delete_associated_enrollment( $post_id ) {
1399
+ global $wpdb;
1400
 
1401
+ $enroll_id = $wpdb->get_var(
1402
+ $wpdb->prepare(
1403
+ "SELECT
1404
+ post_id
1405
+ FROM
1406
  {$wpdb->postmeta}
1407
+ WHERE
1408
+ meta_key='_tutor_enrolled_by_order_id'
1409
  AND meta_value = %d
1410
+ ",
1411
+ $post_id
1412
+ )
1413
+ );
1414
+
1415
+ if ( is_numeric( $enroll_id ) && $enroll_id > 0 ) {
1416
 
1417
+ $course_id = get_post_field( 'post_parent', $enroll_id );
1418
+ $user_id = get_post_field( 'post_author', $enroll_id );
1419
 
1420
+ tutils()->cancel_course_enrol( $course_id, $user_id );
1421
+ }
1422
+ }
1423
 
1424
  public function tutor_reset_course_progress() {
1425
  tutils()->checking_nonce();
1426
+ $course_id = tutor_utils()->array_get( 'course_id', tutor_sanitize_data($_POST) );
1427
 
1428
+ if ( ! $course_id || ! is_numeric( $course_id ) || ! tutor_utils()->is_enrolled( $course_id ) ) {
1429
+ wp_send_json_error( array( 'message' => __( 'Invalid Course ID or Access Denied.', 'tutor' ) ) );
1430
  return;
1431
  }
1432
 
1433
+ tutor_utils()->delete_course_progress( $course_id );
1434
+ wp_send_json_success( array( 'redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ) );
1435
  }
1436
 
1437
  /**
1438
  * Do enroll if guest attempt to enroll and course is free
1439
+ *
1440
  * @param $course_id
1441
+ *
1442
  * @since 1.9.8
1443
  */
1444
  public function enroll_after_login_if_attempt( $course_id ) {
1445
  $course_id = sanitize_text_field( $course_id );
1446
  if ( $course_id ) {
1447
+ $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
1448
+ if ( ! $is_purchasable ) {
1449
+ tutor_utils()->do_enroll( $course_id );
1450
  do_action( 'guest_attempt_after_enrollment', $course_id );
1451
  }
1452
  }
1453
  }
1454
+ }
classes/Course_Filter.php CHANGED
@@ -1,158 +1,167 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- class Course_Filter{
8
- private $category = 'course-category';
9
- private $tag = 'course-tag';
10
- private $current_term_id = null;
11
 
12
- function __construct(){
13
- add_action('wp_ajax_tutor_course_filter_ajax', array($this, 'load_listing'));
14
- add_action('wp_ajax_nopriv_tutor_course_filter_ajax', array($this, 'load_listing'));
15
- }
16
 
17
- public function load_listing(){
18
  tutils()->checking_nonce();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
- $default_per_page = tutils()->get_option('courses_per_page', 12);
21
- $courses_per_page = (int)sanitize_text_field(tutils()->array_get('course_per_page', $_POST, $default_per_page));
22
- $page = (isset($_POST['page']) && is_numeric($_POST['page']) && $_POST['page']>0) ? $_POST['page'] : 1;
23
-
24
- $args = array(
25
- 'post_status' => 'publish',
26
- 'post_type' => 'courses',
27
- 'posts_per_page' => $courses_per_page,
28
- 'paged' => $page,
29
- 'tax_query'=> array(
30
- 'relation' => 'OR',
31
- )
32
- );
33
-
34
- // Prepare taxonomy
35
- foreach(array('category', 'tag') as $taxonomy) {
36
-
37
- $term_array = tutils()->array_get('tutor-course-filter-'.$taxonomy, $_POST, array());
38
- !is_array($term_array) ? $term_array = array($term_array) : 0;
39
-
40
- $term_array = array_filter($term_array, function($term_id) {
41
- return is_numeric($term_id);
42
- });
43
-
44
- if(count( $term_array ) > 0) {
45
- $tax_query =array(
46
- 'taxonomy' => $this->$taxonomy,
47
- 'field' => 'term_id',
48
- 'terms' => $term_array,
49
- 'operator' => 'IN'
50
- );
51
- array_push($args['tax_query'], $tax_query);
52
- }
53
- }
54
-
55
- // Prepare level and price type
56
- $is_membership = get_tutor_option('monetize_by')=='pmpro' && tutils()->has_pmpro();
57
- $level_price=array();
58
- foreach(array( 'level', 'price' ) as $type){
59
-
60
- if($is_membership && $type=='price'){
61
- continue;
62
- }
63
-
64
- $type_array = tutils()->array_get('tutor-course-filter-'.$type, $_POST, array());
65
- $type_array = array_map('sanitize_text_field', (is_array($type_array) ? $type_array : array($type_array)));
66
-
67
- if(count( $type_array ) > 0){
68
- $level_price[] = array(
69
- 'key' => $type=='level' ? '_tutor_course_level' : '_tutor_course_price_type',
70
- 'value' => $type_array,
71
- 'compare' => 'IN'
72
- );
73
- }
74
- }
75
- count($level_price) ? $args['meta_query'] = $level_price : 0;
76
-
77
- $search_key = sanitize_text_field(tutils()->array_get('keyword', $_POST, null));
78
- $search_key ? $args['s'] = $search_key : 0;
79
-
80
- if(isset($_POST['tutor_course_filter'])){
81
- switch ($_POST['tutor_course_filter']){
82
- case 'newest_first':
83
- $args['orderby']='ID';
84
- $args['order']='desc';
85
- break;
86
- case 'oldest_first':
87
- $args['orderby']='ID';
88
- $args['order']='asc';
89
- break;
90
- case 'course_title_az':
91
- $args['orderby']='post_title';
92
- $args['order']='asc';
93
- break;
94
- case 'course_title_za':
95
- $args['orderby']='post_title';
96
- $args['order']='desc';
97
- break;
98
- }
99
- }
100
-
101
- query_posts( apply_filters( 'tutor_course_filter_args', $args ) );
102
- $col_per_row = (int)sanitize_text_field(tutils()->array_get('column_per_row', $_POST, 3));
103
- $GLOBALS['tutor_shortcode_arg']=array(
104
- 'column_per_row' => $col_per_row<=0 ? 3 : $col_per_row,
105
- 'course_per_page' => $courses_per_page
106
  );
107
-
108
- tutor_load_template('archive-course-init');
109
- exit;
110
- }
111
-
112
- private function get_current_term_id(){
113
-
114
- if($this->current_term_id===null){
115
- $queried = get_queried_object();
116
- $this->current_term_id = (is_object($queried) && property_exists($queried, 'term_id')) ? $queried->term_id : false;
117
- }
118
-
119
- return $this->current_term_id;
120
- }
121
-
122
- private function sort_terms_hierarchically($terms, $parent_id=0)
123
- {
124
- $term_array = array();
125
-
126
- foreach($terms as $term) {
127
- if($term->parent==$parent_id) {
128
- $term->children = $this->sort_terms_hierarchically($terms, $term->term_id);
129
- $term_array[] = $term;
130
- }
131
- }
132
-
133
- return $term_array;
134
- }
135
-
136
- private function render_terms_hierarchically($terms, $taxonomy) {
137
-
138
- $term_id = $this->get_current_term_id();
139
-
140
- foreach($terms as $term){
141
- ?>
142
- <div class="tutor-course-filter-nested-terms">
143
- <label>
144
- <input type="checkbox" name="tutor-course-filter-<?php echo $taxonomy; ?>" value="<?php echo $term->term_id; ?>" <?php echo $term->term_id==$term_id ? 'checked="checked"' : ''; ?>/>&nbsp;
145
- <?php echo $term->name; ?>
146
- </label>
147
-
148
- <?php isset($term->children) ? $this->render_terms_hierarchically($term->children, $taxonomy) : 0; ?>
149
- </div>
150
- <?php
151
- }
152
- }
153
-
154
- public function render_terms($taxonomy){
155
- $terms = get_terms( array('taxonomy' => $this->$taxonomy, 'hide_empty' => true));
156
- $this->render_terms_hierarchically( $this->sort_terms_hierarchically( $terms ), $taxonomy );
157
- }
158
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ class Course_Filter {
9
+ private $category = 'course-category';
10
+ private $tag = 'course-tag';
11
+ private $current_term_id = null;
12
 
13
+ function __construct() {
14
+ add_action( 'wp_ajax_tutor_course_filter_ajax', array( $this, 'load_listing' ) );
15
+ add_action( 'wp_ajax_nopriv_tutor_course_filter_ajax', array( $this, 'load_listing' ) );
16
+ }
17
 
18
+ public function load_listing() {
19
  tutils()->checking_nonce();
20
+ $_post = tutor_sanitize_data( $_POST );
21
+
22
+ $default_per_page = tutils()->get_option( 'courses_per_page', 12 );
23
+ $courses_per_page = (int) sanitize_text_field( tutils()->array_get( 'course_per_page', $_post, $default_per_page ) );
24
+ $page = ( isset( $_post['page'] ) && is_numeric( $_post['page'] ) && $_post['page'] > 0 ) ? sanitize_text_field( $_post['page'] ) : 1;
25
+
26
+ $args = array(
27
+ 'post_status' => 'publish',
28
+ 'post_type' => 'courses',
29
+ 'posts_per_page' => $courses_per_page,
30
+ 'paged' => $page,
31
+ 'tax_query' => array(
32
+ 'relation' => 'OR',
33
+ ),
34
+ );
35
+
36
+ // Prepare taxonomy
37
+ foreach ( array( 'category', 'tag' ) as $taxonomy ) {
38
+
39
+ $term_array = tutils()->array_get( 'tutor-course-filter-' . $taxonomy, $_post, array() );
40
+ ! is_array( $term_array ) ? $term_array = array( $term_array ) : 0;
41
+
42
+ $term_array = array_filter(
43
+ $term_array,
44
+ function( $term_id ) {
45
+ return is_numeric( $term_id );
46
+ }
47
+ );
48
+
49
+ if ( count( $term_array ) > 0 ) {
50
+ $tax_query = array(
51
+ 'taxonomy' => $this->$taxonomy,
52
+ 'field' => 'term_id',
53
+ 'terms' => $term_array,
54
+ 'operator' => 'IN',
55
+ );
56
+ array_push( $args['tax_query'], $tax_query );
57
+ }
58
+ }
59
+
60
+ // Prepare level and price type
61
+ $is_membership = get_tutor_option( 'monetize_by' ) == 'pmpro' && tutils()->has_pmpro();
62
+ $level_price = array();
63
+ foreach ( array( 'level', 'price' ) as $type ) {
64
+
65
+ if ( $is_membership && 'price' === $type ) {
66
+ continue;
67
+ }
68
+
69
+ $type_array = tutils()->array_get( 'tutor-course-filter-' . $type, $_post, array() );
70
+ $type_array = array_map( 'sanitize_text_field', ( is_array( $type_array ) ? $type_array : array( $type_array ) ) );
71
+
72
+ if ( count( $type_array ) > 0 ) {
73
+ $level_price[] = array(
74
+ 'key' => 'level' === $type ? '_tutor_course_level' : '_tutor_course_price_type',
75
+ 'value' => $type_array,
76
+ 'compare' => 'IN',
77
+ );
78
+ }
79
+ }
80
+ count( $level_price ) ? $args['meta_query'] = $level_price : 0;
81
+
82
+ $search_key = sanitize_text_field( tutils()->array_get( 'keyword', $_post, null ) );
83
+ $search_key ? $args['s'] = $search_key : 0;
84
+
85
+ if ( isset( $_post['tutor_course_filter'] ) ) {
86
+ switch ( $_post['tutor_course_filter'] ) {
87
+ case 'newest_first':
88
+ $args['orderby'] = 'ID';
89
+ $args['order'] = 'desc';
90
+ break;
91
+ case 'oldest_first':
92
+ $args['orderby'] = 'ID';
93
+ $args['order'] = 'asc';
94
+ break;
95
+ case 'course_title_az':
96
+ $args['orderby'] = 'post_title';
97
+ $args['order'] = 'asc';
98
+ break;
99
+ case 'course_title_za':
100
+ $args['orderby'] = 'post_title';
101
+ $args['order'] = 'desc';
102
+ break;
103
+ }
104
+ }
105
+
106
+ query_posts( apply_filters( 'tutor_course_filter_args', $args ) );
107
+ $col_per_row = (int) sanitize_text_field( tutils()->array_get( 'column_per_row', $_post, 3 ) );
108
+ $GLOBALS['tutor_shortcode_arg'] = array(
109
+ 'column_per_row' => $col_per_row <= 0 ? 3 : $col_per_row,
110
+ 'course_per_page' => $courses_per_page,
111
+ );
112
 
113
+ tutor_load_template( 'archive-course-init' );
114
+ exit;
115
+ }
116
+
117
+ private function get_current_term_id() {
118
+
119
+ if ( $this->current_term_id === null ) {
120
+ $queried = get_queried_object();
121
+ $this->current_term_id = ( is_object( $queried ) && property_exists( $queried, 'term_id' ) ) ? $queried->term_id : false;
122
+ }
123
+
124
+ return $this->current_term_id;
125
+ }
126
+
127
+ private function sort_terms_hierarchically( $terms, $parent_id = 0 ) {
128
+ $term_array = array();
129
+
130
+ foreach ( $terms as $term ) {
131
+ if ( $term->parent == $parent_id ) {
132
+ $term->children = $this->sort_terms_hierarchically( $terms, $term->term_id );
133
+ $term_array[] = $term;
134
+ }
135
+ }
136
+
137
+ return $term_array;
138
+ }
139
+
140
+ private function render_terms_hierarchically( $terms, $taxonomy ) {
141
+
142
+ $term_id = $this->get_current_term_id();
143
+
144
+ foreach ( $terms as $term ) {
145
+ ?>
146
+ <div class="tutor-course-filter-nested-terms">
147
+ <label>
148
+ <input type="checkbox" name="tutor-course-filter-<?php echo esc_attr( $taxonomy ); ?>" value="<?php echo $term->term_id; ?>" <?php echo $term->term_id == $term_id ? 'checked' : ''; ?>/>&nbsp;
149
+ <?php echo $term->name; ?>
150
+ </label>
151
+
152
+ <?php isset( $term->children ) ? $this->render_terms_hierarchically( $term->children, $taxonomy ) : 0; ?>
153
+ </div>
154
+ <?php
155
+ }
156
+ }
157
+
158
+ public function render_terms( $taxonomy ) {
159
+ $terms = get_terms(
160
+ array(
161
+ 'taxonomy' => $this->$taxonomy,
162
+ 'hide_empty' => true,
163
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  );
165
+ $this->render_terms_hierarchically( $this->sort_terms_hierarchically( $terms ), $taxonomy );
166
+ }
167
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
classes/Course_Settings_Tabs.php CHANGED
@@ -1,119 +1,120 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
- exit;
6
-
7
- class Course_Settings_Tabs{
8
-
9
- public $course_post_type = '';
10
- public $is_gutenberg_enable = false;
11
- public $args = array();
12
- public $settings_meta = null;
13
-
14
- public function __construct() {
15
- $this->course_post_type = tutor()->course_post_type;
16
- $isGutenberg = apply_filters( 'use_block_editor_for_post_type', true, 'courses' );
17
- $this->is_gutenberg_enable = $isGutenberg;
18
-
19
- if ($isGutenberg){
20
- //MetaBox
21
- add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
22
- }else{
23
- add_action( 'edit_form_after_editor', array($this, 'display'), 10, 0 );
24
- }
25
- add_action( 'tutor/frontend_course_edit/after/description', array($this, 'display'), 10, 0 );
26
-
27
- add_action('tutor_save_course', array($this, 'save_course'), 10, 2);
28
- }
29
-
30
- public function register_meta_box(){
31
- add_meta_box( 'course-settings', __( 'Course Settings', 'tutor' ), array($this, 'display'), $this->course_post_type, 'advanced', 'high' );
32
- }
33
-
34
- public function get_default_args(){
35
- $args = array(
36
- 'general' => array(
37
- 'label' => __('General', 'tutor'),
38
- 'desc' => __('General Settings', 'tutor'),
39
- 'icon_class' => ' tutor-icon-settings-1',
40
- 'callback' => '',
41
- 'fields' => array(
42
- 'maximum_students' => array(
43
- 'type' => 'number',
44
- 'label' => __('Maximum Students', 'tutor'),
45
- 'label_title' => __('Enable', 'tutor'),
46
- 'default' => '0',
47
- 'desc' => __('Number of students that can enrol in this course. Set 0 for no limits.', 'tutor'),
48
- ),
49
- ),
50
- ),
51
- );
52
-
53
- return apply_filters('tutor_course_settings_tabs', $args);
54
- }
55
-
56
- public function display(){
57
- global $post;
58
- $this->args = $this->get_default_args();
59
-
60
- $settings_meta = get_post_meta(get_the_ID(), '_tutor_course_settings', true);
61
- $this->settings_meta = (array) maybe_unserialize($settings_meta);
62
-
63
- if (tutils()->count($this->args) && $post->post_type === $this->course_post_type) {
64
- include tutor()->path . "views/metabox/course/settings-tabs.php";
65
- }
66
- }
67
-
68
- public function generate_field($fields = array()){
69
- if (tutils()->count($fields)){
70
- foreach ($fields as $field_key => $field){
71
- $type = tutils()->array_get('type', $field);
72
- ?>
73
- <div class="tutor-option-field-row tutor-field-row-<?php echo $type; ?>">
74
- <?php
75
- if (isset($field['label'])){
76
- ?>
77
- <div class="tutor-option-field-label">
78
- <label for=""><?php echo $field['label']; ?></label>
79
- </div>
80
- <?php
81
- }
82
- ?>
83
- <div class="tutor-option-field tutor-field-<?php echo $type; ?>">
84
- <?php
85
- $field['field_key'] = $field_key;
86
- $this->field_type($field);
87
- if (isset($field['desc'])){
88
- echo "<p class='desc'>{$field['desc']}</p>";
89
- }
90
- ?>
91
- </div>
92
- </div>
93
- <?php
94
- }
95
- }
96
- }
97
-
98
- public function field_type($field = array()){
99
- include tutor()->path."views/metabox/course/field-types/{$field['type']}.php";
100
- }
101
-
102
- public function get($key = null, $default = false){
103
- return tutils()->array_get($key, $this->settings_meta, $default);
104
- }
105
-
106
- /**
107
- * @param $post_ID
108
- * @param $post
109
- *
110
- * Fire when course saving...
111
- */
112
- public function save_course($post_ID, $post){
113
- $_tutor_course_settings = tutils()->array_get('_tutor_course_settings', $_POST);
114
- if (tutils()->count($_tutor_course_settings)){
115
- update_post_meta($post_ID, '_tutor_course_settings', $_tutor_course_settings);
116
- }
117
- }
118
-
119
- }
 
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
+ exit;
6
+ }
7
+
8
+ class Course_Settings_Tabs {
9
+
10
+ public $course_post_type = '';
11
+ public $is_gutenberg_enable = false;
12
+ public $args = array();
13
+ public $settings_meta = null;
14
+
15
+ public function __construct() {
16
+ $this->course_post_type = tutor()->course_post_type;
17
+ $isGutenberg = apply_filters( 'use_block_editor_for_post_type', true, 'courses' );
18
+ $this->is_gutenberg_enable = $isGutenberg;
19
+
20
+ if ( $isGutenberg ) {
21
+ // MetaBox
22
+ add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ) );
23
+ } else {
24
+ add_action( 'edit_form_after_editor', array( $this, 'display' ), 10, 0 );
25
+ }
26
+ add_action( 'tutor/frontend_course_edit/after/description', array( $this, 'display' ), 10, 0 );
27
+
28
+ add_action( 'tutor_save_course', array( $this, 'save_course' ), 10, 2 );
29
+ }
30
+
31
+ public function register_meta_box() {
32
+ add_meta_box( 'course-settings', __( 'Course Settings', 'tutor' ), array( $this, 'display' ), $this->course_post_type, 'advanced', 'high' );
33
+ }
34
+
35
+ public function get_default_args() {
36
+ $args = array(
37
+ 'general' => array(
38
+ 'label' => __( 'General', 'tutor' ),
39
+ 'desc' => __( 'General Settings', 'tutor' ),
40
+ 'icon_class' => ' tutor-icon-settings-1',
41
+ 'callback' => '',
42
+ 'fields' => array(
43
+ 'maximum_students' => array(
44
+ 'type' => 'number',
45
+ 'label' => __( 'Maximum Students', 'tutor' ),
46
+ 'label_title' => __( 'Enable', 'tutor' ),
47
+ 'default' => '0',
48
+ 'desc' => __( 'Number of students that can enrol in this course. Set 0 for no limits.', 'tutor' ),
49
+ ),
50
+ ),
51
+ ),
52
+ );
53
+
54
+ return apply_filters( 'tutor_course_settings_tabs', $args );
55
+ }
56
+
57
+ public function display() {
58
+ global $post;
59
+ $this->args = $this->get_default_args();
60
+
61
+ $settings_meta = get_post_meta( get_the_ID(), '_tutor_course_settings', true );
62
+ $this->settings_meta = (array) maybe_unserialize( $settings_meta );
63
+
64
+ if ( tutils()->count( $this->args ) && $post->post_type === $this->course_post_type ) {
65
+ include tutor()->path . 'views/metabox/course/settings-tabs.php';
66
+ }
67
+ }
68
+
69
+ public function generate_field( $fields = array() ) {
70
+ if ( tutils()->count( $fields ) ) {
71
+ foreach ( $fields as $field_key => $field ) {
72
+ $type = tutils()->array_get( 'type', $field );
73
+ ?>
74
+ <div class="tutor-option-field-row tutor-field-row-<?php echo esc_attr( $type ); ?>">
75
+ <?php
76
+ if ( isset( $field['label'] ) ) {
77
+ ?>
78
+ <div class="tutor-option-field-label">
79
+ <label for=""><?php echo $field['label']; ?></label>
80
+ </div>
81
+ <?php
82
+ }
83
+ ?>
84
+ <div class="tutor-option-field tutor-field-<?php echo esc_attr( $type ); ?>">
85
+ <?php
86
+ $field['field_key'] = $field_key;
87
+ $this->field_type( $field );
88
+ if ( isset( $field['desc'] ) ) {
89
+ printf( "<p class='desc'>%s</p>", $field['desc'] );
90
+ }
91
+ ?>
92
+ </div>
93
+ </div>
94
+ <?php
95
+ }
96
+ }
97
+ }
98
+
99
+ public function field_type( $field = array() ) {
100
+ include tutor()->path . "views/metabox/course/field-types/{$field['type']}.php";
101
+ }
102
+
103
+ public function get( $key = null, $default = false ) {
104
+ return tutils()->array_get( $key, $this->settings_meta, $default );
105
+ }
106
+
107
+ /**
108
+ * @param $post_ID
109
+ * @param $post
110
+ *
111
+ * Fire when course saving...
112
+ */
113
+ public function save_course( $post_ID, $post ) {
114
+ $_tutor_course_settings = tutils()->array_get( '_tutor_course_settings', tutor_sanitize_data($_POST) );
115
+ if ( tutils()->count( $_tutor_course_settings ) ) {
116
+ update_post_meta( $post_ID, '_tutor_course_settings', $_tutor_course_settings );
117
+ }
118
+ }
119
+
120
+ }
classes/Course_Widget.php CHANGED
@@ -11,16 +11,17 @@
11
 
12
  namespace TUTOR;
13
 
14
- if ( ! defined( 'ABSPATH' ) )
15
  exit;
 
16
 
17
  class Course_Widget extends \WP_Widget {
18
-
19
  function __construct() {
20
  parent::__construct(
21
  'tutor_course_widget', // Base ID
22
  esc_html__( 'Tutor Course', 'tutor' ), // Name
23
- array( 'description' => esc_html__( 'Display courses wherever widget support is available.', 'tutor' ), ) // Args
24
  );
25
  }
26
 
@@ -41,34 +42,34 @@ class Course_Widget extends \WP_Widget {
41
  $course_post_type = tutor()->course_post_type;
42
 
43
  $form_args = $instance;
44
- unset($form_args['title']);
45
 
46
  $default_args = array(
47
- 'post_type' => $course_post_type,
48
- 'post_status' => 'publish',
49
 
50
- 'id' => '',
51
- 'exclude_ids' => '',
52
- 'category' => '',
53
 
54
- 'orderby' => 'ID',
55
- 'order' => 'DESC',
56
- 'count' => '6',
57
  );
58
 
59
- $a = array_merge($default_args, $form_args);
60
 
61
- if ( ! empty($a['id'])){
62
- $ids = (array) explode(',', $a['id']);
63
  $a['post__in'] = $ids;
64
  }
65
 
66
- if ( ! empty($a['exclude_ids'])){
67
- $exclude_ids = (array) explode(',', $a['exclude_ids']);
68
  $a['post__not_in'] = $exclude_ids;
69
  }
70
- if ( ! empty($a['category'])){
71
- $category = (array) explode(',', $a['category']);
72
 
73
  $a['tax_query'] = array(
74
  array(
@@ -82,13 +83,12 @@ class Course_Widget extends \WP_Widget {
82
  $a['posts_per_page'] = (int) $a['count'];
83
 
84
  wp_reset_query();
85
- query_posts($a);
86
  ob_start();
87
- tutor_load_template('widget.courses');
88
  $output = ob_get_clean();
89
  wp_reset_query();
90
 
91
-
92
  echo $output;
93
 
94
  echo $args['after_widget'];
@@ -102,70 +102,83 @@ class Course_Widget extends \WP_Widget {
102
  * @param array $instance Previously saved values from database.
103
  */
104
  public function form( $instance ) {
105
- $title = ! empty( $instance['title'] ) ? $instance['title'] : esc_html__( 'New title', 'tutor' );
106
- $id = ! empty( $instance['id'] ) ? $instance['id'] : '';
107
  $exclude_ids = ! empty( $instance['exclude_ids'] ) ? $instance['exclude_ids'] : '';
108
- $category = ! empty( $instance['category'] ) ? $instance['category'] : '';
109
- $orderby = ! empty( $instance['orderby'] ) ? $instance['orderby'] : '';
110
- $order = ! empty( $instance['order'] ) ? $instance['order'] : '';
111
- $count = ! empty( $instance['count'] ) ? $instance['count'] : '6';
112
  ?>
113
  <p>
114
- <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php esc_attr_e( 'Title:', 'tutor' ); ?></label>
 
 
115
  <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
116
  </p>
117
 
118
  <p>
119
- <label for="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>"><?php esc_attr_e( 'ID:', 'tutor' ); ?></label>
 
 
120
  <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>" type="text" value="<?php echo esc_attr( $id ); ?>"> <br />
121
- <span style="color: #AAAAAA"><?php _e('Place single course id or comma (,) separated course ids', 'tutor'); ?></span>
 
 
122
  </p>
123
 
124
  <p>
125
  <label for="<?php echo esc_attr( $this->get_field_id( 'exclude_ids' ) ); ?>"><?php esc_attr_e( 'Exclude IDS:', 'tutor' ); ?></label>
126
- <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'exclude_ids' ) ); ?>" name="<?php echo esc_attr(
127
- $this->get_field_name( 'exclude_ids' ) ); ?>" type="text" value="<?php echo esc_attr( $exclude_ids ); ?>"> <br />
128
- <span style="color: #AAAAAA"><?php _e('Place comma (,) separated courses ids which you like to exclude from the query', 'tutor');
129
- ?></span>
130
  </p>
131
 
132
  <p>
133
- <label for="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>"><?php esc_attr_e( 'Category:', 'tutor' ); ?></label>
134
- <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>" name="<?php echo esc_attr(
135
- $this->get_field_name( 'category' ) ); ?>" type="text" value="<?php echo esc_attr( $category ); ?>"> <br />
136
- <span style="color: #AAAAAA"><?php _e('Place comma (,) separated category ids', 'tutor');
137
- ?></span>
 
 
138
  </p>
139
 
140
  <p>
141
- <label for="<?php echo esc_attr( $this->get_field_id( 'orderby' ) ); ?>"><?php esc_attr_e( 'OrderBy', 'tutor' ); ?></label>
142
-
143
- <select class="widefat" name="<?php echo esc_attr($this->get_field_name( 'orderby' ) ); ?>" >
144
- <option value="ID" <?php selected('ID', $orderby) ?> >ID</option>
145
- <option value="title" <?php selected('title', $orderby) ?> >title</option>
146
- <option value="rand" <?php selected('rand', $orderby) ?> >rand</option>
147
- <option value="date" <?php selected('date', $orderby) ?> >date</option>
148
- <option value="menu_order" <?php selected('menu_order', $orderby) ?> >menu_order</option>
149
- <option value="post__in" <?php selected('post__in', $orderby) ?> >post__in</option>
 
 
150
  </select> <br />
151
  </p>
152
 
153
  <p>
154
- <label for="<?php echo esc_attr( $this->get_field_id( 'order' ) ); ?>"><?php esc_attr_e( 'order', 'tutor' ); ?></label>
 
 
155
 
156
- <select class="widefat" name="<?php echo esc_attr($this->get_field_name( 'order' ) ); ?>" >
157
- <option value="DESC" <?php selected('DESC', $order) ?> >DESC</option>
158
- <option value="ASC" <?php selected('ASC', $order) ?> >ASC</option>
159
  </select> <br />
160
  </p>
161
 
162
  <p>
163
  <label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_attr_e( 'Count:', 'tutor' ); ?></label>
164
- <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr(
165
- $this->get_field_name( 'count' ) ); ?>" type="number" value="<?php echo esc_attr( $count ); ?>"> <br />
166
- <span style="color: #AAAAAA"><?php _e('Total results you like to show', 'tutor'); ?></span>
 
167
  </p>
168
-
169
  <?php
170
  }
171
 
@@ -180,18 +193,15 @@ class Course_Widget extends \WP_Widget {
180
  * @return array Updated safe values to be saved.
181
  */
182
  public function update( $new_instance, $old_instance ) {
183
- $instance = array();
184
- $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? sanitize_text_field( $new_instance['title'] ) : '';
185
- $instance['id'] = ( ! empty( $new_instance['id'] ) ) ? sanitize_text_field( $new_instance['id'] ) : '';
186
- $instance['exclude_ids'] = ( ! empty( $new_instance['exclude_ids'] ) ) ? sanitize_text_field( $new_instance['exclude_ids'] ) : '';
187
- $instance['category'] = ( ! empty( $new_instance['category'] ) ) ? sanitize_text_field( $new_instance['category'] ) : '';
188
- $instance['orderby'] = ( ! empty( $new_instance['orderby'] ) ) ? sanitize_text_field( $new_instance['orderby'] ) : '';
189
- $instance['order'] = ( ! empty( $new_instance['order'] ) ) ? sanitize_text_field( $new_instance['order'] ) : '';
190
- $instance['count'] = ( ! empty( $new_instance['count'] ) ) ? sanitize_text_field( $new_instance['count'] ) : '';
191
 
192
  return $instance;
193
  }
194
-
195
-
196
-
197
- }
11
 
12
  namespace TUTOR;
13
 
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
  exit;
16
+ }
17
 
18
  class Course_Widget extends \WP_Widget {
19
+
20
  function __construct() {
21
  parent::__construct(
22
  'tutor_course_widget', // Base ID
23
  esc_html__( 'Tutor Course', 'tutor' ), // Name
24
+ array( 'description' => esc_html__( 'Display courses wherever widget support is available.', 'tutor' ) ) // Args
25
  );
26
  }
27
 
42
  $course_post_type = tutor()->course_post_type;
43
 
44
  $form_args = $instance;
45
+ unset( $form_args['title'] );
46
 
47
  $default_args = array(
48
+ 'post_type' => $course_post_type,
49
+ 'post_status' => 'publish',
50
 
51
+ 'id' => '',
52
+ 'exclude_ids' => '',
53
+ 'category' => '',
54
 
55
+ 'orderby' => 'ID',
56
+ 'order' => 'DESC',
57
+ 'count' => '6',
58
  );
59
 
60
+ $a = array_merge( $default_args, $form_args );
61
 
62
+ if ( ! empty( $a['id'] ) ) {
63
+ $ids = (array) explode( ',', $a['id'] );
64
  $a['post__in'] = $ids;
65
  }
66
 
67
+ if ( ! empty( $a['exclude_ids'] ) ) {
68
+ $exclude_ids = (array) explode( ',', $a['exclude_ids'] );
69
  $a['post__not_in'] = $exclude_ids;
70
  }
71
+ if ( ! empty( $a['category'] ) ) {
72
+ $category = (array) explode( ',', $a['category'] );
73
 
74
  $a['tax_query'] = array(
75
  array(
83
  $a['posts_per_page'] = (int) $a['count'];
84
 
85
  wp_reset_query();
86
+ query_posts( $a );
87
  ob_start();
88
+ tutor_load_template( 'widget.courses' );
89
  $output = ob_get_clean();
90
  wp_reset_query();
91
 
 
92
  echo $output;
93
 
94
  echo $args['after_widget'];
102
  * @param array $instance Previously saved values from database.
103
  */
104
  public function form( $instance ) {
105
+ $title = ! empty( $instance['title'] ) ? $instance['title'] : esc_html__( 'New title', 'tutor' );
106
+ $id = ! empty( $instance['id'] ) ? $instance['id'] : '';
107
  $exclude_ids = ! empty( $instance['exclude_ids'] ) ? $instance['exclude_ids'] : '';
108
+ $category = ! empty( $instance['category'] ) ? $instance['category'] : '';
109
+ $orderby = ! empty( $instance['orderby'] ) ? $instance['orderby'] : '';
110
+ $order = ! empty( $instance['order'] ) ? $instance['order'] : '';
111
+ $count = ! empty( $instance['count'] ) ? $instance['count'] : '6';
112
  ?>
113
  <p>
114
+ <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
115
+ <?php _e( 'Title', 'tutor' ); ?>:
116
+ </label>
117
  <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
118
  </p>
119
 
120
  <p>
121
+ <label for="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>">
122
+ <?php _e( 'ID', 'tutor' ); ?>:
123
+ </label>
124
  <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'id' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'id' ) ); ?>" type="text" value="<?php echo esc_attr( $id ); ?>"> <br />
125
+ <span style="color: #AAAAAA">
126
+ <?php _e( 'Place single course id or comma (,) separated course ids', 'tutor' ); ?>
127
+ </span>
128
  </p>
129
 
130
  <p>
131
  <label for="<?php echo esc_attr( $this->get_field_id( 'exclude_ids' ) ); ?>"><?php esc_attr_e( 'Exclude IDS:', 'tutor' ); ?></label>
132
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'exclude_ids' ) ); ?>" name="<?php echo esc_attr($this->get_field_name( 'exclude_ids' )); ?>" type="text" value="<?php echo esc_attr( $exclude_ids ); ?>"> <br />
133
+ <span style="color: #AAAAAA">
134
+ <?php _e( 'Place comma (,) separated courses ids which you like to exclude from the query', 'tutor' ); ?>
135
+ </span>
136
  </p>
137
 
138
  <p>
139
+ <label for="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>">
140
+ <?php _e( 'Category', 'tutor' ); ?>:
141
+ </label>
142
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'category' ) ); ?>" name="<?php echo esc_attr($this->get_field_name( 'category' )); ?>" type="text" value="<?php echo esc_attr( $category ); ?>"> <br />
143
+ <span style="color: #AAAAAA">
144
+ <?php _e( 'Place comma (,) separated category ids', 'tutor' ); ?>
145
+ </span>
146
  </p>
147
 
148
  <p>
149
+ <label for="<?php echo esc_attr( $this->get_field_id( 'orderby' ) ); ?>">
150
+ <?php _e( 'OrderBy', 'tutor' ); ?>
151
+ </label>
152
+
153
+ <select class="widefat" name="<?php echo esc_attr( $this->get_field_name( 'orderby' ) ); ?>" >
154
+ <option value="ID" <?php selected( 'ID', $orderby ); ?> >ID</option>
155
+ <option value="title" <?php selected( 'title', $orderby ); ?> >title</option>
156
+ <option value="rand" <?php selected( 'rand', $orderby ); ?> >rand</option>
157
+ <option value="date" <?php selected( 'date', $orderby ); ?> >date</option>
158
+ <option value="menu_order" <?php selected( 'menu_order', $orderby ); ?> >menu_order</option>
159
+ <option value="post__in" <?php selected( 'post__in', $orderby ); ?> >post__in</option>
160
  </select> <br />
161
  </p>
162
 
163
  <p>
164
+ <label for="<?php echo esc_attr( $this->get_field_id( 'order' ) ); ?>">
165
+ <?php _e( 'Order', 'tutor' ); ?>
166
+ </label>
167
 
168
+ <select class="widefat" name="<?php echo esc_attr( $this->get_field_name( 'order' ) ); ?>" >
169
+ <option value="DESC" <?php selected( 'DESC', $order ); ?> >DESC</option>
170
+ <option value="ASC" <?php selected( 'ASC', $order ); ?> >ASC</option>
171
  </select> <br />
172
  </p>
173
 
174
  <p>
175
  <label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"><?php esc_attr_e( 'Count:', 'tutor' ); ?></label>
176
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" value="<?php echo esc_attr( $count ); ?>"> <br />
177
+ <span style="color: #AAAAAA">
178
+ <?php _e( 'Total results you like to show', 'tutor' ); ?>
179
+ </span>
180
  </p>
181
+
182
  <?php
183
  }
184
 
193
  * @return array Updated safe values to be saved.
194
  */
195
  public function update( $new_instance, $old_instance ) {
196
+ $instance = array();
197
+ $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? sanitize_text_field( $new_instance['title'] ) : '';
198
+ $instance['id'] = ( ! empty( $new_instance['id'] ) ) ? sanitize_text_field( $new_instance['id'] ) : '';
199
+ $instance['exclude_ids'] = ( ! empty( $new_instance['exclude_ids'] ) ) ? sanitize_text_field( $new_instance['exclude_ids'] ) : '';
200
+ $instance['category'] = ( ! empty( $new_instance['category'] ) ) ? sanitize_text_field( $new_instance['category'] ) : '';
201
+ $instance['orderby'] = ( ! empty( $new_instance['orderby'] ) ) ? sanitize_text_field( $new_instance['orderby'] ) : '';
202
+ $instance['order'] = ( ! empty( $new_instance['order'] ) ) ? sanitize_text_field( $new_instance['order'] ) : '';
203
+ $instance['count'] = ( ! empty( $new_instance['count'] ) ) ? sanitize_text_field( $new_instance['count'] ) : '';
204
 
205
  return $instance;
206
  }
207
+ }
 
 
 
classes/Dashboard.php CHANGED
@@ -10,42 +10,48 @@
10
 
11
  namespace TUTOR;
12
 
13
- if ( ! defined( 'ABSPATH' ) )
14
  exit;
 
15
 
16
  class Dashboard {
17
 
18
  public function __construct() {
19
- add_action('tutor_load_template_before', array($this, 'tutor_load_template_before'), 10, 2);
20
- add_action('tutor_load_template_after', array($this, 'tutor_load_template_after'), 10, 2);
21
- add_filter('should_tutor_load_template', array($this, 'should_tutor_load_template'), 10, 2);
22
 
23
- add_action('tutor_dashboard/notification_area', array($this, 'profile_completion_notification'), 10, 2);
24
  }
25
 
26
  /**
27
  * @param $template
28
  * @param $variables
29
  */
30
- public function tutor_load_template_before($template, $variables){
31
  global $wp_query;
32
 
33
- $tutor_dashboard_page = tutor_utils()->array_get('query_vars.tutor_dashboard_page', $wp_query);
34
- if ($tutor_dashboard_page === 'create-course') {
35
  global $post;
36
  wp_reset_query();
37
 
38
-
39
  /**
40
  * Get course which currently in edit, or insert new course
41
  */
42
- $course_ID = (int) sanitize_text_field(tutor_utils()->array_get('course_ID', $_GET));
43
 
44
- if ($course_ID){
45
  $post_id = $course_ID;
46
- }else{
47
  $post_type = tutor()->course_post_type;
48
- $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft', 'tutor' ), 'post_type' => $post_type, 'post_status' => 'draft' ) );
 
 
 
 
 
 
49
  }
50
 
51
  $post = get_post( $post_id );
@@ -53,17 +59,17 @@ class Dashboard {
53
  }
54
  }
55
 
56
- public function tutor_load_template_after(){
57
  global $wp_query;
58
 
59
- $tutor_dashboard_page = tutor_utils()->array_get('query_vars.tutor_dashboard_page', $wp_query);
60
- if ($tutor_dashboard_page === 'create-course'){
61
  wp_reset_query();
62
  }
63
  }
64
 
65
- public function should_tutor_load_template($bool, $template){
66
- if ($template === 'dashboard.create-course' && ! tutor()->has_pro){
67
  return false;
68
  }
69
  return $bool;
@@ -72,20 +78,20 @@ class Dashboard {
72
 
73
  /**
74
  * Display completion notification
75
- *
76
  * @return string
77
  *
78
  * @since v.1.6.6
79
  */
80
  public function profile_completion_notification() {
81
- $output = '';
82
- $enable_profile_completion = tutils()->get_option('enable_profile_completion');
83
- if ($enable_profile_completion) {
84
- ob_start();
85
- tutor_load_template('dashboard.notifications.profile-completion');
86
- $output = apply_filters('tutor_profile_completion_notification_html', ob_get_clean());
87
- }
88
-
89
- echo $output;
90
- }
91
- }
10
 
11
  namespace TUTOR;
12
 
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
15
+ }
16
 
17
  class Dashboard {
18
 
19
  public function __construct() {
20
+ add_action( 'tutor_load_template_before', array( $this, 'tutor_load_template_before' ), 10, 2 );
21
+ add_action( 'tutor_load_template_after', array( $this, 'tutor_load_template_after' ), 10, 2 );
22
+ add_filter( 'should_tutor_load_template', array( $this, 'should_tutor_load_template' ), 10, 2 );
23
 
24
+ add_action( 'tutor_dashboard/notification_area', array( $this, 'profile_completion_notification' ), 10, 2 );
25
  }
26
 
27
  /**
28
  * @param $template
29
  * @param $variables
30
  */
31
+ public function tutor_load_template_before( $template, $variables ) {
32
  global $wp_query;
33
 
34
+ $tutor_dashboard_page = tutor_utils()->array_get( 'query_vars.tutor_dashboard_page', $wp_query );
35
+ if ( $tutor_dashboard_page === 'create-course' ) {
36
  global $post;
37
  wp_reset_query();
38
 
 
39
  /**
40
  * Get course which currently in edit, or insert new course
41
  */
42
+ $course_ID = (int) sanitize_text_field( tutor_utils()->array_get( 'course_ID', $_GET ) );
43
 
44
+ if ( $course_ID ) {
45
  $post_id = $course_ID;
46
+ } else {
47
  $post_type = tutor()->course_post_type;
48
+ $post_id = wp_insert_post(
49
+ array(
50
+ 'post_title' => __( 'Auto Draft', 'tutor' ),
51
+ 'post_type' => $post_type,
52
+ 'post_status' => 'draft',
53
+ )
54
+ );
55
  }
56
 
57
  $post = get_post( $post_id );
59
  }
60
  }
61
 
62
+ public function tutor_load_template_after() {
63
  global $wp_query;
64
 
65
+ $tutor_dashboard_page = tutor_utils()->array_get( 'query_vars.tutor_dashboard_page', $wp_query );
66
+ if ( $tutor_dashboard_page === 'create-course' ) {
67
  wp_reset_query();
68
  }
69
  }
70
 
71
+ public function should_tutor_load_template( $bool, $template ) {
72
+ if ( $template === 'dashboard.create-course' && ! tutor()->has_pro ) {
73
  return false;
74
  }
75
  return $bool;
78
 
79
  /**
80
  * Display completion notification
81
+ *
82
  * @return string
83
  *
84
  * @since v.1.6.6
85
  */
86
  public function profile_completion_notification() {
87
+ $output = '';
88
+ $enable_profile_completion = tutils()->get_option( 'enable_profile_completion' );
89
+ if ( $enable_profile_completion ) {
90
+ ob_start();
91
+ tutor_load_template( 'dashboard.notifications.profile-completion' );
92
+ $output = apply_filters( 'tutor_profile_completion_notification_html', ob_get_clean() );
93
+ }
94
+
95
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
96
+ }
97
+ }
classes/FormHandler.php CHANGED
@@ -10,28 +10,28 @@
10
 
11
  namespace TUTOR;
12
 
13
-
14
- if ( ! defined( 'ABSPATH' ) )
15
  exit;
 
16
 
17
 
18
  class FormHandler {
19
 
20
  public function __construct() {
21
- add_action('tutor_action_tutor_retrieve_password', array($this, 'tutor_retrieve_password'));
22
- add_action('tutor_action_tutor_process_reset_password', array($this, 'tutor_process_reset_password'));
23
 
24
  add_action( 'tutor_reset_password_notification', array( $this, 'reset_password_notification' ), 10, 2 );
25
  add_filter( 'tutor_lostpassword_url', array( $this, 'lostpassword_url' ) );
26
  }
27
 
28
- public function tutor_retrieve_password(){
29
  tutils()->checking_nonce();
30
 
31
- $login = sanitize_user( tutils()->array_get('user_login', $_POST));
32
 
33
  if ( empty( $login ) ) {
34
- tutor_flash_set('danger', __( 'Enter a username or email address.', 'tutor' ));
35
  return false;
36
  } else {
37
  // Check on username first, as customers can use emails as usernames.
@@ -48,17 +48,17 @@ class FormHandler {
48
  do_action( 'lostpassword_post', $errors );
49
 
50
  if ( $errors->get_error_code() ) {
51
- tutor_flash_set('danger', $errors->get_error_message() );
52
  return false;
53
  }
54
 
55
  if ( ! $user_data ) {
56
- tutor_flash_set('danger', __( 'Invalid username or email.', 'tutor' ) );
57
  return false;
58
  }
59
 
60
  if ( is_multisite() && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
61
- tutor_flash_set('danger', __( 'Invalid username or email.', 'tutor' ) );
62
  return false;
63
  }
64
 
@@ -70,68 +70,71 @@ class FormHandler {
70
  $allow = apply_filters( 'allow_password_reset', true, $user_data->ID );
71
 
72
  if ( ! $allow ) {
73
- tutor_flash_set('danger', __( 'Password reset is not allowed for this user', 'tutor' ) );
74
  return false;
75
  } elseif ( is_wp_error( $allow ) ) {
76
- tutor_flash_set('danger', $allow->get_error_message() );
77
  return false;
78
  }
79
 
80
  // Get password reset key (function introduced in WordPress 4.4).
81
- $key = get_password_reset_key($user_data);
82
 
83
  // Send email notification.
84
  do_action( 'tutor_reset_password_notification', $user_login, $key );
85
  }
86
 
87
- public function reset_password_notification( $user_login = '', $reset_key = ''){
88
- $this->sendNotification($user_login, $reset_key);
89
 
90
- $html = "<h3>".__('Check your E-Mail', 'tutor')."</h3>";
91
- $html .= "<p>".__("We've sent an email to this account's email address. Click the link in the email to reset your password", 'tutor')."</p>";
92
- $html .= "<p>".__("If you don't see the email, check other places it might be, like your junk, spam, social, promotion or others folders.", 'tutor')."</p>";
93
- tutor_flash_set('success', $html);
94
  }
95
 
96
- public function lostpassword_url($url){
97
- return tutils()->tutor_dashboard_url('retrieve-password');
98
  }
99
 
100
- public function tutor_process_reset_password(){
101
  tutils()->checking_nonce();
102
 
103
- $reset_key = sanitize_text_field(tutils()->array_get('reset_key', $_POST));
104
- $user_id = (int) sanitize_text_field(tutils()->array_get('user_id', $_POST));
105
- $password = sanitize_text_field(tutils()->array_get('password', $_POST));
106
- $confirm_password = sanitize_text_field(tutils()->array_get('confirm_password', $_POST));
107
 
108
- $user = get_user_by('ID', $user_id);
109
  $user = check_password_reset_key( $reset_key, $user->user_login );
110
 
111
  if ( is_wp_error( $user ) ) {
112
- tutor_flash_set('danger', __( 'This key is invalid or has already been used. Please reset your password again if needed.', 'tutor') );
113
  return false;
114
  }
115
 
116
-
117
  if ( $user instanceof \WP_User ) {
118
- if ( !$password ) {
119
- tutor_flash_set('danger', __( 'Please enter your password.', 'tutor') );
120
  return false;
121
  }
122
 
123
- if ( $password !== $confirm_password) {
124
- tutor_flash_set('danger', __( 'Passwords do not match.', 'tutor') );
125
  return false;
126
  }
127
 
128
- tutils()->reset_password($user, $password);
129
 
130
  do_action( 'tutor_user_reset_password', $user );
131
 
132
  // Perform the login.
133
- $creds = array('user_login' => $user->user_login, 'user_password' => $password, 'remember' => true);
134
- $user = wp_signon( apply_filters( 'tutor_login_credentials', $creds ), is_ssl() );
 
 
 
 
135
 
136
  do_action( 'tutor_user_reset_password_login', $user );
137
 
@@ -147,38 +150,38 @@ class FormHandler {
147
  * Send E-Mail notification
148
  * We are sending directly right now, later we will introduce centralised E-Mail notification System...
149
  */
150
- public function sendNotification($user_login, $reset_key){
151
- //Send the E-Mail to user
152
 
153
  $user_data = get_user_by( 'login', $user_login );
154
 
155
  $variable = array(
156
  'user_login' => $user_login,
157
- 'reset_key' => $reset_key,
158
- 'user_id' => $user_data->ID,
159
  );
160
 
161
- $html = tutor_get_template_html('email.send-reset-password', $variable);
162
- $subject = sprintf(__( 'Password Reset Request for %s', 'tutor' ), get_option( 'blogname' ));
163
 
164
  $header = 'Content-Type: text/html' . "\r\n";
165
 
166
  add_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
167
  add_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
168
 
169
- wp_mail($user_data->user_email, $subject, $html, $header);
170
 
171
  remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
172
  remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
173
  }
174
 
175
- public function get_from_address(){
176
- return apply_filters('tutor_email_from_address', get_tutor_option('email_from_address'));
177
  }
178
 
179
- public function get_from_name(){
180
- return apply_filters('tutor_email_from_name', get_tutor_option('email_from_name'));
181
  }
182
 
183
 
184
- }
10
 
11
  namespace TUTOR;
12
 
13
+ if ( ! defined( 'ABSPATH' ) ) {
 
14
  exit;
15
+ }
16
 
17
 
18
  class FormHandler {
19
 
20
  public function __construct() {
21
+ add_action( 'tutor_action_tutor_retrieve_password', array( $this, 'tutor_retrieve_password' ) );
22
+ add_action( 'tutor_action_tutor_process_reset_password', array( $this, 'tutor_process_reset_password' ) );
23
 
24
  add_action( 'tutor_reset_password_notification', array( $this, 'reset_password_notification' ), 10, 2 );
25
  add_filter( 'tutor_lostpassword_url', array( $this, 'lostpassword_url' ) );
26
  }
27
 
28
+ public function tutor_retrieve_password() {
29
  tutils()->checking_nonce();
30
 
31
+ $login = sanitize_user( tutils()->array_get( 'user_login', $_POST ) );
32
 
33
  if ( empty( $login ) ) {
34
+ tutor_flash_set( 'danger', __( 'Enter a username or email address.', 'tutor' ) );
35
  return false;
36
  } else {
37
  // Check on username first, as customers can use emails as usernames.
48
  do_action( 'lostpassword_post', $errors );
49
 
50
  if ( $errors->get_error_code() ) {
51
+ tutor_flash_set( 'danger', $errors->get_error_message() );
52
  return false;
53
  }
54
 
55
  if ( ! $user_data ) {
56
+ tutor_flash_set( 'danger', __( 'Invalid username or email.', 'tutor' ) );
57
  return false;
58
  }
59
 
60
  if ( is_multisite() && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
61
+ tutor_flash_set( 'danger', __( 'Invalid username or email.', 'tutor' ) );
62
  return false;
63
  }
64
 
70
  $allow = apply_filters( 'allow_password_reset', true, $user_data->ID );
71
 
72
  if ( ! $allow ) {
73
+ tutor_flash_set( 'danger', __( 'Password reset is not allowed for this user', 'tutor' ) );
74
  return false;
75
  } elseif ( is_wp_error( $allow ) ) {
76
+ tutor_flash_set( 'danger', $allow->get_error_message() );
77
  return false;
78
  }
79
 
80
  // Get password reset key (function introduced in WordPress 4.4).
81
+ $key = get_password_reset_key( $user_data );
82
 
83
  // Send email notification.
84
  do_action( 'tutor_reset_password_notification', $user_login, $key );
85
  }
86
 
87
+ public function reset_password_notification( $user_login = '', $reset_key = '' ) {
88
+ $this->sendNotification( $user_login, $reset_key );
89
 
90
+ $html = '<h3>' . __( 'Check your E-Mail', 'tutor' ) . '</h3>';
91
+ $html .= '<p>' . __( "We've sent an email to this account's email address. Click the link in the email to reset your password", 'tutor' ) . '</p>';
92
+ $html .= '<p>' . __( "If you don't see the email, check other places it might be, like your junk, spam, social, promotion or others folders.", 'tutor' ) . '</p>';
93
+ tutor_flash_set( 'success', $html );
94
  }
95
 
96
+ public function lostpassword_url( $url ) {
97
+ return tutils()->tutor_dashboard_url( 'retrieve-password' );
98
  }
99
 
100
+ public function tutor_process_reset_password() {
101
  tutils()->checking_nonce();
102
 
103
+ $reset_key = sanitize_text_field( tutils()->array_get( 'reset_key', $_POST ) );
104
+ $user_id = (int) sanitize_text_field( tutils()->array_get( 'user_id', $_POST ) );
105
+ $password = sanitize_text_field( tutils()->array_get( 'password', $_POST ) );
106
+ $confirm_password = sanitize_text_field( tutils()->array_get( 'confirm_password', $_POST ) );
107
 
108
+ $user = get_user_by( 'ID', $user_id );
109
  $user = check_password_reset_key( $reset_key, $user->user_login );
110
 
111
  if ( is_wp_error( $user ) ) {
112
+ tutor_flash_set( 'danger', __( 'This key is invalid or has already been used. Please reset your password again if needed.', 'tutor' ) );
113
  return false;
114
  }
115
 
 
116
  if ( $user instanceof \WP_User ) {
117
+ if ( ! $password ) {
118
+ tutor_flash_set( 'danger', __( 'Please enter your password.', 'tutor' ) );
119
  return false;
120
  }
121
 
122
+ if ( $password !== $confirm_password ) {
123
+ tutor_flash_set( 'danger', __( 'Passwords do not match.', 'tutor' ) );
124
  return false;
125
  }
126
 
127
+ tutils()->reset_password( $user, $password );
128
 
129
  do_action( 'tutor_user_reset_password', $user );
130
 
131
  // Perform the login.
132
+ $creds = array(
133
+ 'user_login' => $user->user_login,
134
+ 'user_password' => $password,
135
+ 'remember' => true,
136
+ );
137
+ $user = wp_signon( apply_filters( 'tutor_login_credentials', $creds ), is_ssl() );
138
 
139
  do_action( 'tutor_user_reset_password_login', $user );
140
 
150
  * Send E-Mail notification
151
  * We are sending directly right now, later we will introduce centralised E-Mail notification System...
152
  */
153
+ public function sendNotification( $user_login, $reset_key ) {
154
+ // Send the E-Mail to user
155
 
156
  $user_data = get_user_by( 'login', $user_login );
157
 
158
  $variable = array(
159
  'user_login' => $user_login,
160
+ 'reset_key' => $reset_key,
161
+ 'user_id' => $user_data->ID,
162
  );
163
 
164
+ $html = tutor_get_template_html( 'email.send-reset-password', $variable );
165
+ $subject = sprintf( __( 'Password Reset Request for %s', 'tutor' ), get_option( 'blogname' ) );
166
 
167
  $header = 'Content-Type: text/html' . "\r\n";
168
 
169
  add_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
170
  add_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
171
 
172
+ wp_mail( $user_data->user_email, $subject, $html, $header );
173
 
174
  remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
175
  remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
176
  }
177
 
178
+ public function get_from_address() {
179
+ return apply_filters( 'tutor_email_from_address', get_tutor_option( 'email_from_address' ) );
180
  }
181
 
182
+ public function get_from_name() {
183
+ return apply_filters( 'tutor_email_from_name', get_tutor_option( 'email_from_name' ) );
184
  }
185
 
186
 
187
+ }
classes/Instructors_List.php CHANGED
@@ -1,47 +1,55 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- if (! class_exists('Tutor_List_Table')){
8
- include_once tutor()->path.'classes/Tutor_List_Table.php';
9
  }
10
 
11
  class Instructors_List extends \Tutor_List_Table {
12
 
13
  const INSTRUCTOR_LIST_PAGE = 'tutor-instructors';
14
 
15
- function __construct(){
16
  global $status, $page;
17
 
18
- //Set parent defaults
19
- parent::__construct( array(
20
- 'singular' => 'instructor', //singular name of the listed records
21
- 'plural' => 'instructors', //plural name of the listed records
22
- 'ajax' => false //does this table support ajax?
23
- ) );
 
 
24
 
25
- //$this->process_bulk_action();
26
  }
27
 
28
- function column_default($item, $column_name){
29
- switch($column_name){
30
  case 'user_email':
31
  case 'display_name':
32
  return $item->$column_name;
33
  case 'registration_date':
34
- return esc_html( date( get_option( 'date_format'), strtotime($item->user_registered ) ) );
35
  default:
36
- return print_r($item,true); //Show the whole array for troubleshooting purposes
37
  }
38
  }
39
 
40
- function column_total_course($item){
41
  global $wpdb;
42
  $course_post_type = tutor()->course_post_type;
43
 
44
- $total_course = (int) $wpdb->get_var($wpdb->prepare("SELECT count(ID) from {$wpdb->posts} WHERE post_author=%d AND post_type=%s ", $item->ID, $course_post_type));
 
 
 
 
 
45
 
46
  echo $total_course;
47
  }
@@ -51,132 +59,133 @@ class Instructors_List extends \Tutor_List_Table {
51
  *
52
  * Completed Course by User
53
  */
54
- function column_status($item){
55
- $status = tutor_utils()->instructor_status($item->ID, false);
56
- $status_name = tutor_utils()->instructor_status($item->ID);
57
- echo "<span class='tutor-status-context tutor-status-{$status}-context'>{$status_name}</span>";
58
  }
59
 
60
- function column_display_name($item) {
61
- //Build row actions
62
  $actions = array();
63
 
64
- $status = tutor_utils()->instructor_status($item->ID, false);
65
 
66
- switch ($status){
67
  case 'pending':
68
- $actions['approved'] = sprintf('<a class="instructor-action" data-action="approve" data-instructor-id="'.$item->ID.'" href="?page=%s&action=%s&instructor=%s">'.__('Approve', 'tutor').'</a>', self::INSTRUCTOR_LIST_PAGE, 'approve', $item->ID);
69
  break;
70
  case 'approved':
71
- $actions['blocked'] = sprintf('<a data-prompt-message="'.__('Sure to Block?', 'tutor').'" class="instructor-action" data-action="blocked" data-instructor-id="'.$item->ID.'" href="?page=%s&action=%s&instructor=%s">'.__('Block', 'tutor').'</a>', self::INSTRUCTOR_LIST_PAGE, 'blocked', $item->ID);
72
  break;
73
  case 'blocked':
74
- $actions['approved'] = sprintf('<a data-prompt-message="'.__('Sure to Un Block?', 'tutor').'" class="instructor-action" data-action="approve" data-instructor-id="'.$item->ID.'" href="?page=%s&action=%s&instructor=%s">'.__('Unblock', 'tutor').'</a>', self::INSTRUCTOR_LIST_PAGE, 'approve', $item->ID);
75
  break;
76
  }
77
 
78
  // Add user edit link
79
- $edit_link = get_edit_user_link($item->ID);
80
- $edit_link = '<a href="' . esc_url( $edit_link ) . '">'. esc_html__( 'Edit' ) . '</a>';
81
- $actions['tutor-instructor-edit-link']=$edit_link;
82
 
83
  // Add remove instructor action
84
- $removal_title = $status=='pending' ? __('Reject', 'tutor') : __('Remove as Instructor', 'tutor');
85
- $removal_warning = $status=='pending' ? __('Sure to Reject?', 'tutor') : __('Sure to Remove as Instructor?', 'tutor');
86
- $actions['tutor-remove-instructor'] = sprintf('<a data-prompt-message="' . $removal_warning . '" class="instructor-action" data-action="remove-instructor" data-instructor-id="'.$item->ID.'" href="?page=%s&action=%s&instructor=%s">' . $removal_title . '</a>', self::INSTRUCTOR_LIST_PAGE, 'remove-instructor', $item->ID);
87
 
88
- //Return the title contents
89
- return sprintf('%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
 
90
  $item->display_name,
91
  $item->ID,
92
- $this->row_actions($actions)
93
  );
94
  }
95
 
96
- function column_cb($item){
97
  return sprintf(
98
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
99
- /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label ("instructor")
100
- /*$2%s*/ $item->ID //The value of the checkbox should be the record's id
101
  );
102
  }
103
 
104
- function column_instructor_commission($item){
105
- $commision = apply_filters('tutor_pro_instructor_commission_string', $item->ID);
106
 
107
  // If the return value is numeric, it means the filter was not executed.
108
  // may be pro is not installed. So show N\A. The return value will something like '23 percent'
109
 
110
- return !is_numeric($commision) ? $commision : 'N\\A';
111
  }
112
 
113
- function get_columns(){
114
  $columns = array(
115
- 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
116
- 'display_name' => __('Name', 'tutor'),
117
- 'user_email' => __('E-Mail', 'tutor'),
118
- 'total_course' => __('Total Course', 'tutor'),
119
- 'instructor_commission' => __('Instructor Commission', 'tutor'),
120
- 'registration_date' => __('Date', 'tutor'),
121
- 'status' => __('Status', 'tutor'),
122
  );
123
  return $columns;
124
  }
125
 
126
  function get_sortable_columns() {
127
  $sortable_columns = array(
128
- //'display_name' => array('title',false), //true means it's already sorted
129
  );
130
  return $sortable_columns;
131
  }
132
 
133
  function get_bulk_actions() {
134
  $actions = array(
135
- 'delete' => 'Delete'
136
  );
137
  return $actions;
138
  }
139
 
140
  function process_bulk_action() {
141
- if( 'approve' === $this->current_action() ) {
142
- $instructor_id = (int) sanitize_text_field($_GET['instructor']);
143
 
144
- do_action('tutor_before_approved_instructor', $instructor_id);
145
 
146
- update_user_meta($instructor_id, '_tutor_instructor_status', 'approved');
147
- update_user_meta($instructor_id, '_tutor_instructor_approved', tutor_time());
148
 
149
- $instructor = new \WP_User($instructor_id);
150
- $instructor->add_role(tutor()->instructor_role);
151
 
152
- //TODO: send E-Mail to this user about instructor approval, should via hook
153
- do_action('tutor_after_approved_instructor', $instructor_id);
154
  }
155
 
156
- if( 'blocked' === $this->current_action() ) {
157
- $instructor_id = (int) sanitize_text_field($_GET['instructor']);
158
 
159
- do_action('tutor_before_blocked_instructor', $instructor_id);
160
- update_user_meta($instructor_id, '_tutor_instructor_status', 'blocked');
161
 
162
- $instructor = new \WP_User($instructor_id);
163
- $instructor->remove_role(tutor()->instructor_role);
164
- do_action('tutor_after_blocked_instructor', $instructor_id);
165
 
166
- //TODO: send E-Mail to this user about instructor blocked, should via hook
167
  }
168
 
169
- //Detect when a bulk action is being triggered...
170
- if( 'delete'=== $this->current_action() ) {
171
-
172
- $delete_instructors = $_GET['instructor'];
173
- if ( count($delete_instructors) ) {
174
- foreach( $delete_instructors as $instructor ) {
175
- do_action( 'tutor_insctructor_before_delete', $instructor);
176
 
177
- wp_delete_user($instructor);
178
 
179
- do_action( 'tutor_insctructor_after_delete', $instructor);
180
 
181
  }
182
  }
@@ -185,34 +194,36 @@ class Instructors_List extends \Tutor_List_Table {
185
 
186
  /**
187
  * Filter support added
188
- *
189
  * @param optional
190
- *
191
  * @since 1.9.7
192
  */
193
- function prepare_items($search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '') {
194
  $per_page = 20;
195
 
196
  // $search_term = '';
197
  // if (isset($_REQUEST['s'])){
198
- // $search_term = sanitize_text_field($_REQUEST['s']);
199
  // }
200
 
201
- $columns = $this->get_columns();
202
- $hidden = array();
203
  $sortable = $this->get_sortable_columns();
204
 
205
- $this->_column_headers = array($columns, $hidden, $sortable);
206
  $this->process_bulk_action();
207
  $current_page = $this->get_pagenum();
208
 
209
- $total_items = tutor_utils()->get_total_instructors($search_filter);
210
- $this->items = tutor_utils()->get_instructors(($current_page-1)*$per_page, $per_page, $search_filter, $course_filter, $date_filter,$order_filter, $status = null, $cat_ids = array() );
211
 
212
- $this->set_pagination_args( array(
213
- 'total_items' => $total_items,
214
- 'per_page' => $per_page,
215
- 'total_pages' => ceil($total_items/$per_page)
216
- ) );
 
 
217
  }
218
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ if ( ! class_exists( 'Tutor_List_Table' ) ) {
9
+ include_once tutor()->path . 'classes/Tutor_List_Table.php';
10
  }
11
 
12
  class Instructors_List extends \Tutor_List_Table {
13
 
14
  const INSTRUCTOR_LIST_PAGE = 'tutor-instructors';
15
 
16
+ function __construct() {
17
  global $status, $page;
18
 
19
+ // Set parent defaults
20
+ parent::__construct(
21
+ array(
22
+ 'singular' => 'instructor', // singular name of the listed records
23
+ 'plural' => 'instructors', // plural name of the listed records
24
+ 'ajax' => false, // does this table support ajax?
25
+ )
26
+ );
27
 
28
+ // $this->process_bulk_action();
29
  }
30
 
31
+ function column_default( $item, $column_name ) {
32
+ switch ( $column_name ) {
33
  case 'user_email':
34
  case 'display_name':
35
  return $item->$column_name;
36
  case 'registration_date':
37
+ return esc_html( date( get_option( 'date_format' ), strtotime( $item->user_registered ) ) );
38
  default:
39
+ return print_r( $item, true ); // Show the whole array for troubleshooting purposes
40
  }
41
  }
42
 
43
+ function column_total_course( $item ) {
44
  global $wpdb;
45
  $course_post_type = tutor()->course_post_type;
46
 
47
+ $total_course = (int) $wpdb->get_var( $wpdb->prepare(
48
+ "SELECT count(ID) from {$wpdb->posts}
49
+ WHERE post_author=%d AND post_type=%s ",
50
+ $item->ID,
51
+ $course_post_type
52
+ ) );
53
 
54
  echo $total_course;
55
  }
59
  *
60
  * Completed Course by User
61
  */
62
+ function column_status( $item ) {
63
+ $status = tutor_utils()->instructor_status( $item->ID, false );
64
+ $status_name = tutor_utils()->instructor_status( $item->ID );
65
+ echo '<span class="tutor-status-context tutor-status-' . $status . '-context">' . $status_name . '</span>';
66
  }
67
 
68
+ function column_display_name( $item ) {
69
+ // Build row actions
70
  $actions = array();
71
 
72
+ $status = tutor_utils()->instructor_status( $item->ID, false );
73
 
74
+ switch ( $status ) {
75
  case 'pending':
76
+ $actions['approved'] = sprintf( '<a class="instructor-action" data-action="approve" data-instructor-id="' . $item->ID . '" href="?page=%s&action=%s&instructor=%s">' . __( 'Approve', 'tutor' ) . '</a>', self::INSTRUCTOR_LIST_PAGE, 'approve', $item->ID );
77
  break;
78
  case 'approved':
79
+ $actions['blocked'] = sprintf( '<a data-prompt-message="' . __( 'Sure to Block?', 'tutor' ) . '" class="instructor-action" data-action="blocked" data-instructor-id="' . $item->ID . '" href="?page=%s&action=%s&instructor=%s">' . __( 'Block', 'tutor' ) . '</a>', self::INSTRUCTOR_LIST_PAGE, 'blocked', $item->ID );
80
  break;
81
  case 'blocked':
82
+ $actions['approved'] = sprintf( '<a data-prompt-message="' . __( 'Sure to Un Block?', 'tutor' ) . '" class="instructor-action" data-action="approve" data-instructor-id="' . $item->ID . '" href="?page=%s&action=%s&instructor=%s">' . __( 'Unblock', 'tutor' ) . '</a>', self::INSTRUCTOR_LIST_PAGE, 'approve', $item->ID );
83
  break;
84
  }
85
 
86
  // Add user edit link
87
+ $edit_link = get_edit_user_link( $item->ID );
88
+ $edit_link = '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit' ) . '</a>';
89
+ $actions['tutor-instructor-edit-link'] = $edit_link;
90
 
91
  // Add remove instructor action
92
+ $removal_title = $status == 'pending' ? __( 'Reject', 'tutor' ) : __( 'Remove as Instructor', 'tutor' );
93
+ $removal_warning = $status == 'pending' ? __( 'Sure to Reject?', 'tutor' ) : __( 'Sure to Remove as Instructor?', 'tutor' );
94
+ $actions['tutor-remove-instructor'] = sprintf( '<a data-prompt-message="' . $removal_warning . '" class="instructor-action" data-action="remove-instructor" data-instructor-id="' . $item->ID . '" href="?page=%s&action=%s&instructor=%s">' . $removal_title . '</a>', self::INSTRUCTOR_LIST_PAGE, 'remove-instructor', $item->ID );
95
 
96
+ // Return the title contents
97
+ return sprintf(
98
+ '%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
99
  $item->display_name,
100
  $item->ID,
101
+ $this->row_actions( $actions )
102
  );
103
  }
104
 
105
+ function column_cb( $item ) {
106
  return sprintf(
107
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
108
+ /*$1%s*/ $this->_args['singular'], // Let's simply repurpose the table's singular label ("instructor")
109
+ /*$2%s*/ $item->ID // The value of the checkbox should be the record's id
110
  );
111
  }
112
 
113
+ function column_instructor_commission( $item ) {
114
+ $commision = apply_filters( 'tutor_pro_instructor_commission_string', $item->ID );
115
 
116
  // If the return value is numeric, it means the filter was not executed.
117
  // may be pro is not installed. So show N\A. The return value will something like '23 percent'
118
 
119
+ return ! is_numeric( $commision ) ? $commision : 'N\\A';
120
  }
121
 
122
+ function get_columns() {
123
  $columns = array(
124
+ 'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
125
+ 'display_name' => __( 'Name', 'tutor' ),
126
+ 'user_email' => __( 'E-Mail', 'tutor' ),
127
+ 'total_course' => __( 'Total Course', 'tutor' ),
128
+ 'instructor_commission' => __( 'Instructor Commission', 'tutor' ),
129
+ 'registration_date' => __( 'Date', 'tutor' ),
130
+ 'status' => __( 'Status', 'tutor' ),
131
  );
132
  return $columns;
133
  }
134
 
135
  function get_sortable_columns() {
136
  $sortable_columns = array(
137
+ // 'display_name' => array('title',false), //true means it's already sorted
138
  );
139
  return $sortable_columns;
140
  }
141
 
142
  function get_bulk_actions() {
143
  $actions = array(
144
+ 'delete' => 'Delete',
145
  );
146
  return $actions;
147
  }
148
 
149
  function process_bulk_action() {
150
+ if ( 'approve' === $this->current_action() ) {
151
+ $instructor_id = (int) sanitize_text_field( $_GET['instructor'] );
152
 
153
+ do_action( 'tutor_before_approved_instructor', $instructor_id );
154
 
155
+ update_user_meta( $instructor_id, '_tutor_instructor_status', 'approved' );
156
+ update_user_meta( $instructor_id, '_tutor_instructor_approved', tutor_time() );
157
 
158
+ $instructor = new \WP_User( $instructor_id );
159
+ $instructor->add_role( tutor()->instructor_role );
160
 
161
+ // TODO: send E-Mail to this user about instructor approval, should via hook
162
+ do_action( 'tutor_after_approved_instructor', $instructor_id );
163
  }
164
 
165
+ if ( 'blocked' === $this->current_action() ) {
166
+ $instructor_id = (int) sanitize_text_field( $_GET['instructor'] );
167
 
168
+ do_action( 'tutor_before_blocked_instructor', $instructor_id );
169
+ update_user_meta( $instructor_id, '_tutor_instructor_status', 'blocked' );
170
 
171
+ $instructor = new \WP_User( $instructor_id );
172
+ $instructor->remove_role( tutor()->instructor_role );
173
+ do_action( 'tutor_after_blocked_instructor', $instructor_id );
174
 
175
+ // TODO: send E-Mail to this user about instructor blocked, should via hook
176
  }
177
 
178
+ // Detect when a bulk action is being triggered...
179
+ if ( 'delete' === $this->current_action() ) {
180
+
181
+ $delete_instructors = tutor_sanitize_data($_GET['instructor']);
182
+ if ( count( $delete_instructors ) ) {
183
+ foreach ( $delete_instructors as $instructor ) {
184
+ do_action( 'tutor_insctructor_before_delete', $instructor );
185
 
186
+ wp_delete_user( $instructor );
187
 
188
+ do_action( 'tutor_insctructor_after_delete', $instructor );
189
 
190
  }
191
  }
194
 
195
  /**
196
  * Filter support added
197
+ *
198
  * @param optional
199
+ *
200
  * @since 1.9.7
201
  */
202
+ function prepare_items( $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '' ) {
203
  $per_page = 20;
204
 
205
  // $search_term = '';
206
  // if (isset($_REQUEST['s'])){
207
+ // $search_term = sanitize_text_field($_REQUEST['s']);
208
  // }
209
 
210
+ $columns = $this->get_columns();
211
+ $hidden = array();
212
  $sortable = $this->get_sortable_columns();
213
 
214
+ $this->_column_headers = array( $columns, $hidden, $sortable );
215
  $this->process_bulk_action();
216
  $current_page = $this->get_pagenum();
217
 
218
+ $total_items = tutor_utils()->get_total_instructors( $search_filter );
219
+ $this->items = tutor_utils()->get_instructors( ( $current_page - 1 ) * $per_page, $per_page, $search_filter, $course_filter, $date_filter, $order_filter, $status = null, $cat_ids = array() );
220
 
221
+ $this->set_pagination_args(
222
+ array(
223
+ 'total_items' => $total_items,
224
+ 'per_page' => $per_page,
225
+ 'total_pages' => ceil( $total_items / $per_page ),
226
+ )
227
+ );
228
  }
229
+ }
classes/Lesson.php CHANGED
@@ -1,225 +1,227 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
  class Lesson extends Tutor_Base {
8
  public function __construct() {
9
  parent::__construct();
10
 
11
- add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
12
- add_action('save_post_'.$this->lesson_post_type, array($this, "save_lesson_meta"));
13
 
14
- add_action('wp_ajax_tutor_load_edit_lesson_modal', array($this, "tutor_load_edit_lesson_modal"));
15
- add_action('wp_ajax_tutor_modal_create_or_update_lesson', array($this, "tutor_modal_create_or_update_lesson"));
16
- add_action('wp_ajax_tutor_delete_lesson_by_id', array($this, "tutor_delete_lesson_by_id"));
17
 
18
- add_filter('get_sample_permalink', array($this, 'change_lesson_permalink'), 10, 2);
19
- add_action('admin_init', array($this, 'flush_rewrite_rules'));
20
 
21
  /**
22
  * Add Column
23
  */
24
 
25
- add_filter( "manage_{$this->lesson_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
26
- add_action( "manage_{$this->lesson_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
27
 
28
- //Frontend Action
29
- add_action('template_redirect', array($this, 'mark_lesson_complete'));
30
 
31
- add_action('wp_ajax_tutor_render_lesson_content', array($this, "tutor_render_lesson_content"));
32
- add_action('wp_ajax_nopriv_tutor_render_lesson_content', array($this, "tutor_render_lesson_content")); // For public course access
33
 
34
  /**
35
  * Autoplay next video
 
36
  * @since v.1.4.9
37
  */
38
- add_action('wp_ajax_autoload_next_course_content', array($this, 'autoload_next_course_content'));
39
 
40
  /**
41
  * Load next course item after click complete button
 
42
  * @since v.1.5.3
43
  */
44
- add_action('tutor_lesson_completed_after', array($this, 'tutor_lesson_completed_after'), 999);
45
  }
46
 
47
  /**
48
  * Registering metabox
49
  */
50
- public function register_meta_box(){
51
  $lesson_post_type = $this->lesson_post_type;
52
 
53
- add_meta_box( 'tutor-course-select', __( 'Select Course', 'tutor' ), array($this, 'lesson_metabox'), $lesson_post_type );
54
- add_meta_box( 'tutor-lesson-videos', __( 'Lesson Video', 'tutor' ), array($this, 'lesson_video_metabox'), $lesson_post_type );
55
- add_meta_box( 'tutor-lesson-attachments', __( 'Attachments', 'tutor' ), array($this, 'lesson_attachments_metabox'), $lesson_post_type );
56
  }
57
 
58
- public function lesson_metabox(){
59
- include tutor()->path.'views/metabox/lesson-metabox.php';
60
  }
61
 
62
- public function lesson_video_metabox(){
63
- include tutor()->path.'views/metabox/video-metabox.php';
64
  }
65
 
66
- public function lesson_attachments_metabox(){
67
- include tutor()->path.'views/metabox/lesson-attachments-metabox.php';
68
  }
69
 
70
  /**
71
  * @param $post_ID
72
  *
73
  * Saving lesson meta and assets
74
- *
75
  */
76
- public function save_lesson_meta($post_ID){
77
- //Course
78
- if (isset($_POST['selected_course'])) {
79
  $course_id = (int) sanitize_text_field( $_POST['selected_course'] );
80
  if ( $course_id ) {
81
  update_post_meta( $post_ID, '_tutor_course_id_for_lesson', $course_id );
82
  }
83
  }
84
 
85
- //Video
86
- $video_source = sanitize_text_field( tutils()->array_get('video.source', $_POST) );
87
- if ( $video_source === '-1'){
88
- delete_post_meta($post_ID, '_video');
89
- }elseif($video_source) {
90
- $video = (array)tutor_utils()->array_get('video', $_POST, array());
91
- update_post_meta($post_ID, '_video', $video);
92
  }
93
 
94
- //Attachments
95
  $attachments = array();
96
- if ( ! empty($_POST['tutor_attachments'])){
97
- $attachments = tutor_utils()->sanitize_array($_POST['tutor_attachments']);
98
- $attachments = array_unique($attachments);
99
- }
100
 
101
  /**
102
  * it !empty attachment then update meta else
103
  * delete meta key to prevetn empty data in db
 
104
  * @since 1.8.9
105
  */
106
- if( ! empty($attachments) ) {
107
- update_post_meta($post_ID, '_tutor_attachments', $attachments);
108
  } else {
109
- delete_post_meta($post_ID, '_tutor_attachments');
110
  }
111
-
112
  }
113
 
114
- public function tutor_load_edit_lesson_modal(){
115
  tutils()->checking_nonce();
116
 
117
- $lesson_id = (int) tutor_utils()->avalue_dot('lesson_id', $_POST);
118
- $topic_id = (int) sanitize_text_field( $_POST['topic_id'] );
119
 
120
- if(!tutils()->can_user_manage('topic', $topic_id)) {
121
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
122
  }
123
 
124
  /**
125
  * If Lesson Not Exists, provide dummy
126
  */
127
  $post_arr = array(
128
- 'ID' => 0,
129
  'post_content' => '',
130
  'post_type' => $this->lesson_post_type,
131
- 'post_title' => __('Draft Lesson', 'tutor'),
132
  'post_status' => 'publish',
133
  'post_author' => get_current_user_id(),
134
  'post_parent' => $topic_id,
135
  );
136
 
137
- $post = $lesson_id ? get_post($lesson_id) : (object)$post_arr;
138
-
139
  ob_start();
140
- include tutor()->path.'views/modal/edit-lesson.php';
141
  $output = ob_get_clean();
142
 
143
- wp_send_json_success(array('output' => $output));
144
  }
145
 
146
  /**
147
  * @since v.1.0.0
148
  * @updated v.1.5.1
149
  */
150
- public function tutor_modal_create_or_update_lesson(){
151
  tutils()->checking_nonce();
152
 
153
  global $wpdb;
154
-
155
- $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
156
- $topic_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('current_topic_id', $_POST));
157
- $course_id = tutor_utils()->get_course_id_by('topic', $topic_id);
158
- $_lesson_thumbnail_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('_lesson_thumbnail_id', $_POST));
159
-
160
- if(!tutils()->can_user_manage('topic', $topic_id)) {
161
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
162
- }
163
 
 
 
 
 
 
 
 
 
164
 
165
- $title = sanitize_text_field($_POST['lesson_title']);
166
- $lesson_content = wp_kses_post($_POST['lesson_content']);
167
 
168
  $lesson_data = array(
169
  'post_type' => $this->lesson_post_type,
170
  'post_title' => $title,
171
- 'post_name' => sanitize_title($title),
172
  'post_content' => $lesson_content,
173
  'post_status' => 'publish',
174
  'post_author' => get_current_user_id(),
175
- 'post_parent' => $topic_id
176
  );
177
 
178
- if($lesson_id==0) {
179
 
180
  $lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
181
- $lesson_id = wp_insert_post( $lesson_data );
182
 
183
- if ($lesson_id ) {
184
- do_action('tutor/lesson/created', $lesson_id);
185
  update_post_meta( $lesson_id, '_tutor_course_id_for_lesson', $course_id );
186
  } else {
187
- wp_send_json_error( array('message' => __('Couldn\'t create lesson.', 'tutor')) );
188
  }
189
  } else {
190
- $lesson_data['ID']=$lesson_id;
191
 
192
- do_action('tutor/lesson_update/before', $lesson_id);
193
- wp_update_post($lesson_data);
194
- if ($_lesson_thumbnail_id){
195
- update_post_meta($lesson_id, '_thumbnail_id', $_lesson_thumbnail_id);
196
  } else {
197
- delete_post_meta($lesson_id, '_thumbnail_id');
198
  }
199
- do_action('tutor/lesson_update/after', $lesson_id);
200
  }
201
-
202
  ob_start();
203
- include tutor()->path.'views/metabox/course-contents.php';
204
  $course_contents = ob_get_clean();
205
 
206
- wp_send_json_success(array('course_contents' => $course_contents));
207
  }
208
 
209
  /**
210
  * Delete Lesson from course builder
211
  */
212
- public function tutor_delete_lesson_by_id(){
213
  tutils()->checking_nonce();
214
 
215
- $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
216
 
217
- if(!tutils()->can_user_manage('lesson', $lesson_id)) {
218
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
219
  }
220
 
221
- wp_delete_post($lesson_id, true);
222
- delete_post_meta($lesson_id, '_tutor_course_id_for_lesson');
223
  wp_send_json_success();
224
  }
225
 
@@ -233,43 +235,43 @@ class Lesson extends Tutor_Base {
233
  * Changed the URI based
234
  */
235
 
236
- public function change_lesson_permalink($uri, $lesson_id){
237
- $post = get_post($lesson_id);
238
 
239
- if ($post && $post->post_type === $this->lesson_post_type){
240
- $uri_base = trailingslashit(site_url());
241
 
242
- $sample_course = "sample-course";
243
- $is_course = tutor_utils()->get_course_id_by('lesson', get_the_ID());
244
- if ($is_course){
245
- $course = get_post($is_course);
246
- if ($course){
247
  $sample_course = $course->post_name;
248
  }
249
  }
250
 
251
- $new_course_base = $uri_base."course/{$sample_course}/lesson/%pagename%/";
252
- $uri[0] = $new_course_base;
253
  }
254
 
255
  return $uri;
256
  }
257
 
258
 
259
- public function flush_rewrite_rules(){
260
- $is_required_flush = get_option('required_rewrite_flush');
261
- if ($is_required_flush){
262
  flush_rewrite_rules();
263
  delete_option( 'required_rewrite_flush' );
264
  }
265
  }
266
 
267
 
268
- public function add_column($columns){
269
  $date_col = $columns['date'];
270
- unset($columns['date']);
271
- $columns['course'] = __('Course', 'tutor');
272
- $columns['date'] = $date_col;
273
 
274
  return $columns;
275
  }
@@ -277,16 +279,14 @@ class Lesson extends Tutor_Base {
277
  /**
278
  * @param $column
279
  * @param $post_id
280
- *
281
  */
282
- public function custom_lesson_column($column, $post_id ){
283
- if ($column === 'course'){
284
 
285
- $course_id = tutor_utils()->get_course_id_by('lesson', $post_id);
286
- if ($course_id){
287
- echo '<a href="'.admin_url('post.php?post='.$course_id.'&action=edit').'">'.get_the_title($course_id).'</a>';
288
  }
289
-
290
  }
291
  }
292
 
@@ -296,50 +296,50 @@ class Lesson extends Tutor_Base {
296
  *
297
  * @since v.1.0.0
298
  */
299
- public function mark_lesson_complete(){
300
- if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_lesson' ){
301
  return;
302
  }
303
- //Checking nonce
304
  tutor_utils()->checking_nonce();
305
 
306
  $user_id = get_current_user_id();
307
 
308
- //TODO: need to show view if not signed_in
309
- if ( ! $user_id){
310
- die(__('Please Sign-In', 'tutor'));
311
  }
312
 
313
- $lesson_id = (int) sanitize_text_field($_POST['lesson_id']);
314
 
315
- do_action('tutor_lesson_completed_before', $lesson_id);
316
  /**
317
  * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
318
  */
319
- tutor_utils()->mark_lesson_complete($lesson_id);
320
 
321
- do_action('tutor_lesson_completed_after', $lesson_id, $user_id);
322
  }
323
 
324
  /**
325
  * Render the lesson content
326
  */
327
- public function tutor_render_lesson_content(){
328
  tutils()->checking_nonce();
329
 
330
- $lesson_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('lesson_id', $_POST));
331
 
332
- $ancestors = get_post_ancestors($lesson_id);
333
- $course_id = !empty($ancestors) ? array_pop($ancestors): $lesson_id;
334
 
335
  // Course must be public or current user must be enrolled to access this lesson
336
- if(get_post_meta($course_id, '_tutor_is_public_course', true)!=='yes' && !tutils()->is_enrolled($course_id)){
337
-
338
- $is_admin = tutor_utils()->has_user_role('administrator');
339
- $allowed = $is_admin ? true : tutor_utils()->is_instructor_of_this_course(get_current_user_id(), $course_id);
340
 
341
- if( !$allowed ) {
342
- http_response_code(400);
343
  exit;
344
  }
345
  }
@@ -347,13 +347,13 @@ class Lesson extends Tutor_Base {
347
  ob_start();
348
  global $post;
349
 
350
- $post = get_post($lesson_id);
351
- setup_postdata($post);
352
  tutor_lesson_content();
353
  wp_reset_postdata();
354
 
355
  $html = ob_get_clean();
356
- wp_send_json_success(array('html' => $html));
357
  }
358
 
359
  /**
@@ -361,19 +361,19 @@ class Lesson extends Tutor_Base {
361
  *
362
  * @since v.1.4.9
363
  */
364
- public function autoload_next_course_content(){
365
  tutor_utils()->checking_nonce();
366
 
367
- $post_id = sanitize_text_field($_POST['post_id']);
368
- $content_id = tutils()->get_post_id($post_id);
369
- $contents = tutor_utils()->get_course_prev_next_contents_by_id($content_id);
370
 
371
- $autoload_course_content = (bool) get_tutor_option('autoload_next_course_content');
372
- $next_url = false;
373
- if($autoload_course_content) {
374
- $next_url = get_the_permalink($contents->next_id);
375
  }
376
- wp_send_json_success(array('next_url' => $next_url));
377
  }
378
 
379
  /**
@@ -381,13 +381,13 @@ class Lesson extends Tutor_Base {
381
  *
382
  * @since v.1.5.3
383
  */
384
- public function tutor_lesson_completed_after($content_id){
385
- $contents = tutor_utils()->get_course_prev_next_contents_by_id($content_id);
386
- $autoload_course_content = (bool) get_tutor_option('autoload_next_course_content');
387
- if($autoload_course_content) {
388
- wp_redirect(get_the_permalink($contents->next_id));
389
  } else {
390
- wp_redirect(get_the_permalink($content_id));
391
  }
392
  die();
393
  }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
  class Lesson extends Tutor_Base {
9
  public function __construct() {
10
  parent::__construct();
11
 
12
+ add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ) );
13
+ add_action( 'save_post_' . $this->lesson_post_type, array( $this, 'save_lesson_meta' ) );
14
 
15
+ add_action( 'wp_ajax_tutor_load_edit_lesson_modal', array( $this, 'tutor_load_edit_lesson_modal' ) );
16
+ add_action( 'wp_ajax_tutor_modal_create_or_update_lesson', array( $this, 'tutor_modal_create_or_update_lesson' ) );
17
+ add_action( 'wp_ajax_tutor_delete_lesson_by_id', array( $this, 'tutor_delete_lesson_by_id' ) );
18
 
19
+ add_filter( 'get_sample_permalink', array( $this, 'change_lesson_permalink' ), 10, 2 );
20
+ add_action( 'admin_init', array( $this, 'flush_rewrite_rules' ) );
21
 
22
  /**
23
  * Add Column
24
  */
25
 
26
+ add_filter( "manage_{$this->lesson_post_type}_posts_columns", array( $this, 'add_column' ), 10, 1 );
27
+ add_action( "manage_{$this->lesson_post_type}_posts_custom_column", array( $this, 'custom_lesson_column' ), 10, 2 );
28
 
29
+ // Frontend Action
30
+ add_action( 'template_redirect', array( $this, 'mark_lesson_complete' ) );
31
 
32
+ add_action( 'wp_ajax_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) );
33
+ add_action( 'wp_ajax_nopriv_tutor_render_lesson_content', array( $this, 'tutor_render_lesson_content' ) ); // For public course access
34
 
35
  /**
36
  * Autoplay next video
37
+ *
38
  * @since v.1.4.9
39
  */
40
+ add_action( 'wp_ajax_autoload_next_course_content', array( $this, 'autoload_next_course_content' ) );
41
 
42
  /**
43
  * Load next course item after click complete button
44
+ *
45
  * @since v.1.5.3
46
  */
47
+ add_action( 'tutor_lesson_completed_after', array( $this, 'tutor_lesson_completed_after' ), 999 );
48
  }
49
 
50
  /**
51
  * Registering metabox
52
  */
53
+ public function register_meta_box() {
54
  $lesson_post_type = $this->lesson_post_type;
55
 
56
+ add_meta_box( 'tutor-course-select', __( 'Select Course', 'tutor' ), array( $this, 'lesson_metabox' ), $lesson_post_type );
57
+ add_meta_box( 'tutor-lesson-videos', __( 'Lesson Video', 'tutor' ), array( $this, 'lesson_video_metabox' ), $lesson_post_type );
58
+ add_meta_box( 'tutor-lesson-attachments', __( 'Attachments', 'tutor' ), array( $this, 'lesson_attachments_metabox' ), $lesson_post_type );
59
  }
60
 
61
+ public function lesson_metabox() {
62
+ include tutor()->path . 'views/metabox/lesson-metabox.php';
63
  }
64
 
65
+ public function lesson_video_metabox() {
66
+ include tutor()->path . 'views/metabox/video-metabox.php';
67
  }
68
 
69
+ public function lesson_attachments_metabox() {
70
+ include tutor()->path . 'views/metabox/lesson-attachments-metabox.php';
71
  }
72
 
73
  /**
74
  * @param $post_ID
75
  *
76
  * Saving lesson meta and assets
 
77
  */
78
+ public function save_lesson_meta( $post_ID ) {
79
+ // Course
80
+ if ( isset( $_POST['selected_course'] ) ) {
81
  $course_id = (int) sanitize_text_field( $_POST['selected_course'] );
82
  if ( $course_id ) {
83
  update_post_meta( $post_ID, '_tutor_course_id_for_lesson', $course_id );
84
  }
85
  }
86
 
87
+ // Video
88
+ $video_source = sanitize_text_field( tutils()->array_get( 'video.source', $_POST ) );
89
+ if ( $video_source === '-1' ) {
90
+ delete_post_meta( $post_ID, '_video' );
91
+ } elseif ( $video_source ) {
92
+ $video = (array) tutor_utils()->array_get( 'video', tutor_sanitize_data($_POST), array() );
93
+ update_post_meta( $post_ID, '_video', $video );
94
  }
95
 
96
+ // Attachments
97
  $attachments = array();
98
+ if ( ! empty( $_POST['tutor_attachments'] ) ) {
99
+ $attachments = tutor_utils()->sanitize_array( $_POST['tutor_attachments'] );
100
+ $attachments = array_unique( $attachments );
101
+ }
102
 
103
  /**
104
  * it !empty attachment then update meta else
105
  * delete meta key to prevetn empty data in db
106
+ *
107
  * @since 1.8.9
108
  */
109
+ if ( ! empty( $attachments ) ) {
110
+ update_post_meta( $post_ID, '_tutor_attachments', $attachments );
111
  } else {
112
+ delete_post_meta( $post_ID, '_tutor_attachments' );
113
  }
114
+
115
  }
116
 
117
+ public function tutor_load_edit_lesson_modal() {
118
  tutils()->checking_nonce();
119
 
120
+ $lesson_id = (int) tutor_utils()->avalue_dot( 'lesson_id', tutor_sanitize_data($_POST) );
121
+ $topic_id = (int) sanitize_text_field( $_POST['topic_id'] );
122
 
123
+ if ( ! tutils()->can_user_manage( 'topic', $topic_id ) ) {
124
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
125
  }
126
 
127
  /**
128
  * If Lesson Not Exists, provide dummy
129
  */
130
  $post_arr = array(
131
+ 'ID' => 0,
132
  'post_content' => '',
133
  'post_type' => $this->lesson_post_type,
134
+ 'post_title' => __( 'Draft Lesson', 'tutor' ),
135
  'post_status' => 'publish',
136
  'post_author' => get_current_user_id(),
137
  'post_parent' => $topic_id,
138
  );
139
 
140
+ $post = $lesson_id ? get_post( $lesson_id ) : (object) $post_arr;
141
+
142
  ob_start();
143
+ include tutor()->path . 'views/modal/edit-lesson.php';
144
  $output = ob_get_clean();
145
 
146
+ wp_send_json_success( array( 'output' => $output ) );
147
  }
148
 
149
  /**
150
  * @since v.1.0.0
151
  * @updated v.1.5.1
152
  */
153
+ public function tutor_modal_create_or_update_lesson() {
154
  tutils()->checking_nonce();
155
 
156
  global $wpdb;
 
 
 
 
 
 
 
 
 
157
 
158
+ $lesson_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'lesson_id', $_POST ) );
159
+ $topic_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'current_topic_id', $_POST ) );
160
+ $course_id = tutor_utils()->get_course_id_by( 'topic', $topic_id );
161
+ $_lesson_thumbnail_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( '_lesson_thumbnail_id', $_POST ) );
162
+
163
+ if ( ! tutils()->can_user_manage( 'topic', $topic_id ) ) {
164
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
165
+ }
166
 
167
+ $title = sanitize_text_field( $_POST['lesson_title'] );
168
+ $lesson_content = wp_kses_post( $_POST['lesson_content'] );
169
 
170
  $lesson_data = array(
171
  'post_type' => $this->lesson_post_type,
172
  'post_title' => $title,
173
+ 'post_name' => sanitize_title( $title ),
174
  'post_content' => $lesson_content,
175
  'post_status' => 'publish',
176
  'post_author' => get_current_user_id(),
177
+ 'post_parent' => $topic_id,
178
  );
179
 
180
+ if ( $lesson_id == 0 ) {
181
 
182
  $lesson_data['menu_order'] = tutor_utils()->get_next_course_content_order_id( $topic_id );
183
+ $lesson_id = wp_insert_post( $lesson_data );
184
 
185
+ if ( $lesson_id ) {
186
+ do_action( 'tutor/lesson/created', $lesson_id );
187
  update_post_meta( $lesson_id, '_tutor_course_id_for_lesson', $course_id );
188
  } else {
189
+ wp_send_json_error( array( 'message' => __( 'Couldn\'t create lesson.', 'tutor' ) ) );
190
  }
191
  } else {
192
+ $lesson_data['ID'] = $lesson_id;
193
 
194
+ do_action( 'tutor/lesson_update/before', $lesson_id );
195
+ wp_update_post( $lesson_data );
196
+ if ( $_lesson_thumbnail_id ) {
197
+ update_post_meta( $lesson_id, '_thumbnail_id', $_lesson_thumbnail_id );
198
  } else {
199
+ delete_post_meta( $lesson_id, '_thumbnail_id' );
200
  }
201
+ do_action( 'tutor/lesson_update/after', $lesson_id );
202
  }
203
+
204
  ob_start();
205
+ include tutor()->path . 'views/metabox/course-contents.php';
206
  $course_contents = ob_get_clean();
207
 
208
+ wp_send_json_success( array( 'course_contents' => $course_contents ) );
209
  }
210
 
211
  /**
212
  * Delete Lesson from course builder
213
  */
214
+ public function tutor_delete_lesson_by_id() {
215
  tutils()->checking_nonce();
216
 
217
+ $lesson_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'lesson_id', $_POST ) );
218
 
219
+ if ( ! tutils()->can_user_manage( 'lesson', $lesson_id ) ) {
220
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
221
  }
222
 
223
+ wp_delete_post( $lesson_id, true );
224
+ delete_post_meta( $lesson_id, '_tutor_course_id_for_lesson' );
225
  wp_send_json_success();
226
  }
227
 
235
  * Changed the URI based
236
  */
237
 
238
+ public function change_lesson_permalink( $uri, $lesson_id ) {
239
+ $post = get_post( $lesson_id );
240
 
241
+ if ( $post && $post->post_type === $this->lesson_post_type ) {
242
+ $uri_base = trailingslashit( site_url() );
243
 
244
+ $sample_course = 'sample-course';
245
+ $is_course = tutor_utils()->get_course_id_by( 'lesson', get_the_ID() );
246
+ if ( $is_course ) {
247
+ $course = get_post( $is_course );
248
+ if ( $course ) {
249
  $sample_course = $course->post_name;
250
  }
251
  }
252
 
253
+ $new_course_base = $uri_base . "course/{$sample_course}/lesson/%pagename%/";
254
+ $uri[0] = $new_course_base;
255
  }
256
 
257
  return $uri;
258
  }
259
 
260
 
261
+ public function flush_rewrite_rules() {
262
+ $is_required_flush = get_option( 'required_rewrite_flush' );
263
+ if ( $is_required_flush ) {
264
  flush_rewrite_rules();
265
  delete_option( 'required_rewrite_flush' );
266
  }
267
  }
268
 
269
 
270
+ public function add_column( $columns ) {
271
  $date_col = $columns['date'];
272
+ unset( $columns['date'] );
273
+ $columns['course'] = __( 'Course', 'tutor' );
274
+ $columns['date'] = $date_col;
275
 
276
  return $columns;
277
  }
279
  /**
280
  * @param $column
281
  * @param $post_id
 
282
  */
283
+ public function custom_lesson_column( $column, $post_id ) {
284
+ if ( $column === 'course' ) {
285
 
286
+ $course_id = tutor_utils()->get_course_id_by( 'lesson', $post_id );
287
+ if ( $course_id ) {
288
+ echo '<a href="' . admin_url( 'post.php?post=' . $course_id . '&action=edit' ) . '">' . get_the_title( $course_id ) . '</a>';
289
  }
 
290
  }
291
  }
292
 
296
  *
297
  * @since v.1.0.0
298
  */
299
+ public function mark_lesson_complete() {
300
+ if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_complete_lesson' ) {
301
  return;
302
  }
303
+ // Checking nonce
304
  tutor_utils()->checking_nonce();
305
 
306
  $user_id = get_current_user_id();
307
 
308
+ // TODO: need to show view if not signed_in
309
+ if ( ! $user_id ) {
310
+ die( __( 'Please Sign-In', 'tutor' ) );
311
  }
312
 
313
+ $lesson_id = (int) sanitize_text_field( $_POST['lesson_id'] );
314
 
315
+ do_action( 'tutor_lesson_completed_before', $lesson_id );
316
  /**
317
  * Marking lesson at user meta, meta format, _tutor_completed_lesson_id_{id} and value = tutor_time();
318
  */
319
+ tutor_utils()->mark_lesson_complete( $lesson_id );
320
 
321
+ do_action( 'tutor_lesson_completed_after', $lesson_id, $user_id );
322
  }
323
 
324
  /**
325
  * Render the lesson content
326
  */
327
+ public function tutor_render_lesson_content() {
328
  tutils()->checking_nonce();
329
 
330
+ $lesson_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'lesson_id', $_POST ) );
331
 
332
+ $ancestors = get_post_ancestors( $lesson_id );
333
+ $course_id = ! empty( $ancestors ) ? array_pop( $ancestors ) : $lesson_id;
334
 
335
  // Course must be public or current user must be enrolled to access this lesson
336
+ if ( get_post_meta( $course_id, '_tutor_is_public_course', true ) !== 'yes' && ! tutils()->is_enrolled( $course_id ) ) {
337
+
338
+ $is_admin = tutor_utils()->has_user_role( 'administrator' );
339
+ $allowed = $is_admin ? true : tutor_utils()->is_instructor_of_this_course( get_current_user_id(), $course_id );
340
 
341
+ if ( ! $allowed ) {
342
+ http_response_code( 400 );
343
  exit;
344
  }
345
  }
347
  ob_start();
348
  global $post;
349
 
350
+ $post = get_post( $lesson_id );
351
+ setup_postdata( $post );
352
  tutor_lesson_content();
353
  wp_reset_postdata();
354
 
355
  $html = ob_get_clean();
356
+ wp_send_json_success( array( 'html' => $html ) );
357
  }
358
 
359
  /**
361
  *
362
  * @since v.1.4.9
363
  */
364
+ public function autoload_next_course_content() {
365
  tutor_utils()->checking_nonce();
366
 
367
+ $post_id = sanitize_text_field( $_POST['post_id'] );
368
+ $content_id = tutils()->get_post_id( $post_id );
369
+ $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
370
 
371
+ $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
372
+ $next_url = false;
373
+ if ( $autoload_course_content ) {
374
+ $next_url = get_the_permalink( $contents->next_id );
375
  }
376
+ wp_send_json_success( array( 'next_url' => $next_url ) );
377
  }
378
 
379
  /**
381
  *
382
  * @since v.1.5.3
383
  */
384
+ public function tutor_lesson_completed_after( $content_id ) {
385
+ $contents = tutor_utils()->get_course_prev_next_contents_by_id( $content_id );
386
+ $autoload_course_content = (bool) get_tutor_option( 'autoload_next_course_content' );
387
+ if ( $autoload_course_content ) {
388
+ wp_redirect( get_the_permalink( $contents->next_id ) );
389
  } else {
390
+ wp_redirect( get_the_permalink( $content_id ) );
391
  }
392
  die();
393
  }
classes/Options.php CHANGED
@@ -59,8 +59,9 @@ class Options {
59
 
60
  do_action('tutor_option_save_before');
61
 
62
- $option = (array)tutils()->array_get('tutor_option', $_POST, array());
63
-
 
64
  foreach ( $option as $key => $value ) {
65
  if ( 'login_error_message' === $key ) {
66
  $option['login_error_message'] = $this->tutor_sanitize_settings_options( 'login_error_message' );
@@ -74,9 +75,9 @@ class Options {
74
  $option['email_from_address'] = $this->tutor_sanitize_settings_options( 'email_from_address' );
75
  }
76
  }
77
-
78
  $option = apply_filters('tutor_option_input', $option);
79
-
80
  update_option('tutor_option', $option);
81
 
82
  do_action('tutor_option_save_after');
@@ -93,7 +94,7 @@ class Options {
93
  $lesson_sample_url_text = __( "/course/sample-course/<code>lessons</code>/sample-lesson/", 'tutor' );
94
  $lesson_url = site_url().$lesson_sample_url_text;
95
 
96
- $student_url = site_url().'/'._x( 'profile', 'tutor student profile', 'tutor' ).'/'.$current_user->display_name ;
97
 
98
  $attempts_allowed = array();
99
  $attempts_allowed['unlimited'] = __('Unlimited' , 'tutor');
@@ -740,13 +741,13 @@ class Options {
740
  'default' => '',
741
  ),
742
  //tutor button style options
743
-
744
  'tutor_button_primary' => array(
745
  'type' => 'color',
746
  'label' => __('Button Primary Color','tutor'),
747
  'default' => ''
748
- ),
749
-
750
  'tutor_button_danger' => array(
751
  'type' => 'color',
752
  'label' => __('Button Danger Color','tutor'),
@@ -821,13 +822,13 @@ class Options {
821
  public function generate_field($field = array()){
822
  ob_start();
823
  include tutor()->path.'views/options/option_field.php';
824
- return ob_get_clean();
825
  }
826
 
827
  public function field_type($field = array()){
828
  ob_start();
829
- include tutor()->path."views/options/field-types/{$field['type']}.php";
830
- return ob_get_clean();
831
  }
832
 
833
  public function generate(){
59
 
60
  do_action('tutor_option_save_before');
61
 
62
+ $option = (array) tutils()->array_get('tutor_option', $_POST, array());
63
+ $option = tutor_sanitize_data($option);
64
+
65
  foreach ( $option as $key => $value ) {
66
  if ( 'login_error_message' === $key ) {
67
  $option['login_error_message'] = $this->tutor_sanitize_settings_options( 'login_error_message' );
75
  $option['email_from_address'] = $this->tutor_sanitize_settings_options( 'email_from_address' );
76
  }
77
  }
78
+
79
  $option = apply_filters('tutor_option_input', $option);
80
+
81
  update_option('tutor_option', $option);
82
 
83
  do_action('tutor_option_save_after');
94
  $lesson_sample_url_text = __( "/course/sample-course/<code>lessons</code>/sample-lesson/", 'tutor' );
95
  $lesson_url = site_url().$lesson_sample_url_text;
96
 
97
+ $student_url = site_url().'/'._x( 'profile', 'tutor student profile', 'tutor' ).'/'.$current_user->display_name ;
98
 
99
  $attempts_allowed = array();
100
  $attempts_allowed['unlimited'] = __('Unlimited' , 'tutor');
741
  'default' => '',
742
  ),
743
  //tutor button style options
744
+
745
  'tutor_button_primary' => array(
746
  'type' => 'color',
747
  'label' => __('Button Primary Color','tutor'),
748
  'default' => ''
749
+ ),
750
+
751
  'tutor_button_danger' => array(
752
  'type' => 'color',
753
  'label' => __('Button Danger Color','tutor'),
822
  public function generate_field($field = array()){
823
  ob_start();
824
  include tutor()->path.'views/options/option_field.php';
825
+ echo ob_get_clean();
826
  }
827
 
828
  public function field_type($field = array()){
829
  ob_start();
830
+ include tutor()->path.'views/options/field-types/'.$field['type'].'.php';
831
+ echo ob_get_clean();
832
  }
833
 
834
  public function generate(){
classes/Post_types.php CHANGED
@@ -4,14 +4,14 @@ if ( ! defined( 'ABSPATH' ) )
4
  exit;
5
 
6
  class Post_types{
7
-
8
  public $course_post_type;
9
  public $lesson_post_type;
10
 
11
  public function __construct() {
12
  $this->course_post_type = tutor()->course_post_type;
13
  $this->lesson_post_type = tutor()->lesson_post_type;
14
-
15
  add_action( 'init', array($this, 'register_course_post_types') );
16
  add_action( 'init', array($this, 'register_lesson_post_types') );
17
  add_action( 'init', array($this, 'register_quiz_post_types') );
@@ -31,7 +31,7 @@ class Post_types{
31
  */
32
  add_action( 'init', array($this, 'register_tutor_enrolled_post_types') );
33
  }
34
-
35
  public function register_course_post_types() {
36
  $course_post_type = $this->course_post_type;
37
  $courses_base_slug = apply_filters('tutor_courses_base_slug', $course_post_type);
@@ -207,7 +207,7 @@ class Post_types{
207
 
208
  register_post_type($lesson_post_type, $args );
209
  }
210
-
211
  public function register_quiz_post_types() {
212
  $labels = array(
213
  'name' => _x( 'Quizzes', 'post type general name', 'tutor' ),
@@ -327,7 +327,7 @@ class Post_types{
327
  $post = get_post();
328
  $post_type = get_post_type( $post );
329
  $post_type_object = get_post_type_object( $post_type );
330
-
331
  $course_post_type = tutor()->course_post_type;
332
 
333
  $messages[$course_post_type] = array(
@@ -337,7 +337,7 @@ class Post_types{
337
  3 => __( 'Custom field deleted.', 'tutor' ),
338
  4 => __( 'Course updated.', 'tutor' ),
339
  /* translators: %s: date and time of the revision */
340
- 5 => isset( $_GET['revision'] ) ? sprintf( __( 'Course restored to revision from %s', 'tutor' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
341
  6 => __( 'Course published.', 'tutor' ),
342
  7 => __( 'Course saved.', 'tutor' ),
343
  8 => __( 'Course submitted.', 'tutor' ),
4
  exit;
5
 
6
  class Post_types{
7
+
8
  public $course_post_type;
9
  public $lesson_post_type;
10
 
11
  public function __construct() {
12
  $this->course_post_type = tutor()->course_post_type;
13
  $this->lesson_post_type = tutor()->lesson_post_type;
14
+
15
  add_action( 'init', array($this, 'register_course_post_types') );
16
  add_action( 'init', array($this, 'register_lesson_post_types') );
17
  add_action( 'init', array($this, 'register_quiz_post_types') );
31
  */
32
  add_action( 'init', array($this, 'register_tutor_enrolled_post_types') );
33
  }
34
+
35
  public function register_course_post_types() {
36
  $course_post_type = $this->course_post_type;
37
  $courses_base_slug = apply_filters('tutor_courses_base_slug', $course_post_type);
207
 
208
  register_post_type($lesson_post_type, $args );
209
  }
210
+
211
  public function register_quiz_post_types() {
212
  $labels = array(
213
  'name' => _x( 'Quizzes', 'post type general name', 'tutor' ),
327
  $post = get_post();
328
  $post_type = get_post_type( $post );
329
  $post_type_object = get_post_type_object( $post_type );
330
+
331
  $course_post_type = tutor()->course_post_type;
332
 
333
  $messages[$course_post_type] = array(
337
  3 => __( 'Custom field deleted.', 'tutor' ),
338
  4 => __( 'Course updated.', 'tutor' ),
339
  /* translators: %s: date and time of the revision */
340
+ 5 => isset( $_GET['revision'] ) ? sprintf( __( 'Course restored to revision from %s', 'tutor' ), wp_post_revision_title( (int) tutor_sanitize_data($_GET['revision']), false ) ) : false,
341
  6 => __( 'Course published.', 'tutor' ),
342
  7 => __( 'Course saved.', 'tutor' ),
343
  8 => __( 'Course submitted.', 'tutor' ),
classes/Question_Answers_List.php CHANGED
@@ -1,93 +1,96 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- if (! class_exists('Tutor_List_Table')){
8
- include_once tutor()->path.'classes/Tutor_List_Table.php';
9
  }
10
 
11
  class Question_Answers_List extends \Tutor_List_Table {
12
 
13
  const Question_Answer_PAGE = 'question_answer';
14
 
15
- function __construct(){
16
  global $status, $page;
17
 
18
- //Set parent defaults
19
- parent::__construct( array(
20
- 'singular' => 'question', //singular name of the listed records
21
- 'plural' => 'questions', //plural name of the listed records
22
- 'ajax' => false //does this table support ajax?
23
- ) );
 
 
24
  }
25
 
26
- function column_default($item, $column_name){
27
- switch($column_name){
28
  case 'user_email':
29
  case 'display_name':
30
  case 'post_title':
31
  case 'answer_count':
32
  return $item->$column_name;
33
  default:
34
- return print_r($item,true); //Show the whole array for troubleshooting purposes
35
  }
36
  }
37
 
38
- function column_question($item){
39
- //Build row actions
40
  $actions = array(
41
- //'edit' => sprintf('<a href="?page=%s&action=%s&instructor=%s">Edit</a>',$_REQUEST['page'],'edit',$item->comment_ID),
42
- //'delete' => sprintf('<a href="?page=%s&action=%s&instructor=%s">Delete</a>',$_REQUEST['page'],'delete',$item->comment_ID),
43
  );
44
  $answer_action_text = __( 'Answer', 'tutor' );
45
 
46
- $actions['answer'] = sprintf('<a href="?page=%s&sub_page=%s&question_id=%s">'.$answer_action_text.'</a>',$_REQUEST['page'],'answer',$item->comment_ID);
47
-
48
 
49
- //Return the title contents
50
- return sprintf('%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
51
- stripslashes($item->comment_content),
 
52
  $item->comment_ID,
53
- $this->row_actions($actions)
54
  );
55
  }
56
 
57
- function column_cb($item){
58
  return sprintf(
59
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
60
- /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label ("instructor")
61
- /*$2%s*/ $item->comment_ID //The value of the checkbox should be the record's id
62
  );
63
  }
64
 
65
- function column_course($item) {
66
 
67
  return $item->comment_ID;
68
  }
69
 
70
- function get_columns(){
71
  $columns = array(
72
- 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
73
- 'question' => __('Question', 'tutor'),
74
- 'display_name' => __('Student', 'tutor'),
75
- 'post_title' => __('Course', 'tutor'),
76
- 'answer_count' => __('Answer', 'tutor'),
77
  );
78
  return $columns;
79
  }
80
 
81
  function get_sortable_columns() {
82
  $sortable_columns = array(
83
- //'display_name' => array('title',false), //true means it's already sorted
84
  );
85
  return $sortable_columns;
86
  }
87
 
88
  function get_bulk_actions() {
89
  $actions = array(
90
- 'delete' => 'Delete'
91
  );
92
  return $actions;
93
  }
@@ -95,16 +98,16 @@ class Question_Answers_List extends \Tutor_List_Table {
95
  function process_bulk_action() {
96
  global $wpdb;
97
 
98
- //Detect when a bulk action is being triggered...
99
- if( 'delete' === $this->current_action() ) {
100
- if ( empty($_GET['question']) || ! is_array($_GET['question'])){
101
  return;
102
  }
103
 
104
- $question_ids = array_map('sanitize_text_field', $_GET['question']);
105
  $question_ids = implode( ',', array_map( 'absint', $question_ids ) );
106
 
107
- //Deleting question (comment), child question and question meta (comment meta)
108
  $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$wpdb->comments}.comment_ID IN($question_ids)" );
109
  $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$wpdb->comments}.comment_parent IN($question_ids)" );
110
  $wpdb->query( "DELETE FROM {$wpdb->commentmeta} WHERE {$wpdb->commentmeta}.comment_id IN($question_ids)" );
@@ -115,26 +118,28 @@ class Question_Answers_List extends \Tutor_List_Table {
115
  $per_page = 20;
116
 
117
  $search_term = '';
118
- if (isset($_REQUEST['s'])){
119
- $search_term = sanitize_text_field($_REQUEST['s']);
120
  }
121
 
122
- $columns = $this->get_columns();
123
- $hidden = array();
124
  $sortable = $this->get_sortable_columns();
125
 
126
- $this->_column_headers = array($columns, $hidden, $sortable);
127
  $this->process_bulk_action();
128
 
129
  $current_page = $this->get_pagenum();
130
 
131
- $total_items = tutor_utils()->get_total_qa_question($search_term);
132
- $this->items = tutor_utils()->get_qa_questions(($current_page-1)*$per_page, $per_page, $search_term);
133
 
134
- $this->set_pagination_args( array(
135
- 'total_items' => $total_items,
136
- 'per_page' => $per_page,
137
- 'total_pages' => ceil($total_items/$per_page)
138
- ) );
 
 
139
  }
140
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ if ( ! class_exists( 'Tutor_List_Table' ) ) {
9
+ include_once tutor()->path . 'classes/Tutor_List_Table.php';
10
  }
11
 
12
  class Question_Answers_List extends \Tutor_List_Table {
13
 
14
  const Question_Answer_PAGE = 'question_answer';
15
 
16
+ function __construct() {
17
  global $status, $page;
18
 
19
+ // Set parent defaults
20
+ parent::__construct(
21
+ array(
22
+ 'singular' => 'question', // singular name of the listed records
23
+ 'plural' => 'questions', // plural name of the listed records
24
+ 'ajax' => false, // does this table support ajax?
25
+ )
26
+ );
27
  }
28
 
29
+ function column_default( $item, $column_name ) {
30
+ switch ( $column_name ) {
31
  case 'user_email':
32
  case 'display_name':
33
  case 'post_title':
34
  case 'answer_count':
35
  return $item->$column_name;
36
  default:
37
+ return print_r( $item, true ); // Show the whole array for troubleshooting purposes
38
  }
39
  }
40
 
41
+ function column_question( $item ) {
42
+ // Build row actions
43
  $actions = array(
44
+ // 'edit' => sprintf('<a href="?page=%s&action=%s&instructor=%s">Edit</a>',$_REQUEST['page'],'edit',$item->comment_ID),
45
+ // 'delete' => sprintf('<a href="?page=%s&action=%s&instructor=%s">Delete</a>',$_REQUEST['page'],'delete',$item->comment_ID),
46
  );
47
  $answer_action_text = __( 'Answer', 'tutor' );
48
 
49
+ $actions['answer'] = sprintf( '<a href="?page=%s&sub_page=%s&question_id=%s">' . $answer_action_text . '</a>', $_REQUEST['page'], 'answer', $item->comment_ID );
 
50
 
51
+ // Return the title contents
52
+ return sprintf(
53
+ '%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
54
+ wp_kses_post( stripslashes( $item->comment_content ) ),
55
  $item->comment_ID,
56
+ $this->row_actions( $actions )
57
  );
58
  }
59
 
60
+ function column_cb( $item ) {
61
  return sprintf(
62
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
63
+ /*$1%s*/ $this->_args['singular'], // Let's simply repurpose the table's singular label ("instructor")
64
+ /*$2%s*/ $item->comment_ID // The value of the checkbox should be the record's id
65
  );
66
  }
67
 
68
+ function column_course( $item ) {
69
 
70
  return $item->comment_ID;
71
  }
72
 
73
+ function get_columns() {
74
  $columns = array(
75
+ 'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
76
+ 'question' => __( 'Question', 'tutor' ),
77
+ 'display_name' => __( 'Student', 'tutor' ),
78
+ 'post_title' => __( 'Course', 'tutor' ),
79
+ 'answer_count' => __( 'Answer', 'tutor' ),
80
  );
81
  return $columns;
82
  }
83
 
84
  function get_sortable_columns() {
85
  $sortable_columns = array(
86
+ // 'display_name' => array('title',false), //true means it's already sorted
87
  );
88
  return $sortable_columns;
89
  }
90
 
91
  function get_bulk_actions() {
92
  $actions = array(
93
+ 'delete' => 'Delete',
94
  );
95
  return $actions;
96
  }
98
  function process_bulk_action() {
99
  global $wpdb;
100
 
101
+ // Detect when a bulk action is being triggered...
102
+ if ( 'delete' === $this->current_action() ) {
103
+ if ( empty( $_GET['question'] ) || ! is_array( $_GET['question'] ) ) {
104
  return;
105
  }
106
 
107
+ $question_ids = array_map( 'sanitize_text_field', $_GET['question'] );
108
  $question_ids = implode( ',', array_map( 'absint', $question_ids ) );
109
 
110
+ // Deleting question (comment), child question and question meta (comment meta)
111
  $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$wpdb->comments}.comment_ID IN($question_ids)" );
112
  $wpdb->query( "DELETE FROM {$wpdb->comments} WHERE {$wpdb->comments}.comment_parent IN($question_ids)" );
113
  $wpdb->query( "DELETE FROM {$wpdb->commentmeta} WHERE {$wpdb->commentmeta}.comment_id IN($question_ids)" );
118
  $per_page = 20;
119
 
120
  $search_term = '';
121
+ if ( isset( $_REQUEST['s'] ) ) {
122
+ $search_term = sanitize_text_field( $_REQUEST['s'] );
123
  }
124
 
125
+ $columns = $this->get_columns();
126
+ $hidden = array();
127
  $sortable = $this->get_sortable_columns();
128
 
129
+ $this->_column_headers = array( $columns, $hidden, $sortable );
130
  $this->process_bulk_action();
131
 
132
  $current_page = $this->get_pagenum();
133
 
134
+ $total_items = tutor_utils()->get_total_qa_question( $search_term );
135
+ $this->items = tutor_utils()->get_qa_questions( ( $current_page - 1 ) * $per_page, $per_page, $search_term );
136
 
137
+ $this->set_pagination_args(
138
+ array(
139
+ 'total_items' => $total_items,
140
+ 'per_page' => $per_page,
141
+ 'total_pages' => ceil( $total_items / $per_page ),
142
+ )
143
+ );
144
  }
145
+ }
classes/Quiz.php CHANGED
@@ -11,192 +11,193 @@
11
 
12
  namespace TUTOR;
13
 
14
- if ( ! defined( 'ABSPATH' ) )
15
  exit;
 
16
 
17
  class Quiz {
18
 
19
- private $allowed_attributes = array(
20
- 'src' => array(),
21
- 'style' => array(),
22
- 'class' => array(),
23
- 'id' => array(),
24
- 'href' => array(),
25
- 'alt' => array(),
26
  'title' => array(),
27
  'type' => array(),
28
  'controls' => array(),
29
  'muted' => array(),
30
- 'loop' => array(),
31
  'poster' => array(),
32
  'preload' => array(),
33
  'autoplay' => array(),
34
  'width' => array(),
35
- 'height' => array()
36
  );
37
-
38
  private $allowed_html = array( 'img', 'b', 'i', 'br', 'a', 'audio', 'video', 'source' );
39
 
40
  public function __construct() {
41
-
42
- add_action('save_post_tutor_quiz', array($this, 'save_quiz_meta'));
43
 
44
- add_action('wp_ajax_tutor_load_quiz_builder_modal', array($this, 'tutor_load_quiz_builder_modal'));
45
- add_action('wp_ajax_remove_quiz_from_post', array($this, 'remove_quiz_from_post'));
 
 
46
 
47
- add_action('wp_ajax_tutor_quiz_timeout', array($this, 'tutor_quiz_timeout'));
48
 
49
- //User take the quiz
50
- add_action('template_redirect', array($this, 'start_the_quiz'));
51
- add_action('template_redirect', array($this, 'answering_quiz'));
52
- add_action('template_redirect', array($this, 'finishing_quiz_attempt'));
53
 
54
- add_action('admin_action_review_quiz_answer', array($this, 'review_quiz_answer'));
55
- add_action('wp_ajax_review_quiz_answer', array($this, 'review_quiz_answer'));
56
- add_action('wp_ajax_tutor_instructor_feedback', array($this, 'tutor_instructor_feedback')); // Instructor Feedback Action
57
 
58
  /**
59
  * New Design Quiz
60
  */
61
 
62
- add_action('wp_ajax_tutor_create_quiz_and_load_modal', array($this, 'tutor_create_quiz_and_load_modal'));
63
- add_action('wp_ajax_tutor_delete_quiz_by_id', array($this, 'tutor_delete_quiz_by_id'));
64
- add_action('wp_ajax_tutor_quiz_builder_quiz_update', array($this, 'tutor_quiz_builder_quiz_update'));
65
- add_action('wp_ajax_tutor_load_edit_quiz_modal', array($this, 'tutor_load_edit_quiz_modal'));
66
- add_action('wp_ajax_tutor_quiz_builder_get_question_form', array($this, 'tutor_quiz_builder_get_question_form'));
67
- add_action('wp_ajax_tutor_quiz_modal_update_question', array($this, 'tutor_quiz_modal_update_question'));
68
- add_action('wp_ajax_tutor_quiz_builder_question_delete', array($this, 'tutor_quiz_builder_question_delete'));
69
- add_action('wp_ajax_tutor_quiz_add_question_answers', array($this, 'tutor_quiz_add_question_answers'));
70
- add_action('wp_ajax_tutor_quiz_edit_question_answer', array($this, 'tutor_quiz_edit_question_answer'));
71
- add_action('wp_ajax_tutor_save_quiz_answer_options', array($this, 'tutor_save_quiz_answer_options'));
72
- add_action('wp_ajax_tutor_update_quiz_answer_options', array($this, 'tutor_update_quiz_answer_options'));
73
- add_action('wp_ajax_tutor_quiz_builder_get_answers_by_question', array($this, 'tutor_quiz_builder_get_answers_by_question'));
74
- add_action('wp_ajax_tutor_quiz_builder_delete_answer', array($this, 'tutor_quiz_builder_delete_answer'));
75
- add_action('wp_ajax_tutor_quiz_question_sorting', array($this, 'tutor_quiz_question_sorting'));
76
- add_action('wp_ajax_tutor_quiz_answer_sorting', array($this, 'tutor_quiz_answer_sorting'));
77
- add_action('wp_ajax_tutor_mark_answer_as_correct', array($this, 'tutor_mark_answer_as_correct'));
78
- add_action('wp_ajax_tutor_quiz_modal_update_settings', array($this, 'tutor_quiz_modal_update_settings'));
79
 
80
  /**
81
- * Frontend Stuff
82
- */
83
- add_action('wp_ajax_tutor_render_quiz_content', array($this, 'tutor_render_quiz_content'));
84
 
85
  /**
86
  * Quiz abandon action
87
- *
88
  * @since 1.9.6
89
  */
90
- add_action('wp_ajax_tutor_quiz_abandon', array($this, 'tutor_quiz_abandon'));
91
 
92
  $this->prepare_allowed_html();
93
  }
94
 
95
  private function prepare_allowed_html() {
96
-
97
  $allowed = array();
98
 
99
- foreach($this->allowed_html as $tag) {
100
- $allowed[$tag] = $this->allowed_attributes;
101
  }
102
 
103
  $this->allowed_html = $allowed;
104
  }
105
 
106
- public function tutor_instructor_feedback(){
107
  tutils()->checking_nonce();
108
 
109
- $feedback = sanitize_text_field($_POST['feedback']);
110
- $attempt_id = (int) tutor_utils()->avalue_dot('attempts_id', $_POST);
111
 
112
- if ($attempt_id && tutils()->can_user_manage('attempt', $attempt_id)) {
113
- update_post_meta($attempt_id, 'instructor_feedback', $feedback);
114
- do_action('tutor_quiz/attempt/submitted/feedback', $attempt_id);
115
 
116
- wp_send_json_success( );
117
  }
118
  }
119
 
120
- public function save_quiz_meta($post_ID){
121
- if (isset($_POST['quiz_option'])){
122
- $quiz_option = tutor_utils()->sanitize_array($_POST['quiz_option']);
123
- update_post_meta($post_ID, 'tutor_quiz_option', $quiz_option);
124
  }
125
  }
126
 
127
  /**
128
  * Tutor Quiz Builder Modal
129
  */
130
- public function tutor_load_quiz_builder_modal(){
131
  tutils()->checking_nonce();
132
 
133
  ob_start();
134
- include tutor()->path.'views/modal/add_quiz.php';
135
  $output = ob_get_clean();
136
 
137
- wp_send_json_success(array('output' => $output));
138
  }
139
 
140
- public function remove_quiz_from_post(){
141
  tutils()->checking_nonce();
142
 
143
  global $wpdb;
144
- $quiz_id = (int) tutor_utils()->avalue_dot('quiz_id', $_POST);
145
 
146
- if(!tutils()->can_user_manage('quiz', $quiz_id)) {
147
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
148
  }
149
 
150
- $wpdb->update($wpdb->posts, array('post_parent' => 0), array('ID' => $quiz_id) );
151
  wp_send_json_success();
152
  }
153
 
154
  /**
155
  *
156
- * Start Quiz from here...
157
- *
158
- * @since v.1.0.0
159
  */
160
 
161
- public function start_the_quiz(){
162
- if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_start_quiz' ){
163
  return;
164
  }
165
- //Checking nonce
166
  tutor_utils()->checking_nonce();
167
 
168
- if ( ! is_user_logged_in()){
169
- //TODO: need to set a view in the next version
170
- die('Please sign in to do this operation');
171
  }
172
 
173
  global $wpdb;
174
 
175
  $user_id = get_current_user_id();
176
- $user = get_userdata($user_id);
177
 
178
- $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
179
 
180
- $quiz = get_post($quiz_id);
181
- $course = tutor_utils()->get_course_by_quiz($quiz_id);
182
- if ( empty($course->ID)){
183
- die('There is something went wrong with course, please check if quiz attached with a course');
184
- }
185
 
186
- do_action('tutor_quiz/start/before', $quiz_id, $user_id);
187
 
188
- $date = date("Y-m-d H:i:s", tutor_time());
189
 
190
- $tutor_quiz_option = (array) maybe_unserialize(get_post_meta($quiz_id, 'tutor_quiz_option', true));
191
- $attempts_allowed = tutor_utils()->get_quiz_option($quiz_id, 'attempts_allowed', 0);
192
 
193
- $time_limit = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_value');
194
  $time_limit_seconds = 0;
195
- $time_type = 'seconds';
196
- if ($time_limit){
197
- $time_type = tutor_utils()->get_quiz_option($quiz_id, 'time_limit.time_type');
198
 
199
- switch ($time_type){
200
  case 'seconds':
201
  $time_limit_seconds = $time_limit;
202
  break;
@@ -215,54 +216,54 @@ class Quiz {
215
  }
216
  }
217
 
218
- $max_question_allowed = tutor_utils()->max_questions_for_take_quiz($quiz_id);
219
  $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds;
220
 
221
  $attempt_data = array(
222
- 'course_id' => $course->ID,
223
- 'quiz_id' => $quiz_id,
224
- 'user_id' => $user_id,
225
- 'total_questions' => $max_question_allowed,
226
- 'total_answered_questions' => 0,
227
- 'attempt_info' => maybe_serialize($tutor_quiz_option),
228
- 'attempt_status' => 'attempt_started',
229
- 'attempt_ip' => tutor_utils()->get_ip(),
230
- 'attempt_started_at' => $date,
231
- );
232
-
233
- $wpdb->insert($wpdb->prefix.'tutor_quiz_attempts', $attempt_data);
234
  $attempt_id = (int) $wpdb->insert_id;
235
 
236
- do_action('tutor_quiz/start/after', $quiz_id, $user_id, $attempt_id);
237
 
238
- wp_redirect(get_permalink($quiz_id));
239
  die();
240
  }
241
 
242
- public function answering_quiz(){
243
 
244
- if ( tutils()->array_get('tutor_action', $_POST) !== 'tutor_answering_quiz_question' ){
245
  return;
246
  }
247
- //submit quiz attempts
248
  self::tutor_quiz_attemp_submit();
249
 
250
- wp_redirect(get_the_permalink());
251
  die();
252
  }
253
 
254
  /**
255
  * Quiz abandon submission handler
256
- *
257
  * @return JSON response
258
- *
259
  * @since 1.9.6
260
  */
261
- public function tutor_quiz_abandon(){
262
- if ( tutils()->array_get('tutor_action', $_POST) !== 'tutor_answering_quiz_question' ){
263
  return;
264
  }
265
- //submit quiz attempts
266
  if ( self::tutor_quiz_attemp_submit() ) {
267
  wp_send_json_success();
268
  } else {
@@ -272,263 +273,273 @@ class Quiz {
272
 
273
  /**
274
  * This is a unified method for handling normal quiz submit or abandon submit
275
- *
276
  * It will handle ajax or normal form submit and can be used with different hooks
277
- *
278
  * @return true | false
279
- *
280
- * @since 1.9.6
281
  */
282
  public static function tutor_quiz_attemp_submit() {
283
  tutor_utils()->checking_nonce();
284
 
285
- $attempt_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('attempt_id', $_POST));
286
- $attempt = tutor_utils()->get_attempt($attempt_id);
287
- $course_id = tutor_utils()->get_course_by_quiz($attempt->quiz_id)->ID;
288
 
289
- $attempt_answers = isset($_POST['attempt']) ? $_POST['attempt'] : false;
290
- if ( ! is_user_logged_in()){
291
- die('Please sign in to do this operation');
292
  }
293
 
294
  global $wpdb;
295
  $user_id = get_current_user_id();
296
 
297
- do_action('tutor_quiz/attempt_analysing/before', $attempt_id);
298
 
299
- if ($attempt_answers && is_array($attempt_answers) && count($attempt_answers)){
300
- foreach ($attempt_answers as $attempt_id => $attempt_answer){
301
 
302
- /**
303
- * Get total marks of all question comes
304
- */
305
- $question_ids = tutor_utils()->avalue_dot('quiz_question_ids', $attempt_answer);
306
- if (is_array($question_ids) && count($question_ids)){
307
- $question_ids_string = "'".implode("','", $question_ids)."'";
308
- $total_question_marks = $wpdb->get_var("SELECT SUM(question_mark) FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id IN({$question_ids_string}) ;");
309
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', array('total_marks' =>$total_question_marks ), array('attempt_id' => $attempt_id ));
310
- }
311
 
312
- if ( ! $attempt || $user_id != $attempt->user_id){
313
- die('Operation not allowed, attempt not found or permission denied');
314
- }
315
 
316
- $quiz_answers = tutor_utils()->avalue_dot('quiz_question', $attempt_answer);
317
 
318
- $total_marks = 0;
319
- $review_required = false;
320
 
321
- if ( tutils()->count($quiz_answers)) {
322
 
323
- foreach ( $quiz_answers as $question_id => $answers ) {
324
- $question = tutor_utils()->get_quiz_question_by_id( $question_id );
325
- $question_type = $question->question_type;
326
 
327
- $is_answer_was_correct = false;
328
- $given_answer = '';
329
 
330
- if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
331
 
332
- if(!is_numeric($answers) || !$answers) {
333
  wp_send_json_error();
334
  exit;
335
  }
336
 
337
- $given_answer = $answers;
338
- $is_answer_was_correct = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT is_correct FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d ", $answers ) );
339
 
340
- } elseif ( $question_type === 'multiple_choice' ) {
341
 
342
  $given_answer = (array) ( $answers );
343
-
344
- $given_answer = array_filter( $given_answer, function($id) {
345
- return is_numeric($id) && $id>0;
346
- } );
347
-
348
- $get_original_answers = (array) $wpdb->get_col($wpdb->prepare(
349
- "SELECT
350
- answer_id
351
- FROM
352
- {$wpdb->prefix}tutor_quiz_question_answers
353
- WHERE
354
- belongs_question_id = %d
355
- AND belongs_question_type = %s
 
 
 
 
356
  AND is_correct = 1 ;
357
- ",
358
- $question->question_id,
359
- $question_type
360
- ) );
361
-
362
-
363
- if (count(array_diff($get_original_answers, $given_answer)) === 0 && count($get_original_answers) === count($given_answer)) {
364
- $is_answer_was_correct = true;
365
  }
366
  $given_answer = maybe_serialize( $answers );
367
 
368
- } elseif ( $question_type === 'fill_in_the_blank' ) {
 
 
 
369
 
370
- $given_answer = (array) array_map( 'sanitize_text_field', $answers );
371
- $given_answer = maybe_serialize( $given_answer );
372
 
373
- $get_original_answer = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = %d AND belongs_question_type = %s ;", $question->question_id, $question_type ) );
374
- $gap_answer = (array) explode( '|', $get_original_answer->answer_two_gap_match );
 
 
 
 
 
375
 
376
- $gap_answer = array_map( 'sanitize_text_field', $gap_answer );
377
- if ( strtolower($given_answer) == strtolower(maybe_serialize( $gap_answer )) ) {
378
- $is_answer_was_correct = true;
379
- }
380
- } elseif ( $question_type === 'open_ended' || $question_type === 'short_answer' ) {
381
- $review_required = true;
382
- $given_answer = wp_kses_post( $answers );
383
 
384
- } elseif ( $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' ) {
 
385
 
386
- $given_answer = (array) array_map( 'sanitize_text_field', tutor_utils()->avalue_dot( 'answers', $answers ) );
387
- $given_answer = maybe_serialize( $given_answer );
 
 
 
 
 
 
 
388
 
389
- $get_original_answers = (array) $wpdb->get_col($wpdb->prepare(
390
- "SELECT answer_id
391
- FROM {$wpdb->prefix}tutor_quiz_question_answers
392
- WHERE belongs_question_id = %d AND belongs_question_type = %s ORDER BY answer_order ASC ;", $question->question_id, $question_type));
393
-
394
  $get_original_answers = array_map( 'sanitize_text_field', $get_original_answers );
395
 
396
- if ( $given_answer == maybe_serialize( $get_original_answers ) ) {
397
- $is_answer_was_correct = true;
398
- }
399
-
400
- } elseif ( $question_type === 'image_answering' ) {
401
- $image_inputs = tutor_utils()->avalue_dot( 'answer_id', $answers );
402
- $image_inputs = (array) array_map( 'sanitize_text_field', $image_inputs );
403
- $given_answer = maybe_serialize( $image_inputs );
404
- $is_answer_was_correct = false;
405
-
406
- $db_answer = $wpdb->get_col($wpdb->prepare(
407
- "SELECT answer_title
408
- FROM {$wpdb->prefix}tutor_quiz_question_answers
409
- WHERE belongs_question_id = %d AND belongs_question_type = 'image_answering' ORDER BY answer_order asc ;", $question_id));
410
-
411
- if ( is_array( $db_answer ) && count( $db_answer ) ) {
412
- $is_answer_was_correct = ( strtolower( maybe_serialize( array_values( $image_inputs ) ) ) == strtolower( maybe_serialize( $db_answer ) ) );
413
- }
414
- }
415
-
416
- $question_mark = $is_answer_was_correct ? $question->question_mark : 0;
417
- $total_marks += $question_mark;
418
-
419
- $answers_data = array(
420
- 'user_id' => $user_id,
421
- 'quiz_id' => $attempt->quiz_id,
422
- 'question_id' => $question_id,
423
- 'quiz_attempt_id' => $attempt_id,
424
- 'given_answer' => $given_answer,
425
- 'question_mark' => $question->question_mark,
426
- 'achieved_mark' => $question_mark,
427
- 'minus_mark' => 0,
428
- 'is_correct' => $is_answer_was_correct ? 1 : 0,
429
- );
430
-
431
- /*
432
- check if question_type open ended or short ans the set is_correct default value null before saving
433
- */
434
- if($question_type==="open_ended" || $question_type ==="short_answer")
435
- {
436
- $answers_data['is_correct'] = NULL;
 
 
437
  }
438
-
439
- $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answers_data );
440
- }
441
- }
442
-
443
- $attempt_info = array(
444
- 'total_answered_questions' => tutils()->count($quiz_answers),
445
- 'earned_marks' => $total_marks,
446
- 'attempt_status' => 'attempt_ended',
447
- 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
448
- );
449
-
450
- if ($review_required){
451
- $attempt_info['attempt_status'] = 'review_required';
452
- }
453
-
454
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
455
- }
456
-
457
- do_action('tutor_quiz/attempt_ended', $attempt_id, $course_id, $user_id);
458
  return true;
459
- }
460
  return false;
461
  }
462
 
463
 
464
  /**
465
  * Quiz attempt will be finish here
466
- *
467
  */
468
 
469
- public function finishing_quiz_attempt(){
470
 
471
- if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_finish_quiz_attempt' ){
472
  return;
473
  }
474
- //Checking nonce
475
  tutor_utils()->checking_nonce();
476
 
477
- if ( ! is_user_logged_in()){
478
- die('Please sign in to do this operation');
479
  }
480
 
481
  global $wpdb;
482
 
483
- $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
484
- $attempt = tutor_utils()->is_started_quiz($quiz_id);
485
  $attempt_id = $attempt->attempt_id;
486
 
487
  $attempt_info = array(
488
- 'total_answered_questions' => 0,
489
- 'earned_marks' => 0,
490
- 'attempt_status' => 'attempt_ended',
491
- 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
492
  );
493
 
494
- do_action('tutor_quiz_before_finish', $attempt_id, $quiz_id, $attempt->user_id);
495
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_info, array('attempt_id' => $attempt_id));
496
- do_action('tutor_quiz_finished', $attempt_id, $quiz_id, $attempt->user_id);
497
 
498
- wp_redirect(tutor_utils()->input_old('_wp_http_referer'));
499
  }
500
 
501
  /**
502
  * Quiz timeout by ajax
503
  */
504
- public function tutor_quiz_timeout(){
505
  tutils()->checking_nonce();
506
 
507
  global $wpdb;
508
 
509
- $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
510
 
511
  // if(!tutils()->can_user_manage('quiz', $quiz_id)) {
512
- // wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
513
  // }
514
 
515
- $attempt = tutor_utils()->is_started_quiz($quiz_id);
516
 
517
- if ($attempt) {
518
  $attempt_id = $attempt->attempt_id;
519
 
520
  $data = array(
521
- 'attempt_status' => 'attempt_timeout',
522
- 'attempt_ended_at' => date("Y-m-d H:i:s", tutor_time()),
523
- );
524
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $data, array('attempt_id' => $attempt->attempt_id));
525
 
526
- do_action('tutor_quiz_timeout', $attempt_id, $quiz_id, $attempt->user_id);
527
 
528
  wp_send_json_success();
529
  }
530
 
531
- wp_send_json_error(__('Quiz has been timeout already', 'tutor'));
532
  }
533
 
534
  /**
@@ -536,94 +547,88 @@ class Quiz {
536
  */
537
 
538
  public function review_quiz_answer() {
539
-
540
- tutils()->checking_nonce(strtolower($_SERVER['REQUEST_METHOD']));
541
 
542
  global $wpdb;
543
 
544
- $attempt_id = (int) sanitize_text_field($_GET['attempt_id']);
545
- $attempt_answer_id = (int) sanitize_text_field($_GET['attempt_answer_id']);
546
- $mark_as = sanitize_text_field($_GET['mark_as']);
547
 
548
- if(!tutils()->can_user_manage('attempt', $attempt_id) || !tutils()->can_user_manage('attempt_answer', $attempt_answer_id)) {
549
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
550
  }
551
 
552
- $attempt_answer = $wpdb->get_row($wpdb->prepare(
553
- "SELECT * FROM {$wpdb->prefix}tutor_quiz_attempt_answers
554
- WHERE attempt_answer_id = %d ",
555
- $attempt_answer_id
556
- ));
 
 
557
 
558
- $attempt = tutor_utils()->get_attempt($attempt_id);
559
- $question = tutils()->get_quiz_question_by_id($attempt_answer->question_id);
560
- $course_id = $attempt->course_id;
561
- $student_id = $attempt->user_id;
562
- $previous_ans = $attempt_answer->is_correct;
563
 
564
- do_action('tutor_quiz_review_answer_before', $attempt_answer_id, $attempt_id, $mark_as);
565
 
566
- if ($mark_as === 'correct'){
567
 
568
  $answer_update_data = array(
569
  'achieved_mark' => $attempt_answer->question_mark,
570
- 'is_correct' => 1,
571
  );
572
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
573
- if($previous_ans ==0 OR $previous_ans ==null)
574
- {
575
-
576
- //if previous answer was wrong or in review then add point as correct
577
  $attempt_update_data = array(
578
- 'earned_marks' => $attempt->earned_marks + $attempt_answer->question_mark,
579
- 'is_manually_reviewed' => 1,
580
- 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
581
  );
582
 
583
-
584
  }
585
-
586
- if ($question->question_type === 'open_ended' || $question->question_type === 'short_answer' ){
587
- $attempt_update_data['attempt_status'] = 'attempt_ended';
588
- }
589
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
590
- }
591
- elseif($mark_as === 'incorrect')
592
- {
593
 
594
  $answer_update_data = array(
595
  'achieved_mark' => '0.00',
596
- 'is_correct' => 0,
597
  );
598
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempt_answers', $answer_update_data, array('attempt_answer_id' => $attempt_answer_id ));
599
 
 
600
 
601
- if($previous_ans ==1)
602
- {
603
-
604
- //if previous ans was right then mynus
605
  $attempt_update_data = array(
606
- 'earned_marks' => $attempt->earned_marks - $attempt_answer->question_mark,
607
- 'is_manually_reviewed' => 1,
608
- 'manually_reviewed_at' => date("Y-m-d H:i:s", tutor_time()),
609
  );
610
 
611
  }
612
- if ($question->question_type === 'open_ended' || $question->question_type === 'short_answer' ){
613
- $attempt_update_data['attempt_status'] = 'attempt_ended';
614
- }
615
-
616
- $wpdb->update($wpdb->prefix.'tutor_quiz_attempts', $attempt_update_data, array('attempt_id' => $attempt_id ));
617
  }
618
- do_action('tutor_quiz_review_answer_after', $attempt_answer_id, $attempt_id, $mark_as);
619
- do_action('tutor_quiz/answer/review/after', $attempt_answer_id, $course_id, $student_id);
620
-
621
- if (wp_doing_ajax())
622
- {
623
- wp_send_json_success();
624
- }
625
- else{
626
- wp_redirect(admin_url("admin.php?page=tutor_quiz_attempts&sub_page=view_attempt&attempt_id=".$attempt_id));
627
  }
628
 
629
  die();
@@ -633,131 +638,143 @@ class Quiz {
633
  /**
634
  * New Design Quiz
635
  */
636
- public function tutor_create_quiz_and_load_modal(){
637
  tutils()->checking_nonce();
638
 
639
- $topic_id = sanitize_text_field($_POST['topic_id']);
640
- $quiz_title = sanitize_text_field($_POST['quiz_title']);
641
- $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
642
- $next_order_id = tutor_utils()->get_next_course_content_order_id($topic_id);
643
-
644
- if(!tutils()->can_user_manage('topic', $topic_id)) {
645
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor'), 'data'=>$_POST) );
 
 
 
 
 
646
  }
647
 
648
  $post_arr = array(
649
- 'post_type' => 'tutor_quiz',
650
- 'post_title' => $quiz_title,
651
- 'post_content' => $quiz_description,
652
- 'post_status' => 'publish',
653
- 'post_author' => get_current_user_id(),
654
- 'post_parent' => $topic_id,
655
- 'menu_order' => $next_order_id,
656
  );
657
- $quiz_id = wp_insert_post( $post_arr );
658
- do_action('tutor_initial_quiz_created', $quiz_id);
659
 
660
  ob_start();
661
- include tutor()->path.'views/modal/edit_quiz.php';
662
  $output = ob_get_clean();
663
 
664
  ob_start();
665
  ?>
666
- <div id="tutor-quiz-<?php echo $quiz_id; ?>" class="course-content-item tutor-quiz tutor-quiz-<?php echo $quiz_id; ?>">
667
- <div class="tutor-lesson-top">
668
- <i class="tutor-icon-move"></i>
669
- <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
670
- ?>"> <i class=" tutor-icon-doubt"></i>[<?php _e('QUIZ', 'tutor'); ?>] <?php echo stripslashes($quiz_title); ?> </a>
671
- <?php do_action('tutor_course_builder_before_quiz_btn_action', $quiz_id); ?>
672
- <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
673
- </div>
674
- </div>
 
 
675
  <?php
676
  $output_quiz_row = ob_get_clean();
677
 
678
- wp_send_json_success(array('output' => $output, 'output_quiz_row' => $output_quiz_row));
 
 
 
 
 
679
  }
680
 
681
- public function tutor_delete_quiz_by_id(){
682
  tutils()->checking_nonce();
683
 
684
- global $wpdb;
685
 
686
- $quiz_id = (int) sanitize_text_field($_POST['quiz_id']);
687
- $post = get_post($quiz_id);
688
 
689
-
690
- if(!tutils()->can_user_manage('quiz', $quiz_id)) {
691
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
692
  }
693
 
694
- if ( $post->post_type === 'tutor_quiz'){
695
- do_action('tutor_delete_quiz_before', $quiz_id);
696
 
697
- $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $quiz_id));
698
- $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $quiz_id));
699
 
700
- $questions_ids = $wpdb->get_col($wpdb->prepare("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $quiz_id));
701
-
702
- if (is_array($questions_ids) && count($questions_ids)){
703
- $in_question_ids = "'".implode("','", $questions_ids)."'";
704
- $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
705
  }
706
-
707
- $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $quiz_id));
708
 
709
- wp_delete_post($quiz_id, true);
710
- delete_post_meta($quiz_id, '_tutor_course_id_for_lesson');
711
 
712
- do_action('tutor_delete_quiz_after', $quiz_id);
 
713
 
 
714
 
715
- wp_send_json_success();
716
- }
717
 
718
- wp_send_json_error();
719
- }
720
 
721
  /**
722
  * Update Quiz from quiz builder modal
723
  *
724
  * @since v.1.0.0
725
  */
726
- public function tutor_quiz_builder_quiz_update(){
727
  tutils()->checking_nonce();
728
 
729
- $quiz_id = sanitize_text_field($_POST['quiz_id']);
730
- $topic_id = sanitize_text_field($_POST['topic_id']);
731
- $quiz_title = sanitize_text_field($_POST['quiz_title']);
732
- $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
733
 
734
- if(!tutils()->can_user_manage('quiz', $quiz_id)) {
735
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
736
  }
737
 
738
  $post_arr = array(
739
- 'ID' => $quiz_id,
740
- 'post_title' => $quiz_title,
741
- 'post_content' => $quiz_description,
742
 
743
  );
744
  $quiz_id = wp_update_post( $post_arr );
745
 
746
- do_action('tutor_quiz_updated', $quiz_id);
747
 
748
  ob_start();
749
  ?>
750
- <div class="tutor-lesson-top">
751
- <i class="tutor-icon-move"></i>
752
- <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id;
753
- ?>"> <i class=" tutor-icon-doubt"></i>[<?php _e('QUIZ', 'tutor'); ?>] <?php echo stripslashes($quiz_title); ?> </a>
754
- <?php do_action('tutor_course_builder_before_quiz_btn_action', $quiz_id); ?>
755
- <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
756
- </div>
 
 
757
  <?php
758
  $output_quiz_row = ob_get_clean();
759
 
760
- wp_send_json_success(array('output_quiz_row' => $output_quiz_row));
761
  }
762
 
763
  /**
@@ -765,21 +782,21 @@ class Quiz {
765
  *
766
  * @since v.1.0.0
767
  */
768
- public function tutor_load_edit_quiz_modal(){
769
  tutils()->checking_nonce();
770
 
771
- $quiz_id = sanitize_text_field ($_POST['quiz_id'] );
772
- $topic_id = sanitize_text_field( $_POST['topic_id'] );
773
-
774
- if(!tutils()->can_user_manage('quiz', $quiz_id)) {
775
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
776
  }
777
-
778
  ob_start();
779
- include tutor()->path.'views/modal/edit_quiz.php';
780
  $output = ob_get_clean();
781
 
782
- wp_send_json_success(array('output' => $output));
783
  }
784
 
785
  /**
@@ -787,115 +804,114 @@ class Quiz {
787
  *
788
  * @since v.1.0.0
789
  */
790
- public function tutor_quiz_builder_get_question_form(){
791
  tutils()->checking_nonce();
792
 
793
  global $wpdb;
794
- $quiz_id = sanitize_text_field($_POST['quiz_id']);
795
- $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
796
 
797
- if(!tutils()->can_user_manage('quiz', $quiz_id)) {
798
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
799
  }
800
-
801
- if ( ! $question_id){
802
- $next_question_id = tutor_utils()->quiz_next_question_id();
803
- $next_question_order = tutor_utils()->quiz_next_question_order_id($quiz_id);
804
 
805
  $new_question_data = array(
806
- 'quiz_id' => $quiz_id,
807
- 'question_title' => __('Question', 'tutor').' '.$next_question_id,
808
- 'question_description' => '',
809
- 'question_type' => 'true_false',
810
- 'question_mark' => 1,
811
- 'question_settings' => maybe_serialize(array()),
812
- 'question_order' => esc_sql( $next_question_order ) ,
813
  );
814
 
815
- $wpdb->insert($wpdb->prefix.'tutor_quiz_questions', $new_question_data);
816
  $question_id = $wpdb->insert_id;
817
  }
818
 
819
- $question = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = %d ", $question_id));
820
 
821
  ob_start();
822
- include tutor()->path.'views/modal/question_form.php';
823
  $output = ob_get_clean();
824
 
825
- wp_send_json_success(array('output' => $output));
826
  }
827
 
828
- public function tutor_quiz_modal_update_question(){
829
  tutils()->checking_nonce();
830
 
831
  global $wpdb;
832
 
833
- $question_data = $_POST['tutor_quiz_question'];
834
 
835
- foreach ($question_data as $question_id => $question) {
836
 
837
- if(!tutils()->can_user_manage('question', $question_id)) {
838
  continue;
839
  }
840
 
841
- $question_title = sanitize_text_field($question['question_title']);
842
- $question_description = wp_kses( $question['question_description'], $this->allowed_html ); // sanitize_text_field($question['question_description']);
843
- $question_type = sanitize_text_field($question['question_type']);
844
- $question_mark = sanitize_text_field($question['question_mark']);
845
 
846
- unset($question['question_title']);
847
- unset($question['question_description']);
848
 
849
  $data = array(
850
- 'question_title' => $question_title,
851
- 'question_description' => $question_description,
852
- 'question_type' => $question_type,
853
- 'question_mark' => $question_mark,
854
- 'question_settings' => maybe_serialize($question),
855
  );
856
 
857
- $wpdb->update($wpdb->prefix.'tutor_quiz_questions', $data, array('question_id' => $question_id) );
858
-
859
 
860
  /**
861
  * Validation
862
  */
863
- if ($question_type === 'true_false' || $question_type === 'single_choice'){
864
- $question_options = tutils()->get_answers_by_quiz_question($question_id);
865
- if (tutils()->count($question_options)){
866
- $required_validate = true;
867
- foreach ($question_options as $question_option){
868
- if ($question_option->is_correct){
869
- $required_validate = false;
870
- }
871
- }
872
- if ($required_validate){
873
- $validation_msg = "<p class='tutor-error-msg'>".__('Please select the correct answer', 'tutor')."</p>";
874
- wp_send_json_error(array('validation_msg' => $validation_msg ));
875
- }
876
- }else{
877
- $validation_msg = "<p class='tutor-error-msg'>".__('Please make sure you have added more than one option and saved them', 'tutor')."</p>";
878
- wp_send_json_error(array('validation_msg' => $validation_msg ));
879
- }
880
- }
881
  }
882
 
883
  wp_send_json_success();
884
  }
885
 
886
- public function tutor_quiz_builder_question_delete(){
887
  tutils()->checking_nonce();
888
 
889
  global $wpdb;
890
 
891
- $question_id = sanitize_text_field(tutor_utils()->avalue_dot('question_id', $_POST));
892
-
893
- if(!tutils()->can_user_manage('question', $question_id)) {
894
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
895
  }
896
 
897
- if ($question_id){
898
- $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('question_id' => esc_sql( $question_id ) ));
899
  }
900
 
901
  wp_send_json_success();
@@ -906,126 +922,143 @@ class Quiz {
906
  *
907
  * @since v.1.0.0
908
  */
909
- public function tutor_quiz_add_question_answers(){
910
  tutils()->checking_nonce();
911
 
912
- $question_id = sanitize_text_field($_POST['question_id']);
913
- $question = tutor_utils()->avalue_dot($question_id, $_POST['tutor_quiz_question']);
914
  $question_type = $question['question_type'];
915
 
916
- if(!tutils()->can_user_manage('question', $question_id)) {
917
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
918
  }
919
 
920
  ob_start();
921
- include tutor()->path.'views/modal/question_answer_form.php';
922
  $output = ob_get_clean();
923
 
924
- wp_send_json_success(array('output' => $output));
925
  }
926
 
927
  /**
928
  * Edit Answer Form
929
- *
930
- * @since v.1.0.0
931
  */
932
- public function tutor_quiz_edit_question_answer(){
933
  tutils()->checking_nonce();
934
 
935
- $answer_id = (int) sanitize_text_field($_POST['answer_id']);
 
 
 
 
936
 
937
- if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
938
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
939
  }
940
-
941
- $old_answer = tutor_utils()->get_answer_by_id($answer_id);
942
- foreach ($old_answer as $old_answer);
943
- $question_id = $old_answer->belongs_question_id;
944
  $question_type = $old_answer->belongs_question_type;
945
 
946
  ob_start();
947
- include tutor()->path.'views/modal/question_answer_edit_form.php';
948
  $output = ob_get_clean();
949
 
950
- wp_send_json_success(array('output' => $output));
951
- }
952
 
953
- public function tutor_save_quiz_answer_options(){
954
  tutils()->checking_nonce();
955
 
956
  global $wpdb;
957
 
958
- $questions = $_POST['tutor_quiz_question'];
959
- $answers = $_POST['quiz_answer'];
960
 
961
- foreach ($answers as $question_id => $answer){
962
 
963
- if(!tutils()->can_user_manage('question', $question_id)) {
964
  continue;
965
  }
966
 
967
- $question = tutor_utils()->avalue_dot($question_id, $questions);
968
  $question_type = $question['question_type'];
969
 
970
- //Getting next sorting order
971
- $next_order_id = (int) $wpdb->get_var($wpdb->prepare(
972
- "SELECT MAX(answer_order)
973
- FROM {$wpdb->prefix}tutor_quiz_question_answers
974
- where belongs_question_id = %d
975
- AND belongs_question_type = %s ", $question_id, esc_sql( $question_type )));
 
 
 
 
 
976
 
977
  $next_order_id = $next_order_id + 1;
978
 
979
- if ($question){
980
- if ($question_type === 'true_false'){
981
- $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
 
 
 
 
 
 
982
  $data_true_false = array(
983
  array(
984
- 'belongs_question_id' => esc_sql( $question_id ) ,
985
  'belongs_question_type' => $question_type,
986
- 'answer_title' => __('True', 'tutor'),
987
  'is_correct' => $answer['true_false'] == 'true' ? 1 : 0,
988
  'answer_two_gap_match' => 'true',
989
  ),
990
  array(
991
- 'belongs_question_id' => esc_sql( $question_id ) ,
992
  'belongs_question_type' => $question_type,
993
- 'answer_title' => __('False', 'tutor'),
994
  'is_correct' => $answer['true_false'] == 'false' ? 1 : 0,
995
  'answer_two_gap_match' => 'false',
996
  ),
997
  );
998
 
999
- foreach ($data_true_false as $true_false_data){
1000
- $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $true_false_data);
1001
  }
1002
-
1003
- }elseif($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' ||
1004
- $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'image_answering' ){
1005
 
1006
  $answer_data = array(
1007
  'belongs_question_id' => sanitize_text_field( $question_id ),
1008
  'belongs_question_type' => $question_type,
1009
  'answer_title' => sanitize_text_field( $answer['answer_title'] ),
1010
- 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
1011
- 'answer_view_format' => isset($answer['answer_view_format']) ? $answer['answer_view_format'] : 0,
1012
  'answer_order' => $next_order_id,
1013
  );
1014
- if (isset($answer['matched_answer_title'])){
1015
  $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] );
1016
- }
1017
 
1018
- $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
1019
 
1020
- }elseif($question_type === 'fill_in_the_blank'){
1021
- $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('belongs_question_id' => $question_id, 'belongs_question_type' => $question_type));
 
 
 
 
 
 
1022
  $answer_data = array(
1023
- 'belongs_question_id' => sanitize_text_field( $question_id ) ,
1024
  'belongs_question_type' => $question_type,
1025
  'answer_title' => sanitize_text_field( $answer['answer_title'] ),
1026
- 'answer_two_gap_match' => isset($answer['answer_two_gap_match']) ? sanitize_text_field( trim($answer['answer_two_gap_match']) ) : null,
1027
  );
1028
- $wpdb->insert($wpdb->prefix.'tutor_quiz_question_answers', $answer_data);
1029
  }
1030
  }
1031
  }
@@ -1035,275 +1068,275 @@ class Quiz {
1035
 
1036
  /**
1037
  * Tutor Update Answer
1038
- *
1039
- * @since v.1.0.0
1040
  */
1041
- public function tutor_update_quiz_answer_options(){
1042
  tutils()->checking_nonce();
1043
 
1044
  global $wpdb;
1045
 
1046
- $answer_id = (int) sanitize_text_field($_POST['tutor_quiz_answer_id']);
1047
 
1048
- if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1049
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1050
  }
1051
 
1052
- $questions = $_POST['tutor_quiz_question'];
1053
- $answers = $_POST['quiz_answer'];
1054
 
1055
- foreach ($answers as $question_id => $answer){
1056
- $question = tutor_utils()->avalue_dot($question_id, $questions);
1057
  $question_type = $question['question_type'];
1058
 
1059
- if ($question){
1060
- if($question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'fill_in_the_blank' || $question_type === 'image_answering' ){
1061
 
1062
  $answer_data = array(
1063
  'belongs_question_id' => $question_id,
1064
  'belongs_question_type' => $question_type,
1065
- 'answer_title' => sanitize_text_field( $answer['answer_title'] ) ,
1066
- 'image_id' => isset($answer['image_id']) ? $answer['image_id'] : 0,
1067
- 'answer_view_format' => isset($answer['answer_view_format']) ? sanitize_text_field( $answer['answer_view_format'] ) : '',
1068
  );
1069
- if (isset($answer['matched_answer_title'])){
1070
- $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] ) ;
1071
  }
1072
 
1073
- if ($question_type === 'fill_in_the_blank'){
1074
- $answer_data['answer_two_gap_match'] = isset($answer['answer_two_gap_match']) ? sanitize_text_field(trim($answer['answer_two_gap_match'])) : null;
1075
  }
1076
 
1077
- $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', $answer_data, array('answer_id' => $answer_id));
1078
  }
1079
  }
1080
  }
1081
 
1082
- //die(print_r($_POST));
1083
  wp_send_json_success();
1084
- }
1085
 
1086
- public function tutor_quiz_builder_get_answers_by_question(){
1087
  tutils()->checking_nonce();
1088
 
1089
  global $wpdb;
1090
- $question_id = sanitize_text_field($_POST['question_id']);
1091
- $question_type = sanitize_text_field($_POST['question_type']);
1092
 
1093
- if(!tutils()->can_user_manage('question', $question_id)) {
1094
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1095
  }
1096
 
1097
- $question = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = %d ", $question_id));
1098
- $answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = %d AND belongs_question_type = %s order by answer_order asc ;", $question_id, esc_sql( $question_type ) ));
1099
 
1100
  ob_start();
1101
 
1102
- switch ($question_type){
1103
  case 'true_false':
1104
- echo '<label>'.__('Answer options &amp; mark correct', 'tutor').'</label>';
1105
  break;
1106
  case 'ordering':
1107
- echo '<label>'.__('Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor').'</label>';
1108
  break;
1109
  }
1110
 
1111
- if (is_array($answers) && count($answers)){
1112
- foreach ($answers as $answer){
1113
  ?>
1114
- <div class="tutor-quiz-answer-wrap" data-answer-id="<?php echo $answer->answer_id; ?>">
1115
- <div class="tutor-quiz-answer">
1116
- <span class="tutor-quiz-answer-title">
1117
- <?php
1118
- echo stripslashes($answer->answer_title);
1119
- if ($answer->belongs_question_type === 'fill_in_the_blank'){
1120
- echo ' ('.__('Answer', 'tutor').' : ';
1121
- echo '<strong>'. stripslashes($answer->answer_two_gap_match). '</strong>)';
1122
- }
1123
- if ($answer->belongs_question_type === 'matching'){
1124
- echo ' - '.stripslashes($answer->answer_two_gap_match);
1125
- }
1126
- ?>
1127
- </span>
1128
 
1129
  <?php
1130
- if ($answer->image_id){
1131
- echo '<span class="tutor-question-answer-image"><img src="'.wp_get_attachment_image_url($answer->image_id).'" /> </span>';
1132
  }
1133
- if ($question_type === 'true_false' || $question_type === 'single_choice'){
1134
  ?>
1135
- <span class="tutor-quiz-answers-mark-correct-wrap">
1136
- <input type="radio" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e('Mark as correct', 'tutor'); ?>" <?php checked(1, $answer->is_correct); ?> >
1137
- </span>
1138
  <?php
1139
- }elseif ($question_type === 'multiple_choice'){
1140
  ?>
1141
- <span class="tutor-quiz-answers-mark-correct-wrap">
1142
- <input type="checkbox" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e('Mark as correct', 'tutor'); ?>" <?php checked(1, $answer->is_correct); ?> >
1143
- </span>
1144
  <?php
1145
  }
1146
  ?>
1147
- <?php if( "true_false" != $question_type ):?>
1148
  <span class="tutor-quiz-answer-edit">
1149
  <a href="javascript:;"><i class="tutor-icon-pencil"></i> </a>
1150
  </span>
1151
- <?php endif;?>
1152
- <span class="tutor-quiz-answer-sort-icon"><i class="tutor-icon-menu-2"></i> </span>
1153
- </div>
1154
- <?php if( "true_false" != $question_type ):?>
1155
  <div class="tutor-quiz-answer-trash-wrap">
1156
- <a href="javascript:;" class="answer-trash-btn" data-answer-id="<?php echo $answer->answer_id; ?>"><i class="tutor-icon-garbage"></i> </a>
1157
  </div>
1158
- <?php endif;?>
1159
- </div>
1160
  <?php
1161
  }
1162
  }
1163
  $output = ob_get_clean();
1164
 
1165
- wp_send_json_success(array('output' => $output));
1166
  }
1167
 
1168
- public function tutor_quiz_builder_delete_answer(){
1169
  tutils()->checking_nonce();
1170
 
1171
  global $wpdb;
1172
- $answer_id = sanitize_text_field($_POST['answer_id']);
1173
-
1174
- if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1175
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1176
  }
1177
 
1178
- $wpdb->delete($wpdb->prefix.'tutor_quiz_question_answers', array('answer_id' => esc_sql( $answer_id ) ));
1179
  wp_send_json_success();
1180
  }
1181
 
1182
  /**
1183
  * Save quiz questions sorting
1184
  */
1185
- public function tutor_quiz_question_sorting(){
1186
  tutils()->checking_nonce();
1187
 
1188
  global $wpdb;
1189
 
1190
- $question_ids = tutor_utils()->avalue_dot('sorted_question_ids', $_POST);
1191
- if (is_array($question_ids) && count($question_ids) ){
1192
  $i = 0;
1193
- foreach ($question_ids as $key => $question_id){
1194
- if(tutils()->can_user_manage('question', $question_id)) {
1195
  $i++;
1196
- $wpdb->update($wpdb->prefix.'tutor_quiz_questions', array('question_order' => $i), array('question_id' => $question_id));
1197
  }
1198
  }
1199
  }
1200
- }
1201
 
1202
  /**
1203
  * Save sorting data for quiz answers
1204
  */
1205
- public function tutor_quiz_answer_sorting(){
1206
  tutils()->checking_nonce();
1207
 
1208
- global $wpdb;
1209
 
1210
- if ( ! empty($_POST['sorted_answer_ids']) && is_array($_POST['sorted_answer_ids']) && count($_POST['sorted_answer_ids']) ){
1211
- $answer_ids = $_POST['sorted_answer_ids'];
1212
- $i = 0;
1213
- foreach ($answer_ids as $key => $answer_id){
1214
- if(tutils()->can_user_manage('quiz_answer', $answer_id)) {
1215
  $i++;
1216
- $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('answer_order' => $i), array('answer_id' => $answer_id));
1217
  }
1218
- }
1219
- }
1220
- }
1221
 
1222
  /**
1223
  * Mark answer as correct
1224
  */
1225
 
1226
- public function tutor_mark_answer_as_correct(){
1227
  tutils()->checking_nonce();
1228
 
1229
- global $wpdb;
1230
 
1231
- $answer_id = sanitize_text_field($_POST['answer_id']);
1232
- $inputValue = sanitize_text_field($_POST['inputValue']);
1233
-
1234
- if(!tutils()->can_user_manage('quiz_answer', $answer_id)) {
1235
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1236
  }
1237
 
1238
- $answer = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d LIMIT 0,1 ;", $answer_id));
1239
- if ($answer->belongs_question_type === 'single_choice') {
1240
- $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => 0), array('belongs_question_id' => esc_sql( $answer->belongs_question_id ) ));
1241
- }
1242
- $wpdb->update($wpdb->prefix.'tutor_quiz_question_answers', array('is_correct' => esc_sql( $inputValue ) ), array('answer_id' => esc_sql( $answer_id ) ));
1243
- }
1244
 
1245
  /**
1246
  * Update quiz settings from modal
1247
  *
1248
  * @since : v.1.0.0
1249
  */
1250
- public function tutor_quiz_modal_update_settings(){
1251
  tutils()->checking_nonce();
1252
- //while creating quiz if creating step is not follow then it may throw error that why check added
1253
- $quiz_id = ( isset( $_POST['quiz_id'] ) ) ? sanitize_text_field( $_POST['quiz_id'] ) : '' ;
1254
  $current_topic_id = sanitize_text_field( $_POST['topic_id'] );
1255
- $course_id = tutor_utils()->get_course_id_by('topic', sanitize_textarea_field( $current_topic_id ) );
1256
 
1257
  $quiz_option = tutor_utils()->sanitize_array( $_POST['quiz_option'] );
1258
-
1259
- if( !tutils()->can_user_manage('quiz', $quiz_id) ) {
1260
- wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
1261
  }
1262
 
1263
- update_post_meta($quiz_id, 'tutor_quiz_option', $quiz_option);
1264
- do_action('tutor_quiz_settings_updated', $quiz_id);
1265
 
1266
- //@since 1.9.6
1267
  ob_start();
1268
- include tutor()->path.'views/metabox/course-contents.php';
1269
  $course_contents = ob_get_clean();
1270
 
1271
  wp_send_json_success( array( 'course_contents' => $course_contents ) );
1272
  }
1273
 
1274
 
1275
- //=========================//
1276
- // Front end stuffs
1277
- //=========================//
1278
 
1279
  /**
1280
  * Rendering quiz for frontend
1281
- *
1282
- * @since v.1.0.0
1283
  */
1284
 
1285
- public function tutor_render_quiz_content(){
1286
 
1287
  tutils()->checking_nonce();
1288
 
1289
- $quiz_id = (int) sanitize_text_field(tutor_utils()->avalue_dot('quiz_id', $_POST));
1290
 
1291
- if(!tutils()->has_enrolled_content_access('quiz', $quiz_id)) {
1292
- wp_send_json_error( array('message'=>__('Access Denied.', 'tutor')) );
1293
  }
1294
 
1295
  ob_start();
1296
  global $post;
1297
 
1298
- $post = get_post($quiz_id);
1299
- setup_postdata($post);
1300
- //tutor_lesson_content();
1301
 
1302
  single_quiz_contents();
1303
  wp_reset_postdata();
1304
 
1305
  $html = ob_get_clean();
1306
- wp_send_json_success(array('html' => $html));
1307
  }
1308
 
1309
- }
11
 
12
  namespace TUTOR;
13
 
14
+ if ( ! defined( 'ABSPATH' ) ) {
15
  exit;
16
+ }
17
 
18
  class Quiz {
19
 
20
+ private $allowed_attributes = array(
21
+ 'src' => array(),
22
+ 'style' => array(),
23
+ 'class' => array(),
24
+ 'id' => array(),
25
+ 'href' => array(),
26
+ 'alt' => array(),
27
  'title' => array(),
28
  'type' => array(),
29
  'controls' => array(),
30
  'muted' => array(),
31
+ 'loop' => array(),
32
  'poster' => array(),
33
  'preload' => array(),
34
  'autoplay' => array(),
35
  'width' => array(),
36
+ 'height' => array(),
37
  );
38
+
39
  private $allowed_html = array( 'img', 'b', 'i', 'br', 'a', 'audio', 'video', 'source' );
40
 
41
  public function __construct() {
 
 
42
 
43
+ add_action( 'save_post_tutor_quiz', array( $this, 'save_quiz_meta' ) );
44
+
45
+ add_action( 'wp_ajax_tutor_load_quiz_builder_modal', array( $this, 'tutor_load_quiz_builder_modal' ) );
46
+ add_action( 'wp_ajax_remove_quiz_from_post', array( $this, 'remove_quiz_from_post' ) );
47
 
48
+ add_action( 'wp_ajax_tutor_quiz_timeout', array( $this, 'tutor_quiz_timeout' ) );
49
 
50
+ // User take the quiz
51
+ add_action( 'template_redirect', array( $this, 'start_the_quiz' ) );
52
+ add_action( 'template_redirect', array( $this, 'answering_quiz' ) );
53
+ add_action( 'template_redirect', array( $this, 'finishing_quiz_attempt' ) );
54
 
55
+ add_action( 'admin_action_review_quiz_answer', array( $this, 'review_quiz_answer' ) );
56
+ add_action( 'wp_ajax_review_quiz_answer', array( $this, 'review_quiz_answer' ) );
57
+ add_action( 'wp_ajax_tutor_instructor_feedback', array( $this, 'tutor_instructor_feedback' ) ); // Instructor Feedback Action
58
 
59
  /**
60
  * New Design Quiz
61
  */
62
 
63
+ add_action( 'wp_ajax_tutor_create_quiz_and_load_modal', array( $this, 'tutor_create_quiz_and_load_modal' ) );
64
+ add_action( 'wp_ajax_tutor_delete_quiz_by_id', array( $this, 'tutor_delete_quiz_by_id' ) );
65
+ add_action( 'wp_ajax_tutor_quiz_builder_quiz_update', array( $this, 'tutor_quiz_builder_quiz_update' ) );
66
+ add_action( 'wp_ajax_tutor_load_edit_quiz_modal', array( $this, 'tutor_load_edit_quiz_modal' ) );
67
+ add_action( 'wp_ajax_tutor_quiz_builder_get_question_form', array( $this, 'tutor_quiz_builder_get_question_form' ) );
68
+ add_action( 'wp_ajax_tutor_quiz_modal_update_question', array( $this, 'tutor_quiz_modal_update_question' ) );
69
+ add_action( 'wp_ajax_tutor_quiz_builder_question_delete', array( $this, 'tutor_quiz_builder_question_delete' ) );
70
+ add_action( 'wp_ajax_tutor_quiz_add_question_answers', array( $this, 'tutor_quiz_add_question_answers' ) );
71
+ add_action( 'wp_ajax_tutor_quiz_edit_question_answer', array( $this, 'tutor_quiz_edit_question_answer' ) );
72
+ add_action( 'wp_ajax_tutor_save_quiz_answer_options', array( $this, 'tutor_save_quiz_answer_options' ) );
73
+ add_action( 'wp_ajax_tutor_update_quiz_answer_options', array( $this, 'tutor_update_quiz_answer_options' ) );
74
+ add_action( 'wp_ajax_tutor_quiz_builder_get_answers_by_question', array( $this, 'tutor_quiz_builder_get_answers_by_question' ) );
75
+ add_action( 'wp_ajax_tutor_quiz_builder_delete_answer', array( $this, 'tutor_quiz_builder_delete_answer' ) );
76
+ add_action( 'wp_ajax_tutor_quiz_question_sorting', array( $this, 'tutor_quiz_question_sorting' ) );
77
+ add_action( 'wp_ajax_tutor_quiz_answer_sorting', array( $this, 'tutor_quiz_answer_sorting' ) );
78
+ add_action( 'wp_ajax_tutor_mark_answer_as_correct', array( $this, 'tutor_mark_answer_as_correct' ) );
79
+ add_action( 'wp_ajax_tutor_quiz_modal_update_settings', array( $this, 'tutor_quiz_modal_update_settings' ) );
80
 
81
  /**
82
+ * Frontend Stuff
83
+ */
84
+ add_action( 'wp_ajax_tutor_render_quiz_content', array( $this, 'tutor_render_quiz_content' ) );
85
 
86
  /**
87
  * Quiz abandon action
88
+ *
89
  * @since 1.9.6
90
  */
91
+ add_action( 'wp_ajax_tutor_quiz_abandon', array( $this, 'tutor_quiz_abandon' ) );
92
 
93
  $this->prepare_allowed_html();
94
  }
95
 
96
  private function prepare_allowed_html() {
97
+
98
  $allowed = array();
99
 
100
+ foreach ( $this->allowed_html as $tag ) {
101
+ $allowed[ $tag ] = $this->allowed_attributes;
102
  }
103
 
104
  $this->allowed_html = $allowed;
105
  }
106
 
107
+ public function tutor_instructor_feedback() {
108
  tutils()->checking_nonce();
109
 
110
+ $feedback = sanitize_text_field( $_POST['feedback'] );
111
+ $attempt_id = (int) tutor_utils()->avalue_dot( 'attempts_id', tutor_sanitize_data( $_POST ) );
112
 
113
+ if ( $attempt_id && tutils()->can_user_manage( 'attempt', $attempt_id ) ) {
114
+ update_post_meta( $attempt_id, 'instructor_feedback', $feedback );
115
+ do_action( 'tutor_quiz/attempt/submitted/feedback', $attempt_id );
116
 
117
+ wp_send_json_success();
118
  }
119
  }
120
 
121
+ public function save_quiz_meta( $post_ID ) {
122
+ if ( isset( $_POST['quiz_option'] ) ) {
123
+ $quiz_option = tutor_utils()->sanitize_array( $_POST['quiz_option'] );
124
+ update_post_meta( $post_ID, 'tutor_quiz_option', $quiz_option );
125
  }
126
  }
127
 
128
  /**
129
  * Tutor Quiz Builder Modal
130
  */
131
+ public function tutor_load_quiz_builder_modal() {
132
  tutils()->checking_nonce();
133
 
134
  ob_start();
135
+ include tutor()->path . 'views/modal/add_quiz.php';
136
  $output = ob_get_clean();
137
 
138
+ wp_send_json_success( array( 'output' => $output ) );
139
  }
140
 
141
+ public function remove_quiz_from_post() {
142
  tutils()->checking_nonce();
143
 
144
  global $wpdb;
145
+ $quiz_id = (int) tutor_utils()->avalue_dot( 'quiz_id', tutor_sanitize_data($_POST) );
146
 
147
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
148
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
149
  }
150
 
151
+ $wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $quiz_id ) );
152
  wp_send_json_success();
153
  }
154
 
155
  /**
156
  *
157
+ * Start Quiz from here...
158
+ *
159
+ * @since v.1.0.0
160
  */
161
 
162
+ public function start_the_quiz() {
163
+ if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_start_quiz' ) {
164
  return;
165
  }
166
+ // Checking nonce
167
  tutor_utils()->checking_nonce();
168
 
169
+ if ( ! is_user_logged_in() ) {
170
+ // TODO: need to set a view in the next version
171
+ die( 'Please sign in to do this operation' );
172
  }
173
 
174
  global $wpdb;
175
 
176
  $user_id = get_current_user_id();
177
+ $user = get_userdata( $user_id );
178
 
179
+ $quiz_id = (int) sanitize_text_field( $_POST['quiz_id'] );
180
 
181
+ $quiz = get_post( $quiz_id );
182
+ $course = tutor_utils()->get_course_by_quiz( $quiz_id );
183
+ if ( empty( $course->ID ) ) {
184
+ die( 'There is something went wrong with course, please check if quiz attached with a course' );
185
+ }
186
 
187
+ do_action( 'tutor_quiz/start/before', $quiz_id, $user_id );
188
 
189
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
190
 
191
+ $tutor_quiz_option = (array) maybe_unserialize( get_post_meta( $quiz_id, 'tutor_quiz_option', true ) );
192
+ $attempts_allowed = tutor_utils()->get_quiz_option( $quiz_id, 'attempts_allowed', 0 );
193
 
194
+ $time_limit = tutor_utils()->get_quiz_option( $quiz_id, 'time_limit.time_value' );
195
  $time_limit_seconds = 0;
196
+ $time_type = 'seconds';
197
+ if ( $time_limit ) {
198
+ $time_type = tutor_utils()->get_quiz_option( $quiz_id, 'time_limit.time_type' );
199
 
200
+ switch ( $time_type ) {
201
  case 'seconds':
202
  $time_limit_seconds = $time_limit;
203
  break;
216
  }
217
  }
218
 
219
+ $max_question_allowed = tutor_utils()->max_questions_for_take_quiz( $quiz_id );
220
  $tutor_quiz_option['time_limit']['time_limit_seconds'] = $time_limit_seconds;
221
 
222
  $attempt_data = array(
223
+ 'course_id' => $course->ID,
224
+ 'quiz_id' => $quiz_id,
225
+ 'user_id' => $user_id,
226
+ 'total_questions' => $max_question_allowed,
227
+ 'total_answered_questions' => 0,
228
+ 'attempt_info' => maybe_serialize( $tutor_quiz_option ),
229
+ 'attempt_status' => 'attempt_started',
230
+ 'attempt_ip' => tutor_utils()->get_ip(),
231
+ 'attempt_started_at' => $date,
232
+ );
233
+
234
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_data );
235
  $attempt_id = (int) $wpdb->insert_id;
236
 
237
+ do_action( 'tutor_quiz/start/after', $quiz_id, $user_id, $attempt_id );
238
 
239
+ wp_redirect( get_permalink( $quiz_id ) );
240
  die();
241
  }
242
 
243
+ public function answering_quiz() {
244
 
245
+ if ( tutils()->array_get( 'tutor_action', $_POST ) !== 'tutor_answering_quiz_question' ) {
246
  return;
247
  }
248
+ // submit quiz attempts
249
  self::tutor_quiz_attemp_submit();
250
 
251
+ wp_redirect( get_the_permalink() );
252
  die();
253
  }
254
 
255
  /**
256
  * Quiz abandon submission handler
257
+ *
258
  * @return JSON response
259
+ *
260
  * @since 1.9.6
261
  */
262
+ public function tutor_quiz_abandon() {
263
+ if ( tutils()->array_get( 'tutor_action', $_POST ) !== 'tutor_answering_quiz_question' ) {
264
  return;
265
  }
266
+ // submit quiz attempts
267
  if ( self::tutor_quiz_attemp_submit() ) {
268
  wp_send_json_success();
269
  } else {
273
 
274
  /**
275
  * This is a unified method for handling normal quiz submit or abandon submit
276
+ *
277
  * It will handle ajax or normal form submit and can be used with different hooks
278
+ *
279
  * @return true | false
280
+ *
281
+ * @since 1.9.6
282
  */
283
  public static function tutor_quiz_attemp_submit() {
284
  tutor_utils()->checking_nonce();
285
 
286
+ $attempt_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'attempt_id', $_POST ) );
287
+ $attempt = tutor_utils()->get_attempt( $attempt_id );
288
+ $course_id = tutor_utils()->get_course_by_quiz( $attempt->quiz_id )->ID;
289
 
290
+ $attempt_answers = isset( $_POST['attempt'] ) ? tutor_sanitize_data( $_POST['attempt'] ) : false;
291
+ if ( ! is_user_logged_in() ) {
292
+ die( 'Please sign in to do this operation' );
293
  }
294
 
295
  global $wpdb;
296
  $user_id = get_current_user_id();
297
 
298
+ do_action( 'tutor_quiz/attempt_analysing/before', $attempt_id );
299
 
300
+ if ( $attempt_answers && is_array( $attempt_answers ) && count( $attempt_answers ) ) {
301
+ foreach ( $attempt_answers as $attempt_id => $attempt_answer ) {
302
 
303
+ /**
304
+ * Get total marks of all question comes
305
+ */
306
+ $question_ids = tutor_utils()->avalue_dot( 'quiz_question_ids', $attempt_answer );
307
+ if ( is_array( $question_ids ) && count( $question_ids ) ) {
308
+ $question_ids_string = "'" . implode( "','", $question_ids ) . "'";
309
+ $total_question_marks = $wpdb->get_var( "SELECT SUM(question_mark) FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id IN({$question_ids_string}) ;" );
310
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', array( 'total_marks' => $total_question_marks ), array( 'attempt_id' => $attempt_id ) );
311
+ }
312
 
313
+ if ( ! $attempt || $user_id != $attempt->user_id ) {
314
+ die( 'Operation not allowed, attempt not found or permission denied' );
315
+ }
316
 
317
+ $quiz_answers = tutor_utils()->avalue_dot( 'quiz_question', $attempt_answer );
318
 
319
+ $total_marks = 0;
320
+ $review_required = false;
321
 
322
+ if ( tutils()->count( $quiz_answers ) ) {
323
 
324
+ foreach ( $quiz_answers as $question_id => $answers ) {
325
+ $question = tutor_utils()->get_quiz_question_by_id( $question_id );
326
+ $question_type = $question->question_type;
327
 
328
+ $is_answer_was_correct = false;
329
+ $given_answer = '';
330
 
331
+ if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
332
 
333
+ if ( ! is_numeric( $answers ) || ! $answers ) {
334
  wp_send_json_error();
335
  exit;
336
  }
337
 
338
+ $given_answer = $answers;
339
+ $is_answer_was_correct = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT is_correct FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d ", $answers ) );
340
 
341
+ } elseif ( $question_type === 'multiple_choice' ) {
342
 
343
  $given_answer = (array) ( $answers );
344
+
345
+ $given_answer = array_filter(
346
+ $given_answer,
347
+ function( $id ) {
348
+ return is_numeric( $id ) && $id > 0;
349
+ }
350
+ );
351
+
352
+ $get_original_answers = (array) $wpdb->get_col(
353
+ $wpdb->prepare(
354
+ "SELECT
355
+ answer_id
356
+ FROM
357
+ {$wpdb->prefix}tutor_quiz_question_answers
358
+ WHERE
359
+ belongs_question_id = %d
360
+ AND belongs_question_type = %s
361
  AND is_correct = 1 ;
362
+ ",
363
+ $question->question_id,
364
+ $question_type
365
+ )
366
+ );
367
+
368
+ if ( count( array_diff( $get_original_answers, $given_answer ) ) === 0 && count( $get_original_answers ) === count( $given_answer ) ) {
369
+ $is_answer_was_correct = true;
370
  }
371
  $given_answer = maybe_serialize( $answers );
372
 
373
+ } elseif ( $question_type === 'fill_in_the_blank' ) {
374
+
375
+ $given_answer = (array) array_map( 'sanitize_text_field', $answers );
376
+ $given_answer = maybe_serialize( $given_answer );
377
 
378
+ $get_original_answer = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id = %d AND belongs_question_type = %s ;", $question->question_id, $question_type ) );
379
+ $gap_answer = (array) explode( '|', $get_original_answer->answer_two_gap_match );
380
 
381
+ $gap_answer = array_map( 'sanitize_text_field', $gap_answer );
382
+ if ( strtolower( $given_answer ) == strtolower( maybe_serialize( $gap_answer ) ) ) {
383
+ $is_answer_was_correct = true;
384
+ }
385
+ } elseif ( $question_type === 'open_ended' || $question_type === 'short_answer' ) {
386
+ $review_required = true;
387
+ $given_answer = wp_kses_post( $answers );
388
 
389
+ } elseif ( $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' ) {
 
 
 
 
 
 
390
 
391
+ $given_answer = (array) array_map( 'sanitize_text_field', tutor_utils()->avalue_dot( 'answers', $answers ) );
392
+ $given_answer = maybe_serialize( $given_answer );
393
 
394
+ $get_original_answers = (array) $wpdb->get_col(
395
+ $wpdb->prepare(
396
+ "SELECT answer_id
397
+ FROM {$wpdb->prefix}tutor_quiz_question_answers
398
+ WHERE belongs_question_id = %d AND belongs_question_type = %s ORDER BY answer_order ASC ;",
399
+ $question->question_id,
400
+ $question_type
401
+ )
402
+ );
403
 
 
 
 
 
 
404
  $get_original_answers = array_map( 'sanitize_text_field', $get_original_answers );
405
 
406
+ if ( $given_answer == maybe_serialize( $get_original_answers ) ) {
407
+ $is_answer_was_correct = true;
408
+ }
409
+ } elseif ( $question_type === 'image_answering' ) {
410
+ $image_inputs = tutor_utils()->avalue_dot( 'answer_id', $answers );
411
+ $image_inputs = (array) array_map( 'sanitize_text_field', $image_inputs );
412
+ $given_answer = maybe_serialize( $image_inputs );
413
+ $is_answer_was_correct = false;
414
+
415
+ $db_answer = $wpdb->get_col(
416
+ $wpdb->prepare(
417
+ "SELECT answer_title
418
+ FROM {$wpdb->prefix}tutor_quiz_question_answers
419
+ WHERE belongs_question_id = %d AND belongs_question_type = 'image_answering' ORDER BY answer_order asc ;",
420
+ $question_id
421
+ )
422
+ );
423
+
424
+ if ( is_array( $db_answer ) && count( $db_answer ) ) {
425
+ $is_answer_was_correct = ( strtolower( maybe_serialize( array_values( $image_inputs ) ) ) == strtolower( maybe_serialize( $db_answer ) ) );
426
+ }
427
+ }
428
+
429
+ $question_mark = $is_answer_was_correct ? $question->question_mark : 0;
430
+ $total_marks += $question_mark;
431
+
432
+ $answers_data = array(
433
+ 'user_id' => $user_id,
434
+ 'quiz_id' => $attempt->quiz_id,
435
+ 'question_id' => $question_id,
436
+ 'quiz_attempt_id' => $attempt_id,
437
+ 'given_answer' => $given_answer,
438
+ 'question_mark' => $question->question_mark,
439
+ 'achieved_mark' => $question_mark,
440
+ 'minus_mark' => 0,
441
+ 'is_correct' => $is_answer_was_correct ? 1 : 0,
442
+ );
443
+
444
+ /*
445
+ check if question_type open ended or short ans the set is_correct default value null before saving
446
+ */
447
+ if ( $question_type === 'open_ended' || $question_type === 'short_answer' ) {
448
+ $answers_data['is_correct'] = null;
449
  }
450
+
451
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answers_data );
452
+ }
453
+ }
454
+
455
+ $attempt_info = array(
456
+ 'total_answered_questions' => tutils()->count( $quiz_answers ),
457
+ 'earned_marks' => $total_marks,
458
+ 'attempt_status' => 'attempt_ended',
459
+ 'attempt_ended_at' => date( 'Y-m-d H:i:s', tutor_time() ),
460
+ );
461
+
462
+ if ( $review_required ) {
463
+ $attempt_info['attempt_status'] = 'review_required';
464
+ }
465
+
466
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_info, array( 'attempt_id' => $attempt_id ) );
467
+ }
468
+
469
+ do_action( 'tutor_quiz/attempt_ended', $attempt_id, $course_id, $user_id );
470
  return true;
471
+ }
472
  return false;
473
  }
474
 
475
 
476
  /**
477
  * Quiz attempt will be finish here
 
478
  */
479
 
480
+ public function finishing_quiz_attempt() {
481
 
482
+ if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_finish_quiz_attempt' ) {
483
  return;
484
  }
485
+ // Checking nonce
486
  tutor_utils()->checking_nonce();
487
 
488
+ if ( ! is_user_logged_in() ) {
489
+ die( 'Please sign in to do this operation' );
490
  }
491
 
492
  global $wpdb;
493
 
494
+ $quiz_id = (int) sanitize_text_field( $_POST['quiz_id'] );
495
+ $attempt = tutor_utils()->is_started_quiz( $quiz_id );
496
  $attempt_id = $attempt->attempt_id;
497
 
498
  $attempt_info = array(
499
+ 'total_answered_questions' => 0,
500
+ 'earned_marks' => 0,
501
+ 'attempt_status' => 'attempt_ended',
502
+ 'attempt_ended_at' => date( 'Y-m-d H:i:s', tutor_time() ),
503
  );
504
 
505
+ do_action( 'tutor_quiz_before_finish', $attempt_id, $quiz_id, $attempt->user_id );
506
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_info, array( 'attempt_id' => $attempt_id ) );
507
+ do_action( 'tutor_quiz_finished', $attempt_id, $quiz_id, $attempt->user_id );
508
 
509
+ wp_redirect( tutor_utils()->input_old( '_wp_http_referer' ) );
510
  }
511
 
512
  /**
513
  * Quiz timeout by ajax
514
  */
515
+ public function tutor_quiz_timeout() {
516
  tutils()->checking_nonce();
517
 
518
  global $wpdb;
519
 
520
+ $quiz_id = (int) sanitize_text_field( $_POST['quiz_id'] );
521
 
522
  // if(!tutils()->can_user_manage('quiz', $quiz_id)) {
523
+ // wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
524
  // }
525
 
526
+ $attempt = tutor_utils()->is_started_quiz( $quiz_id );
527
 
528
+ if ( $attempt ) {
529
  $attempt_id = $attempt->attempt_id;
530
 
531
  $data = array(
532
+ 'attempt_status' => 'attempt_timeout',
533
+ 'attempt_ended_at' => date( 'Y-m-d H:i:s', tutor_time() ),
534
+ );
535
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', $data, array( 'attempt_id' => $attempt->attempt_id ) );
536
 
537
+ do_action( 'tutor_quiz_timeout', $attempt_id, $quiz_id, $attempt->user_id );
538
 
539
  wp_send_json_success();
540
  }
541
 
542
+ wp_send_json_error( __( 'Quiz has been timeout already', 'tutor' ) );
543
  }
544
 
545
  /**
547
  */
548
 
549
  public function review_quiz_answer() {
550
+
551
+ tutils()->checking_nonce( strtolower( $_SERVER['REQUEST_METHOD'] ) );
552
 
553
  global $wpdb;
554
 
555
+ $attempt_id = (int) sanitize_text_field( $_GET['attempt_id'] );
556
+ $attempt_answer_id = (int) sanitize_text_field( $_GET['attempt_answer_id'] );
557
+ $mark_as = sanitize_text_field( $_GET['mark_as'] );
558
 
559
+ if ( ! tutils()->can_user_manage( 'attempt', $attempt_id ) || ! tutils()->can_user_manage( 'attempt_answer', $attempt_answer_id ) ) {
560
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
561
  }
562
 
563
+ $attempt_answer = $wpdb->get_row(
564
+ $wpdb->prepare(
565
+ "SELECT * FROM {$wpdb->prefix}tutor_quiz_attempt_answers
566
+ WHERE attempt_answer_id = %d ",
567
+ $attempt_answer_id
568
+ )
569
+ );
570
 
571
+ $attempt = tutor_utils()->get_attempt( $attempt_id );
572
+ $question = tutils()->get_quiz_question_by_id( $attempt_answer->question_id );
573
+ $course_id = $attempt->course_id;
574
+ $student_id = $attempt->user_id;
575
+ $previous_ans = $attempt_answer->is_correct;
576
 
577
+ do_action( 'tutor_quiz_review_answer_before', $attempt_answer_id, $attempt_id, $mark_as );
578
 
579
+ if ( $mark_as === 'correct' ) {
580
 
581
  $answer_update_data = array(
582
  'achieved_mark' => $attempt_answer->question_mark,
583
+ 'is_correct' => 1,
584
  );
585
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answer_update_data, array( 'attempt_answer_id' => $attempt_answer_id ) );
586
+ if ( $previous_ans == 0 or $previous_ans == null ) {
587
+
588
+ // if previous answer was wrong or in review then add point as correct
 
589
  $attempt_update_data = array(
590
+ 'earned_marks' => $attempt->earned_marks + $attempt_answer->question_mark,
591
+ 'is_manually_reviewed' => 1,
592
+ 'manually_reviewed_at' => date( 'Y-m-d H:i:s', tutor_time() ),
593
  );
594
 
 
595
  }
596
+
597
+ if ( $question->question_type === 'open_ended' || $question->question_type === 'short_answer' ) {
598
+ $attempt_update_data['attempt_status'] = 'attempt_ended';
599
+ }
600
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_update_data, array( 'attempt_id' => $attempt_id ) );
601
+ } elseif ( $mark_as === 'incorrect' ) {
 
 
602
 
603
  $answer_update_data = array(
604
  'achieved_mark' => '0.00',
605
+ 'is_correct' => 0,
606
  );
607
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempt_answers', $answer_update_data, array( 'attempt_answer_id' => $attempt_answer_id ) );
608
 
609
+ if ( $previous_ans == 1 ) {
610
 
611
+ // if previous ans was right then mynus
 
 
 
612
  $attempt_update_data = array(
613
+ 'earned_marks' => $attempt->earned_marks - $attempt_answer->question_mark,
614
+ 'is_manually_reviewed' => 1,
615
+ 'manually_reviewed_at' => date( 'Y-m-d H:i:s', tutor_time() ),
616
  );
617
 
618
  }
619
+ if ( $question->question_type === 'open_ended' || $question->question_type === 'short_answer' ) {
620
+ $attempt_update_data['attempt_status'] = 'attempt_ended';
621
+ }
622
+
623
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_attempts', $attempt_update_data, array( 'attempt_id' => $attempt_id ) );
624
  }
625
+ do_action( 'tutor_quiz_review_answer_after', $attempt_answer_id, $attempt_id, $mark_as );
626
+ do_action( 'tutor_quiz/answer/review/after', $attempt_answer_id, $course_id, $student_id );
627
+
628
+ if ( wp_doing_ajax() ) {
629
+ wp_send_json_success();
630
+ } else {
631
+ wp_redirect( admin_url( 'admin.php?page=tutor_quiz_attempts&sub_page=view_attempt&attempt_id=' . $attempt_id ) );
 
 
632
  }
633
 
634
  die();
638
  /**
639
  * New Design Quiz
640
  */
641
+ public function tutor_create_quiz_and_load_modal() {
642
  tutils()->checking_nonce();
643
 
644
+ $topic_id = sanitize_text_field( $_POST['topic_id'] );
645
+ $quiz_title = sanitize_text_field( $_POST['quiz_title'] );
646
+ $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
647
+ $next_order_id = tutor_utils()->get_next_course_content_order_id( $topic_id );
648
+
649
+ if ( ! tutils()->can_user_manage( 'topic', $topic_id ) ) {
650
+ wp_send_json_error(
651
+ array(
652
+ 'message' => __( 'Access Denied', 'tutor' ),
653
+ 'data' => tutor_sanitize_data($_POST),
654
+ )
655
+ );
656
  }
657
 
658
  $post_arr = array(
659
+ 'post_type' => 'tutor_quiz',
660
+ 'post_title' => $quiz_title,
661
+ 'post_content' => $quiz_description,
662
+ 'post_status' => 'publish',
663
+ 'post_author' => get_current_user_id(),
664
+ 'post_parent' => $topic_id,
665
+ 'menu_order' => $next_order_id,
666
  );
667
+ $quiz_id = wp_insert_post( $post_arr );
668
+ do_action( 'tutor_initial_quiz_created', $quiz_id );
669
 
670
  ob_start();
671
+ include tutor()->path . 'views/modal/edit_quiz.php';
672
  $output = ob_get_clean();
673
 
674
  ob_start();
675
  ?>
676
+ <div id="tutor-quiz-<?php echo esc_attr( $quiz_id ); ?>" class="course-content-item tutor-quiz tutor-quiz-<?php echo $quiz_id; ?>">
677
+ <div class="tutor-lesson-top">
678
+ <i class="tutor-icon-move"></i>
679
+ <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo $quiz_id; ?>" data-topic-id="<?php echo $topic_id; ?>">
680
+ <i class=" tutor-icon-doubt"></i>[<?php _e( 'QUIZ', 'tutor' ); ?>]&nbsp;
681
+ <?php echo stripslashes( $quiz_title ); ?>
682
+ </a>
683
+ <?php do_action( 'tutor_course_builder_before_quiz_btn_action', $quiz_id ); ?>
684
+ <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo $quiz_id; ?>"><i class="tutor-icon-garbage"></i></a>
685
+ </div>
686
+ </div>
687
  <?php
688
  $output_quiz_row = ob_get_clean();
689
 
690
+ wp_send_json_success(
691
+ array(
692
+ 'output' => $output,
693
+ 'output_quiz_row' => $output_quiz_row,
694
+ )
695
+ );
696
  }
697
 
698
+ public function tutor_delete_quiz_by_id() {
699
  tutils()->checking_nonce();
700
 
701
+ global $wpdb;
702
 
703
+ $quiz_id = (int) sanitize_text_field( $_POST['quiz_id'] );
704
+ $post = get_post( $quiz_id );
705
 
706
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
707
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
 
708
  }
709
 
710
+ if ( $post->post_type === 'tutor_quiz' ) {
711
+ do_action( 'tutor_delete_quiz_before', $quiz_id );
712
 
713
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempts', array( 'quiz_id' => $quiz_id ) );
714
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempt_answers', array( 'quiz_id' => $quiz_id ) );
715
 
716
+ $questions_ids = $wpdb->get_col( $wpdb->prepare( "SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $quiz_id ) );
717
+
718
+ if ( is_array( $questions_ids ) && count( $questions_ids ) ) {
719
+ $in_question_ids = "'" . implode( "','", $questions_ids ) . "'";
720
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) " );
721
  }
 
 
722
 
723
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'quiz_id' => $quiz_id ) );
 
724
 
725
+ wp_delete_post( $quiz_id, true );
726
+ delete_post_meta( $quiz_id, '_tutor_course_id_for_lesson' );
727
 
728
+ do_action( 'tutor_delete_quiz_after', $quiz_id );
729
 
730
+ wp_send_json_success();
731
+ }
732
 
733
+ wp_send_json_error();
734
+ }
735
 
736
  /**
737
  * Update Quiz from quiz builder modal
738
  *
739
  * @since v.1.0.0
740
  */
741
+ public function tutor_quiz_builder_quiz_update() {
742
  tutils()->checking_nonce();
743
 
744
+ $quiz_id = sanitize_text_field( $_POST['quiz_id'] );
745
+ $topic_id = sanitize_text_field( $_POST['topic_id'] );
746
+ $quiz_title = sanitize_text_field( $_POST['quiz_title'] );
747
+ $quiz_description = wp_kses( $_POST['quiz_description'], $this->allowed_html );
748
 
749
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
750
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
751
  }
752
 
753
  $post_arr = array(
754
+ 'ID' => $quiz_id,
755
+ 'post_title' => $quiz_title,
756
+ 'post_content' => $quiz_description,
757
 
758
  );
759
  $quiz_id = wp_update_post( $post_arr );
760
 
761
+ do_action( 'tutor_quiz_updated', $quiz_id );
762
 
763
  ob_start();
764
  ?>
765
+ <div class="tutor-lesson-top">
766
+ <i class="tutor-icon-move"></i>
767
+ <a href="javascript:;" class="open-tutor-quiz-modal" data-quiz-id="<?php echo esc_attr( $quiz_id ); ?>" data-topic-id="<?php echo esc_attr( $topic_id ); ?>">
768
+ <i class=" tutor-icon-doubt"></i>[<?php _e( 'QUIZ', 'tutor' ); ?>]&nbsp;
769
+ <?php echo stripslashes( $quiz_title ); ?>
770
+ </a>
771
+ <?php do_action( 'tutor_course_builder_before_quiz_btn_action', $quiz_id ); ?>
772
+ <a href="javascript:;" class="tutor-delete-quiz-btn" data-quiz-id="<?php echo esc_attr( $quiz_id ); ?>"><i class="tutor-icon-garbage"></i></a>
773
+ </div>
774
  <?php
775
  $output_quiz_row = ob_get_clean();
776
 
777
+ wp_send_json_success( array( 'output_quiz_row' => $output_quiz_row ) );
778
  }
779
 
780
  /**
782
  *
783
  * @since v.1.0.0
784
  */
785
+ public function tutor_load_edit_quiz_modal() {
786
  tutils()->checking_nonce();
787
 
788
+ $quiz_id = sanitize_text_field( $_POST['quiz_id'] );
789
+ $topic_id = sanitize_text_field( $_POST['topic_id'] );
790
+
791
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
792
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
793
  }
794
+
795
  ob_start();
796
+ include tutor()->path . 'views/modal/edit_quiz.php';
797
  $output = ob_get_clean();
798
 
799
+ wp_send_json_success( array( 'output' => $output ) );
800
  }
801
 
802
  /**
804
  *
805
  * @since v.1.0.0
806
  */
807
+ public function tutor_quiz_builder_get_question_form() {
808
  tutils()->checking_nonce();
809
 
810
  global $wpdb;
811
+ $quiz_id = sanitize_text_field( $_POST['quiz_id'] );
812
+ $question_id = sanitize_text_field( tutor_utils()->avalue_dot( 'question_id', $_POST ) );
813
 
814
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
815
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
816
  }
817
+
818
+ if ( ! $question_id ) {
819
+ $next_question_id = tutor_utils()->quiz_next_question_id();
820
+ $next_question_order = tutor_utils()->quiz_next_question_order_id( $quiz_id );
821
 
822
  $new_question_data = array(
823
+ 'quiz_id' => $quiz_id,
824
+ 'question_title' => __( 'Question', 'tutor' ) . ' ' . $next_question_id,
825
+ 'question_description' => '',
826
+ 'question_type' => 'true_false',
827
+ 'question_mark' => 1,
828
+ 'question_settings' => maybe_serialize( array() ),
829
+ 'question_order' => esc_sql( $next_question_order ),
830
  );
831
 
832
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_questions', $new_question_data );
833
  $question_id = $wpdb->insert_id;
834
  }
835
 
836
+ $question = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_questions where question_id = %d ", $question_id ) );
837
 
838
  ob_start();
839
+ include tutor()->path . 'views/modal/question_form.php';
840
  $output = ob_get_clean();
841
 
842
+ wp_send_json_success( array( 'output' => $output ) );
843
  }
844
 
845
+ public function tutor_quiz_modal_update_question() {
846
  tutils()->checking_nonce();
847
 
848
  global $wpdb;
849
 
850
+ $question_data = tutor_sanitize_data( $_POST['tutor_quiz_question'] );
851
 
852
+ foreach ( $question_data as $question_id => $question ) {
853
 
854
+ if ( ! tutils()->can_user_manage( 'question', $question_id ) ) {
855
  continue;
856
  }
857
 
858
+ $question_title = sanitize_text_field( $question['question_title'] );
859
+ $question_description = wp_kses( $question['question_description'], $this->allowed_html ); // sanitize_text_field($question['question_description']);
860
+ $question_type = sanitize_text_field( $question['question_type'] );
861
+ $question_mark = sanitize_text_field( $question['question_mark'] );
862
 
863
+ unset( $question['question_title'] );
864
+ unset( $question['question_description'] );
865
 
866
  $data = array(
867
+ 'question_title' => $question_title,
868
+ 'question_description' => $question_description,
869
+ 'question_type' => $question_type,
870
+ 'question_mark' => $question_mark,
871
+ 'question_settings' => maybe_serialize( $question ),
872
  );
873
 
874
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_questions', $data, array( 'question_id' => $question_id ) );
 
875
 
876
  /**
877
  * Validation
878
  */
879
+ if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
880
+ $question_options = tutils()->get_answers_by_quiz_question( $question_id );
881
+ if ( tutils()->count( $question_options ) ) {
882
+ $required_validate = true;
883
+ foreach ( $question_options as $question_option ) {
884
+ if ( $question_option->is_correct ) {
885
+ $required_validate = false;
886
+ }
887
+ }
888
+ if ( $required_validate ) {
889
+ $validation_msg = "<p class='tutor-error-msg'>" . __( 'Please select the correct answer', 'tutor' ) . '</p>';
890
+ wp_send_json_error( array( 'validation_msg' => $validation_msg ) );
891
+ }
892
+ } else {
893
+ $validation_msg = "<p class='tutor-error-msg'>" . __( 'Please make sure you have added more than one option and saved them', 'tutor' ) . '</p>';
894
+ wp_send_json_error( array( 'validation_msg' => $validation_msg ) );
895
+ }
896
+ }
897
  }
898
 
899
  wp_send_json_success();
900
  }
901
 
902
+ public function tutor_quiz_builder_question_delete() {
903
  tutils()->checking_nonce();
904
 
905
  global $wpdb;
906
 
907
+ $question_id = sanitize_text_field( tutor_utils()->avalue_dot( 'question_id', $_POST ) );
908
+
909
+ if ( ! tutils()->can_user_manage( 'question', $question_id ) ) {
910
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
911
  }
912
 
913
+ if ( $question_id ) {
914
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'question_id' => esc_sql( $question_id ) ) );
915
  }
916
 
917
  wp_send_json_success();
922
  *
923
  * @since v.1.0.0
924
  */
925
+ public function tutor_quiz_add_question_answers() {
926
  tutils()->checking_nonce();
927
 
928
+ $question_id = sanitize_text_field( $_POST['question_id'] );
929
+ $question = tutor_utils()->avalue_dot( $question_id, $_POST['tutor_quiz_question'] );
930
  $question_type = $question['question_type'];
931
 
932
+ if ( ! tutils()->can_user_manage( 'question', $question_id ) ) {
933
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
934
  }
935
 
936
  ob_start();
937
+ include tutor()->path . 'views/modal/question_answer_form.php';
938
  $output = ob_get_clean();
939
 
940
+ wp_send_json_success( array( 'output' => $output ) );
941
  }
942
 
943
  /**
944
  * Edit Answer Form
945
+ *
946
+ * @since v.1.0.0
947
  */
948
+ public function tutor_quiz_edit_question_answer() {
949
  tutils()->checking_nonce();
950
 
951
+ $answer_id = (int) sanitize_text_field( $_POST['answer_id'] );
952
+
953
+ if ( ! tutils()->can_user_manage( 'quiz_answer', $answer_id ) ) {
954
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
955
+ }
956
 
957
+ $old_answer = tutor_utils()->get_answer_by_id( $answer_id );
958
+ foreach ( $old_answer as $old_answer ) {
959
  }
960
+ $question_id = $old_answer->belongs_question_id;
 
 
 
961
  $question_type = $old_answer->belongs_question_type;
962
 
963
  ob_start();
964
+ include tutor()->path . 'views/modal/question_answer_edit_form.php';
965
  $output = ob_get_clean();
966
 
967
+ wp_send_json_success( array( 'output' => $output ) );
968
+ }
969
 
970
+ public function tutor_save_quiz_answer_options() {
971
  tutils()->checking_nonce();
972
 
973
  global $wpdb;
974
 
975
+ $questions = tutor_sanitize_data( $_POST['tutor_quiz_question'] );
976
+ $answers = tutor_sanitize_data( $_POST['quiz_answer'] );
977
 
978
+ foreach ( $answers as $question_id => $answer ) {
979
 
980
+ if ( ! tutils()->can_user_manage( 'question', $question_id ) ) {
981
  continue;
982
  }
983
 
984
+ $question = tutor_utils()->avalue_dot( $question_id, $questions );
985
  $question_type = $question['question_type'];
986
 
987
+ // Getting next sorting order
988
+ $next_order_id = (int) $wpdb->get_var(
989
+ $wpdb->prepare(
990
+ "SELECT MAX(answer_order)
991
+ FROM {$wpdb->prefix}tutor_quiz_question_answers
992
+ where belongs_question_id = %d
993
+ AND belongs_question_type = %s ",
994
+ $question_id,
995
+ esc_sql( $question_type )
996
+ )
997
+ );
998
 
999
  $next_order_id = $next_order_id + 1;
1000
 
1001
+ if ( $question ) {
1002
+ if ( $question_type === 'true_false' ) {
1003
+ $wpdb->delete(
1004
+ $wpdb->prefix . 'tutor_quiz_question_answers',
1005
+ array(
1006
+ 'belongs_question_id' => $question_id,
1007
+ 'belongs_question_type' => $question_type,
1008
+ )
1009
+ );
1010
  $data_true_false = array(
1011
  array(
1012
+ 'belongs_question_id' => esc_sql( $question_id ),
1013
  'belongs_question_type' => $question_type,
1014
+ 'answer_title' => __( 'True', 'tutor' ),
1015
  'is_correct' => $answer['true_false'] == 'true' ? 1 : 0,
1016
  'answer_two_gap_match' => 'true',
1017
  ),
1018
  array(
1019
+ 'belongs_question_id' => esc_sql( $question_id ),
1020
  'belongs_question_type' => $question_type,
1021
+ 'answer_title' => __( 'False', 'tutor' ),
1022
  'is_correct' => $answer['true_false'] == 'false' ? 1 : 0,
1023
  'answer_two_gap_match' => 'false',
1024
  ),
1025
  );
1026
 
1027
+ foreach ( $data_true_false as $true_false_data ) {
1028
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_question_answers', $true_false_data );
1029
  }
1030
+ } elseif ( $question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' ||
1031
+ $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'image_answering' ) {
 
1032
 
1033
  $answer_data = array(
1034
  'belongs_question_id' => sanitize_text_field( $question_id ),
1035
  'belongs_question_type' => $question_type,
1036
  'answer_title' => sanitize_text_field( $answer['answer_title'] ),
1037
+ 'image_id' => isset( $answer['image_id'] ) ? $answer['image_id'] : 0,
1038
+ 'answer_view_format' => isset( $answer['answer_view_format'] ) ? $answer['answer_view_format'] : 0,
1039
  'answer_order' => $next_order_id,
1040
  );
1041
+ if ( isset( $answer['matched_answer_title'] ) ) {
1042
  $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] );
1043
+ }
1044
 
1045
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_question_answers', $answer_data );
1046
 
1047
+ } elseif ( $question_type === 'fill_in_the_blank' ) {
1048
+ $wpdb->delete(
1049
+ $wpdb->prefix . 'tutor_quiz_question_answers',
1050
+ array(
1051
+ 'belongs_question_id' => $question_id,
1052
+ 'belongs_question_type' => $question_type,
1053
+ )
1054
+ );
1055
  $answer_data = array(
1056
+ 'belongs_question_id' => sanitize_text_field( $question_id ),
1057
  'belongs_question_type' => $question_type,
1058
  'answer_title' => sanitize_text_field( $answer['answer_title'] ),
1059
+ 'answer_two_gap_match' => isset( $answer['answer_two_gap_match'] ) ? sanitize_text_field( trim( $answer['answer_two_gap_match'] ) ) : null,
1060
  );
1061
+ $wpdb->insert( $wpdb->prefix . 'tutor_quiz_question_answers', $answer_data );
1062
  }
1063
  }
1064
  }
1068
 
1069
  /**
1070
  * Tutor Update Answer
1071
+ *
1072
+ * @since v.1.0.0
1073
  */
1074
+ public function tutor_update_quiz_answer_options() {
1075
  tutils()->checking_nonce();
1076
 
1077
  global $wpdb;
1078
 
1079
+ $answer_id = (int) sanitize_text_field( $_POST['tutor_quiz_answer_id'] );
1080
 
1081
+ if ( ! tutils()->can_user_manage( 'quiz_answer', $answer_id ) ) {
1082
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
1083
  }
1084
 
1085
+ $questions = tutor_sanitize_data( $_POST['tutor_quiz_question'] );
1086
+ $answers = tutor_sanitize_data( $_POST['quiz_answer'] );
1087
 
1088
+ foreach ( $answers as $question_id => $answer ) {
1089
+ $question = tutor_utils()->avalue_dot( $question_id, $questions );
1090
  $question_type = $question['question_type'];
1091
 
1092
+ if ( $question ) {
1093
+ if ( $question_type === 'multiple_choice' || $question_type === 'single_choice' || $question_type === 'ordering' || $question_type === 'matching' || $question_type === 'image_matching' || $question_type === 'fill_in_the_blank' || $question_type === 'image_answering' ) {
1094
 
1095
  $answer_data = array(
1096
  'belongs_question_id' => $question_id,
1097
  'belongs_question_type' => $question_type,
1098
+ 'answer_title' => sanitize_text_field( $answer['answer_title'] ),
1099
+ 'image_id' => isset( $answer['image_id'] ) ? $answer['image_id'] : 0,
1100
+ 'answer_view_format' => isset( $answer['answer_view_format'] ) ? sanitize_text_field( $answer['answer_view_format'] ) : '',
1101
  );
1102
+ if ( isset( $answer['matched_answer_title'] ) ) {
1103
+ $answer_data['answer_two_gap_match'] = sanitize_text_field( $answer['matched_answer_title'] );
1104
  }
1105
 
1106
+ if ( $question_type === 'fill_in_the_blank' ) {
1107
+ $answer_data['answer_two_gap_match'] = isset( $answer['answer_two_gap_match'] ) ? sanitize_text_field( trim( $answer['answer_two_gap_match'] ) ) : null;
1108
  }
1109
 
1110
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_question_answers', $answer_data, array( 'answer_id' => $answer_id ) );
1111
  }
1112
  }
1113
  }
1114
 
1115
+ // die(print_r($_POST));
1116
  wp_send_json_success();
1117
+ }
1118
 
1119
+ public function tutor_quiz_builder_get_answers_by_question() {
1120
  tutils()->checking_nonce();
1121
 
1122
  global $wpdb;
1123
+ $question_id = sanitize_text_field( $_POST['question_id'] );
1124
+ $question_type = sanitize_text_field( $_POST['question_type'] );
1125
 
1126
+ if ( ! tutils()->can_user_manage( 'question', $question_id ) ) {
1127
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
1128
  }
1129
 
1130
+ $question = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_questions WHERE question_id = %d ", $question_id ) );
1131
+ $answers = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers where belongs_question_id = %d AND belongs_question_type = %s order by answer_order asc ;", $question_id, esc_sql( $question_type ) ) );
1132
 
1133
  ob_start();
1134
 
1135
+ switch ( $question_type ) {
1136
  case 'true_false':
1137
+ echo '<label>' . __( 'Answer options &amp; mark correct', 'tutor' ) . '</label>';
1138
  break;
1139
  case 'ordering':
1140
+ echo '<label>' . __( 'Make sure you’re saving the answers in the right order. Students will have to match this order exactly.', 'tutor' ) . '</label>';
1141
  break;
1142
  }
1143
 
1144
+ if ( is_array( $answers ) && count( $answers ) ) {
1145
+ foreach ( $answers as $answer ) {
1146
  ?>
1147
+ <div class="tutor-quiz-answer-wrap" data-answer-id="<?php echo esc_attr( $answer->answer_id ); ?>">
1148
+ <div class="tutor-quiz-answer">
1149
+ <span class="tutor-quiz-answer-title">
1150
+ <?php
1151
+ echo stripslashes( $answer->answer_title );
1152
+ if ( $answer->belongs_question_type === 'fill_in_the_blank' ) {
1153
+ echo ' (' . __( 'Answer', 'tutor' ) . ' : ';
1154
+ echo '<strong>' . stripslashes( $answer->answer_two_gap_match ) . '</strong>)';
1155
+ }
1156
+ if ( $answer->belongs_question_type === 'matching' ) {
1157
+ echo ' - ' . stripslashes( $answer->answer_two_gap_match );
1158
+ }
1159
+ ?>
1160
+ </span>
1161
 
1162
  <?php
1163
+ if ( $answer->image_id ) {
1164
+ echo '<span class="tutor-question-answer-image"><img src="' . wp_get_attachment_image_url( $answer->image_id ) . '" /> </span>';
1165
  }
1166
+ if ( $question_type === 'true_false' || $question_type === 'single_choice' ) {
1167
  ?>
1168
+ <span class="tutor-quiz-answers-mark-correct-wrap">
1169
+ <input type="radio" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e( 'Mark as correct', 'tutor' ); ?>" <?php checked( 1, $answer->is_correct ); ?> >
1170
+ </span>
1171
  <?php
1172
+ } elseif ( $question_type === 'multiple_choice' ) {
1173
  ?>
1174
+ <span class="tutor-quiz-answers-mark-correct-wrap">
1175
+ <input type="checkbox" name="mark_as_correct[<?php echo $answer->belongs_question_id; ?>]" value="<?php echo $answer->answer_id; ?>" title="<?php _e( 'Mark as correct', 'tutor' ); ?>" <?php checked( 1, $answer->is_correct ); ?> >
1176
+ </span>
1177
  <?php
1178
  }
1179
  ?>
1180
+ <?php if ( 'true_false' != $question_type ) : ?>
1181
  <span class="tutor-quiz-answer-edit">
1182
  <a href="javascript:;"><i class="tutor-icon-pencil"></i> </a>
1183
  </span>
1184
+ <?php endif; ?>
1185
+ <span class="tutor-quiz-answer-sort-icon"><i class="tutor-icon-menu-2"></i> </span>
1186
+ </div>
1187
+ <?php if ( 'true_false' != $question_type ) : ?>
1188
  <div class="tutor-quiz-answer-trash-wrap">
1189
+ <a href="javascript:;" class="answer-trash-btn" data-answer-id="<?php echo esc_attr( $answer->answer_id ); ?>"><i class="tutor-icon-garbage"></i> </a>
1190
  </div>
1191
+ <?php endif; ?>
1192
+ </div>
1193
  <?php
1194
  }
1195
  }
1196
  $output = ob_get_clean();
1197
 
1198
+ wp_send_json_success( array( 'output' => $output ) );
1199
  }
1200
 
1201
+ public function tutor_quiz_builder_delete_answer() {
1202
  tutils()->checking_nonce();
1203
 
1204
  global $wpdb;
1205
+ $answer_id = sanitize_text_field( $_POST['answer_id'] );
1206
+
1207
+ if ( ! tutils()->can_user_manage( 'quiz_answer', $answer_id ) ) {
1208
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
1209
  }
1210
 
1211
+ $wpdb->delete( $wpdb->prefix . 'tutor_quiz_question_answers', array( 'answer_id' => esc_sql( $answer_id ) ) );
1212
  wp_send_json_success();
1213
  }
1214
 
1215
  /**
1216
  * Save quiz questions sorting
1217
  */
1218
+ public function tutor_quiz_question_sorting() {
1219
  tutils()->checking_nonce();
1220
 
1221
  global $wpdb;
1222
 
1223
+ $question_ids = tutor_utils()->avalue_dot( 'sorted_question_ids', tutor_sanitize_data($_POST) );
1224
+ if ( is_array( $question_ids ) && count( $question_ids ) ) {
1225
  $i = 0;
1226
+ foreach ( $question_ids as $key => $question_id ) {
1227
+ if ( tutils()->can_user_manage( 'question', $question_id ) ) {
1228
  $i++;
1229
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_questions', array( 'question_order' => $i ), array( 'question_id' => $question_id ) );
1230
  }
1231
  }
1232
  }
1233
+ }
1234
 
1235
  /**
1236
  * Save sorting data for quiz answers
1237
  */
1238
+ public function tutor_quiz_answer_sorting() {
1239
  tutils()->checking_nonce();
1240
 
1241
+ global $wpdb;
1242
 
1243
+ if ( ! empty( $_POST['sorted_answer_ids'] ) && is_array( $_POST['sorted_answer_ids'] ) && count( $_POST['sorted_answer_ids'] ) ) {
1244
+ $answer_ids = tutor_sanitize_data( $_POST['sorted_answer_ids'] );
1245
+ $i = 0;
1246
+ foreach ( $answer_ids as $key => $answer_id ) {
1247
+ if ( tutils()->can_user_manage( 'quiz_answer', $answer_id ) ) {
1248
  $i++;
1249
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_question_answers', array( 'answer_order' => $i ), array( 'answer_id' => $answer_id ) );
1250
  }
1251
+ }
1252
+ }
1253
+ }
1254
 
1255
  /**
1256
  * Mark answer as correct
1257
  */
1258
 
1259
+ public function tutor_mark_answer_as_correct() {
1260
  tutils()->checking_nonce();
1261
 
1262
+ global $wpdb;
1263
 
1264
+ $answer_id = sanitize_text_field( $_POST['answer_id'] );
1265
+ $inputValue = sanitize_text_field( $_POST['inputValue'] );
1266
+
1267
+ if ( ! tutils()->can_user_manage( 'quiz_answer', $answer_id ) ) {
1268
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
1269
  }
1270
 
1271
+ $answer = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE answer_id = %d LIMIT 0,1 ;", $answer_id ) );
1272
+ if ( $answer->belongs_question_type === 'single_choice' ) {
1273
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_question_answers', array( 'is_correct' => 0 ), array( 'belongs_question_id' => esc_sql( $answer->belongs_question_id ) ) );
1274
+ }
1275
+ $wpdb->update( $wpdb->prefix . 'tutor_quiz_question_answers', array( 'is_correct' => esc_sql( $inputValue ) ), array( 'answer_id' => esc_sql( $answer_id ) ) );
1276
+ }
1277
 
1278
  /**
1279
  * Update quiz settings from modal
1280
  *
1281
  * @since : v.1.0.0
1282
  */
1283
+ public function tutor_quiz_modal_update_settings() {
1284
  tutils()->checking_nonce();
1285
+ // while creating quiz if creating step is not follow then it may throw error that why check added
1286
+ $quiz_id = ( isset( $_POST['quiz_id'] ) ) ? sanitize_text_field( $_POST['quiz_id'] ) : '';
1287
  $current_topic_id = sanitize_text_field( $_POST['topic_id'] );
1288
+ $course_id = tutor_utils()->get_course_id_by( 'topic', sanitize_textarea_field( $current_topic_id ) );
1289
 
1290
  $quiz_option = tutor_utils()->sanitize_array( $_POST['quiz_option'] );
1291
+
1292
+ if ( ! tutils()->can_user_manage( 'quiz', $quiz_id ) ) {
1293
+ wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
1294
  }
1295
 
1296
+ update_post_meta( $quiz_id, 'tutor_quiz_option', $quiz_option );
1297
+ do_action( 'tutor_quiz_settings_updated', $quiz_id );
1298
 
1299
+ // @since 1.9.6
1300
  ob_start();
1301
+ include tutor()->path . 'views/metabox/course-contents.php';
1302
  $course_contents = ob_get_clean();
1303
 
1304
  wp_send_json_success( array( 'course_contents' => $course_contents ) );
1305
  }
1306
 
1307
 
1308
+ // =========================//
1309
+ // Front end stuffs
1310
+ // =========================//
1311
 
1312
  /**
1313
  * Rendering quiz for frontend
1314
+ *
1315
+ * @since v.1.0.0
1316
  */
1317
 
1318
+ public function tutor_render_quiz_content() {
1319
 
1320
  tutils()->checking_nonce();
1321
 
1322
+ $quiz_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( 'quiz_id', $_POST ) );
1323
 
1324
+ if ( ! tutils()->has_enrolled_content_access( 'quiz', $quiz_id ) ) {
1325
+ wp_send_json_error( array( 'message' => __( 'Access Denied.', 'tutor' ) ) );
1326
  }
1327
 
1328
  ob_start();
1329
  global $post;
1330
 
1331
+ $post = get_post( $quiz_id );
1332
+ setup_postdata( $post );
1333
+ // tutor_lesson_content();
1334
 
1335
  single_quiz_contents();
1336
  wp_reset_postdata();
1337
 
1338
  $html = ob_get_clean();
1339
+ wp_send_json_success( array( 'html' => $html ) );
1340
  }
1341
 
1342
+ }
classes/Quiz_Attempts_List.php CHANGED
@@ -1,135 +1,139 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- if (! class_exists('Tutor_List_Table')){
8
- include_once tutor()->path.'classes/Tutor_List_Table.php';
9
  }
10
 
11
  class Quiz_Attempts_List extends \Tutor_List_Table {
12
 
13
  const QUIZ_ATTEMPT_PAGE = 'tutor_quiz_attempts';
14
 
15
- function __construct(){
16
  global $status, $page;
17
 
18
- //Set parent defaults
19
- parent::__construct( array(
20
- 'singular' => 'attempt', //singular name of the listed records
21
- 'plural' => 'attempts', //plural name of the listed records
22
- 'ajax' => false //does this table support ajax?
23
- ) );
 
 
24
  }
25
 
26
- function column_default($item, $column_name){
27
- switch($column_name){
28
  case 'unknown_col':
29
  return $item->$column_name;
30
  default:
31
- //return print_r($item,true); //Show the whole array for troubleshooting purposes
32
  }
33
  }
34
 
35
- function column_student($item){
36
  $actions = array();
37
 
38
- $actions['answer'] = sprintf('<a href="?page=%s&sub_page=%s&attempt_id=%s">'.__('Review', 'tutor').'</a>',$_REQUEST['page'],'view_attempt',$item->attempt_id);
39
- //$actions['delete'] = sprintf('<a href="?page=%s&action=%s&attempt_id=%s">Delete</a>',$_REQUEST['page'],'delete',$item->attempt_id);
40
 
41
- $quiz_title = "<p><strong>{$item->display_name}</strong></p>";
42
- $quiz_title .= "<p>{$item->user_email}</p>";
43
- //@since 1.9.5 instead of showing time ago showing original date time
44
- if ($item->attempt_ended_at){
45
- $ended_ago_time = human_time_diff(strtotime($item->attempt_ended_at), tutor_time()).__(' ago', 'tutor');
46
- $attempt_started_at = date_format(date_create($item->attempt_started_at), 'd M, Y, h:i a');
47
- $quiz_title .= "<span>{$attempt_started_at}</span>";
48
  }
49
 
50
- //Return the title contents
51
- return sprintf('%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
 
52
  $quiz_title,
53
  $item->attempt_id,
54
- $this->row_actions($actions)
55
  );
56
  }
57
 
58
- function column_quiz($item){
59
  return $item->post_title;
60
  }
61
 
62
- function column_cb($item){
63
  return sprintf(
64
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
65
- /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label ("instructor")
66
- /*$2%s*/ $item->attempt_id //The value of the checkbox should be the record's id
67
  );
68
  }
69
 
70
- function column_course($item) {
71
- $quiz = tutor_utils()->get_course_by_quiz($item->quiz_id);
72
 
73
- if ($quiz) {
74
  $title = get_the_title( $quiz->ID );
75
- return "<a href='" . admin_url( "post.php?post={$quiz->ID}&action=edit" ) . "'>{$title}</a>";
76
  }
77
  }
78
 
79
- function column_total_questions($item) {
80
  echo $item->total_questions;
81
  }
82
 
83
- function column_earned_marks($item){
84
 
85
- if ($item->attempt_status === 'review_required'){
86
- $output = '<span class="result-review-required">' . __('Under Review', 'tutor') . '</span>';
87
- }else {
88
 
89
- $pass_mark_percent = tutor_utils()->get_quiz_option($item->quiz_id, 'passing_grade', 0);
90
- $earned_percentage = $item->earned_marks > 0 ? (number_format(($item->earned_marks * 100) / $item->total_marks)) : 0;
91
 
92
- $output = $item->earned_marks .__( ' out of ', 'tutor' ). " {$item->total_marks} <br />";
93
- $output .= "({$earned_percentage}%) ".__( ' pass ', 'tutor' )." ({$pass_mark_percent}%) <br />";
94
 
95
- if ($earned_percentage >= $pass_mark_percent) {
96
- $output .= '<span class="result-pass">' . __('Pass', 'tutor') . '</span>';
97
- } else {
98
- $output .= '<span class="result-fail">' . __('Fail', 'tutor') . '</span>';
99
- }
100
- }
101
  return $output;
102
  }
103
 
104
- function column_attempt_status($item){
105
- $status = ucwords(str_replace('quiz_', '', $item->attempt_status));
106
 
107
- return "<span class='attempt-status-{$item->attempt_status}'>{$status}</span>";
108
  }
109
 
110
- function get_columns(){
111
  $columns = array(
112
- 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
113
- 'student' => __('Students', 'tutor'),
114
- 'quiz' => __('Quiz', 'tutor'),
115
- 'course' => __('Course', 'tutor'),
116
- 'total_questions' => __('Total Questions', 'tutor'),
117
- 'earned_marks' => __('Earned Points', 'tutor'),
118
- //'attempt_status' => __('Attempt Status', 'tutor'),
119
  );
120
  return $columns;
121
  }
122
 
123
  function get_sortable_columns() {
124
  $sortable_columns = array(
125
- //'display_name' => array('title',false), //true means it's already sorted
126
  );
127
  return $sortable_columns;
128
  }
129
 
130
  function get_bulk_actions() {
131
  $actions = array(
132
- 'delete' => 'Delete'
133
  );
134
  return $actions;
135
  }
@@ -137,13 +141,13 @@ class Quiz_Attempts_List extends \Tutor_List_Table {
137
  function process_bulk_action() {
138
  global $wpdb;
139
 
140
- //Detect when a bulk action is being triggered...
141
- if( 'delete' === $this->current_action() ) {
142
- if ( empty($_GET['attempt']) || ! is_array($_GET['attempt'])){
143
  return;
144
  }
145
 
146
- $attempt_ids = array_map('sanitize_text_field', $_GET['attempt']);
147
  $attempt_ids = array_map( 'absint', $attempt_ids );
148
 
149
  tutor_utils()->delete_quiz_attempt( $attempt_ids );
@@ -155,11 +159,11 @@ class Quiz_Attempts_List extends \Tutor_List_Table {
155
 
156
  $per_page = 20;
157
 
158
- $columns = $this->get_columns();
159
- $hidden = array();
160
  $sortable = $this->get_sortable_columns();
161
 
162
- $this->_column_headers = array($columns, $hidden, $sortable);
163
  $this->process_bulk_action();
164
 
165
  $current_page = $this->get_pagenum();
@@ -168,39 +172,40 @@ class Quiz_Attempts_List extends \Tutor_List_Table {
168
  $this->items = array();
169
 
170
  if ( current_user_can( 'administrator' ) ) {
171
-
172
  $this->items = tutor_utils()->get_quiz_attempts( ( $current_page - 1 ) * $per_page, $per_page, $search_filter, $course_filter, $date_filter, $order_filter );
173
 
174
- $total_items = tutor_utils()->get_total_quiz_attempts();
175
 
176
- } elseif ( current_user_can( 'tutor_instructor' ) ){
177
  /**
178
  * Instructors course specific quiz attempts
179
  */
180
- $user_id = get_current_user_id();
181
- $get_assigned_courses_ids = $wpdb->get_col($wpdb->prepare("SELECT meta_value from {$wpdb->usermeta} WHERE meta_key = '_tutor_instructor_course_id' AND user_id = %d", $user_id));
182
 
183
- $custom_author_query = "AND {$wpdb->posts}.post_author = {$user_id}";
184
- if (is_array($get_assigned_courses_ids) && count($get_assigned_courses_ids)){
185
- $in_query_pre = implode(',', $get_assigned_courses_ids);
186
- $custom_author_query = " AND ( {$wpdb->posts}.post_author = {$user_id} OR {$wpdb->posts}.ID IN({$in_query_pre}) ) ";
187
  }
188
  $course_post_type = tutor()->course_post_type;
189
- $get_course_ids = $wpdb->get_col("SELECT ID from {$wpdb->posts} where post_type = '{$course_post_type}' $custom_author_query ; ");
190
 
191
- if (is_array($get_course_ids) && count($get_course_ids)){
192
 
193
- $this->items = tutor_utils()->get_quiz_attempts_by_course_ids(( $current_page - 1 ) * $per_page, $per_page, $get_course_ids, $search_filter, $course_filter, $date_filter, $order_filter );
194
-
195
- $total_items = tutor_utils()->get_total_quiz_attempts_by_course_ids($get_course_ids);
196
- }
197
 
 
 
198
  }
199
 
200
- $this->set_pagination_args( array(
201
- 'total_items' => $total_items,
202
- 'per_page' => $per_page,
203
- 'total_pages' => ceil($total_items/$per_page)
204
- ) );
 
 
205
  }
206
- }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ if ( ! class_exists( 'Tutor_List_Table' ) ) {
9
+ include_once tutor()->path . 'classes/Tutor_List_Table.php';
10
  }
11
 
12
  class Quiz_Attempts_List extends \Tutor_List_Table {
13
 
14
  const QUIZ_ATTEMPT_PAGE = 'tutor_quiz_attempts';
15
 
16
+ function __construct() {
17
  global $status, $page;
18
 
19
+ // Set parent defaults
20
+ parent::__construct(
21
+ array(
22
+ 'singular' => 'attempt', // singular name of the listed records
23
+ 'plural' => 'attempts', // plural name of the listed records
24
+ 'ajax' => false, // does this table support ajax?
25
+ )
26
+ );
27
  }
28
 
29
+ function column_default( $item, $column_name ) {
30
+ switch ( $column_name ) {
31
  case 'unknown_col':
32
  return $item->$column_name;
33
  default:
34
+ // return print_r($item,true); //Show the whole array for troubleshooting purposes
35
  }
36
  }
37
 
38
+ function column_student( $item ) {
39
  $actions = array();
40
 
41
+ $actions['answer'] = sprintf( '<a href="?page=%s&sub_page=%s&attempt_id=%s">' . __( 'Review', 'tutor' ) . '</a>', $_REQUEST['page'], 'view_attempt', $item->attempt_id );
42
+ // $actions['delete'] = sprintf('<a href="?page=%s&action=%s&attempt_id=%s">Delete</a>',$_REQUEST['page'],'delete',$item->attempt_id);
43
 
44
+ $quiz_title = '<p><strong>' . $item->display_name . '</strong></p>';
45
+ $quiz_title .= '<p>' . $item->user_email . '</p>';
46
+ // @since 1.9.5 instead of showing time ago showing original date time
47
+ if ( $item->attempt_ended_at ) {
48
+ $ended_ago_time = human_time_diff( strtotime( $item->attempt_ended_at ), tutor_time() ) . __( ' ago', 'tutor' );
49
+ $attempt_started_at = date_format( date_create( $item->attempt_started_at ), 'd M, Y, h:i a' );
50
+ $quiz_title .= '<span>' . $attempt_started_at . '</span>';
51
  }
52
 
53
+ // Return the title contents
54
+ return sprintf(
55
+ '%1$s <span style="color:silver">(id:%2$s)</span>%3$s',
56
  $quiz_title,
57
  $item->attempt_id,
58
+ $this->row_actions( $actions )
59
  );
60
  }
61
 
62
+ function column_quiz( $item ) {
63
  return $item->post_title;
64
  }
65
 
66
+ function column_cb( $item ) {
67
  return sprintf(
68
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
69
+ /*$1%s*/ $this->_args['singular'], // Let's simply repurpose the table's singular label ("instructor")
70
+ /*$2%s*/ $item->attempt_id // The value of the checkbox should be the record's id
71
  );
72
  }
73
 
74
+ function column_course( $item ) {
75
+ $quiz = tutor_utils()->get_course_by_quiz( $item->quiz_id );
76
 
77
+ if ( $quiz ) {
78
  $title = get_the_title( $quiz->ID );
79
+ return '<a href="' . admin_url( "post.php?post={$quiz->ID}&action=edit" ) . '">' . $title . '</a>';
80
  }
81
  }
82
 
83
+ function column_total_questions( $item ) {
84
  echo $item->total_questions;
85
  }
86
 
87
+ function column_earned_marks( $item ) {
88
 
89
+ if ( $item->attempt_status === 'review_required' ) {
90
+ $output = ' <span class="result-review-required">' . __( 'Under Review', 'tutor' ) . '</span>';
91
+ } else {
92
 
93
+ $pass_mark_percent = tutor_utils()->get_quiz_option( $item->quiz_id, 'passing_grade', 0 );
94
+ $earned_percentage = $item->earned_marks > 0 ? ( number_format( ( $item->earned_marks * 100 ) / $item->total_marks ) ) : 0;
95
 
96
+ $output = $item->earned_marks . __( ' out of ', 'tutor' ) . $item->total_marks . '<br/>';
97
+ $output .= '(' . $earned_percentage . '%)' . __( ' pass ', 'tutor' ) . '(' . $pass_mark_percent . ' %)<br/>';
98
 
99
+ if ( $earned_percentage >= $pass_mark_percent ) {
100
+ $output .= '<span class="result-pass"> ' . __( 'Pass', 'tutor' ) . '</span>';
101
+ } else {
102
+ $output .= '<span class="result-fail"> ' . __( 'Fail', 'tutor' ) . '</span>';
103
+ }
104
+ }
105
  return $output;
106
  }
107
 
108
+ function column_attempt_status( $item ) {
109
+ $status = ucwords( str_replace( 'quiz_', '', $item->attempt_status ) );
110
 
111
+ return '<span class="attempt-status-' . $item->attempt_status . '"> ' . $status . ' </span>';
112
  }
113
 
114
+ function get_columns() {
115
  $columns = array(
116
+ 'cb' => '<input type="checkbox"/> ', // Render a checkbox instead of text
117
+ 'student' => __( 'Students', 'tutor' ),
118
+ 'quiz' => __( 'Quiz', 'tutor' ),
119
+ 'course' => __( 'Course', 'tutor' ),
120
+ 'total_questions' => __( 'Total Questions', 'tutor' ),
121
+ 'earned_marks' => __( 'Earned Points', 'tutor' ),
122
+ // 'attempt_status' => __('Attempt Status', 'tutor'),
123
  );
124
  return $columns;
125
  }
126
 
127
  function get_sortable_columns() {
128
  $sortable_columns = array(
129
+ // 'display_name' => array('title',false), //true means it's already sorted
130
  );
131
  return $sortable_columns;
132
  }
133
 
134
  function get_bulk_actions() {
135
  $actions = array(
136
+ 'delete' => 'Delete',
137
  );
138
  return $actions;
139
  }
141
  function process_bulk_action() {
142
  global $wpdb;
143
 
144
+ // Detect when a bulk action is being triggered...
145
+ if ( 'delete' === $this->current_action() ) {
146
+ if ( empty( $_GET['attempt'] ) || ! is_array( $_GET['attempt'] ) ) {
147
  return;
148
  }
149
 
150
+ $attempt_ids = array_map( 'sanitize_text_field', $_GET['attempt'] );
151
  $attempt_ids = array_map( 'absint', $attempt_ids );
152
 
153
  tutor_utils()->delete_quiz_attempt( $attempt_ids );
159
 
160
  $per_page = 20;
161
 
162
+ $columns = $this->get_columns();
163
+ $hidden = array();
164
  $sortable = $this->get_sortable_columns();
165
 
166
+ $this->_column_headers = array( $columns, $hidden, $sortable );
167
  $this->process_bulk_action();
168
 
169
  $current_page = $this->get_pagenum();
172
  $this->items = array();
173
 
174
  if ( current_user_can( 'administrator' ) ) {
175
+
176
  $this->items = tutor_utils()->get_quiz_attempts( ( $current_page - 1 ) * $per_page, $per_page, $search_filter, $course_filter, $date_filter, $order_filter );
177
 
178
+ $total_items = tutor_utils()->get_total_quiz_attempts();
179
 
180
+ } elseif ( current_user_can( 'tutor_instructor' ) ) {
181
  /**
182
  * Instructors course specific quiz attempts
183
  */
184
+ $user_id = get_current_user_id();
185
+ $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value from {$wpdb->usermeta} WHERE meta_key = '_tutor_instructor_course_id' and user_id = % d", $user_id ) );
186
 
187
+ $custom_author_query = " and {$wpdb->posts} . post_author = {$user_id}";
188
+ if ( is_array( $get_assigned_courses_ids ) && count( $get_assigned_courses_ids ) ) {
189
+ $in_query_pre = implode( ',', $get_assigned_courses_ids );
190
+ $custom_author_query = " and ( {$wpdb->posts} . post_author = {$user_id} or {$wpdb->posts} . ID IN( {$in_query_pre} ) ) ";
191
  }
192
  $course_post_type = tutor()->course_post_type;
193
+ $get_course_ids = $wpdb->get_col( "SELECT ID from {$wpdb->posts} where post_type = '{$course_post_type}' $custom_author_query; " );
194
 
195
+ if ( is_array( $get_course_ids ) && count( $get_course_ids ) ) {
196
 
197
+ $this->items = tutor_utils()->get_quiz_attempts_by_course_ids( ( $current_page - 1 ) * $per_page, $per_page, $get_course_ids, $search_filter, $course_filter, $date_filter, $order_filter );
 
 
 
198
 
199
+ $total_items = tutor_utils()->get_total_quiz_attempts_by_course_ids( $get_course_ids );
200
+ }
201
  }
202
 
203
+ $this->set_pagination_args(
204
+ array(
205
+ 'total_items' => $total_items,
206
+ 'per_page' => $per_page,
207
+ 'total_pages' => ceil( $total_items / $per_page ),
208
+ )
209
+ );
210
  }
211
+ }
classes/Shortcode.php CHANGED
@@ -20,7 +20,7 @@ class Shortcode {
20
  'pp-left-middle',
21
  'pp-left-full'
22
  );
23
-
24
  public function __construct() {
25
  add_shortcode('tutor_student_registration_form', array($this, 'student_registration_form'));
26
  add_shortcode('tutor_dashboard', array($this, 'tutor_dashboard'));
@@ -170,13 +170,13 @@ class Shortcode {
170
 
171
  $previous_page = $page>0 ? $current_page-1 : null;
172
  $next_page = (is_array($next_instructors) && count($next_instructors)>0) ? $current_page+1 : null;
173
-
174
  $layout = sanitize_text_field(tutils()->array_get('layout', $atts, ''));
175
  $layout = in_array($layout, $this->instructor_layout) ? $layout : tutor_utils()->get_option('instructor_list_layout', $this->instructor_layout[0]);
176
 
177
  $payload=array(
178
- 'instructors' => is_array($instructors) ? $instructors : array(),
179
- 'next_page' => $next_page,
180
  'previous_page' => $previous_page,
181
  'column_count' => sanitize_text_field(tutils()->array_get('column_per_row', $atts, 3)),
182
  'layout' => $layout,
@@ -186,7 +186,7 @@ class Shortcode {
186
 
187
  return $payload;
188
  }
189
-
190
  /**
191
  * @param $atts
192
  *
@@ -198,11 +198,11 @@ class Shortcode {
198
 
199
  !is_array( $atts ) ? $atts = array() : 0;
200
 
201
- $current_page = (int)tutor_utils()->array_get('instructor-page', $_GET, 1);
202
  $current_page = $current_page>=1 ? $current_page : 1;
203
-
204
  $show_filter = isset( $atts['filter'] ) ? $atts['filter']=='on' : tutor_utils()->get_option( 'instructor_list_show_filter', false );
205
-
206
  // Get instructor list to sow
207
  $payload = $this->prepare_instructor_list($current_page, $atts);
208
  $payload['show_filter'] = $show_filter;
@@ -212,7 +212,7 @@ class Shortcode {
212
  $content = ob_get_clean();
213
 
214
  if($show_filter) {
215
-
216
  $course_cats = get_terms( array(
217
  'taxonomy' => 'course-category',
218
  'hide_empty' => true,
@@ -222,7 +222,7 @@ class Shortcode {
222
  $attributes = $payload;
223
  unset( $attributes['instructors'] );
224
 
225
- $payload = array(
226
  'show_filter' => $show_filter,
227
  'content' => $content,
228
  'categories' => $course_cats,
@@ -232,7 +232,7 @@ class Shortcode {
232
  ob_start();
233
 
234
  tutor_load_template('shortcode.instructor-filter', $payload);
235
-
236
  $content = ob_get_clean();
237
  }
238
 
@@ -242,11 +242,11 @@ class Shortcode {
242
  public function load_filtered_instructor() {
243
  tutor_utils()->checking_nonce();
244
 
245
- $attributes = (array)tutils()->array_get('attributes', $_POST, array());
246
  $current_page = (int)sanitize_text_field(tutils()->array_get('current_page', $attributes, 1));
247
  $keyword = (string)sanitize_text_field(tutils()->array_get('keyword', $_POST, ''));
248
 
249
- $category = (array)tutils()->array_get('category', $_POST, array());
250
  $category = array_filter($category, function($cat) {
251
  return is_numeric($cat);
252
  });
@@ -256,7 +256,7 @@ class Shortcode {
256
  tutor_load_template('shortcode.tutor-instructor', $payload);
257
  exit;
258
  }
259
-
260
  /**
261
  * Show layout selection dashboard in instructor setting
262
  */
20
  'pp-left-middle',
21
  'pp-left-full'
22
  );
23
+
24
  public function __construct() {
25
  add_shortcode('tutor_student_registration_form', array($this, 'student_registration_form'));
26
  add_shortcode('tutor_dashboard', array($this, 'tutor_dashboard'));
170
 
171
  $previous_page = $page>0 ? $current_page-1 : null;
172
  $next_page = (is_array($next_instructors) && count($next_instructors)>0) ? $current_page+1 : null;
173
+
174
  $layout = sanitize_text_field(tutils()->array_get('layout', $atts, ''));
175
  $layout = in_array($layout, $this->instructor_layout) ? $layout : tutor_utils()->get_option('instructor_list_layout', $this->instructor_layout[0]);
176
 
177
  $payload=array(
178
+ 'instructors' => is_array($instructors) ? $instructors : array(),
179
+ 'next_page' => $next_page,
180
  'previous_page' => $previous_page,
181
  'column_count' => sanitize_text_field(tutils()->array_get('column_per_row', $atts, 3)),
182
  'layout' => $layout,
186
 
187
  return $payload;
188
  }
189
+
190
  /**
191
  * @param $atts
192
  *
198
 
199
  !is_array( $atts ) ? $atts = array() : 0;
200
 
201
+ $current_page = (int)tutor_utils()->array_get('instructor-page', tutor_sanitize_data($_GET), 1);
202
  $current_page = $current_page>=1 ? $current_page : 1;
203
+
204
  $show_filter = isset( $atts['filter'] ) ? $atts['filter']=='on' : tutor_utils()->get_option( 'instructor_list_show_filter', false );
205
+
206
  // Get instructor list to sow
207
  $payload = $this->prepare_instructor_list($current_page, $atts);
208
  $payload['show_filter'] = $show_filter;
212
  $content = ob_get_clean();
213
 
214
  if($show_filter) {
215
+
216
  $course_cats = get_terms( array(
217
  'taxonomy' => 'course-category',
218
  'hide_empty' => true,
222
  $attributes = $payload;
223
  unset( $attributes['instructors'] );
224
 
225
+ $payload = array(
226
  'show_filter' => $show_filter,
227
  'content' => $content,
228
  'categories' => $course_cats,
232
  ob_start();
233
 
234
  tutor_load_template('shortcode.instructor-filter', $payload);
235
+
236
  $content = ob_get_clean();
237
  }
238
 
242
  public function load_filtered_instructor() {
243
  tutor_utils()->checking_nonce();
244
 
245
+ $attributes = (array)tutils()->array_get('attributes', tutor_sanitize_data($_POST), array());
246
  $current_page = (int)sanitize_text_field(tutils()->array_get('current_page', $attributes, 1));
247
  $keyword = (string)sanitize_text_field(tutils()->array_get('keyword', $_POST, ''));
248
 
249
+ $category = (array)tutils()->array_get('category', tutor_sanitize_data($_POST), array());
250
  $category = array_filter($category, function($cat) {
251
  return is_numeric($cat);
252
  });
256
  tutor_load_template('shortcode.tutor-instructor', $payload);
257
  exit;
258
  }
259
+
260
  /**
261
  * Show layout selection dashboard in instructor setting
262
  */
classes/Student.php CHANGED
@@ -33,7 +33,7 @@ class Student {
33
  // Action must be register, and registrtion must be enabled in dashoard
34
  return;
35
  }
36
-
37
  //Checking nonce
38
  tutor_utils()->checking_nonce();
39
 
@@ -45,19 +45,19 @@ class Student {
45
  'password' => __('Password field is required', 'tutor'),
46
  'password_confirmation' => __('Password Confirmation field is required', 'tutor'),
47
  ));
48
-
49
 
50
  $validation_errors = array();
51
 
52
  /*
53
  *registration_errors
54
- *push into validation_errors
55
  */
56
  $errors = apply_filters('registration_errors',new \WP_Error,'','');
57
- foreach ($errors->errors as $key => $value)
58
  {
59
  $validation_errors[$key] = $value[0];
60
-
61
  }
62
 
63
  foreach ($required_fields as $required_key => $required_value){
@@ -104,7 +104,7 @@ class Student {
104
 
105
  do_action('tutor_after_student_signup', $user_id);
106
  //since 1.9.8 do enroll if guest attempt to enroll
107
- do_action( 'tutor_do_enroll_after_login_if_attempt', $_POST['tutor_course_enroll_attempt'] );
108
  //Redirect page
109
  $redirect_page = tutils()->array_get('redirect_to', $_REQUEST);
110
  if ( ! $redirect_page){
@@ -133,7 +133,7 @@ class Student {
133
  }
134
 
135
  $user_id = get_current_user_id();
136
-
137
  //Checking nonce
138
  tutor_utils()->checking_nonce();
139
  do_action('tutor_profile_update_before', $user_id);
33
  // Action must be register, and registrtion must be enabled in dashoard
34
  return;
35
  }
36
+
37
  //Checking nonce
38
  tutor_utils()->checking_nonce();
39
 
45
  'password' => __('Password field is required', 'tutor'),
46
  'password_confirmation' => __('Password Confirmation field is required', 'tutor'),
47
  ));
48
+
49
 
50
  $validation_errors = array();
51
 
52
  /*
53
  *registration_errors
54
+ *push into validation_errors
55
  */
56
  $errors = apply_filters('registration_errors',new \WP_Error,'','');
57
+ foreach ($errors->errors as $key => $value)
58
  {
59
  $validation_errors[$key] = $value[0];
60
+
61
  }
62
 
63
  foreach ($required_fields as $required_key => $required_value){
104
 
105
  do_action('tutor_after_student_signup', $user_id);
106
  //since 1.9.8 do enroll if guest attempt to enroll
107
+ do_action( 'tutor_do_enroll_after_login_if_attempt', tutor_sanitize_data($_POST['tutor_course_enroll_attempt']) );
108
  //Redirect page
109
  $redirect_page = tutils()->array_get('redirect_to', $_REQUEST);
110
  if ( ! $redirect_page){
133
  }
134
 
135
  $user_id = get_current_user_id();
136
+
137
  //Checking nonce
138
  tutor_utils()->checking_nonce();
139
  do_action('tutor_profile_update_before', $user_id);
classes/Taxonomies.php CHANGED
@@ -104,7 +104,7 @@ class Taxonomies{
104
  <div class="form-field term-thumbnail-wrap">
105
  <div id="course-category_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div>
106
  <div style="line-height: 60px;">
107
- <input type="hidden" id="course-category_thumbnail_id" name="course_category_thumbnail_id" value="<?php echo esc_attr( $thumbnail_id ); ?>" />
108
  <button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'tutor' ); ?></button>
109
  <button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'tutor' ); ?></button>
110
  </div>
@@ -210,10 +210,10 @@ class Taxonomies{
210
 
211
  // Prevent esc_url from breaking spaces in urls for image embeds. Ref: https://core.trac.wordpress.org/ticket/23605 .
212
  $image = str_replace( ' ', '%20', $image );
213
- $columns .= '<img src="' . esc_url( $image ) . '" alt="' . esc_attr__( 'Thumbnail', 'tutor' ) . '" class="wp-post-image" height="48" width="48" />';
214
  }
215
  if ( 'handle' === $column ) {
216
- $columns .= '<input type="hidden" name="term_id" value="' . esc_attr( $id ) . '" />';
217
  }
218
  return $columns;
219
  }
104
  <div class="form-field term-thumbnail-wrap">
105
  <div id="course-category_thumbnail" style="float: left; margin-right: 10px;"><img src="<?php echo esc_url( $image ); ?>" width="60px" height="60px" /></div>
106
  <div style="line-height: 60px;">
107
+ <input type="hidden" id="course-category_thumbnail_id" name="course_category_thumbnail_id" value="<?php echo $thumbnail_id; ?>" />
108
  <button type="button" class="upload_image_button button"><?php esc_html_e( 'Upload/Add image', 'tutor' ); ?></button>
109
  <button type="button" class="remove_image_button button"><?php esc_html_e( 'Remove image', 'tutor' ); ?></button>
110
  </div>
210
 
211
  // Prevent esc_url from breaking spaces in urls for image embeds. Ref: https://core.trac.wordpress.org/ticket/23605 .
212
  $image = str_replace( ' ', '%20', $image );
213
+ $columns .= '<img src="' . esc_url( $image ) . '" alt="' . __( 'Thumbnail', 'tutor' ) . '" class="wp-post-image" height="48" width="48" />';
214
  }
215
  if ( 'handle' === $column ) {
216
+ $columns .= '<input type="hidden" name="term_id" value="' . $id . '" />';
217
  }
218
  return $columns;
219
  }
classes/Template.php CHANGED
@@ -141,7 +141,7 @@ class Template extends Tutor_Base {
141
  if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type){
142
 
143
  do_action( 'single_course_template_before_load', get_the_ID() );
144
-
145
  $student_must_login_to_view_course = tutor_utils()->get_option('student_must_login_to_view_course');
146
  if ($student_must_login_to_view_course){
147
  if ( ! is_user_logged_in() ) {
@@ -223,7 +223,7 @@ class Template extends Tutor_Base {
223
  if(get_post_meta($course_id, '_tutor_is_public_course', true)=='yes' && !tutor_utils()->is_course_purchasable($course_id)){
224
  $template = tutor_get_template( 'single-lesson' );
225
  }
226
-
227
  return apply_filters('tutor_lesson_template', $template);
228
  }
229
  return $template;
@@ -334,7 +334,7 @@ class Template extends Tutor_Base {
334
  global $wp;
335
  $full_path = explode('/', trim( str_replace( get_home_url(), '', home_url( $wp->request ) ), '/' ) );
336
  $template = tutor_get_template( end($full_path)=='create-course' ? implode('/', $full_path) : 'dashboard' );
337
-
338
  /**
339
  * Check page page permission
340
  *
141
  if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type){
142
 
143
  do_action( 'single_course_template_before_load', get_the_ID() );
144
+
145
  $student_must_login_to_view_course = tutor_utils()->get_option('student_must_login_to_view_course');
146
  if ($student_must_login_to_view_course){
147
  if ( ! is_user_logged_in() ) {
223
  if(get_post_meta($course_id, '_tutor_is_public_course', true)=='yes' && !tutor_utils()->is_course_purchasable($course_id)){
224
  $template = tutor_get_template( 'single-lesson' );
225
  }
226
+
227
  return apply_filters('tutor_lesson_template', $template);
228
  }
229
  return $template;
334
  global $wp;
335
  $full_path = explode('/', trim( str_replace( get_home_url(), '', home_url( $wp->request ) ), '/' ) );
336
  $template = tutor_get_template( end($full_path)=='create-course' ? implode('/', $full_path) : 'dashboard' );
337
+
338
  /**
339
  * Check page page permission
340
  *
classes/TutorEDD.php CHANGED
@@ -115,7 +115,7 @@ class TutorEDD extends Tutor_Base {
115
  }
116
 
117
  public function save_course_meta($post_ID) {
118
- $product_id = tutor_utils()->avalue_dot('_tutor_course_product_id', $_POST);
119
 
120
  if ($product_id !== '-1') {
121
  $product_id = (int) $product_id;
115
  }
116
 
117
  public function save_course_meta($post_ID) {
118
+ $product_id = tutor_utils()->avalue_dot('_tutor_course_product_id', tutor_sanitize_data($_POST));
119
 
120
  if ($product_id !== '-1') {
121
  $product_id = (int) $product_id;
classes/Tutor_List_Table.php CHANGED
@@ -7,8 +7,9 @@
7
  */
8
 
9
 
10
- if ( ! defined( 'ABSPATH' ) )
11
  exit;
 
12
 
13
  /**
14
  * Base class for displaying a list of items in an ajaxified HTML table.
@@ -94,10 +95,24 @@ class Tutor_List_Table {
94
  *
95
  * @var array
96
  */
97
- protected $compat_methods = array( 'set_pagination_args', 'get_views', 'get_bulk_actions', 'bulk_actions',
98
- 'row_actions', 'months_dropdown', 'view_switcher', 'comments_bubble', 'get_items_per_page', 'pagination',
99
- 'get_sortable_columns', 'get_column_info', 'get_table_classes', 'display_tablenav', 'extra_tablenav',
100
- 'single_row_columns' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  /**
103
  * Constructor.
@@ -125,21 +140,25 @@ class Tutor_List_Table {
125
  * }
126
  */
127
  public function __construct( $args = array() ) {
128
- $args = wp_parse_args( $args, array(
129
- 'plural' => '',
130
- 'singular' => '',
131
- 'ajax' => false,
132
- 'screen' => null,
133
- ) );
 
 
 
134
 
135
  $this->screen = convert_to_screen( $args['screen'] );
136
 
137
  add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
138
 
139
- if ( !$args['plural'] )
140
  $args['plural'] = $this->screen->base;
 
141
 
142
- $args['plural'] = sanitize_key( $args['plural'] );
143
  $args['singular'] = sanitize_key( $args['singular'] );
144
 
145
  $this->_args = $args;
@@ -152,7 +171,7 @@ class Tutor_List_Table {
152
  if ( empty( $this->modes ) ) {
153
  $this->modes = array(
154
  'list' => __( 'List View' ),
155
- 'excerpt' => __( 'Excerpt View' )
156
  );
157
  }
158
  }
@@ -241,6 +260,7 @@ class Tutor_List_Table {
241
 
242
  /**
243
  * Prepares the list of items for displaying.
 
244
  * @uses Tutor_List_Table::set_pagination_args()
245
  *
246
  * @since 3.1.0
@@ -258,14 +278,18 @@ class Tutor_List_Table {
258
  * @param array|string $args Array or string of arguments with information about the pagination.
259
  */
260
  protected function set_pagination_args( $args ) {
261
- $args = wp_parse_args( $args, array(
262
- 'total_items' => 0,
263
- 'total_pages' => 0,
264
- 'per_page' => 0,
265
- ) );
 
 
 
266
 
267
- if ( !$args['total_pages'] && $args['per_page'] > 0 )
268
  $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
 
269
 
270
  // Redirect if page number is invalid and headers are not already sent.
271
  if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
@@ -290,8 +314,8 @@ class Tutor_List_Table {
290
  return $this->get_pagenum();
291
  }
292
 
293
- if ( isset( $this->_pagination_args[$key] ) ) {
294
- return $this->_pagination_args[$key];
295
  }
296
  }
297
 
@@ -303,7 +327,7 @@ class Tutor_List_Table {
303
  * @return bool
304
  */
305
  public function has_items() {
306
- return !empty( $this->items );
307
  }
308
 
309
  /**
@@ -324,22 +348,27 @@ class Tutor_List_Table {
324
  * @param string $input_id ID attribute value for the search input field.
325
  */
326
  public function search_box( $text, $input_id ) {
327
- if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
328
- return;
 
329
 
330
  $input_id = $input_id . '-search-input';
331
 
332
- if ( ! empty( $_REQUEST['orderby'] ) )
333
  echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
334
- if ( ! empty( $_REQUEST['order'] ) )
 
335
  echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
336
- if ( ! empty( $_REQUEST['post_mime_type'] ) )
 
337
  echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
338
- if ( ! empty( $_REQUEST['detached'] ) )
 
339
  echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
 
340
  ?>
341
  <p class="search-box">
342
- <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo $text; ?>:</label>
343
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
344
  <?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
345
  </p>
@@ -351,24 +380,24 @@ class Tutor_List_Table {
351
  * get course list
352
  * @param $selected | optional
353
  */
354
- public function course_dropdown($selected = ''){
355
- $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
356
- $markup = '
357
  <div class="alignright">
358
- <label>'.__('Course', 'tutor-pro').'</label>
359
  <select class="tutor-assignment-course-sorting">
360
- <option value="0">'.__('All','tutor').'</option>
361
  OPTIONS_PLACEHOLDER
362
- </select>
363
  </div>
364
  ';
365
  $options = '';
366
  foreach ( $courses as $course ) {
367
- $options .= '<option value="' . $course->ID . '" ' . selected( $selected,$course->ID, false ) . '> ' . $course->post_title . ' </option>';
368
  }
369
-
370
  $content = str_replace( 'OPTIONS_PLACEHOLDER', $options, $markup );
371
- echo $content;
372
  }
373
 
374
  /**
@@ -377,22 +406,22 @@ class Tutor_List_Table {
377
  * @param $selected | optional
378
  */
379
 
380
- public function sorting_order($selected='DESC'){
381
- $orders = ['DESC','ASC'];
382
- $markup = '
383
  <div class="alignright">
384
- <label>'.__('Sort By', 'tutor').'</label>
385
  <select class="tutor-assignment-order-sorting">
386
  OPTION_PLACEHOLDER
387
- </select>
388
  </div>
389
  ';
390
  $options = '';
391
- foreach( $orders as $order ) {
392
- $options .= '<option value="' . $order . '" '. selected( $selected, $order, false ) . '> '. __( $order, 'tutor' ) . ' </option>';
393
- }
394
  $content = str_replace( 'OPTION_PLACEHOLDER', $options, $markup );
395
- echo $content;
396
  }
397
  /**
398
  * @since 1.8.0
@@ -404,14 +433,14 @@ class Tutor_List_Table {
404
  $placeholder = __( get_option( 'date_format' ), 'tutor' );
405
  $date_filter = sanitize_text_field( tutor_utils()->array_get( 'date', $_GET, '' ) );
406
  $date_input = '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : '';
407
- $markup = '
408
  <div class="alignright assignment-date-box">
409
- <label>'.__('Date', 'tutor').'</label>
410
  <input type="" class="tutor_date_picker tutor-assignment-date-sorting" placeholder="' . $placeholder . '" value="' . $date_input . '">
411
  <i class="tutor-icon-calendar"></i>
412
  </div>
413
- ';
414
- echo $markup;
415
  }
416
 
417
  /**
@@ -445,17 +474,18 @@ class Tutor_List_Table {
445
  */
446
  $views = apply_filters( "views_{$this->screen->id}", $views );
447
 
448
- if ( empty( $views ) )
449
  return;
 
450
 
451
  $this->screen->render_screen_reader_content( 'heading_views' );
452
 
453
- echo "<ul class='subsubsub'>\n";
454
  foreach ( $views as $class => $view ) {
455
  $views[ $class ] = "\t<li class='$class'>$view";
456
  }
457
- echo implode( " |</li>\n", $views ) . "</li>\n";
458
- echo "</ul>";
459
  }
460
 
461
  /**
@@ -494,28 +524,29 @@ class Tutor_List_Table {
494
  * @param array $actions An array of the available bulk actions.
495
  */
496
  $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
497
- $two = '';
498
  } else {
499
  $two = '2';
500
  }
501
 
502
- if ( empty( $this->_actions ) )
503
  return;
 
504
 
505
  echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
506
- echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
507
- echo '<option value="-1">' . __( 'Bulk Actions', 'tutor' ) . "</option>\n";
508
 
509
  foreach ( $this->_actions as $name => $title ) {
510
  $class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
511
 
512
- echo "\t" . '<option value="' . $name . '"' . $class . '>' . $title . "</option>\n";
513
  }
514
 
515
- echo "</select>\n";
516
 
517
- submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction$two" ) );
518
- echo "\n";
519
  }
520
 
521
  /**
@@ -526,14 +557,17 @@ class Tutor_List_Table {
526
  * @return string|false The action name or False if no action was selected
527
  */
528
  public function current_action() {
529
- if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) )
530
  return false;
 
531
 
532
- if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
533
  return $_REQUEST['action'];
 
534
 
535
- if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
536
  return $_REQUEST['action2'];
 
537
 
538
  return false;
539
  }
@@ -544,27 +578,29 @@ class Tutor_List_Table {
544
  * @since 3.1.0
545
  *
546
  * @param array $actions The list of actions
547
- * @param bool $always_visible Whether the actions should be always visible
548
  * @return string
549
  */
550
  protected function row_actions( $actions, $always_visible = false ) {
551
  $action_count = count( $actions );
552
- $i = 0;
553
 
554
- if ( !$action_count )
555
  return '';
 
556
 
557
- $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
558
  foreach ( $actions as $action => $link ) {
559
  ++$i;
560
  ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
561
- $out .= "<span class='$action'>$link$sep</span>";
562
  }
563
  $out .= '</div>';
564
 
565
  $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
566
 
567
- return $out;
 
568
  }
569
 
570
  /**
@@ -596,16 +632,21 @@ class Tutor_List_Table {
596
  if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
597
  $extra_checks .= " AND post_status != 'trash'";
598
  } elseif ( isset( $_GET['post_status'] ) ) {
599
- $extra_checks = $wpdb->prepare( ' AND post_status = %s', $_GET['post_status'] );
600
  }
601
 
602
- $months = $wpdb->get_results( $wpdb->prepare( "
 
 
603
  SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
604
  FROM $wpdb->posts
605
  WHERE post_type = %s
606
  $extra_checks
607
  ORDER BY post_date DESC
608
- ", $post_type ) );
 
 
 
609
 
610
  /**
611
  * Filters the 'Months' drop-down results.
@@ -619,8 +660,9 @@ class Tutor_List_Table {
619
 
620
  $month_count = count( $months );
621
 
622
- if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
623
  return;
 
624
 
625
  $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
626
  ?>
@@ -629,13 +671,15 @@ class Tutor_List_Table {
629
  <option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
630
  <?php
631
  foreach ( $months as $arc_row ) {
632
- if ( 0 == $arc_row->year )
633
  continue;
 
634
 
635
  $month = zeroise( $arc_row->month, 2 );
636
- $year = $arc_row->year;
637
 
638
- printf( "<option %s value='%s'>%s</option>\n",
 
639
  selected( $m, $year . $month, false ),
640
  esc_attr( $arc_row->year . $month ),
641
  /* translators: 1: month name, 2: 4-digit year */
@@ -661,10 +705,11 @@ class Tutor_List_Table {
661
  <?php
662
  foreach ( $this->modes as $mode => $title ) {
663
  $classes = array( 'view-' . $mode );
664
- if ( $current_mode === $mode )
665
  $classes[] = 'current';
 
666
  printf(
667
- "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>\n",
668
  esc_url( add_query_arg( 'mode', $mode ) ),
669
  implode( ' ', $classes ),
670
  $title
@@ -687,39 +732,60 @@ class Tutor_List_Table {
687
  $approved_comments = get_comments_number();
688
 
689
  $approved_comments_number = number_format_i18n( $approved_comments );
690
- $pending_comments_number = number_format_i18n( $pending_comments );
691
 
692
  $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
693
- $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
694
- $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
695
 
696
  // No comments at all.
697
  if ( ! $approved_comments && ! $pending_comments ) {
698
- printf( '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
 
699
  __( 'No comments' )
700
  );
701
  // Approved comments have different display depending on some conditions.
702
  } elseif ( $approved_comments ) {
703
- printf( '<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
704
- esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'approved' ), admin_url( 'edit-comments.php' ) ) ),
 
 
 
 
 
 
 
 
 
705
  $approved_comments_number,
706
  $pending_comments ? $approved_phrase : $approved_only_phrase
707
  );
708
  } else {
709
- printf( '<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
 
710
  $approved_comments_number,
711
  $pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
712
  );
713
  }
714
 
715
  if ( $pending_comments ) {
716
- printf( '<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
717
- esc_url( add_query_arg( array( 'p' => $post_id, 'comment_status' => 'moderated' ), admin_url( 'edit-comments.php' ) ) ),
 
 
 
 
 
 
 
 
 
718
  $pending_comments_number,
719
  $pending_phrase
720
  );
721
  } else {
722
- printf( '<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
 
723
  $pending_comments_number,
724
  $approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
725
  );
@@ -736,8 +802,9 @@ class Tutor_List_Table {
736
  public function get_pagenum() {
737
  $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
738
 
739
- if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
740
  $pagenum = $this->_pagination_args['total_pages'];
 
741
 
742
  return max( 1, $pagenum );
743
  }
@@ -753,8 +820,9 @@ class Tutor_List_Table {
753
  */
754
  protected function get_items_per_page( $option, $default = 20 ) {
755
  $per_page = (int) get_user_option( $option );
756
- if ( empty( $per_page ) || $per_page < 1 )
757
  $per_page = $default;
 
758
 
759
  /**
760
  * Filters the number of items to be displayed on each page of the list table.
@@ -784,8 +852,8 @@ class Tutor_List_Table {
784
  return;
785
  }
786
 
787
- $total_items = $this->_pagination_args['total_items'];
788
- $total_pages = $this->_pagination_args['total_pages'];
789
  $infinite_scroll = false;
790
  if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
791
  $infinite_scroll = $this->_pagination_args['infinite_scroll'];
@@ -797,7 +865,7 @@ class Tutor_List_Table {
797
 
798
  $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
799
 
800
- $current = $this->get_pagenum();
801
  $removable_query_args = wp_removable_query_args();
802
 
803
  $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
@@ -813,7 +881,7 @@ class Tutor_List_Table {
813
 
814
  if ( $current == 1 ) {
815
  $disable_first = true;
816
- $disable_prev = true;
817
  }
818
  if ( $current == 2 ) {
819
  $disable_first = true;
@@ -829,7 +897,8 @@ class Tutor_List_Table {
829
  if ( $disable_first ) {
830
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
831
  } else {
832
- $page_links[] = sprintf( "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
 
833
  esc_url( remove_query_arg( 'paged', $current_url ) ),
834
  __( 'First page' ),
835
  '&laquo;'
@@ -839,8 +908,9 @@ class Tutor_List_Table {
839
  if ( $disable_prev ) {
840
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
841
  } else {
842
- $page_links[] = sprintf( "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
843
- esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
 
844
  __( 'Previous page' ),
845
  '&lsaquo;'
846
  );
@@ -850,20 +920,22 @@ class Tutor_List_Table {
850
  $html_current_page = $current;
851
  $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
852
  } else {
853
- $html_current_page = sprintf( "%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
 
854
  '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
855
  $current,
856
  strlen( $total_pages )
857
  );
858
  }
859
- $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
860
- $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
861
 
862
  if ( $disable_next ) {
863
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
864
  } else {
865
- $page_links[] = sprintf( "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
866
- esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
 
867
  __( 'Next page' ),
868
  '&rsaquo;'
869
  );
@@ -872,7 +944,8 @@ class Tutor_List_Table {
872
  if ( $disable_last ) {
873
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
874
  } else {
875
- $page_links[] = sprintf( "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
 
876
  esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
877
  __( 'Last page' ),
878
  '&raquo;'
@@ -883,16 +956,16 @@ class Tutor_List_Table {
883
  if ( ! empty( $infinite_scroll ) ) {
884
  $pagination_links_class .= ' hide-if-js';
885
  }
886
- $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
887
 
888
  if ( $total_pages ) {
889
  $page_class = $total_pages < 2 ? ' one-page' : '';
890
  } else {
891
  $page_class = ' no-pages';
892
  }
893
- $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
894
 
895
- echo $this->_pagination;
896
  }
897
 
898
  /**
@@ -933,7 +1006,7 @@ class Tutor_List_Table {
933
  */
934
  protected function get_default_primary_column_name() {
935
  $columns = $this->get_columns();
936
- $column = '';
937
 
938
  if ( empty( $columns ) ) {
939
  return $column;
@@ -978,7 +1051,7 @@ class Tutor_List_Table {
978
  // If the primary column doesn't exist fall back to the
979
  // first non-checkbox column.
980
  if ( ! isset( $columns[ $default ] ) ) {
981
- $default = Tutor_List_Table::get_default_primary_column_name();
982
  }
983
 
984
  /**
@@ -989,7 +1062,7 @@ class Tutor_List_Table {
989
  * @param string $default Column name default for the specific list table, e.g. 'name'.
990
  * @param string $context Screen ID for specific list table, e.g. 'plugins'.
991
  */
992
- $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
993
 
994
  if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
995
  $column = $default;
@@ -1019,7 +1092,7 @@ class Tutor_List_Table {
1019
  }
1020
 
1021
  $columns = get_column_headers( $this->screen );
1022
- $hidden = get_hidden_columns( $this->screen );
1023
 
1024
  $sortable_columns = $this->get_sortable_columns();
1025
  /**
@@ -1032,21 +1105,23 @@ class Tutor_List_Table {
1032
  *
1033
  * @param array $sortable_columns An array of sortable columns.
1034
  */
1035
- $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
1036
 
1037
  $sortable = array();
1038
  foreach ( $_sortable as $id => $data ) {
1039
- if ( empty( $data ) )
1040
  continue;
 
1041
 
1042
  $data = (array) $data;
1043
- if ( !isset( $data[1] ) )
1044
  $data[1] = false;
 
1045
 
1046
- $sortable[$id] = $data;
1047
  }
1048
 
1049
- $primary = $this->get_primary_column_name();
1050
  $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
1051
 
1052
  return $this->_column_headers;
@@ -1061,7 +1136,7 @@ class Tutor_List_Table {
1061
  */
1062
  public function get_column_count() {
1063
  list ( $columns, $hidden ) = $this->get_column_info();
1064
- $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
1065
  return count( $columns ) - count( $hidden );
1066
  }
1067
 
@@ -1081,7 +1156,7 @@ class Tutor_List_Table {
1081
  $current_url = remove_query_arg( 'paged', $current_url );
1082
 
1083
  if ( isset( $_GET['orderby'] ) ) {
1084
- $current_orderby = $_GET['orderby'];
1085
  } else {
1086
  $current_orderby = '';
1087
  }
@@ -1094,8 +1169,7 @@ class Tutor_List_Table {
1094
 
1095
  if ( ! empty( $columns['cb'] ) ) {
1096
  static $cb_counter = 1;
1097
- $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
1098
- . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
1099
  $cb_counter++;
1100
  }
1101
 
@@ -1106,24 +1180,25 @@ class Tutor_List_Table {
1106
  $class[] = 'hidden';
1107
  }
1108
 
1109
- if ( 'cb' === $column_key )
1110
  $class[] = 'check-column';
1111
- elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
1112
  $class[] = 'num';
 
1113
 
1114
  if ( $column_key === $primary ) {
1115
  $class[] = 'column-primary';
1116
  }
1117
 
1118
- if ( isset( $sortable[$column_key] ) ) {
1119
- list( $orderby, $desc_first ) = $sortable[$column_key];
1120
 
1121
  if ( $current_orderby === $orderby ) {
1122
- $order = 'asc' === $current_order ? 'desc' : 'asc';
1123
  $class[] = 'sorted';
1124
  $class[] = $current_order;
1125
  } else {
1126
- $order = $desc_first ? 'desc' : 'asc';
1127
  $class[] = 'sortable';
1128
  $class[] = $desc_first ? 'asc' : 'desc';
1129
  }
@@ -1131,14 +1206,15 @@ class Tutor_List_Table {
1131
  $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
1132
  }
1133
 
1134
- $tag = ( 'cb' === $column_key ) ? 'td' : 'th';
1135
  $scope = ( 'th' === $tag ) ? 'scope="col"' : '';
1136
- $id = $with_id ? "id='$column_key'" : '';
1137
 
1138
- if ( !empty( $class ) )
1139
  $class = "class='" . join( ' ', $class ) . "'";
 
1140
 
1141
- echo "<$tag $scope $id $class>$column_display_name</$tag>";
1142
  }
1143
  }
1144
 
@@ -1147,27 +1223,30 @@ class Tutor_List_Table {
1147
  *
1148
  * @since 3.1.0
1149
  */
1150
- public function display($enable_sorting_field_with_bulk_action = false) {
1151
  $singular = $this->_args['singular'];
1152
  if ( $enable_sorting_field_with_bulk_action ) {
1153
- $this->display_sorting_fields( );
1154
  } else {
1155
- $this->display_tablenav('top');
1156
  }
1157
 
1158
  $this->screen->render_screen_reader_content( 'heading_list' );
1159
  ?>
1160
- <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
1161
  <thead>
1162
  <tr>
1163
  <?php $this->print_column_headers(); ?>
1164
  </tr>
1165
  </thead>
1166
 
1167
- <tbody id="the-list"<?php
 
1168
  if ( $singular ) {
1169
- echo " data-wp-lists='list:$singular'";
1170
- } ?>>
 
 
1171
  <?php $this->display_rows_or_placeholder(); ?>
1172
  </tbody>
1173
 
@@ -1206,11 +1285,12 @@ class Tutor_List_Table {
1206
  ?>
1207
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
1208
 
1209
- <?php if ( $this->has_items() ): ?>
1210
  <div class="alignleft actions bulkactions">
1211
  <?php $this->bulk_actions( $which ); ?>
1212
  </div>
1213
- <?php endif;
 
1214
  $this->extra_tablenav( $which );
1215
  $this->pagination( $which );
1216
  ?>
@@ -1222,85 +1302,86 @@ class Tutor_List_Table {
1222
 
1223
  /**
1224
  * Sorting fields added on tutor table
1225
- *
1226
  * Course id | Search | Date | Order
1227
- *
1228
  * @since 1.9.5
1229
  */
1230
  protected function display_sorting_fields() {
1231
- $search_filter = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
1232
- $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
1233
- $date_filter = isset( $_GET['date'] ) ? sanitize_text_field( $_GET['date'] ) : '';
1234
- $order_filter = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : '';
1235
- $which = 'top';
1236
  ?>
1237
  <div class="tutor-sorting-bulk-action-wrapper">
1238
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
1239
- <?php if ( $this->has_items() ): ?>
1240
  <div class="alignleft actions bulkactions">
1241
  <?php $this->bulk_actions( $which ); ?>
1242
  </div>
1243
- <?php endif;
 
1244
  $this->extra_tablenav( $which );
1245
 
1246
  ?>
1247
  </div>
1248
-
1249
  <div class="tutor-admin-search-box-container" style="margin:0px;">
1250
 
1251
  <div>
1252
- <div class="menu-label"><?php _e('Courses', 'tutor'); ?></div>
1253
  <div>
1254
  <?php
1255
- //get courses
1256
- $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
1257
  ?>
1258
 
1259
  <select class="tutor-report-category tutor-announcement-course-sorting">
1260
-
1261
- <option value=""><?php _e('All', 'tutor'); ?></option>
1262
-
1263
- <?php if ($courses) : ?>
1264
- <?php foreach ($courses as $course) : ?>
1265
- <option value="<?php echo esc_attr($course->ID) ?>" <?php selected($course_id, $course->ID, 'selected') ?>>
1266
- <?php echo $course->post_title; ?>
1267
  </option>
1268
  <?php endforeach; ?>
1269
  <?php else : ?>
1270
- <option value=""><?php _e('No course found', 'tutor'); ?></option>
1271
  <?php endif; ?>
1272
  </select>
1273
  </div>
1274
  </div>
1275
 
1276
  <div>
1277
- <div class="menu-label"><?php _e('Sort By', 'tutor'); ?></div>
1278
  <div>
1279
  <select class="tutor-report-sort tutor-announcement-order-sorting">
1280
- <option <?php selected($order_filter, 'ASC'); ?>>ASC</option>
1281
- <option <?php selected($order_filter, 'DESC'); ?>>DESC</option>
1282
  </select>
1283
  </div>
1284
  </div>
1285
 
1286
  <div>
1287
- <div class="menu-label"><?php _e('Date', 'tutor'); ?></div>
1288
  <div class="date-range-input">
1289
- <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" id="tutor-announcement-datepicker" placeholder="<?php _e( get_option( 'date_format' ) , 'tutor' );?>" value="<?php echo '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" autocomplete="off" />
1290
  <i class="tutor-icon-calendar"></i>
1291
  </div>
1292
  </div>
1293
 
1294
  <div class="tutor-search-form-group">
1295
- <div class="menu-label"><?php _e('Search', 'tutor'); ?></div>
1296
  <div style="position:relative;">
1297
- <input type="text" name="search" class="tutor-report-search tutor-announcement-search-field" value="<?php echo $search_filter; ?>" autocomplete="off" placeholder="<?php _e('Search', 'tutor'); ?>" />
1298
  <button class="tutor-report-search-btn tutor-announcement-search-sorting"><i class="tutor-icon-magnifying-glass-1"></i></button>
1299
  </div>
1300
  </div>
1301
-
1302
- </div>
1303
- </div>
1304
  <?php
1305
  }
1306
 
@@ -1334,8 +1415,9 @@ class Tutor_List_Table {
1334
  * @since 3.1.0
1335
  */
1336
  public function display_rows() {
1337
- foreach ( $this->items as $item )
1338
  $this->single_row( $item );
 
1339
  }
1340
 
1341
  /**
@@ -1388,7 +1470,7 @@ class Tutor_List_Table {
1388
  // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
1389
  $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
1390
 
1391
- $attributes = "class='$classes' $data";
1392
 
1393
  if ( 'cb' === $column_name ) {
1394
  echo '<th scope="row" class="check-column">';
@@ -1403,15 +1485,15 @@ class Tutor_List_Table {
1403
  $primary
1404
  );
1405
  } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1406
- echo "<td $attributes>";
1407
  echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1408
  echo $this->handle_row_actions( $item, $column_name, $primary );
1409
- echo "</td>";
1410
  } else {
1411
- echo "<td $attributes>";
1412
  echo $this->column_default( $item, $column_name );
1413
  echo $this->handle_row_actions( $item, $column_name, $primary );
1414
- echo "</td>";
1415
  }
1416
  }
1417
  }
@@ -1456,7 +1538,7 @@ class Tutor_List_Table {
1456
  );
1457
  }
1458
  if ( isset( $this->_pagination_args['total_pages'] ) ) {
1459
- $response['total_pages'] = $this->_pagination_args['total_pages'];
1460
  $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
1461
  }
1462
 
@@ -1465,7 +1547,6 @@ class Tutor_List_Table {
1465
 
1466
  /**
1467
  * Send required variables to JavaScript land
1468
- *
1469
  */
1470
  public function _js_vars() {
1471
  $args = array(
@@ -1473,9 +1554,9 @@ class Tutor_List_Table {
1473
  'screen' => array(
1474
  'id' => $this->screen->id,
1475
  'base' => $this->screen->base,
1476
- )
1477
  );
1478
 
1479
- printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
1480
  }
1481
  }
7
  */
8
 
9
 
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
  exit;
12
+ }
13
 
14
  /**
15
  * Base class for displaying a list of items in an ajaxified HTML table.
95
  *
96
  * @var array
97
  */
98
+ protected $compat_methods = array(
99
+ 'set_pagination_args',
100
+ 'get_views',
101
+ 'get_bulk_actions',
102
+ 'bulk_actions',
103
+ 'row_actions',
104
+ 'months_dropdown',
105
+ 'view_switcher',
106
+ 'comments_bubble',
107
+ 'get_items_per_page',
108
+ 'pagination',
109
+ 'get_sortable_columns',
110
+ 'get_column_info',
111
+ 'get_table_classes',
112
+ 'display_tablenav',
113
+ 'extra_tablenav',
114
+ 'single_row_columns',
115
+ );
116
 
117
  /**
118
  * Constructor.
140
  * }
141
  */
142
  public function __construct( $args = array() ) {
143
+ $args = wp_parse_args(
144
+ $args,
145
+ array(
146
+ 'plural' => '',
147
+ 'singular' => '',
148
+ 'ajax' => false,
149
+ 'screen' => null,
150
+ )
151
+ );
152
 
153
  $this->screen = convert_to_screen( $args['screen'] );
154
 
155
  add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
156
 
157
+ if ( ! $args['plural'] ) {
158
  $args['plural'] = $this->screen->base;
159
+ }
160
 
161
+ $args['plural'] = sanitize_key( $args['plural'] );
162
  $args['singular'] = sanitize_key( $args['singular'] );
163
 
164
  $this->_args = $args;
171
  if ( empty( $this->modes ) ) {
172
  $this->modes = array(
173
  'list' => __( 'List View' ),
174
+ 'excerpt' => __( 'Excerpt View' ),
175
  );
176
  }
177
  }
260
 
261
  /**
262
  * Prepares the list of items for displaying.
263
+ *
264
  * @uses Tutor_List_Table::set_pagination_args()
265
  *
266
  * @since 3.1.0
278
  * @param array|string $args Array or string of arguments with information about the pagination.
279
  */
280
  protected function set_pagination_args( $args ) {
281
+ $args = wp_parse_args(
282
+ $args,
283
+ array(
284
+ 'total_items' => 0,
285
+ 'total_pages' => 0,
286
+ 'per_page' => 0,
287
+ )
288
+ );
289
 
290
+ if ( ! $args['total_pages'] && $args['per_page'] > 0 ) {
291
  $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
292
+ }
293
 
294
  // Redirect if page number is invalid and headers are not already sent.
295
  if ( ! headers_sent() && ! wp_doing_ajax() && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
314
  return $this->get_pagenum();
315
  }
316
 
317
+ if ( isset( $this->_pagination_args[ $key ] ) ) {
318
+ return $this->_pagination_args[ $key ];
319
  }
320
  }
321
 
327
  * @return bool
328
  */
329
  public function has_items() {
330
+ return ! empty( $this->items );
331
  }
332
 
333
  /**
348
  * @param string $input_id ID attribute value for the search input field.
349
  */
350
  public function search_box( $text, $input_id ) {
351
+ if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
352
+ return;
353
+ }
354
 
355
  $input_id = $input_id . '-search-input';
356
 
357
+ if ( ! empty( $_REQUEST['orderby'] ) ) {
358
  echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
359
+ }
360
+ if ( ! empty( $_REQUEST['order'] ) ) {
361
  echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
362
+ }
363
+ if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
364
  echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
365
+ }
366
+ if ( ! empty( $_REQUEST['detached'] ) ) {
367
  echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
368
+ }
369
  ?>
370
  <p class="search-box">
371
+ <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
372
  <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" />
373
  <?php submit_button( $text, '', '', false, array( 'id' => 'search-submit' ) ); ?>
374
  </p>
380
  * get course list
381
  * @param $selected | optional
382
  */
383
+ public function course_dropdown( $selected = '' ) {
384
+ $courses = ( current_user_can( 'administrator' ) ) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
385
+ $markup = '
386
  <div class="alignright">
387
+ <label>' . __( 'Course', 'tutor-pro' ) . '</label>
388
  <select class="tutor-assignment-course-sorting">
389
+ <option value="0">' . __( 'All', 'tutor' ) . '</option>
390
  OPTIONS_PLACEHOLDER
391
+ </select>
392
  </div>
393
  ';
394
  $options = '';
395
  foreach ( $courses as $course ) {
396
+ $options .= '<option value="' . $course->ID . '" ' . selected( $selected, $course->ID, false ) . '> ' . $course->post_title . ' </option>';
397
  }
398
+
399
  $content = str_replace( 'OPTIONS_PLACEHOLDER', $options, $markup );
400
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
401
  }
402
 
403
  /**
406
  * @param $selected | optional
407
  */
408
 
409
+ public function sorting_order( $selected = 'DESC' ) {
410
+ $orders = array( 'DESC', 'ASC' );
411
+ $markup = '
412
  <div class="alignright">
413
+ <label>' . __( 'Sort By', 'tutor' ) . '</label>
414
  <select class="tutor-assignment-order-sorting">
415
  OPTION_PLACEHOLDER
416
+ </select>
417
  </div>
418
  ';
419
  $options = '';
420
+ foreach ( $orders as $order ) {
421
+ $options .= '<option value="' . $order . '" ' . selected( $selected, $order, false ) . '> ' . __( $order, 'tutor' ) . ' </option>';
422
+ }
423
  $content = str_replace( 'OPTION_PLACEHOLDER', $options, $markup );
424
+ echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
425
  }
426
  /**
427
  * @since 1.8.0
433
  $placeholder = __( get_option( 'date_format' ), 'tutor' );
434
  $date_filter = sanitize_text_field( tutor_utils()->array_get( 'date', $_GET, '' ) );
435
  $date_input = '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : '';
436
+ $markup = '
437
  <div class="alignright assignment-date-box">
438
+ <label>' . __( 'Date', 'tutor' ) . '</label>
439
  <input type="" class="tutor_date_picker tutor-assignment-date-sorting" placeholder="' . $placeholder . '" value="' . $date_input . '">
440
  <i class="tutor-icon-calendar"></i>
441
  </div>
442
+ ';
443
+ echo $markup; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
444
  }
445
 
446
  /**
474
  */
475
  $views = apply_filters( "views_{$this->screen->id}", $views );
476
 
477
+ if ( empty( $views ) ) {
478
  return;
479
+ }
480
 
481
  $this->screen->render_screen_reader_content( 'heading_views' );
482
 
483
+ echo '<ul class="subsubsub">';
484
  foreach ( $views as $class => $view ) {
485
  $views[ $class ] = "\t<li class='$class'>$view";
486
  }
487
+ echo implode( ' |</li>', $views ) . '</li>';
488
+ echo '</ul>';
489
  }
490
 
491
  /**
524
  * @param array $actions An array of the available bulk actions.
525
  */
526
  $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions );
527
+ $two = '';
528
  } else {
529
  $two = '2';
530
  }
531
 
532
+ if ( empty( $this->_actions ) ) {
533
  return;
534
+ }
535
 
536
  echo '<label for="bulk-action-selector-' . esc_attr( $which ) . '" class="screen-reader-text">' . __( 'Select bulk action' ) . '</label>';
537
+ echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . '">';
538
+ echo '<option value="-1">' . __( 'Bulk Actions', 'tutor' ) . '</option>';
539
 
540
  foreach ( $this->_actions as $name => $title ) {
541
  $class = 'edit' === $name ? ' class="hide-if-no-js"' : '';
542
 
543
+ echo '\t' . '<option value="' . $name . '"' . $class . '>' . $title . '</option>';
544
  }
545
 
546
+ echo '</select>';
547
 
548
+ submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => 'doaction' . $two ) );
549
+ echo '';
550
  }
551
 
552
  /**
557
  * @return string|false The action name or False if no action was selected
558
  */
559
  public function current_action() {
560
+ if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
561
  return false;
562
+ }
563
 
564
+ if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] ) {
565
  return $_REQUEST['action'];
566
+ }
567
 
568
+ if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] ) {
569
  return $_REQUEST['action2'];
570
+ }
571
 
572
  return false;
573
  }
578
  * @since 3.1.0
579
  *
580
  * @param array $actions The list of actions
581
+ * @param bool $always_visible Whether the actions should be always visible
582
  * @return string
583
  */
584
  protected function row_actions( $actions, $always_visible = false ) {
585
  $action_count = count( $actions );
586
+ $i = 0;
587
 
588
+ if ( ! $action_count ) {
589
  return '';
590
+ }
591
 
592
+ $out = '<div class="' . esc_attr( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
593
  foreach ( $actions as $action => $link ) {
594
  ++$i;
595
  ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
596
+ $out .= '<span class="' . $action . '">' . $link . $sep . '</span>';
597
  }
598
  $out .= '</div>';
599
 
600
  $out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
601
 
602
+ return $out; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
603
+
604
  }
605
 
606
  /**
632
  if ( ! isset( $_GET['post_status'] ) || 'trash' !== $_GET['post_status'] ) {
633
  $extra_checks .= " AND post_status != 'trash'";
634
  } elseif ( isset( $_GET['post_status'] ) ) {
635
+ $extra_checks = $wpdb->prepare( ' AND post_status = %s', tutor_sanitize_data($_GET['post_status']) );
636
  }
637
 
638
+ $months = $wpdb->get_results(
639
+ $wpdb->prepare(
640
+ "
641
  SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
642
  FROM $wpdb->posts
643
  WHERE post_type = %s
644
  $extra_checks
645
  ORDER BY post_date DESC
646
+ ",
647
+ $post_type
648
+ )
649
+ );
650
 
651
  /**
652
  * Filters the 'Months' drop-down results.
660
 
661
  $month_count = count( $months );
662
 
663
+ if ( ! $month_count || ( 1 == $month_count && 0 == $months[0]->month ) ) {
664
  return;
665
+ }
666
 
667
  $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
668
  ?>
671
  <option<?php selected( $m, 0 ); ?> value="0"><?php _e( 'All dates' ); ?></option>
672
  <?php
673
  foreach ( $months as $arc_row ) {
674
+ if ( 0 == $arc_row->year ) {
675
  continue;
676
+ }
677
 
678
  $month = zeroise( $arc_row->month, 2 );
679
+ $year = $arc_row->year;
680
 
681
+ printf(
682
+ "<option %s value='%s'>%s</option>",
683
  selected( $m, $year . $month, false ),
684
  esc_attr( $arc_row->year . $month ),
685
  /* translators: 1: month name, 2: 4-digit year */
705
  <?php
706
  foreach ( $this->modes as $mode => $title ) {
707
  $classes = array( 'view-' . $mode );
708
+ if ( $current_mode === $mode ) {
709
  $classes[] = 'current';
710
+ }
711
  printf(
712
+ "<a href='%s' class='%s' id='view-switch-$mode'><span class='screen-reader-text'>%s</span></a>",
713
  esc_url( add_query_arg( 'mode', $mode ) ),
714
  implode( ' ', $classes ),
715
  $title
732
  $approved_comments = get_comments_number();
733
 
734
  $approved_comments_number = number_format_i18n( $approved_comments );
735
+ $pending_comments_number = number_format_i18n( $pending_comments );
736
 
737
  $approved_only_phrase = sprintf( _n( '%s comment', '%s comments', $approved_comments ), $approved_comments_number );
738
+ $approved_phrase = sprintf( _n( '%s approved comment', '%s approved comments', $approved_comments ), $approved_comments_number );
739
+ $pending_phrase = sprintf( _n( '%s pending comment', '%s pending comments', $pending_comments ), $pending_comments_number );
740
 
741
  // No comments at all.
742
  if ( ! $approved_comments && ! $pending_comments ) {
743
+ printf(
744
+ '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
745
  __( 'No comments' )
746
  );
747
  // Approved comments have different display depending on some conditions.
748
  } elseif ( $approved_comments ) {
749
+ printf(
750
+ '<a href="%s" class="post-com-count post-com-count-approved"><span class="comment-count-approved" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
751
+ esc_url(
752
+ add_query_arg(
753
+ array(
754
+ 'p' => $post_id,
755
+ 'comment_status' => 'approved',
756
+ ),
757
+ admin_url( 'edit-comments.php' )
758
+ )
759
+ ),
760
  $approved_comments_number,
761
  $pending_comments ? $approved_phrase : $approved_only_phrase
762
  );
763
  } else {
764
+ printf(
765
+ '<span class="post-com-count post-com-count-no-comments"><span class="comment-count comment-count-no-comments" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
766
  $approved_comments_number,
767
  $pending_comments ? __( 'No approved comments' ) : __( 'No comments' )
768
  );
769
  }
770
 
771
  if ( $pending_comments ) {
772
+ printf(
773
+ '<a href="%s" class="post-com-count post-com-count-pending"><span class="comment-count-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
774
+ esc_url(
775
+ add_query_arg(
776
+ array(
777
+ 'p' => $post_id,
778
+ 'comment_status' => 'moderated',
779
+ ),
780
+ admin_url( 'edit-comments.php' )
781
+ )
782
+ ),
783
  $pending_comments_number,
784
  $pending_phrase
785
  );
786
  } else {
787
+ printf(
788
+ '<span class="post-com-count post-com-count-pending post-com-count-no-pending"><span class="comment-count comment-count-no-pending" aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></span>',
789
  $pending_comments_number,
790
  $approved_comments ? __( 'No pending comments' ) : __( 'No comments' )
791
  );
802
  public function get_pagenum() {
803
  $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
804
 
805
+ if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) {
806
  $pagenum = $this->_pagination_args['total_pages'];
807
+ }
808
 
809
  return max( 1, $pagenum );
810
  }
820
  */
821
  protected function get_items_per_page( $option, $default = 20 ) {
822
  $per_page = (int) get_user_option( $option );
823
+ if ( empty( $per_page ) || $per_page < 1 ) {
824
  $per_page = $default;
825
+ }
826
 
827
  /**
828
  * Filters the number of items to be displayed on each page of the list table.
852
  return;
853
  }
854
 
855
+ $total_items = $this->_pagination_args['total_items'];
856
+ $total_pages = $this->_pagination_args['total_pages'];
857
  $infinite_scroll = false;
858
  if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
859
  $infinite_scroll = $this->_pagination_args['infinite_scroll'];
865
 
866
  $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
867
 
868
+ $current = $this->get_pagenum();
869
  $removable_query_args = wp_removable_query_args();
870
 
871
  $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
881
 
882
  if ( $current == 1 ) {
883
  $disable_first = true;
884
+ $disable_prev = true;
885
  }
886
  if ( $current == 2 ) {
887
  $disable_first = true;
897
  if ( $disable_first ) {
898
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&laquo;</span>';
899
  } else {
900
+ $page_links[] = sprintf(
901
+ "<a class='first-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
902
  esc_url( remove_query_arg( 'paged', $current_url ) ),
903
  __( 'First page' ),
904
  '&laquo;'
908
  if ( $disable_prev ) {
909
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&lsaquo;</span>';
910
  } else {
911
+ $page_links[] = sprintf(
912
+ "<a class='prev-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
913
+ esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
914
  __( 'Previous page' ),
915
  '&lsaquo;'
916
  );
920
  $html_current_page = $current;
921
  $total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
922
  } else {
923
+ $html_current_page = sprintf(
924
+ '%s<input class="current-page" id="current-page-selector" type="text" name="paged" value="%s" size="%d" aria-describedby="table-paging" /><span class="tablenav-paging-text">',
925
  '<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>',
926
  $current,
927
  strlen( $total_pages )
928
  );
929
  }
930
+ $html_total_pages = sprintf( '<span class="total-pages">%s</span>', number_format_i18n( $total_pages ) );
931
+ $page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after;
932
 
933
  if ( $disable_next ) {
934
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&rsaquo;</span>';
935
  } else {
936
+ $page_links[] = sprintf(
937
+ "<a class='next-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
938
+ esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ),
939
  __( 'Next page' ),
940
  '&rsaquo;'
941
  );
944
  if ( $disable_last ) {
945
  $page_links[] = '<span class="tablenav-pages-navspan" aria-hidden="true">&raquo;</span>';
946
  } else {
947
+ $page_links[] = sprintf(
948
+ "<a class='last-page' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
949
  esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
950
  __( 'Last page' ),
951
  '&raquo;'
956
  if ( ! empty( $infinite_scroll ) ) {
957
  $pagination_links_class .= ' hide-if-js';
958
  }
959
+ $output .= '<span class="' . $pagination_links_class . '">' . join( '', $page_links ) . '</span>';
960
 
961
  if ( $total_pages ) {
962
  $page_class = $total_pages < 2 ? ' one-page' : '';
963
  } else {
964
  $page_class = ' no-pages';
965
  }
966
+ $this->_pagination = '<div class="tablenav-pages' . $page_class . '">' . $output . '</div>';
967
 
968
+ echo $this->_pagination; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
969
  }
970
 
971
  /**
1006
  */
1007
  protected function get_default_primary_column_name() {
1008
  $columns = $this->get_columns();
1009
+ $column = '';
1010
 
1011
  if ( empty( $columns ) ) {
1012
  return $column;
1051
  // If the primary column doesn't exist fall back to the
1052
  // first non-checkbox column.
1053
  if ( ! isset( $columns[ $default ] ) ) {
1054
+ $default = self::get_default_primary_column_name();
1055
  }
1056
 
1057
  /**
1062
  * @param string $default Column name default for the specific list table, e.g. 'name'.
1063
  * @param string $context Screen ID for specific list table, e.g. 'plugins'.
1064
  */
1065
+ $column = apply_filters( 'list_table_primary_column', $default, $this->screen->id );
1066
 
1067
  if ( empty( $column ) || ! isset( $columns[ $column ] ) ) {
1068
  $column = $default;
1092
  }
1093
 
1094
  $columns = get_column_headers( $this->screen );
1095
+ $hidden = get_hidden_columns( $this->screen );
1096
 
1097
  $sortable_columns = $this->get_sortable_columns();
1098
  /**
1105
  *
1106
  * @param array $sortable_columns An array of sortable columns.
1107
  */
1108
+ $_sortable = apply_filters( 'manage_' . esc_attr( $this->screen->id ) . '_sortable_columns', $sortable_columns );
1109
 
1110
  $sortable = array();
1111
  foreach ( $_sortable as $id => $data ) {
1112
+ if ( empty( $data ) ) {
1113
  continue;
1114
+ }
1115
 
1116
  $data = (array) $data;
1117
+ if ( ! isset( $data[1] ) ) {
1118
  $data[1] = false;
1119
+ }
1120
 
1121
+ $sortable[ $id ] = $data;
1122
  }
1123
 
1124
+ $primary = $this->get_primary_column_name();
1125
  $this->_column_headers = array( $columns, $hidden, $sortable, $primary );
1126
 
1127
  return $this->_column_headers;
1136
  */
1137
  public function get_column_count() {
1138
  list ( $columns, $hidden ) = $this->get_column_info();
1139
+ $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
1140
  return count( $columns ) - count( $hidden );
1141
  }
1142
 
1156
  $current_url = remove_query_arg( 'paged', $current_url );
1157
 
1158
  if ( isset( $_GET['orderby'] ) ) {
1159
+ $current_orderby = tutor_sanitize_data( $_GET['orderby'] );
1160
  } else {
1161
  $current_orderby = '';
1162
  }
1169
 
1170
  if ( ! empty( $columns['cb'] ) ) {
1171
  static $cb_counter = 1;
1172
+ $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>' . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
 
1173
  $cb_counter++;
1174
  }
1175
 
1180
  $class[] = 'hidden';
1181
  }
1182
 
1183
+ if ( 'cb' === $column_key ) {
1184
  $class[] = 'check-column';
1185
+ } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
1186
  $class[] = 'num';
1187
+ }
1188
 
1189
  if ( $column_key === $primary ) {
1190
  $class[] = 'column-primary';
1191
  }
1192
 
1193
+ if ( isset( $sortable[ $column_key ] ) ) {
1194
+ list( $orderby, $desc_first ) = $sortable[ $column_key ];
1195
 
1196
  if ( $current_orderby === $orderby ) {
1197
+ $order = 'asc' === $current_order ? 'desc' : 'asc';
1198
  $class[] = 'sorted';
1199
  $class[] = $current_order;
1200
  } else {
1201
+ $order = $desc_first ? 'desc' : 'asc';
1202
  $class[] = 'sortable';
1203
  $class[] = $desc_first ? 'asc' : 'desc';
1204
  }
1206
  $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
1207
  }
1208
 
1209
+ $tag = ( 'cb' === $column_key ) ? 'td' : 'th';
1210
  $scope = ( 'th' === $tag ) ? 'scope="col"' : '';
1211
+ $id = $with_id ? "id='$column_key'" : '';
1212
 
1213
+ if ( ! empty( $class ) ) {
1214
  $class = "class='" . join( ' ', $class ) . "'";
1215
+ }
1216
 
1217
+ echo ( "<$tag $scope $id $class>$column_display_name</$tag>" );
1218
  }
1219
  }
1220
 
1223
  *
1224
  * @since 3.1.0
1225
  */
1226
+ public function display( $enable_sorting_field_with_bulk_action = false ) {
1227
  $singular = $this->_args['singular'];
1228
  if ( $enable_sorting_field_with_bulk_action ) {
1229
+ $this->display_sorting_fields();
1230
  } else {
1231
+ $this->display_tablenav( 'top' );
1232
  }
1233
 
1234
  $this->screen->render_screen_reader_content( 'heading_list' );
1235
  ?>
1236
+ <table class="wp-list-table <?php echo esc_attr( implode( ' ', $this->get_table_classes() ) ); ?>">
1237
  <thead>
1238
  <tr>
1239
  <?php $this->print_column_headers(); ?>
1240
  </tr>
1241
  </thead>
1242
 
1243
+ <tbody id="the-list"
1244
+ <?php
1245
  if ( $singular ) {
1246
+ echo 'data-wp-lists=list:' . $singular;
1247
+ }
1248
+ ?>
1249
+ >
1250
  <?php $this->display_rows_or_placeholder(); ?>
1251
  </tbody>
1252
 
1285
  ?>
1286
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
1287
 
1288
+ <?php if ( $this->has_items() ) : ?>
1289
  <div class="alignleft actions bulkactions">
1290
  <?php $this->bulk_actions( $which ); ?>
1291
  </div>
1292
+ <?php
1293
+ endif;
1294
  $this->extra_tablenav( $which );
1295
  $this->pagination( $which );
1296
  ?>
1302
 
1303
  /**
1304
  * Sorting fields added on tutor table
1305
+ *
1306
  * Course id | Search | Date | Order
1307
+ *
1308
  * @since 1.9.5
1309
  */
1310
  protected function display_sorting_fields() {
1311
+ $search_filter = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
1312
+ $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
1313
+ $date_filter = isset( $_GET['date'] ) ? sanitize_text_field( $_GET['date'] ) : '';
1314
+ $order_filter = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : '';
1315
+ $which = 'top';
1316
  ?>
1317
  <div class="tutor-sorting-bulk-action-wrapper">
1318
  <div class="tablenav <?php echo esc_attr( $which ); ?>">
1319
+ <?php if ( $this->has_items() ) : ?>
1320
  <div class="alignleft actions bulkactions">
1321
  <?php $this->bulk_actions( $which ); ?>
1322
  </div>
1323
+ <?php
1324
+ endif;
1325
  $this->extra_tablenav( $which );
1326
 
1327
  ?>
1328
  </div>
1329
+
1330
  <div class="tutor-admin-search-box-container" style="margin:0px;">
1331
 
1332
  <div>
1333
+ <div class="menu-label"><?php _e( 'Courses', 'tutor' ); ?></div>
1334
  <div>
1335
  <?php
1336
+ // get courses
1337
+ $courses = ( current_user_can( 'administrator' ) ) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
1338
  ?>
1339
 
1340
  <select class="tutor-report-category tutor-announcement-course-sorting">
1341
+
1342
+ <option value=""><?php _e( 'All', 'tutor' ); ?></option>
1343
+
1344
+ <?php if ( $courses ) : ?>
1345
+ <?php foreach ( $courses as $course ) : ?>
1346
+ <option value="<?php echo esc_attr( $course->ID ); ?>" <?php selected( $course_id, $course->ID, 'selected' ); ?>>
1347
+ <?php echo esc_attr( $course->post_title ); ?>
1348
  </option>
1349
  <?php endforeach; ?>
1350
  <?php else : ?>
1351
+ <option value=""><?php _e( 'No course found', 'tutor' ); ?></option>
1352
  <?php endif; ?>
1353
  </select>
1354
  </div>
1355
  </div>
1356
 
1357
  <div>
1358
+ <div class="menu-label"><?php _e( 'Sort By', 'tutor' ); ?></div>
1359
  <div>
1360
  <select class="tutor-report-sort tutor-announcement-order-sorting">
1361
+ <option <?php selected( $order_filter, 'ASC' ); ?>>ASC</option>
1362
+ <option <?php selected( $order_filter, 'DESC' ); ?>>DESC</option>
1363
  </select>
1364
  </div>
1365
  </div>
1366
 
1367
  <div>
1368
+ <div class="menu-label"><?php _e( 'Date', 'tutor' ); ?></div>
1369
  <div class="date-range-input">
1370
+ <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" id="tutor-announcement-datepicker" placeholder="<?php _e( get_option( 'date_format' ), 'tutor' ); ?>" value="<?php echo '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" autocomplete="off" />
1371
  <i class="tutor-icon-calendar"></i>
1372
  </div>
1373
  </div>
1374
 
1375
  <div class="tutor-search-form-group">
1376
+ <div class="menu-label"><?php _e( 'Search', 'tutor' ); ?></div>
1377
  <div style="position:relative;">
1378
+ <input type="text" name="search" class="tutor-report-search tutor-announcement-search-field" value="<?php echo esc_attr( $search_filter ); ?>" autocomplete="off" placeholder="<?php _e( 'Search', 'tutor' ); ?>" />
1379
  <button class="tutor-report-search-btn tutor-announcement-search-sorting"><i class="tutor-icon-magnifying-glass-1"></i></button>
1380
  </div>
1381
  </div>
1382
+
1383
+ </div>
1384
+ </div>
1385
  <?php
1386
  }
1387
 
1415
  * @since 3.1.0
1416
  */
1417
  public function display_rows() {
1418
+ foreach ( $this->items as $item ) {
1419
  $this->single_row( $item );
1420
+ }
1421
  }
1422
 
1423
  /**
1470
  // Instead of using esc_attr(), we strip tags to get closer to a user-friendly string.
1471
  $data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
1472
 
1473
+ $attributes = 'class="' . $classes . '" ' . $data;
1474
 
1475
  if ( 'cb' === $column_name ) {
1476
  echo '<th scope="row" class="check-column">';
1485
  $primary
1486
  );
1487
  } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1488
+ echo '<td ' . $attributes . '>';
1489
  echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1490
  echo $this->handle_row_actions( $item, $column_name, $primary );
1491
+ echo '</td>';
1492
  } else {
1493
+ echo '<td ' . $attributes . '>';
1494
  echo $this->column_default( $item, $column_name );
1495
  echo $this->handle_row_actions( $item, $column_name, $primary );
1496
+ echo '</td>';
1497
  }
1498
  }
1499
  }
1538
  );
1539
  }
1540
  if ( isset( $this->_pagination_args['total_pages'] ) ) {
1541
+ $response['total_pages'] = $this->_pagination_args['total_pages'];
1542
  $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
1543
  }
1544
 
1547
 
1548
  /**
1549
  * Send required variables to JavaScript land
 
1550
  */
1551
  public function _js_vars() {
1552
  $args = array(
1554
  'screen' => array(
1555
  'id' => $this->screen->id,
1556
  'base' => $this->screen->base,
1557
+ ),
1558
  );
1559
 
1560
+ printf( "<script type='text/javascript'>list_args = %s;</script>", wp_json_encode( $args ) );
1561
  }
1562
  }
classes/Tutor_Setup.php CHANGED
@@ -26,11 +26,11 @@ if ( ! defined( 'ABSPATH' ) )
26
  }
27
  return $final_arr;
28
  }
29
-
30
 
31
  public function tutor_setup_action(){
32
  tutils()->checking_nonce();
33
-
34
  $options = (array) maybe_unserialize(get_option('tutor_option'));
35
  if (!isset($_POST['action']) || $_POST['action'] != 'setup_action' || !current_user_can( 'manage_options' )) {
36
  return;
@@ -44,7 +44,7 @@ if ( ! defined( 'ABSPATH' ) )
44
  if ($_POST[$key] == '') {
45
  unset($options[$key]);
46
  } else {
47
- $options[$key] = $_POST[$key];
48
  }
49
  }
50
  } else {
@@ -69,7 +69,7 @@ if ( ! defined( 'ABSPATH' ) )
69
  }
70
  }
71
  update_option('tutor_withdraw_options', $payments);
72
-
73
  // Add wizard flug
74
  update_option('tutor_wizard', 'active');
75
 
@@ -95,7 +95,7 @@ if ( ! defined( 'ABSPATH' ) )
95
  }
96
 
97
  public function tutor_setup_generator() {
98
-
99
  $i = 1;
100
  $html = '';
101
  $options = (array) maybe_unserialize(get_option('tutor_option'));
@@ -147,11 +147,11 @@ if ( ! defined( 'ABSPATH' ) )
147
  $html .= '<span class="label-on">'.__('ON', 'tutor').'</span>';
148
  $html .= '</label>';
149
  break;
150
-
151
  case 'text':
152
- $html .= '<input type="text" name="'.$key.'" class="lesson-permalink" value="'.(isset($options[$key]) ? $options[$key] : '').'" />';
153
  break;
154
-
155
  case 'rows':
156
  $html .= '<div class="content">';
157
  $html .= '<div class="course-per-row">';
@@ -182,7 +182,7 @@ if ( ! defined( 'ABSPATH' ) )
182
  $html .= '</div>';
183
  $html .= '</div>';
184
  break;
185
-
186
  case 'radio':
187
  if ( isset($field['options']) ) {
188
  foreach ($field['options'] as $k => $val) {
@@ -191,7 +191,7 @@ if ( ! defined( 'ABSPATH' ) )
191
  }
192
  }
193
  break;
194
-
195
  case 'slider':
196
  $available_times = array(
197
  'seconds' => __( 'seconds' , 'tutor' ),
@@ -226,11 +226,11 @@ if ( ! defined( 'ABSPATH' ) )
226
  $html .= '<h5>'.$val['desc'].'</h5>';
227
  $html .= '</label>';
228
  $html .= '</div>';
229
-
230
  if (isset($options[$key]) && $options[$key] == $val['value']) {
231
  $selected_data .= '<div class="selected">';
232
  $selected_data .= '<h3>'.$val['title'].'</h3>';
233
- $selected_data .= '<h5>'.$val['desc'].'</h5>';
234
  $selected_data .= '</div>';
235
  }
236
  }
@@ -306,7 +306,7 @@ if ( ! defined( 'ABSPATH' ) )
306
 
307
  case 'attempt':
308
  $html .= '<div class="tutor-setting course-setting-wrapper">';
309
-
310
  $html .= '<input type="hidden" name="quiz_attempts_allowed" value="'.$options[$key].'">';
311
 
312
  $html .= '<div class="content">';
@@ -331,7 +331,7 @@ if ( ! defined( 'ABSPATH' ) )
331
  $html .= '</div>';
332
  $html .= '</div>';
333
  break;
334
-
335
  default:
336
  # code...
337
  break;
@@ -538,8 +538,8 @@ if ( ! defined( 'ABSPATH' ) )
538
  'class' => 'tutor-show-hide',
539
  'desc' => __('Choose your preferred withdrawal method from the options.', 'tutor')
540
  ),
541
-
542
-
543
  )
544
  ),
545
 
@@ -548,7 +548,7 @@ if ( ! defined( 'ABSPATH' ) )
548
 
549
  return $general_fields;
550
  }
551
-
552
  public function tutor_setup_wizard_settings() {
553
 
554
  $options = (array) maybe_unserialize(get_option('tutor_option'));
@@ -572,15 +572,15 @@ if ( ! defined( 'ABSPATH' ) )
572
  <?php wp_nonce_field( tutor()->nonce_action, tutor()->nonce ); ?>
573
  <input type="hidden" name="action" value="setup_action">
574
  <?php $course_marketplace = tutor_utils()->get_option('enable_course_marketplace'); ?>
575
- <input type="hidden" name="enable_course_marketplace" class="enable_course_marketplace_data" value="<?php echo ($course_marketplace ? 1 : 0); ?>">
576
  <?php $earning = tutor_utils()->get_option('enable_tutor_earning'); ?>
577
- <input type="hidden" name="enable_tutor_earning" class="enable_tutor_earning_data" value="<?php echo ($earning ? 1 : 0); ?>">
578
  <ul class="tutor-setup-content">
579
  <?php $this->tutor_setup_generator(); ?>
580
  <li>
581
  <div class="tutor-setup-content-heading greetings">
582
  <div class="header">
583
- <img src="<?php echo tutor()->url . 'assets/images/greeting-img.jpg'; ?>" alt="greeting">
584
  </div>
585
  <div class="content">
586
  <h2><?php _e('Congratulations, you’re all set!', 'tutor'); ?></h2>
@@ -588,8 +588,8 @@ if ( ! defined( 'ABSPATH' ) )
588
  <p><?php _e( 'If you need further assistance, please don’t hesitate to contact us via our <a target="_blank" href="https://www.themeum.com/contact-us/">contact form.</a>', 'tutor' ); ?></p>
589
  </div>
590
  <div class="tutor-setup-content-footer footer">
591
- <button class="tutor-redirect primary-btn" data-url="<?php echo admin_url('post-new.php?post_type=courses'); ?>"><?php _e('CREATE A NEW COURSE', 'tutor'); ?></button>
592
- <button class="tutor-redirect primary-btn" data-url="<?php echo admin_url('admin.php?page=tutor-addons'); ?>"><?php _e('EXPLORE ADDONS', 'tutor'); ?></button>
593
  </div>
594
  </div>
595
  </li>
@@ -605,7 +605,7 @@ if ( ! defined( 'ABSPATH' ) )
605
 
606
 
607
  public function tutor_setup_wizard_action() {
608
-
609
  $html = '<div class="tutor-setup-content-footer footer">';
610
  $html .= '<div class="tutor-setup-btn-wrapper">';
611
  $html .= '<button class="tutor-setup-previous previous animated-btn">';
@@ -637,34 +637,34 @@ if ( ! defined( 'ABSPATH' ) )
637
  <div class="tutor-wizard-container">
638
  <div class="tutor-wrapper-boarding tutor-setup-wizard-boarding active">
639
  <div class="wizard-boarding-header">
640
- <div><img src="<?php echo tutor()->url.'assets/images/tutor-logo.svg'; ?>" /></div>
641
  <div><?php printf(__('Hello %s, welcome to Tutor LMS! Thank you for choosing us.', 'tutor'), $current_user->user_login); ?></div>
642
  </div>
643
  <div class="wizard-boarding-body">
644
  <ul class="slider tutor-boarding">
645
  <li>
646
 
647
- <div class="slide-thumb"><img src="<?php echo tutor()->url . 'assets/images/scalable_lms_solution.jpg'; ?>" alt="<?php _e('A Powerful, Smart, and Scalable LMS Solution', 'tutor') ?>"/></div>
648
  <div class="slide-title"><?php _e('A Powerful, Smart, and Scalable LMS Solution', 'tutor'); ?></div>
649
  <div class="slide-subtitle"><?php _e('From individual instructors to vast eLearning platforms, Tutor LMS grows with you to create your ideal vision of an LMS website.', 'tutor'); ?></div>
650
  </li>
651
  <li>
652
- <div class="slide-thumb"><img src="<?php echo tutor()->url . 'assets/images/extensive_course_builder.jpg'; ?>" alt="<?php _e('Extensive Course Builder', 'tutor') ?>"/></div>
653
  <div class="slide-title"><?php _e('Extensive Course Builder', 'tutor'); ?></div>
654
  <div class="slide-subtitle"><?php _e('Tutor LMS comes with a state-of-the-art frontend course builder. Construct rich and resourceful courses with ease.', 'tutor'); ?></div>
655
  </li>
656
  <li>
657
- <div class="slide-thumb"><img src="<?php echo tutor()->url . 'assets/images/advanced_quiz_creator.jpg'; ?>" alt="<?php _e('Advanced Quiz Creator', 'tutor'); ?>"/></div>
658
  <div class="slide-title"><?php _e('Advanced Quiz Creator', 'tutor'); ?></div>
659
  <div class="slide-subtitle"><?php _e('Build interactive quizzes with the vast selection of question types and verify the learning of your students.', 'tutor'); ?></div>
660
  </li>
661
  <li>
662
- <div class="slide-thumb"><img src="<?php echo tutor()->url . 'assets/images/freedom_with_ecommerce.jpg'; ?>" alt="<?php _e('Freedom With eCommerce', 'tutor'); ?>"/></div>
663
  <div class="slide-title"><?php _e('Freedom With eCommerce', 'tutor'); ?></div>
664
  <div class="slide-subtitle"><?php _e('Select an eCommerce plugin and sell courses any way you like and use any payment gateway you want!', 'tutor'); ?></div>
665
  </li>
666
  <li>
667
- <div class="slide-thumb"><img src="<?php echo tutor()->url . 'assets/images/reports_and_analytics.jpg'; ?>" alt="<?php _e('Reports and Analytics', 'tutor'); ?>"/></div>
668
  <div class="slide-title"><?php _e('Reports and Analytics', 'tutor'); ?></div>
669
  <div class="slide-subtitle"><?php _e('Track what type of courses sell the most! Gain insights on user purchases, manage reviews and track quiz attempts.', 'tutor'); ?></div>
670
  </li>
@@ -679,7 +679,7 @@ if ( ! defined( 'ABSPATH' ) )
679
  </svg>
680
  </button>
681
  </div>
682
- <div><a href="<?php echo admin_url(); ?>"><?php _e('I already know, skip this!', 'tutor'); ?></a></div>
683
  </div>
684
  </div>
685
  </div>
@@ -692,7 +692,7 @@ if ( ! defined( 'ABSPATH' ) )
692
  <div class="tutor-wizard-container">
693
  <div class="tutor-wrapper-type tutor-setup-wizard-type">
694
  <div class="wizard-type-header">
695
- <div class="logo"><img src="<?php echo tutor()->url.'assets/images/tutor-logo.svg'; ?>" /></div>
696
  <div class="title"><?php _e('Let’s get the platform up and running', 'tutor'); ?></div>
697
  <div class="subtitle"><?php _e('Pick a category for your LMS platform. You can always update this later.', 'tutor'); ?></div>
698
  </div>
@@ -701,7 +701,7 @@ if ( ! defined( 'ABSPATH' ) )
701
  <input id="enable_course_marketplace-0" type="radio" name="enable_course_marketplace_setup" value="0" <?php if(!$course_marketplace){ echo 'checked'; } ?> />
702
  <span class="icon"></span>
703
  <label for="enable_course_marketplace-0">
704
- <img src="<?php echo tutor()->url.'assets/images/single-marketplace.png'; ?>" />
705
  <div class="title"><?php _e( 'Individual', 'tutor' ); ?></div>
706
  <div class="subtitle"><?php _e( 'I want to start my solo journey as an educator and spread my knowledge.', 'tutor' ); ?></div>
707
  </label>
@@ -711,7 +711,7 @@ if ( ! defined( 'ABSPATH' ) )
711
  <input id="enable_course_marketplace-1" type="radio" name="enable_course_marketplace_setup" value="1" <?php if($course_marketplace){ echo 'checked'; } ?>/>
712
  <span class="icon"></span>
713
  <label for="enable_course_marketplace-1">
714
- <img src="<?php echo tutor()->url.'assets/images/multiple-marketplace.png'; ?>" />
715
  <div class="title"><?php _e( 'Marketplace', 'tutor' ); ?></div>
716
  <div class="subtitle"><?php _e( 'I want to create an eLearning platform to let anyone earn by teaching online.', 'tutor' ); ?></div>
717
  </label>
26
  }
27
  return $final_arr;
28
  }
29
+
30
 
31
  public function tutor_setup_action(){
32
  tutils()->checking_nonce();
33
+
34
  $options = (array) maybe_unserialize(get_option('tutor_option'));
35
  if (!isset($_POST['action']) || $_POST['action'] != 'setup_action' || !current_user_can( 'manage_options' )) {
36
  return;
44
  if ($_POST[$key] == '') {
45
  unset($options[$key]);
46
  } else {
47
+ $options[$key] = tutor_sanitize_data($_POST[$key]);
48
  }
49
  }
50
  } else {
69
  }
70
  }
71
  update_option('tutor_withdraw_options', $payments);
72
+
73
  // Add wizard flug
74
  update_option('tutor_wizard', 'active');
75
 
95
  }
96
 
97
  public function tutor_setup_generator() {
98
+
99
  $i = 1;
100
  $html = '';
101
  $options = (array) maybe_unserialize(get_option('tutor_option'));
147
  $html .= '<span class="label-on">'.__('ON', 'tutor').'</span>';
148
  $html .= '</label>';
149
  break;
150
+
151
  case 'text':
152
+ $html .= '<input type="text" name="'.$key.'" class="lesson-permalink" value="'.(isset($options[$key]) ? $options[$key] : '').'" />';
153
  break;
154
+
155
  case 'rows':
156
  $html .= '<div class="content">';
157
  $html .= '<div class="course-per-row">';
182
  $html .= '</div>';
183
  $html .= '</div>';
184
  break;
185
+
186
  case 'radio':
187
  if ( isset($field['options']) ) {
188
  foreach ($field['options'] as $k => $val) {
191
  }
192
  }
193
  break;
194
+
195
  case 'slider':
196
  $available_times = array(
197
  'seconds' => __( 'seconds' , 'tutor' ),
226
  $html .= '<h5>'.$val['desc'].'</h5>';
227
  $html .= '</label>';
228
  $html .= '</div>';
229
+
230
  if (isset($options[$key]) && $options[$key] == $val['value']) {
231
  $selected_data .= '<div class="selected">';
232
  $selected_data .= '<h3>'.$val['title'].'</h3>';
233
+ $selected_data .= '<h5>'.$val['desc'].'</h5>';
234
  $selected_data .= '</div>';
235
  }
236
  }
306
 
307
  case 'attempt':
308
  $html .= '<div class="tutor-setting course-setting-wrapper">';
309
+
310
  $html .= '<input type="hidden" name="quiz_attempts_allowed" value="'.$options[$key].'">';
311
 
312
  $html .= '<div class="content">';
331
  $html .= '</div>';
332
  $html .= '</div>';
333
  break;
334
+
335
  default:
336
  # code...
337
  break;
538
  'class' => 'tutor-show-hide',
539
  'desc' => __('Choose your preferred withdrawal method from the options.', 'tutor')
540
  ),
541
+
542
+
543
  )
544
  ),
545
 
548
 
549
  return $general_fields;
550
  }
551
+
552
  public function tutor_setup_wizard_settings() {
553
 
554
  $options = (array) maybe_unserialize(get_option('tutor_option'));
572
  <?php wp_nonce_field( tutor()->nonce_action, tutor()->nonce ); ?>
573
  <input type="hidden" name="action" value="setup_action">
574
  <?php $course_marketplace = tutor_utils()->get_option('enable_course_marketplace'); ?>
575
+ <input type="hidden" name="enable_course_marketplace" class="enable_course_marketplace_data" value="<?php echo $course_marketplace ? 1 : 0; ?>">
576
  <?php $earning = tutor_utils()->get_option('enable_tutor_earning'); ?>
577
+ <input type="hidden" name="enable_tutor_earning" class="enable_tutor_earning_data" value="<?php echo $earning ? 1 : 0; ?>">
578
  <ul class="tutor-setup-content">
579
  <?php $this->tutor_setup_generator(); ?>
580
  <li>
581
  <div class="tutor-setup-content-heading greetings">
582
  <div class="header">
583
+ <img src="<?php echo esc_url(tutor()->url . 'assets/images/greeting-img.jpg'); ?>" alt="greeting">
584
  </div>
585
  <div class="content">
586
  <h2><?php _e('Congratulations, you’re all set!', 'tutor'); ?></h2>
588
  <p><?php _e( 'If you need further assistance, please don’t hesitate to contact us via our <a target="_blank" href="https://www.themeum.com/contact-us/">contact form.</a>', 'tutor' ); ?></p>
589
  </div>
590
  <div class="tutor-setup-content-footer footer">
591
+ <button class="tutor-redirect primary-btn" data-url="<?php echo esc_url( admin_url('post-new.php?post_type=courses') ); ?>"><?php _e('CREATE A NEW COURSE', 'tutor'); ?></button>
592
+ <button class="tutor-redirect primary-btn" data-url="<?php echo esc_url( admin_url('admin.php?page=tutor-addons') ); ?>"><?php _e('EXPLORE ADDONS', 'tutor'); ?></button>
593
  </div>
594
  </div>
595
  </li>
605
 
606
 
607
  public function tutor_setup_wizard_action() {
608
+
609
  $html = '<div class="tutor-setup-content-footer footer">';
610
  $html .= '<div class="tutor-setup-btn-wrapper">';
611
  $html .= '<button class="tutor-setup-previous previous animated-btn">';
637
  <div class="tutor-wizard-container">
638
  <div class="tutor-wrapper-boarding tutor-setup-wizard-boarding active">
639
  <div class="wizard-boarding-header">
640
+ <div><img src="<?php echo esc_url( tutor()->url.'assets/images/tutor-logo.svg' ); ?>" /></div>
641
  <div><?php printf(__('Hello %s, welcome to Tutor LMS! Thank you for choosing us.', 'tutor'), $current_user->user_login); ?></div>
642
  </div>
643
  <div class="wizard-boarding-body">
644
  <ul class="slider tutor-boarding">
645
  <li>
646
 
647
+ <div class="slide-thumb"><img src="<?php echo esc_url( tutor()->url . 'assets/images/scalable_lms_solution.jpg' ); ?>" alt="<?php _e('A Powerful, Smart, and Scalable LMS Solution', 'tutor') ?>"/></div>
648
  <div class="slide-title"><?php _e('A Powerful, Smart, and Scalable LMS Solution', 'tutor'); ?></div>
649
  <div class="slide-subtitle"><?php _e('From individual instructors to vast eLearning platforms, Tutor LMS grows with you to create your ideal vision of an LMS website.', 'tutor'); ?></div>
650
  </li>
651
  <li>
652
+ <div class="slide-thumb"><img src="<?php echo esc_url( tutor()->url . 'assets/images/extensive_course_builder.jpg' ); ?>" alt="<?php _e('Extensive Course Builder', 'tutor') ?>"/></div>
653
  <div class="slide-title"><?php _e('Extensive Course Builder', 'tutor'); ?></div>
654
  <div class="slide-subtitle"><?php _e('Tutor LMS comes with a state-of-the-art frontend course builder. Construct rich and resourceful courses with ease.', 'tutor'); ?></div>
655
  </li>
656
  <li>
657
+ <div class="slide-thumb"><img src="<?php echo esc_url( tutor()->url . 'assets/images/advanced_quiz_creator.jpg' ); ?>" alt="<?php _e('Advanced Quiz Creator', 'tutor'); ?>"/></div>
658
  <div class="slide-title"><?php _e('Advanced Quiz Creator', 'tutor'); ?></div>
659
  <div class="slide-subtitle"><?php _e('Build interactive quizzes with the vast selection of question types and verify the learning of your students.', 'tutor'); ?></div>
660
  </li>
661
  <li>
662
+ <div class="slide-thumb"><img src="<?php echo esc_url( tutor()->url . 'assets/images/freedom_with_ecommerce.jpg' ); ?>" alt="<?php _e('Freedom With eCommerce', 'tutor'); ?>"/></div>
663
  <div class="slide-title"><?php _e('Freedom With eCommerce', 'tutor'); ?></div>
664
  <div class="slide-subtitle"><?php _e('Select an eCommerce plugin and sell courses any way you like and use any payment gateway you want!', 'tutor'); ?></div>
665
  </li>
666
  <li>
667
+ <div class="slide-thumb"><img src="<?php echo esc_url( tutor()->url . 'assets/images/reports_and_analytics.jpg' ); ?>" alt="<?php _e('Reports and Analytics', 'tutor'); ?>"/></div>
668
  <div class="slide-title"><?php _e('Reports and Analytics', 'tutor'); ?></div>
669
  <div class="slide-subtitle"><?php _e('Track what type of courses sell the most! Gain insights on user purchases, manage reviews and track quiz attempts.', 'tutor'); ?></div>
670
  </li>
679
  </svg>
680
  </button>
681
  </div>
682
+ <div><a href="<?php echo esc_url( admin_url() ); ?>"><?php _e('I already know, skip this!', 'tutor'); ?></a></div>
683
  </div>
684
  </div>
685
  </div>
692
  <div class="tutor-wizard-container">
693
  <div class="tutor-wrapper-type tutor-setup-wizard-type">
694
  <div class="wizard-type-header">
695
+ <div class="logo"><img src="<?php echo esc_url( tutor()->url.'assets/images/tutor-logo.svg' ); ?>" /></div>
696
  <div class="title"><?php _e('Let’s get the platform up and running', 'tutor'); ?></div>
697
  <div class="subtitle"><?php _e('Pick a category for your LMS platform. You can always update this later.', 'tutor'); ?></div>
698
  </div>
701
  <input id="enable_course_marketplace-0" type="radio" name="enable_course_marketplace_setup" value="0" <?php if(!$course_marketplace){ echo 'checked'; } ?> />
702
  <span class="icon"></span>
703
  <label for="enable_course_marketplace-0">
704
+ <img src="<?php echo esc_url( tutor()->url.'assets/images/single-marketplace.png' ); ?>" />
705
  <div class="title"><?php _e( 'Individual', 'tutor' ); ?></div>
706
  <div class="subtitle"><?php _e( 'I want to start my solo journey as an educator and spread my knowledge.', 'tutor' ); ?></div>
707
  </label>
711
  <input id="enable_course_marketplace-1" type="radio" name="enable_course_marketplace_setup" value="1" <?php if($course_marketplace){ echo 'checked'; } ?>/>
712
  <span class="icon"></span>
713
  <label for="enable_course_marketplace-1">
714
+ <img src="<?php echo esc_url( tutor()->url.'assets/images/multiple-marketplace.png' ); ?>" />
715
  <div class="title"><?php _e( 'Marketplace', 'tutor' ); ?></div>
716
  <div class="subtitle"><?php _e( 'I want to create an eLearning platform to let anyone earn by teaching online.', 'tutor' ); ?></div>
717
  </label>
classes/Upgrader.php CHANGED
@@ -2,42 +2,41 @@
2
 
3
  namespace TUTOR;
4
 
5
-
6
- if ( ! defined( 'ABSPATH' ) )
7
  exit;
 
8
 
9
  class Upgrader {
10
 
11
  public function __construct() {
12
- add_action('admin_init', array($this, 'init_upgrader'));
13
 
14
  $base_name = tutor()->basename;
15
- add_action( 'in_plugin_update_message-'.$base_name, array( $this, 'in_plugin_update_message' ), 10, 2 );
16
 
17
  /**
18
  * Installing Gradebook Addon from TutorPro
19
- *
20
  */
21
- add_action('tutor_addon_before_enable_tutor-pro/addons/gradebook/gradebook.php', array($this, 'install_gradebook'));
22
- add_action('tutor_addon_before_enable_tutor-pro/addons/tutor-email/tutor-email.php', array($this, 'install_tutor_email_queue'));
23
- add_action('upgrader_process_complete', array($this, 'init_email_table_deployment'), 10, 2);
24
  }
25
 
26
- public function init_upgrader(){
27
  $upgrades = $this->available_upgrades();
28
 
29
- if (tutor_utils()->count($upgrades)){
30
- foreach ($upgrades as $upgrade){
31
  $this->{$upgrade}();
32
  }
33
  }
34
  }
35
 
36
- public function available_upgrades(){
37
- $version = get_option('tutor_version');
38
 
39
  $upgrades = array();
40
- if ($version){
41
  $upgrades[] = 'upgrade_to_1_3_1';
42
  }
43
 
@@ -47,26 +46,26 @@ class Upgrader {
47
  /**
48
  * Upgrade to version 1.3.1
49
  */
50
- public function upgrade_to_1_3_1(){
51
- if (version_compare(get_option('tutor_version'), '1.3.1', '<')) {
52
  global $wpdb;
53
 
54
- if ( ! get_option('is_course_post_type_updated')){
55
- $wpdb->update($wpdb->posts, array('post_type' => 'courses'), array('post_type' => 'course'));
56
- update_option('is_course_post_type_updated', true);
57
- update_option('tutor_version', '1.3.1');
58
  flush_rewrite_rules();
59
  }
60
  }
61
  }
62
 
63
 
64
- public function in_plugin_update_message( $args, $response ){
65
- $upgrade_notice = strip_tags(tutils()->array_get('upgrade_notice', $response));
66
- if ($upgrade_notice){
67
- $upgrade_notice = "<span class='version'><code>v.{$response->new_version}</code></span> <br />".$upgrade_notice;
68
 
69
- echo apply_filters( 'tutor_in_plugin_update_message', $upgrade_notice ? '</p> <div class="tutor_plugin_update_notice">' .$upgrade_notice. '</div> <p class="dummy">' : '' );
70
  }
71
  }
72
 
@@ -76,16 +75,16 @@ class Upgrader {
76
  *
77
  * @since v.1.4.2
78
  */
79
- public function install_gradebook(){
80
  global $wpdb;
81
 
82
- $exists_gradebook_table = $wpdb->query("SHOW TABLES LIKE '{$wpdb->tutor_gradebooks}';");
83
- $exists_gradebook_results_table = $wpdb->query("SHOW TABLES LIKE '{$wpdb->tutor_gradebooks_results}';");
84
- $charset_collate = $wpdb->get_charset_collate();
85
 
86
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
87
 
88
- if ( ! $exists_gradebook_table){
89
  $gradebook_table = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_gradebooks} (
90
  gradebook_id int(11) NOT NULL AUTO_INCREMENT,
91
  grade_name varchar(50) DEFAULT NULL,
@@ -98,7 +97,7 @@ class Upgrader {
98
  ) $charset_collate;";
99
  dbDelta( $gradebook_table );
100
  }
101
- if ( ! $exists_gradebook_results_table){
102
  $gradebook_results = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_gradebooks_results} (
103
  gradebook_result_id int(11) NOT NULL AUTO_INCREMENT,
104
  user_id int(11) DEFAULT NULL,
@@ -120,11 +119,11 @@ class Upgrader {
120
 
121
  }
122
 
123
- public function init_email_table_deployment($upgrader_object, $options ) {
124
 
125
- if( is_object( $upgrader_object ) && is_array($upgrader_object->result) && isset($upgrader_object->result['destination_name']) && $upgrader_object->result['destination_name']=='tutor-pro' ) {
126
- $addonConfig = tutor_utils()->get_addon_config('tutor-pro/addons/tutor-email/tutor-email.php');
127
- $isEnable = (bool) tutor_utils()->avalue_dot('is_enable', $addonConfig);
128
 
129
  $isEnable ? $this->install_tutor_email_queue() : 0;
130
  }
@@ -138,10 +137,10 @@ class Upgrader {
138
  public function install_tutor_email_queue() {
139
 
140
  global $wpdb;
141
- $exists_email_queue_table = $wpdb->query("SHOW TABLES LIKE '{$wpdb->tutor_email_queue}';");
142
- $charset_collate = $wpdb->get_charset_collate();
143
 
144
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
145
 
146
  if ( ! $exists_email_queue_table ) {
147
  $table = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_email_queue} (
@@ -152,8 +151,8 @@ class Upgrader {
152
  headers text NOT NULL,
153
  PRIMARY KEY (id)
154
  ) {$charset_collate};";
155
-
156
  dbDelta( $table );
157
  }
158
  }
159
- }
2
 
3
  namespace TUTOR;
4
 
5
+ if ( ! defined( 'ABSPATH' ) ) {
 
6
  exit;
7
+ }
8
 
9
  class Upgrader {
10
 
11
  public function __construct() {
12
+ add_action( 'admin_init', array( $this, 'init_upgrader' ) );
13
 
14
  $base_name = tutor()->basename;
15
+ add_action( 'in_plugin_update_message-' . $base_name, array( $this, 'in_plugin_update_message' ), 10, 2 );
16
 
17
  /**
18
  * Installing Gradebook Addon from TutorPro
 
19
  */
20
+ add_action( 'tutor_addon_before_enable_tutor-pro/addons/gradebook/gradebook.php', array( $this, 'install_gradebook' ) );
21
+ add_action( 'tutor_addon_before_enable_tutor-pro/addons/tutor-email/tutor-email.php', array( $this, 'install_tutor_email_queue' ) );
22
+ add_action( 'upgrader_process_complete', array( $this, 'init_email_table_deployment' ), 10, 2 );
23
  }
24
 
25
+ public function init_upgrader() {
26
  $upgrades = $this->available_upgrades();
27
 
28
+ if ( tutor_utils()->count( $upgrades ) ) {
29
+ foreach ( $upgrades as $upgrade ) {
30
  $this->{$upgrade}();
31
  }
32
  }
33
  }
34
 
35
+ public function available_upgrades() {
36
+ $version = get_option( 'tutor_version' );
37
 
38
  $upgrades = array();
39
+ if ( $version ) {
40
  $upgrades[] = 'upgrade_to_1_3_1';
41
  }
42
 
46
  /**
47
  * Upgrade to version 1.3.1
48
  */
49
+ public function upgrade_to_1_3_1() {
50
+ if ( version_compare( get_option( 'tutor_version' ), '1.3.1', '<' ) ) {
51
  global $wpdb;
52
 
53
+ if ( ! get_option( 'is_course_post_type_updated' ) ) {
54
+ $wpdb->update( $wpdb->posts, array( 'post_type' => 'courses' ), array( 'post_type' => 'course' ) );
55
+ update_option( 'is_course_post_type_updated', true );
56
+ update_option( 'tutor_version', '1.3.1' );
57
  flush_rewrite_rules();
58
  }
59
  }
60
  }
61
 
62
 
63
+ public function in_plugin_update_message( $args, $response ) {
64
+ $upgrade_notice = strip_tags( tutils()->array_get( 'upgrade_notice', $response ) );
65
+ if ( $upgrade_notice ) {
66
+ $upgrade_notice = '<span class="version"><code>v.' . $response->new_version . '</code></span> <br />' . $upgrade_notice;
67
 
68
+ echo apply_filters( 'tutor_in_plugin_update_message', ($upgrade_notice ? '</p> <div class="tutor_plugin_update_notice">' . $upgrade_notice . '</div> <p class="dummy">' : '') );
69
  }
70
  }
71
 
75
  *
76
  * @since v.1.4.2
77
  */
78
+ public function install_gradebook() {
79
  global $wpdb;
80
 
81
+ $exists_gradebook_table = $wpdb->query( "SHOW TABLES LIKE '{$wpdb->tutor_gradebooks}';" );
82
+ $exists_gradebook_results_table = $wpdb->query( "SHOW TABLES LIKE '{$wpdb->tutor_gradebooks_results}';" );
83
+ $charset_collate = $wpdb->get_charset_collate();
84
 
85
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
86
 
87
+ if ( ! $exists_gradebook_table ) {
88
  $gradebook_table = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_gradebooks} (
89
  gradebook_id int(11) NOT NULL AUTO_INCREMENT,
90
  grade_name varchar(50) DEFAULT NULL,
97
  ) $charset_collate;";
98
  dbDelta( $gradebook_table );
99
  }
100
+ if ( ! $exists_gradebook_results_table ) {
101
  $gradebook_results = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_gradebooks_results} (
102
  gradebook_result_id int(11) NOT NULL AUTO_INCREMENT,
103
  user_id int(11) DEFAULT NULL,
119
 
120
  }
121
 
122
+ public function init_email_table_deployment( $upgrader_object, $options ) {
123
 
124
+ if ( is_object( $upgrader_object ) && is_array( $upgrader_object->result ) && isset( $upgrader_object->result['destination_name'] ) && $upgrader_object->result['destination_name'] == 'tutor-pro' ) {
125
+ $addonConfig = tutor_utils()->get_addon_config( 'tutor-pro/addons/tutor-email/tutor-email.php' );
126
+ $isEnable = (bool) tutor_utils()->avalue_dot( 'is_enable', $addonConfig );
127
 
128
  $isEnable ? $this->install_tutor_email_queue() : 0;
129
  }
137
  public function install_tutor_email_queue() {
138
 
139
  global $wpdb;
140
+ $exists_email_queue_table = $wpdb->query( "SHOW TABLES LIKE '{$wpdb->tutor_email_queue}';" );
141
+ $charset_collate = $wpdb->get_charset_collate();
142
 
143
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
144
 
145
  if ( ! $exists_email_queue_table ) {
146
  $table = "CREATE TABLE IF NOT EXISTS {$wpdb->tutor_email_queue} (
151
  headers text NOT NULL,
152
  PRIMARY KEY (id)
153
  ) {$charset_collate};";
154
+
155
  dbDelta( $table );
156
  }
157
  }
158
+ }
classes/User.php CHANGED
@@ -2,8 +2,9 @@
2
 
3
  namespace TUTOR;
4
 
5
- if ( ! defined( 'ABSPATH' ) )
6
  exit;
 
7
 
8
 
9
  class User {
@@ -11,16 +12,16 @@ class User {
11
  private static $hide_registration_notice = false;
12
 
13
  public function __construct() {
14
- add_action('edit_user_profile', array($this, 'edit_user_profile'));
15
- add_action('show_user_profile', array($this, 'edit_user_profile'), 10, 1);
16
 
17
- add_action('profile_update', array($this, 'profile_update'));
18
- add_action('set_user_role', array($this, 'set_user_role'), 10, 3);
19
 
20
- add_action('wp_ajax_tutor_user_photo_remove', array($this, 'tutor_user_photo_remove'));
21
- add_action('wp_ajax_tutor_user_photo_upload', array($this, 'update_user_photo'));
22
-
23
- add_action('tutor_options_after_instructors', array($this, 'tutor_instructor_profile_layout'));
24
  // add_action('tutor_options_after_students', array($this, 'tutor_student_profile_layout'));
25
 
26
  add_action( 'admin_notices', array( $this, 'show_registration_disabled' ) );
@@ -30,53 +31,64 @@ class User {
30
  private $profile_layout = array(
31
  'pp-circle',
32
  'pp-rectangle',
33
- 'no-cp'
34
  );
35
 
36
  /**
37
  * Show layout selection dashboard in instructor and student setting
38
  */
39
- public function tutor_instructor_profile_layout(){
40
- tutor_load_template('public-profile-setting', array('profile_templates'=>$this->profile_layout, 'layout_option_name'=>'instructor'));
 
 
 
 
 
 
41
  }
42
- public function tutor_student_profile_layout(){
43
- tutor_load_template('public-profile-setting', array('profile_templates'=>$this->profile_layout, 'layout_option_name'=>'student'));
 
 
 
 
 
 
44
  }
45
 
46
- public function edit_user_profile($user){
47
- include tutor()->path.'views/metabox/user-profile-fields.php';
48
  }
49
 
50
- private function delete_existing_user_photo($user_id, $type){
51
- $meta_key = $type=='cover_photo' ? '_tutor_cover_photo' : '_tutor_profile_photo';
52
- $photo_id = get_user_meta($user_id, $meta_key, true);
53
- is_numeric($photo_id) ? wp_delete_attachment( $photo_id, true) : 0;
54
- delete_user_meta( $user_id, $meta_key);
55
  }
56
 
57
- public function tutor_user_photo_remove(){
58
  tutils()->checking_nonce();
59
-
60
- $this->delete_existing_user_photo(get_current_user_id(), $_POST['photo_type']);
61
  }
62
 
63
- public function update_user_photo(){
64
  tutils()->checking_nonce();
65
 
66
- $user_id = get_current_user_id();
67
- $meta_key = $_POST['photo_type']=='cover_photo' ? '_tutor_cover_photo' : '_tutor_profile_photo';
68
-
69
  /**
70
  * Photo Update from profile
71
- *
72
  */
73
- $photo = tutils()->array_get('photo_file', $_FILES);
74
- $photo_size = tutils()->array_get('size', $photo);
75
- $photo_type = tutils()->array_get('type', $photo);
76
 
77
- if ($photo_size && strpos($photo_type, 'image') !== false) {
78
  if ( ! function_exists( 'wp_handle_upload' ) ) {
79
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
80
  }
81
 
82
  $upload_overrides = array( 'test_form' => false );
@@ -86,79 +98,83 @@ class User {
86
  $file_path = tutils()->array_get( 'file', $movefile );
87
  $file_url = tutils()->array_get( 'url', $movefile );
88
 
89
- $media_id = wp_insert_attachment( array(
90
- 'guid' => $file_path,
91
- 'post_mime_type' => mime_content_type( $file_path ),
92
- 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file_url ) ),
93
- 'post_content' => '',
94
- 'post_status' => 'inherit'
95
- ), $file_path, 0 );
96
-
97
- if ($media_id) {
 
 
 
 
98
  // wp_generate_attachment_metadata() won't work if you do not include this file
99
- require_once( ABSPATH . 'wp-admin/includes/image.php' );
100
 
101
  // Generate and save the attachment metas into the database
102
  wp_update_attachment_metadata( $media_id, wp_generate_attachment_metadata( $media_id, $file_path ) );
103
 
104
- //Update it to user profile
105
- $this->delete_existing_user_photo($user_id, $_POST['photo_type']);
106
- update_user_meta($user_id, $meta_key, $media_id );
107
 
108
- exit(json_encode(array('status'=>'success')));
109
  }
110
  }
111
  }
112
  }
113
 
114
- public function profile_update($user_id){
115
- if (tutils()->array_get('tutor_action', $_POST) !== 'tutor_profile_update_by_wp' ){
116
  return;
117
  }
118
 
119
- $_tutor_profile_job_title = sanitize_text_field(tutor_utils()->avalue_dot('_tutor_profile_job_title', $_POST));
120
- $_tutor_profile_bio = wp_kses_post(tutor_utils()->avalue_dot('_tutor_profile_bio', $_POST));
121
- $_tutor_profile_image = wp_kses_post(tutor_utils()->avalue_dot('_tutor_profile_photo', $_POST));
122
 
123
- update_user_meta($user_id, '_tutor_profile_job_title', $_tutor_profile_job_title);
124
- update_user_meta($user_id, '_tutor_profile_bio', $_tutor_profile_bio);
125
- update_user_meta($user_id, '_tutor_profile_photo', $_tutor_profile_image);
126
  }
127
 
128
- public function set_user_role($user_id, $role, $old_roles ){
129
  $instructor_role = tutor()->instructor_role;
130
 
131
- if (in_array($instructor_role, $old_roles)){
132
  // tutor_utils()->remove_instructor_role($user_id);
133
  }
134
 
135
  // if ($role === $instructor_role){
136
- if ($role === $instructor_role || in_array($instructor_role, $old_roles)){
137
- tutor_utils()->add_instructor_role($user_id);
138
  }
139
  }
140
 
141
  public function hide_notices() {
142
- if(is_admin() && isset( $_GET['tutor-hide-notice'] ) && $_GET['tutor-hide-notice']=='registration') {
143
- tutils()->checking_nonce('get');
144
 
145
- if(isset($_GET['tutor-registration']) && $_GET['tutor-registration']==='enable') {
146
  update_option( 'users_can_register', 1 );
147
  } else {
148
  self::$hide_registration_notice = true;
149
- setcookie('tutor_notice_hide_registration', 1, time() + (86400 * 30), tutor()->basepath);
150
  }
151
  }
152
  }
153
 
154
  public function show_registration_disabled() {
155
 
156
- if(
157
  self::$hide_registration_notice ||
158
- !tutils()->is_tutor_dashboard() ||
159
- get_option( 'users_can_register' ) ||
160
  isset( $_COOKIE['tutor_notice_hide_registration'] ) ||
161
- !current_user_can( 'manage_options' )
162
  ) {
163
  return;
164
  }
@@ -168,18 +184,18 @@ class User {
168
  <div class="wrap tutor-user-registration-notice-wrapper">
169
  <div class="tutor-user-registration-notice">
170
  <div>
171
- <img src="<?php echo tutor()->url; ?>assets/images/icon-info-round.svg"/>
172
  </div>
173
  <div>
174
- <?php _e('As membership is turned off, students and instructors will not be able to sign up. <strong>Press Enable</strong> or go to <strong>Settings > General > Membership</strong> and enable "Anyone can register".'); ?>
175
  </div>
176
  <div>
177
- <a href="<?php echo esc_url( add_query_arg( 'tutor-registration', 'enable', $hide_url ) ); ?>"><?php _e('Enable', 'tutor'); ?></a>
178
  <hr/>
179
- <a href="<?php echo esc_url( $hide_url ); ?>"><?php _e('Dismiss', 'tutor'); ?></a>
180
  </div>
181
  </div>
182
  </div>
183
  <?php
184
  }
185
- }
2
 
3
  namespace TUTOR;
4
 
5
+ if ( ! defined( 'ABSPATH' ) ) {
6
  exit;
7
+ }
8
 
9
 
10
  class User {
12
  private static $hide_registration_notice = false;
13
 
14
  public function __construct() {
15
+ add_action( 'edit_user_profile', array( $this, 'edit_user_profile' ) );
16
+ add_action( 'show_user_profile', array( $this, 'edit_user_profile' ), 10, 1 );
17
 
18
+ add_action( 'profile_update', array( $this, 'profile_update' ) );
19
+ add_action( 'set_user_role', array( $this, 'set_user_role' ), 10, 3 );
20
 
21
+ add_action( 'wp_ajax_tutor_user_photo_remove', array( $this, 'tutor_user_photo_remove' ) );
22
+ add_action( 'wp_ajax_tutor_user_photo_upload', array( $this, 'update_user_photo' ) );
23
+
24
+ add_action( 'tutor_options_after_instructors', array( $this, 'tutor_instructor_profile_layout' ) );
25
  // add_action('tutor_options_after_students', array($this, 'tutor_student_profile_layout'));
26
 
27
  add_action( 'admin_notices', array( $this, 'show_registration_disabled' ) );
31
  private $profile_layout = array(
32
  'pp-circle',
33
  'pp-rectangle',
34
+ 'no-cp',
35
  );
36
 
37
  /**
38
  * Show layout selection dashboard in instructor and student setting
39
  */
40
+ public function tutor_instructor_profile_layout() {
41
+ tutor_load_template(
42
+ 'public-profile-setting',
43
+ array(
44
+ 'profile_templates' => $this->profile_layout,
45
+ 'layout_option_name' => 'instructor',
46
+ )
47
+ );
48
  }
49
+ public function tutor_student_profile_layout() {
50
+ tutor_load_template(
51
+ 'public-profile-setting',
52
+ array(
53
+ 'profile_templates' => $this->profile_layout,
54
+ 'layout_option_name' => 'student',
55
+ )
56
+ );
57
  }
58
 
59
+ public function edit_user_profile( $user ) {
60
+ include tutor()->path . 'views/metabox/user-profile-fields.php';
61
  }
62
 
63
+ private function delete_existing_user_photo( $user_id, $type ) {
64
+ $meta_key = $type == 'cover_photo' ? '_tutor_cover_photo' : '_tutor_profile_photo';
65
+ $photo_id = get_user_meta( $user_id, $meta_key, true );
66
+ is_numeric( $photo_id ) ? wp_delete_attachment( $photo_id, true ) : 0;
67
+ delete_user_meta( $user_id, $meta_key );
68
  }
69
 
70
+ public function tutor_user_photo_remove() {
71
  tutils()->checking_nonce();
72
+
73
+ $this->delete_existing_user_photo( get_current_user_id(), tutor_sanitize_data( $_POST['photo_type'] ) );
74
  }
75
 
76
+ public function update_user_photo() {
77
  tutils()->checking_nonce();
78
 
79
+ $user_id = get_current_user_id();
80
+ $meta_key = sanitize_text_field( $_POST['photo_type'] ) == 'cover_photo' ? '_tutor_cover_photo' : '_tutor_profile_photo';
81
+
82
  /**
83
  * Photo Update from profile
 
84
  */
85
+ $photo = tutils()->array_get( 'photo_file', $_FILES );
86
+ $photo_size = tutils()->array_get( 'size', $photo );
87
+ $photo_type = tutils()->array_get( 'type', $photo );
88
 
89
+ if ( $photo_size && strpos( $photo_type, 'image' ) !== false ) {
90
  if ( ! function_exists( 'wp_handle_upload' ) ) {
91
+ require_once ABSPATH . 'wp-admin/includes/file.php';
92
  }
93
 
94
  $upload_overrides = array( 'test_form' => false );
98
  $file_path = tutils()->array_get( 'file', $movefile );
99
  $file_url = tutils()->array_get( 'url', $movefile );
100
 
101
+ $media_id = wp_insert_attachment(
102
+ array(
103
+ 'guid' => $file_path,
104
+ 'post_mime_type' => mime_content_type( $file_path ),
105
+ 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $file_url ) ),
106
+ 'post_content' => '',
107
+ 'post_status' => 'inherit',
108
+ ),
109
+ $file_path,
110
+ 0
111
+ );
112
+
113
+ if ( $media_id ) {
114
  // wp_generate_attachment_metadata() won't work if you do not include this file
115
+ require_once ABSPATH . 'wp-admin/includes/image.php';
116
 
117
  // Generate and save the attachment metas into the database
118
  wp_update_attachment_metadata( $media_id, wp_generate_attachment_metadata( $media_id, $file_path ) );
119
 
120
+ // Update it to user profile
121
+ $this->delete_existing_user_photo( $user_id, tutor_sanitize_data($_POST['photo_type']) );
122
+ update_user_meta( $user_id, $meta_key, $media_id );
123
 
124
+ exit( json_encode( array( 'status' => 'success' ) ) );
125
  }
126
  }
127
  }
128
  }
129
 
130
+ public function profile_update( $user_id ) {
131
+ if ( tutils()->array_get( 'tutor_action', $_POST ) !== 'tutor_profile_update_by_wp' ) {
132
  return;
133
  }
134
 
135
+ $_tutor_profile_job_title = sanitize_text_field( tutor_utils()->avalue_dot( '_tutor_profile_job_title', $_POST ) );
136
+ $_tutor_profile_bio = wp_kses_post( tutor_utils()->avalue_dot( '_tutor_profile_bio', $_POST ) );
137
+ $_tutor_profile_image = wp_kses_post( tutor_utils()->avalue_dot( '_tutor_profile_photo', $_POST ) );
138
 
139
+ update_user_meta( $user_id, '_tutor_profile_job_title', $_tutor_profile_job_title );
140
+ update_user_meta( $user_id, '_tutor_profile_bio', $_tutor_profile_bio );
141
+ update_user_meta( $user_id, '_tutor_profile_photo', $_tutor_profile_image );
142
  }
143
 
144
+ public function set_user_role( $user_id, $role, $old_roles ) {
145
  $instructor_role = tutor()->instructor_role;
146
 
147
+ if ( in_array( $instructor_role, $old_roles ) ) {
148
  // tutor_utils()->remove_instructor_role($user_id);
149
  }
150
 
151
  // if ($role === $instructor_role){
152
+ if ( $role === $instructor_role || in_array( $instructor_role, $old_roles ) ) {
153
+ tutor_utils()->add_instructor_role( $user_id );
154
  }
155
  }
156
 
157
  public function hide_notices() {
158
+ if ( is_admin() && isset( $_GET['tutor-hide-notice'] ) && $_GET['tutor-hide-notice'] == 'registration' ) {
159
+ tutils()->checking_nonce( 'get' );
160
 
161
+ if ( isset( $_GET['tutor-registration'] ) && $_GET['tutor-registration'] === 'enable' ) {
162
  update_option( 'users_can_register', 1 );
163
  } else {
164
  self::$hide_registration_notice = true;
165
+ setcookie( 'tutor_notice_hide_registration', 1, time() + ( 86400 * 30 ), tutor()->basepath );
166
  }
167
  }
168
  }
169
 
170
  public function show_registration_disabled() {
171
 
172
+ if (
173
  self::$hide_registration_notice ||
174
+ ! tutils()->is_tutor_dashboard() ||
175
+ get_option( 'users_can_register' ) ||
176
  isset( $_COOKIE['tutor_notice_hide_registration'] ) ||
177
+ ! current_user_can( 'manage_options' )
178
  ) {
179
  return;
180
  }
184
  <div class="wrap tutor-user-registration-notice-wrapper">
185
  <div class="tutor-user-registration-notice">
186
  <div>
187
+ <img src="<?php echo esc_url( tutor()->url . 'assets/images/icon-info-round.svg' ); ?>"/>
188
  </div>
189
  <div>
190
+ <?php _e( 'As membership is turned off, students and instructors will not be able to sign up. <strong>Press Enable</strong> or go to <strong>Settings > General > Membership</strong> and enable "Anyone can register".' ); ?>
191
  </div>
192
  <div>
193
+ <a href="<?php echo esc_url( add_query_arg( 'tutor-registration', 'enable', $hide_url ) ); ?>"><?php _e( 'Enable', 'tutor' ); ?></a>
194
  <hr/>
195
+ <a href="<?php echo esc_url( $hide_url ); ?>"><?php _e( 'Dismiss', 'tutor' ); ?></a>
196
  </div>
197
  </div>
198
  </div>
199
  <?php
200
  }
201
+ }
classes/Utils.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  /**
3
  * Tutor Utils Helper functions
 
4
  * @package TUTOR
5
  *
6
  * @since v.1.0.0
@@ -8,8 +9,9 @@
8
 
9
  namespace TUTOR;
10
 
11
- if ( ! defined( 'ABSPATH' ) )
12
  exit;
 
13
 
14
  class Utils {
15
  /**
@@ -23,7 +25,7 @@ class Utils {
23
  * @since v.1.0.0
24
  */
25
  public function get_option( $key = null, $default = false ) {
26
- $option = (array) maybe_unserialize(get_option('tutor_option'));
27
 
28
  if ( empty( $option ) || ! is_array( $option ) ) {
29
  return $default;
@@ -32,17 +34,17 @@ class Utils {
32
  return $option;
33
  }
34
  if ( array_key_exists( $key, $option ) ) {
35
- return apply_filters( $key, $option[$key] );
36
  }
37
- //Access array value via dot notation, such as option->get('value.subvalue')
38
- if ( strpos($key, '.') ) {
39
  $option_key_array = explode( '.', $key );
40
 
41
  $new_option = $option;
42
  foreach ( $option_key_array as $dotKey ) {
43
- if ( isset( $new_option[$dotKey] ) ) {
44
- $new_option = $new_option[$dotKey];
45
- }else{
46
  return $default;
47
  }
48
  }
@@ -61,13 +63,13 @@ class Utils {
61
  * @since v.1.0.0
62
  */
63
  public function update_option( $key = null, $value = false ) {
64
- $option = (array) maybe_unserialize( get_option('tutor_option') );
65
- $option[$key] = $value;
66
  update_option( 'tutor_option', $option );
67
  }
68
 
69
  /**
70
- * @param null $key
71
  * @param array $array
72
  *
73
  * @return array|bool|mixed
@@ -80,7 +82,7 @@ class Utils {
80
  */
81
  public function avalue_dot( $key = null, $array = array(), $default = false ) {
82
  $array = (array) $array;
83
- if ( ! $key || ! count($array) ) {
84
  return $default;
85
  }
86
  $option_key_array = explode( '.', $key );
@@ -88,8 +90,8 @@ class Utils {
88
  $value = $array;
89
 
90
  foreach ( $option_key_array as $dotKey ) {
91
- if ( isset( $value[$dotKey] ) ) {
92
- $value = $value[$dotKey];
93
  } else {
94
  return $default;
95
  }
@@ -98,7 +100,7 @@ class Utils {
98
  }
99
 
100
  /**
101
- * @param null $key
102
  * @param array $array
103
  *
104
  * @return array|bool|mixed
@@ -126,15 +128,15 @@ class Utils {
126
 
127
  do_action( 'tutor_utils/get_pages/before' );
128
 
129
- $pages = array();
130
  $wp_pages = get_pages();
131
 
132
- if (is_array($wp_pages) && count($wp_pages)) {
133
- foreach ($wp_pages as $page) {
134
- $pages[$page->ID] = $page->post_title;
135
  }
136
  }
137
-
138
  do_action( 'tutor_utils/get_pages/after' );
139
 
140
  return $pages;
@@ -151,7 +153,7 @@ class Utils {
151
  $course_post_type = tutor()->course_post_type;
152
  $course_page_url = trailingslashit( home_url() ) . $course_post_type;
153
 
154
- $course_archive_page = $this->get_option('course_archive_page');
155
  if ( $course_archive_page && $course_archive_page !== '-1' ) {
156
  $course_page_url = get_permalink( $course_archive_page );
157
  }
@@ -173,23 +175,24 @@ class Utils {
173
  $user_name = '';
174
  if ( $student_id ) {
175
  global $wpdb;
176
- $user = $wpdb->get_row( $wpdb->prepare(
177
- "SELECT user_nicename
178
- FROM {$wpdb->users}
 
179
  WHERE ID = %d;
180
- ",
181
- $student_id
182
- ) );
 
183
 
184
- if ($user) {
185
  $user_name = $user->user_nicename;
186
  }
187
-
188
  } else {
189
  $user_name = 'user_name';
190
  }
191
 
192
- return $site_url.$user_name;
193
  }
194
 
195
  /**
@@ -203,14 +206,16 @@ class Utils {
203
  */
204
  public function get_user_by_login( $user_nicename = '' ) {
205
  global $wpdb;
206
- $user_nicename = sanitize_text_field( $user_nicename );
207
- $user = $wpdb->get_row( $wpdb->prepare(
208
- "SELECT *
 
209
  FROM {$wpdb->users}
210
  WHERE user_nicename = %s;
211
  ",
212
- $user_nicename
213
- ) );
 
214
  return $user;
215
  }
216
 
@@ -220,7 +225,7 @@ class Utils {
220
  * Check if WooCommerce Activated
221
  *
222
  * @since v.1.0.0
223
- * @updated @1.5.9
224
  */
225
  public function has_wc() {
226
  return class_exists( 'WooCommerce' );
@@ -247,29 +252,29 @@ class Utils {
247
  *
248
  * @since v.1.3.6
249
  */
250
- public function has_pmpro($check_monetization=false) {
251
- $has_pmpro = $this->is_plugin_active('paid-memberships-pro/paid-memberships-pro.php');
252
- return $has_pmpro && (!$check_monetization || get_tutor_option('monetize_by') == 'pmpro' );
253
  }
254
 
255
- public function is_plugin_active($plugin_path) {
256
  $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
257
- $depends = is_array($plugin_path) ? $plugin_path : array( $plugin_path );
258
  $has_plugin = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
259
-
260
  return $has_plugin;
261
  }
262
 
263
- public function has_wcs(){
264
- $has_wcs = $this->is_plugin_active('woocommerce-subscriptions/woocommerce-subscriptions.php');
265
  return $has_wcs;
266
  }
267
 
268
- public function is_addon_enabled($basename) {
269
- if($this->is_plugin_active('tutor-pro/tutor-pro.php')) {
270
- $addonConfig = $this->get_addon_config($basename);
271
-
272
- return (bool) $this->avalue_dot('is_enable', $addonConfig);
273
  }
274
  }
275
 
@@ -280,7 +285,7 @@ class Utils {
280
  *
281
  * @since v.1.4.8
282
  */
283
- public function has_bp(){
284
  $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
285
  $depends = array( 'buddypress/bp-loader.php' );
286
  $has_bp = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
@@ -294,141 +299,141 @@ class Utils {
294
  */
295
  public function languages() {
296
  $language_codes = array(
297
- 'en' => 'English' ,
298
- 'aa' => 'Afar' ,
299
- 'ab' => 'Abkhazian' ,
300
- 'af' => 'Afrikaans' ,
301
- 'am' => 'Amharic' ,
302
- 'ar' => 'Arabic' ,
303
- 'as' => 'Assamese' ,
304
- 'ay' => 'Aymara' ,
305
- 'az' => 'Azerbaijani' ,
306
- 'ba' => 'Bashkir' ,
307
- 'be' => 'Byelorussian' ,
308
- 'bg' => 'Bulgarian' ,
309
- 'bh' => 'Bihari' ,
310
- 'bi' => 'Bislama' ,
311
- 'bn' => 'Bengali/Bangla' ,
312
- 'bo' => 'Tibetan' ,
313
- 'br' => 'Breton' ,
314
- 'ca' => 'Catalan' ,
315
- 'co' => 'Corsican' ,
316
- 'cs' => 'Czech' ,
317
- 'cy' => 'Welsh' ,
318
- 'da' => 'Danish' ,
319
- 'de' => 'German' ,
320
- 'dz' => 'Bhutani' ,
321
- 'el' => 'Greek' ,
322
- 'eo' => 'Esperanto' ,
323
- 'es' => 'Spanish' ,
324
- 'et' => 'Estonian' ,
325
- 'eu' => 'Basque' ,
326
- 'fa' => 'Persian' ,
327
- 'fi' => 'Finnish' ,
328
- 'fj' => 'Fiji' ,
329
- 'fo' => 'Faeroese' ,
330
- 'fr' => 'French' ,
331
- 'fy' => 'Frisian' ,
332
- 'ga' => 'Irish' ,
333
- 'gd' => 'Scots/Gaelic' ,
334
- 'gl' => 'Galician' ,
335
- 'gn' => 'Guarani' ,
336
- 'gu' => 'Gujarati' ,
337
- 'ha' => 'Hausa' ,
338
- 'hi' => 'Hindi' ,
339
- 'hr' => 'Croatian' ,
340
- 'hu' => 'Hungarian' ,
341
- 'hy' => 'Armenian' ,
342
- 'ia' => 'Interlingua' ,
343
- 'ie' => 'Interlingue' ,
344
- 'ik' => 'Inupiak' ,
345
- 'in' => 'Indonesian' ,
346
- 'is' => 'Icelandic' ,
347
- 'it' => 'Italian' ,
348
- 'iw' => 'Hebrew' ,
349
- 'ja' => 'Japanese' ,
350
- 'ji' => 'Yiddish' ,
351
- 'jw' => 'Javanese' ,
352
- 'ka' => 'Georgian' ,
353
- 'kk' => 'Kazakh' ,
354
- 'kl' => 'Greenlandic' ,
355
- 'km' => 'Cambodian' ,
356
- 'kn' => 'Kannada' ,
357
- 'ko' => 'Korean' ,
358
- 'ks' => 'Kashmiri' ,
359
- 'ku' => 'Kurdish' ,
360
- 'ky' => 'Kirghiz' ,
361
- 'la' => 'Latin' ,
362
- 'ln' => 'Lingala' ,
363
- 'lo' => 'Laothian' ,
364
- 'lt' => 'Lithuanian' ,
365
- 'lv' => 'Latvian/Lettish' ,
366
- 'mg' => 'Malagasy' ,
367
- 'mi' => 'Maori' ,
368
- 'mk' => 'Macedonian' ,
369
- 'ml' => 'Malayalam' ,
370
- 'mn' => 'Mongolian' ,
371
- 'mo' => 'Moldavian' ,
372
- 'mr' => 'Marathi' ,
373
- 'ms' => 'Malay' ,
374
- 'mt' => 'Maltese' ,
375
- 'my' => 'Burmese' ,
376
- 'na' => 'Nauru' ,
377
- 'ne' => 'Nepali' ,
378
- 'nl' => 'Dutch' ,
379
- 'no' => 'Norwegian' ,
380
- 'oc' => 'Occitan' ,
381
- 'om' => '(Afan)/Oromoor/Oriya' ,
382
- 'pa' => 'Punjabi' ,
383
- 'pl' => 'Polish' ,
384
- 'ps' => 'Pashto/Pushto' ,
385
- 'pt' => 'Portuguese' ,
386
- 'qu' => 'Quechua' ,
387
- 'rm' => 'Rhaeto-Romance' ,
388
- 'rn' => 'Kirundi' ,
389
- 'ro' => 'Romanian' ,
390
- 'ru' => 'Russian' ,
391
- 'rw' => 'Kinyarwanda' ,
392
- 'sa' => 'Sanskrit' ,
393
- 'sd' => 'Sindhi' ,
394
- 'sg' => 'Sangro' ,
395
- 'sh' => 'Serbo-Croatian' ,
396
- 'si' => 'Singhalese' ,
397
- 'sk' => 'Slovak' ,
398
- 'sl' => 'Slovenian' ,
399
- 'sm' => 'Samoan' ,
400
- 'sn' => 'Shona' ,
401
- 'so' => 'Somali' ,
402
- 'sq' => 'Albanian' ,
403
- 'sr' => 'Serbian' ,
404
- 'ss' => 'Siswati' ,
405
- 'st' => 'Sesotho' ,
406
- 'su' => 'Sundanese' ,
407
- 'sv' => 'Swedish' ,
408
- 'sw' => 'Swahili' ,
409
- 'ta' => 'Tamil' ,
410
- 'te' => 'Tegulu' ,
411
- 'tg' => 'Tajik' ,
412
- 'th' => 'Thai' ,
413
- 'ti' => 'Tigrinya' ,
414
- 'tk' => 'Turkmen' ,
415
- 'tl' => 'Tagalog' ,
416
- 'tn' => 'Setswana' ,
417
- 'to' => 'Tonga' ,
418
- 'tr' => 'Turkish' ,
419
- 'ts' => 'Tsonga' ,
420
- 'tt' => 'Tatar' ,
421
- 'tw' => 'Twi' ,
422
- 'uk' => 'Ukrainian' ,
423
- 'ur' => 'Urdu' ,
424
- 'uz' => 'Uzbek' ,
425
- 'vi' => 'Vietnamese' ,
426
- 'vo' => 'Volapuk' ,
427
- 'wo' => 'Wolof' ,
428
- 'xh' => 'Xhosa' ,
429
- 'yo' => 'Yoruba' ,
430
- 'zh' => 'Chinese' ,
431
- 'zu' => 'Zulu' ,
432
  );
433
 
434
  return apply_filters( 'tutor/utils/languages', $language_codes );
@@ -443,7 +448,7 @@ class Utils {
443
  */
444
  public function print_view( $value = '' ) {
445
  echo '<pre>';
446
- print_r( $value );
447
  echo '</pre>';
448
  }
449
 
@@ -466,27 +471,32 @@ class Utils {
466
  $exclude_query = implode( "','", $excludes );
467
  }
468
 
469
- $post_status = array_map( function($element) {
470
- return "'" . $element . "'";
471
- }, $post_status );
 
 
 
472
 
473
  $post_status = implode( ',', $post_status );
474
  $course_post_type = tutor()->course_post_type;
475
 
476
- $query = $wpdb->get_results( $wpdb->prepare(
477
- "SELECT ID,
 
478
  post_author,
479
  post_title,
480
  post_name,
481
  post_status,
482
- menu_order
483
- FROM {$wpdb->posts}
484
  WHERE post_status IN ({$post_status})
485
  AND ID NOT IN('$exclude_query')
486
  AND post_type = %s;
487
  ",
488
- $course_post_type
489
- ) );
 
490
 
491
  return $query;
492
  }
@@ -507,13 +517,15 @@ class Utils {
507
  $course_post_type = tutor()->course_post_type;
508
 
509
  global $current_user;
510
- $courses = get_posts(array(
511
- 'post_type' => $course_post_type,
512
- 'author' => $instructor_id,
513
- 'post_status' => array('publish', 'pending'),
514
- 'posts_per_page' => -1
515
- ));
516
-
 
 
517
  return $courses;
518
  }
519
 
@@ -531,21 +543,23 @@ class Utils {
531
 
532
  $course_post_type = tutor()->course_post_type;
533
 
534
- $count = $wpdb->get_var( $wpdb->prepare(
535
- "SELECT COUNT(ID)
 
536
  FROM {$wpdb->posts}
537
  INNER JOIN {$wpdb->usermeta}
538
  ON user_id = %d
539
  AND meta_key = %s
540
  AND meta_value = ID
541
- WHERE post_status = %s
542
  AND post_type = %s;
543
  ",
544
- $instructor_id,
545
- '_tutor_instructor_course_id',
546
- 'publish',
547
- $course_post_type
548
- ) );
 
549
 
550
  return $count;
551
  }
@@ -562,32 +576,35 @@ class Utils {
562
  public function get_courses_by_instructor( $instructor_id = 0, $post_status = array( 'publish' ) ) {
563
  global $wpdb;
564
 
565
- $instructor_id = $this->get_user_id($instructor_id);
566
  $course_post_type = tutor()->course_post_type;
567
 
568
  if ( $post_status === 'any' ) {
569
- $where_post_status = "";
570
  } else {
571
  $post_status = (array) $post_status;
572
  $statuses = "'" . implode( "','", $post_status ) . "'";
573
  $where_post_status = "AND $wpdb->posts.post_status IN({$statuses}) ";
574
  }
575
 
576
- $pageposts = $wpdb->get_results( $wpdb->prepare(
577
- "SELECT $wpdb->posts.*
 
578
  FROM $wpdb->posts
579
  INNER JOIN {$wpdb->usermeta}
580
  ON $wpdb->usermeta.user_id = %d
581
  AND $wpdb->usermeta.meta_key = %s
582
- AND $wpdb->usermeta.meta_value = $wpdb->posts.ID
583
  WHERE 1 = 1 {$where_post_status}
584
  AND $wpdb->posts.post_type = %s
585
  ORDER BY $wpdb->posts.post_date DESC;
586
  ",
587
- $instructor_id,
588
- '_tutor_instructor_course_id',
589
- $course_post_type
590
- ), OBJECT);
 
 
591
 
592
  return $pageposts;
593
  }
@@ -616,16 +633,18 @@ class Utils {
616
 
617
  $course_post_type = tutor()->course_post_type;
618
 
619
- $count = $wpdb->get_var( $wpdb->prepare(
620
- "SELECT COUNT(ID)
 
621
  FROM {$wpdb->posts}
622
  WHERE post_status = %s
623
  AND post_type = %s;
624
  ",
625
- 'publish',
626
- $course_post_type
627
- ) );
628
-
 
629
  return $count;
630
  }
631
 
@@ -641,16 +660,18 @@ class Utils {
641
 
642
  $lesson_post_type = tutor()->lesson_post_type;
643
 
644
- $count = $wpdb->get_var( $wpdb->prepare(
645
- "SELECT COUNT(ID)
 
646
  FROM {$wpdb->posts}
647
  WHERE post_status = %s
648
  AND post_type = %s;
649
  ",
650
- 'publish',
651
- $lesson_post_type
652
- ) );
653
-
 
654
  return $count;
655
  }
656
 
@@ -715,23 +736,25 @@ class Utils {
715
  $user_id = $this->get_user_id( $user_id );
716
 
717
  $lesson_ids = $this->get_course_content_ids_by( tutor()->lesson_post_type, tutor()->course_post_type, $course_id );
718
-
719
  $count = 0;
720
- if ( count( $lesson_ids) ) {
721
  $completed_lesson_meta_ids = array();
722
  foreach ( $lesson_ids as $lesson_id ) {
723
  $completed_lesson_meta_ids[] = '_tutor_completed_lesson_id_' . $lesson_id;
724
  }
725
  $in_ids = implode( "','", $completed_lesson_meta_ids );
726
 
727
- $count = (int) $wpdb->get_var( $wpdb->prepare(
728
- "SELECT count(umeta_id)
 
729
  FROM {$wpdb->usermeta}
730
  WHERE user_id = %d
731
  AND meta_key IN ('{$in_ids}')
732
  ",
733
- $user_id
734
- ) );
 
735
  }
736
 
737
  return $count;
@@ -744,32 +767,32 @@ class Utils {
744
  * @return float|int
745
  *
746
  * @since v.1.0.0
747
- * @updated v.1.6.1
748
  */
749
  public function get_course_completed_percent( $course_id = 0, $user_id = 0 ) {
750
- $course_id = $this->get_post_id($course_id);
751
- $user_id = $this->get_user_id($user_id);
752
- $completed_lesson = $this->get_completed_lesson_count_by_course($course_id, $user_id);
753
- $course_contents = tutils()->get_course_contents_by_id($course_id);
754
- $totalContents = $this->count($course_contents);
755
- $totalContents = $totalContents ? $totalContents : 0;
756
- $completedCount = $completed_lesson;
757
-
758
- if ( tutils()->count( $course_contents ) ) {
759
- foreach ( $course_contents as $content ) {
760
- if ( $content->post_type === 'tutor_quiz' ) {
761
- $attempt = $this->get_quiz_attempt( $content->ID, $user_id );
762
- if ( $attempt) {
763
- $completedCount++;
764
- }
765
- } elseif ( $content->post_type === 'tutor_assignments' ) {
766
- $isSubmitted = $this->is_assignment_submitted( $content->ID, $user_id );
767
- if ( $isSubmitted ) {
768
- $completedCount++;
769
- }
770
- }
771
- }
772
- }
773
 
774
  if ( $totalContents > 0 && $completedCount > 0 ) {
775
  return number_format( ( $completedCount * 100 ) / $totalContents );
@@ -815,16 +838,18 @@ class Utils {
815
  public function get_next_topic_order_id( $course_ID ) {
816
  global $wpdb;
817
 
818
- $last_order = (int) $wpdb->get_var( $wpdb->prepare(
819
- "SELECT MAX(menu_order)
 
820
  FROM {$wpdb->posts}
821
  WHERE post_parent = %d
822
  AND post_type = %s;
823
  ",
824
- $course_ID,
825
- 'topics'
826
- ) );
827
-
 
828
  return $last_order + 1;
829
  }
830
 
@@ -840,15 +865,17 @@ class Utils {
840
  public function get_next_course_content_order_id( $topic_ID ) {
841
  global $wpdb;
842
 
843
- $last_order = (int) $wpdb->get_var( $wpdb->prepare(
844
- "SELECT MAX(menu_order)
 
845
  FROM {$wpdb->posts}
846
  WHERE post_parent = %d;
847
  ",
848
- $topic_ID
849
- ) );
 
850
 
851
- return is_numeric( $last_order ) ? $last_order+1 : 0;
852
  }
853
 
854
  /**
@@ -864,7 +891,7 @@ class Utils {
864
  public function get_lessons_by_topic( $topics_id = 0, $limit = 10 ) {
865
  $topics_id = $this->get_post_id( $topics_id );
866
  $lesson_post_type = tutor()->lesson_post_type;
867
-
868
  $args = array(
869
  'post_type' => $lesson_post_type,
870
  'post_parent' => $topics_id,
@@ -889,7 +916,7 @@ class Utils {
889
  * @since v.1.0.0
890
  */
891
  public function get_course_contents_by_topic( $topics_id = 0, $limit = 10 ) {
892
- $topics_id = $this->get_post_id($topics_id);
893
  $lesson_post_type = tutor()->lesson_post_type;
894
  $post_type = apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) );
895
 
@@ -915,11 +942,11 @@ class Utils {
915
  */
916
  public function checking_nonce( $request_method = 'post' ) {
917
 
918
- $data = $request_method === 'post' ? $_POST : $_GET;
919
- $nonce_value = sanitize_text_field(tutils()->array_get(tutor()->nonce, $data, null));
920
- $matched = $nonce_value && wp_verify_nonce( $nonce_value, tutor()->nonce_action );
921
 
922
- ! $matched ? exit( __('Nonce not matched', 'tutor') ) : 0;
923
  }
924
 
925
  /**
@@ -957,7 +984,7 @@ class Utils {
957
  $course_id = $this->get_post_id( $course_id );
958
 
959
  if ( $this->is_course_purchasable() ) {
960
- $monetize_by = $this->get_option('monetize_by');
961
 
962
  if ( $this->has_wc() && $monetize_by === 'wc' ) {
963
  $product_id = tutor_utils()->get_course_product_id( $course_id );
@@ -993,7 +1020,7 @@ class Utils {
993
  'sale_price' => 0,
994
  );
995
 
996
- $monetize_by = $this->get_option('monetize_by');
997
 
998
  $product_id = $this->get_course_product_id( $course_id );
999
  if ( $product_id ) {
@@ -1042,8 +1069,9 @@ class Utils {
1042
 
1043
  do_action( 'tutor_is_enrolled_before', $course_id, $user_id );
1044
 
1045
- $getEnrolledInfo = $wpdb->get_row( $wpdb->prepare(
1046
- "SELECT ID,
 
1047
  post_author,
1048
  post_date,
1049
  post_date_gmt,
@@ -1054,11 +1082,12 @@ class Utils {
1054
  AND post_author = %d
1055
  AND post_status = %s;
1056
  ",
1057
- 'tutor_enrolled',
1058
- $course_id,
1059
- $user_id,
1060
- 'completed'
1061
- ) );
 
1062
 
1063
  if ( $getEnrolledInfo ) {
1064
  return apply_filters( 'tutor_is_enrolled', $getEnrolledInfo, $course_id, $user_id );
@@ -1083,29 +1112,32 @@ class Utils {
1083
  $user_id = $this->get_user_id( $user_id );
1084
 
1085
  // Delete Quiz submissions
1086
- $attempts = $this->get_quiz_attempts_by_course_ids( $start = 0, $limit = 99999999, $course_ids = array($course_id), $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $user_id = $user_id );
1087
-
1088
- if( is_array($attempts) ) {
1089
- $attempt_ids = array_map(function($attempt) {
1090
- return is_object($attempt) ? $attempt->attempt_id : 0;
1091
- }, $attempts);
 
 
 
1092
 
1093
- $this->delete_quiz_attempt($attempt_ids);
1094
  }
1095
 
1096
  // Delete Course completion row
1097
  $del_where = array(
1098
- 'user_id' => $user_id,
1099
  'comment_post_ID' => $course_id,
1100
- 'comment_type' => 'course_completed',
1101
- 'comment_agent' => 'TutorLMSPlugin',
1102
  );
1103
- $wpdb->delete($wpdb->comments, $del_where);
1104
 
1105
  // Delete Completed lesson count
1106
- $lesson_ids = $this->get_course_content_ids_by(tutor()->lesson_post_type, tutor()->course_post_type, $course_id);
1107
- foreach($lesson_ids as $id) {
1108
- delete_user_meta( $user_id, '_tutor_completed_lesson_id_'.$id );
1109
  }
1110
 
1111
  // Delete other addon-wise stuffs by hook, specially assignment.
@@ -1129,21 +1161,23 @@ class Utils {
1129
  if ( is_user_logged_in() ) {
1130
  global $wpdb;
1131
 
1132
- $getEnrolledInfo = $wpdb->get_row( $wpdb->prepare(
1133
- "SELECT ID,
 
1134
  post_author,
1135
  post_date,
1136
  post_date_gmt,
1137
  post_title
1138
  FROM {$wpdb->posts}
1139
- WHERE post_type = %s
1140
  AND post_parent = %d
1141
  AND post_author = %d;
1142
  ",
1143
- 'tutor_enrolled',
1144
- $course_id,
1145
- $user_id
1146
- ) );
 
1147
 
1148
  if ( $getEnrolledInfo ) {
1149
  return $getEnrolledInfo;
@@ -1154,37 +1188,39 @@ class Utils {
1154
  }
1155
 
1156
 
1157
- /**
1158
- * @param int $enrol_id
1159
- * @return array|bool|\WP_Post|null
1160
- *
1161
- * Get course by enrol id
1162
- *
1163
- * @since v.1.6.1
1164
- */
1165
  public function get_course_by_enrol_id( $enrol_id = 0 ) {
1166
- if ( ! $enrol_id ) {
1167
- return false;
1168
- }
1169
 
1170
- global $wpdb;
1171
 
1172
- $course_id = (int) $wpdb->get_var( $wpdb->prepare(
1173
- "SELECT post_parent
 
1174
  FROM {$wpdb->posts}
1175
  WHERE post_type = %s
1176
  AND ID = %d
1177
  ",
1178
- 'tutor_enrolled',
1179
- $enrol_id
1180
- ) );
 
1181
 
1182
- if ( $course_id ) {
1183
- return get_post( $course_id );
1184
- }
1185
 
1186
- return null;
1187
- }
1188
 
1189
  /**
1190
  * @param int $lesson_id
@@ -1218,7 +1254,7 @@ class Utils {
1218
  */
1219
  public function get_course_id_by_lesson( $lesson_id = 0 ) {
1220
  $lesson_id = $this->get_post_id( $lesson_id );
1221
- $course_id = tutor_utils()->get_course_id_by('lesson', $lesson_id);
1222
 
1223
  if ( ! $course_id ) {
1224
  $course_id = $this->get_course_id_by_content( $lesson_id );
@@ -1239,33 +1275,35 @@ class Utils {
1239
  *
1240
  * @since v.1.0.0
1241
  */
1242
- public function get_course_first_lesson( $course_id = 0, $post_type=null ) {
1243
  global $wpdb;
1244
 
1245
  $course_id = $this->get_post_id( $course_id );
1246
  $user_id = get_current_user_id();
1247
 
1248
- $lessons = $wpdb->get_results( $wpdb->prepare(
1249
- "SELECT items.ID
 
1250
  FROM {$wpdb->posts} topic
1251
  INNER JOIN {$wpdb->posts} items
1252
  ON topic.ID = items.post_parent
1253
  WHERE topic.post_parent = %d
1254
  AND items.post_status = %s
1255
- ".( $post_type ? " AND items.post_type='{$post_type}' " : "")."
1256
  ORDER BY topic.menu_order ASC,
1257
  items.menu_order ASC;
1258
- ",
1259
- $course_id,
1260
- 'publish'
1261
- ) );
 
1262
 
1263
  $first_lesson = false;
1264
 
1265
  if ( tutils()->count( $lessons ) ) {
1266
- if ( ! empty( $lessons[0] ) ) {
1267
- $first_lesson = $lessons[0];
1268
- }
1269
 
1270
  foreach ( $lessons as $lesson ) {
1271
  $is_complete = get_user_meta( $user_id, "_tutor_completed_lesson_id_{$lesson->ID}", true );
@@ -1275,7 +1313,7 @@ class Utils {
1275
  }
1276
  }
1277
 
1278
- if ( ! empty($first_lesson->ID) ) {
1279
  return get_permalink( $first_lesson->ID );
1280
  }
1281
  }
@@ -1291,8 +1329,8 @@ class Utils {
1291
  */
1292
  public function course_sub_pages() {
1293
  $nav_items = array(
1294
- 'questions' => __('Q&A', 'tutor'),
1295
- 'announcements' => __('Announcements', 'tutor'),
1296
  );
1297
 
1298
  return apply_filters( 'tutor_course/single/enrolled/nav_items', $nav_items );
@@ -1315,7 +1353,7 @@ class Utils {
1315
  }
1316
 
1317
  /**
1318
- * @param int $post_id
1319
  * @param array $video_data
1320
  *
1321
  * @return bool
@@ -1342,28 +1380,31 @@ class Utils {
1342
  $attachments = maybe_unserialize( get_post_meta( $post_id, '_tutor_attachments', true ) );
1343
  $attachments_arr = array();
1344
 
1345
- $font_icons = apply_filters( 'tutor_file_types_icon', array(
1346
- 'archive',
1347
- 'audio',
1348
- 'code',
1349
- 'default',
1350
- 'document',
1351
- 'interactive',
1352
- 'spreadsheet',
1353
- 'text',
1354
- 'video',
1355
- 'image',
1356
- ));
 
 
 
1357
 
1358
  if ( is_array( $attachments ) && count( $attachments ) ) {
1359
  foreach ( $attachments as $attachment ) {
1360
  $url = wp_get_attachment_url( $attachment );
1361
  $file_type = wp_check_filetype( $url );
1362
  $ext = $file_type['ext'];
1363
- $title = get_the_title($attachment);
1364
 
1365
  $file_path = get_attached_file( $attachment );
1366
- $size_bytes = file_exists($file_path) ? filesize( $file_path ) : 0;
1367
  $size = size_format( $size_bytes, 2 );
1368
  $type = wp_ext2type( $ext );
1369
 
@@ -1402,12 +1443,12 @@ class Utils {
1402
  * @since v.1.0.0
1403
  */
1404
  public function playtime_string( $seconds ) {
1405
- $sign = ( ( $seconds < 0 ) ? '-' : '' );
1406
  $seconds = round( abs( $seconds ) );
1407
- $H = (int) floor( $seconds / 3600);
1408
- $M = (int) floor( ($seconds - (3600 * $H) ) / 60 );
1409
- $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
1410
- return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
1411
  }
1412
 
1413
  /**
@@ -1426,21 +1467,21 @@ class Utils {
1426
  'seconds' => '00',
1427
  );
1428
 
1429
- if ($seconds <= 0 ) {
1430
  return $run_time_format;
1431
  }
1432
 
1433
  $playTimeString = $this->playtime_string( $seconds );
1434
  $timeInArray = explode( ':', $playTimeString );
1435
 
1436
- $run_time_size = count($timeInArray);
1437
  if ( $run_time_size === 3 ) {
1438
- $run_time_format[ 'hours' ] = $timeInArray[0];
1439
- $run_time_format[ 'minutes' ] = $timeInArray[1];
1440
- $run_time_format[ 'seconds' ] = $timeInArray[2];
1441
  } elseif ( $run_time_size === 2 ) {
1442
- $run_time_format[ 'minutes' ] = $timeInArray[0];
1443
- $run_time_format[ 'seconds' ] = $timeInArray[1];
1444
  }
1445
 
1446
  return $run_time_format;
@@ -1456,13 +1497,13 @@ class Utils {
1456
  * @since v.1.0.0
1457
  */
1458
  public function seconds_to_time_context( $seconds ) {
1459
- $sign = ( ($seconds < 0) ? '-' : '');
1460
  $seconds = round( abs( $seconds ) );
1461
- $H = (int) floor( $seconds / 3600);
1462
- $M = (int) floor( ($seconds - (3600 * $H) ) / 60 );
1463
- $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
1464
 
1465
- return $sign.($H ? $H.'h ' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).'m '.str_pad($S, 2, 0, STR_PAD_LEFT).'s';
1466
  }
1467
 
1468
  /**
@@ -1484,15 +1525,22 @@ class Utils {
1484
  'playtime' => '00:00',
1485
  );
1486
 
1487
- $types = apply_filters( 'tutor_video_types', array( "mp4" => "video/mp4", "webm" => "video/webm", "ogg" => "video/ogg" ) );
 
 
 
 
 
 
 
1488
 
1489
- $videoSource = $this->avalue_dot('source', $video);
1490
 
1491
  if ( $videoSource === 'html5' ) {
1492
  $sourceVideoID = $this->avalue_dot( 'source_video_id', $video );
1493
  $video_info = get_post_meta( $sourceVideoID, '_wp_attachment_metadata', true );
1494
 
1495
- if ( $video_info && in_array( $this->array_get('mime_type', $video_info), $types ) ) {
1496
  $path = get_attached_file( $sourceVideoID );
1497
  $info['playtime'] = $video_info['length_formatted'];
1498
  $info['path'] = $path;
@@ -1521,7 +1569,8 @@ class Utils {
1521
  }
1522
 
1523
  public function get_optimized_duration( $duration ) {
1524
- /* if(is_string($duration)){
 
1525
  strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove Empty hour
1526
  strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove empty minute
1527
  } */
@@ -1555,7 +1604,7 @@ class Utils {
1555
  *
1556
  * return lesson type icon
1557
  *
1558
- * @param int $lesson_id
1559
  * @param bool $html
1560
  * @param bool $echo
1561
  *
@@ -1579,7 +1628,7 @@ class Utils {
1579
  }
1580
 
1581
  if ( $echo ) {
1582
- echo $tutor_lesson_type_icon;
1583
  }
1584
 
1585
  return $tutor_lesson_type_icon;
@@ -1596,7 +1645,7 @@ class Utils {
1596
  public function is_completed_lesson( $lesson_id = 0, $user_id = 0 ) {
1597
  $lesson_id = $this->get_post_id( $lesson_id );
1598
  $user_id = $this->get_user_id( $user_id );
1599
- $is_completed = get_user_meta( $user_id, '_tutor_completed_lesson_id_'.$lesson_id, true );
1600
 
1601
  if ( $is_completed ) {
1602
  return $is_completed;
@@ -1618,28 +1667,30 @@ class Utils {
1618
  * @updated v.1.4.9
1619
  */
1620
  public function is_completed_course( $course_id = 0, $user_id = 0 ) {
1621
-
1622
  global $wpdb;
1623
- $course_id = $this->get_post_id($course_id);
1624
- $user_id = $this->get_user_id($user_id);
1625
-
1626
- $is_completed = $wpdb->get_row( $wpdb->prepare(
1627
- "SELECT comment_ID,
1628
- comment_post_ID AS course_id,
1629
- comment_author AS completed_user_id,
1630
- comment_date AS completion_date,
1631
- comment_content AS completed_hash
1632
- FROM {$wpdb->comments}
1633
- WHERE comment_agent = %s
1634
- AND comment_type = %s
1635
- AND comment_post_ID = %d
 
1636
  AND user_id = %d;
1637
  ",
1638
- 'TutorLMSPlugin',
1639
- 'course_completed',
1640
- $course_id,
1641
- $user_id
1642
- ) );
 
1643
 
1644
  if ( $is_completed ) {
1645
  return apply_filters( 'is_completed_course', $is_completed, $course_id, $user_id );
@@ -1662,12 +1713,12 @@ class Utils {
1662
 
1663
  if ( is_array( $input ) && count( $input ) ) {
1664
  foreach ( $input as $key => $value ) {
1665
- if ( is_array( $value )) {
1666
- $array[$key] = $this->sanitize_array( $value );
1667
  } else {
1668
- $key = sanitize_text_field( $key );
1669
- $value = sanitize_text_field( $value );
1670
- $array[$key] = $value;
1671
  }
1672
  }
1673
  }
@@ -1687,16 +1738,16 @@ class Utils {
1687
  public function has_video_in_single( $post_id = 0 ) {
1688
  if ( is_single() ) {
1689
  $post_id = $this->get_post_id( $post_id );
1690
-
1691
  $video = $this->get_video( $post_id );
1692
  if ( $video && $this->array_get( 'source', $video ) !== '-1' ) {
1693
-
1694
- $not_empty =!empty( $video[ 'source_video_id' ] ) ||
1695
- !empty( $video[ 'source_external_url' ] ) ||
1696
- !empty( $video[ 'source_youtube' ] ) ||
1697
- !empty( $video[ 'source_vimeo' ] ) ||
1698
- !empty( $video[ 'source_embedded' ] );
1699
-
1700
  return $not_empty ? $video : false;
1701
  }
1702
  }
@@ -1704,10 +1755,10 @@ class Utils {
1704
  }
1705
 
1706
  /**
1707
- * @param int $start
1708
- * @param int $limit
1709
  * @param string $search_term
1710
- * @param int $course_id
1711
  *
1712
  * @return array|null|object
1713
  *
@@ -1723,8 +1774,9 @@ class Utils {
1723
 
1724
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
1725
 
1726
- $students = $wpdb->get_results( $wpdb->prepare(
1727
- "SELECT SQL_CALC_FOUND_ROWS {$wpdb->users}.*
 
1728
  FROM {$wpdb->users}
1729
  INNER JOIN {$wpdb->usermeta}
1730
  ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
@@ -1733,10 +1785,11 @@ class Utils {
1733
  ORDER BY {$wpdb->usermeta}.meta_value DESC
1734
  LIMIT {$start}, {$limit};
1735
  ",
1736
- '_is_tutor_student',
1737
- $search_term,
1738
- $search_term
1739
- ) );
 
1740
 
1741
  return $students;
1742
  }
@@ -1756,18 +1809,20 @@ class Utils {
1756
 
1757
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
1758
 
1759
- $count = $wpdb->get_var( $wpdb->prepare(
1760
- "SELECT COUNT({$wpdb->users}.ID)
 
1761
  FROM {$wpdb->users}
1762
  INNER JOIN {$wpdb->usermeta}
1763
  ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
1764
  WHERE {$wpdb->usermeta}.meta_key = %s
1765
  AND ( {$wpdb->users}.display_name LIKE %s OR {$wpdb->users}.user_email LIKE %s );
1766
  ",
1767
- '_is_tutor_student',
1768
- $search_term,
1769
- $search_term
1770
- ) );
 
1771
 
1772
  return (int) $count;
1773
  }
@@ -1786,17 +1841,19 @@ class Utils {
1786
 
1787
  $user_id = $this->get_user_id( $user_id );
1788
 
1789
- $course_ids = (array) $wpdb->get_col( $wpdb->prepare(
1790
- "SELECT comment_post_ID AS course_id
1791
- FROM {$wpdb->comments}
1792
- WHERE comment_agent = %s
 
1793
  AND comment_type = %s
1794
  AND user_id = %d
1795
  ",
1796
- 'TutorLMSPlugin',
1797
- 'course_completed',
1798
- $user_id
1799
- ) );
 
1800
 
1801
  return $course_ids;
1802
  }
@@ -1814,13 +1871,13 @@ class Utils {
1814
  $user_id = $this->get_user_id( $user_id );
1815
  $course_ids = $this->get_completed_courses_ids_by_user( $user_id );
1816
 
1817
- if ( count($course_ids) ) {
1818
  $course_post_type = tutor()->course_post_type;
1819
- $course_args = array(
1820
  'post_type' => $course_post_type,
1821
  'post_status' => 'publish',
1822
  'post__in' => $course_ids,
1823
- 'posts_per_page' => -1
1824
  );
1825
 
1826
  return new \WP_Query( $course_args );
@@ -1846,11 +1903,11 @@ class Utils {
1846
 
1847
  if ( count( $active_courses ) ) {
1848
  $course_post_type = tutor()->course_post_type;
1849
- $course_args = array(
1850
  'post_type' => $course_post_type,
1851
  'post_status' => 'publish',
1852
  'post__in' => $active_courses,
1853
- 'posts_per_page' => -1,
1854
  );
1855
 
1856
  return new \WP_Query( $course_args );
@@ -1870,61 +1927,65 @@ class Utils {
1870
  */
1871
  public function get_enrolled_courses_ids_by_user( $user_id = 0 ) {
1872
  global $wpdb;
1873
- $user_id = $this->get_user_id( $user_id );
1874
- $course_ids = $wpdb->get_col( $wpdb->prepare(
1875
- "SELECT DISTINCT post_parent
 
1876
  FROM {$wpdb->posts}
1877
  WHERE post_type = %s
1878
  AND post_status = %s
1879
  AND post_author = %d;
1880
  ",
1881
- 'tutor_enrolled',
1882
- 'completed',
1883
- $user_id
1884
- ) );
 
1885
 
1886
  return $course_ids;
1887
  }
1888
 
1889
  /**
1890
  * Get total enrolled students by course id
1891
- *
1892
- * @param int $course_id
1893
  *
1894
  * @param $period string | optional added since 1.9.9
1895
- *
1896
  * @return int
1897
- *
1898
  * @since 1.9.9
1899
  */
1900
- public function count_enrolled_users_by_course( $course_id = 0 , $period = '') {
1901
  global $wpdb;
1902
 
1903
  $course_id = $this->get_post_id( $course_id );
1904
- //set period wise query
1905
  $period_filter = '';
1906
  if ( 'today' === $period ) {
1907
- $period_filter = "AND DATE(post_date) = CURDATE()";
1908
- }
1909
  if ( 'monthly' === $period ) {
1910
- $period_filter = "AND MONTH(post_date) = MONTH(CURDATE()) ";
1911
  }
1912
  if ( 'yearly' === $period ) {
1913
- $period_filter = "AND YEAR(post_date) = YEAR(CURDATE()) ";
1914
  }
1915
 
1916
- $course_ids = $wpdb->get_var($wpdb->prepare(
1917
- "SELECT COUNT(ID)
1918
- FROM {$wpdb->posts}
 
1919
  WHERE post_type = %s
1920
  AND post_status = %s
1921
  AND post_parent = %d;
1922
  {$period_filter}
1923
  ",
1924
- 'tutor_enrolled',
1925
- 'completed',
1926
- $course_id
1927
- ) );
 
1928
 
1929
  return (int) $course_ids;
1930
  }
@@ -1936,19 +1997,19 @@ class Utils {
1936
  *
1937
  * Get the enrolled courses by user
1938
  */
1939
- public function get_enrolled_courses_by_user( $user_id = 0, $post_status='publish' ) {
1940
  global $wpdb;
1941
 
1942
- $user_id = $this->get_user_id( $user_id );
1943
  $course_ids = $this->get_enrolled_courses_ids_by_user( $user_id );
1944
 
1945
  if ( count( $course_ids ) ) {
1946
  $course_post_type = tutor()->course_post_type;
1947
- $course_args = array(
1948
  'post_type' => $course_post_type,
1949
  'post_status' => $post_status,
1950
  'post__in' => $course_ids,
1951
- 'posts_per_page' => -1
1952
  );
1953
  return new \WP_Query( $course_args );
1954
  }
@@ -1971,7 +2032,7 @@ class Utils {
1971
  $video_url = trailingslashit( home_url() ) . 'video-url/' . $post->post_name;
1972
  } else {
1973
  $video_info = tutor_utils()->get_video_info( $post_id );
1974
- $video_url = $video_info->url;
1975
  }
1976
 
1977
  return $video_url;
@@ -1989,7 +2050,7 @@ class Utils {
1989
  */
1990
  public function get_lesson_reading_info_full( $lesson_id = 0, $user_id = 0 ) {
1991
  $lesson_id = $this->get_post_id( $lesson_id );
1992
- $user_id = $this->get_user_id( $user_id );
1993
 
1994
  $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
1995
  return $this->avalue_dot( $lesson_id, $lesson_info );
@@ -2004,7 +2065,7 @@ class Utils {
2004
  *
2005
  * @since v.1.0.0
2006
  */
2007
- public function get_post_id( $post_id = 0) {
2008
  if ( ! $post_id ) {
2009
  $post_id = get_the_ID();
2010
  if ( ! $post_id ) {
@@ -2025,7 +2086,7 @@ class Utils {
2025
  * @since v.1.0.0
2026
  */
2027
  public function get_user_id( $user_id = 0 ) {
2028
- if ( ! $user_id) {
2029
  $user_id = get_current_user_id();
2030
  if ( ! $user_id ) {
2031
  return false;
@@ -2036,8 +2097,8 @@ class Utils {
2036
  }
2037
 
2038
  /**
2039
- * @param int $lesson_id
2040
- * @param int $user_id
2041
  * @param string $key
2042
  *
2043
  * @return array|bool|mixed
@@ -2051,12 +2112,12 @@ class Utils {
2051
  $user_id = $this->get_user_id( $user_id );
2052
  $lesson_info = $this->get_lesson_reading_info_full( $lesson_id, $user_id );
2053
 
2054
- return $this->avalue_dot($key, $lesson_info);
2055
  }
2056
 
2057
  /**
2058
- * @param int $lesson_id
2059
- * @param int $user_id
2060
  * @param array $data
2061
  *
2062
  * @return bool
@@ -2066,11 +2127,11 @@ class Utils {
2066
  * @since v.1.0.0
2067
  */
2068
  public function update_lesson_reading_info( $lesson_id = 0, $user_id = 0, $key = '', $value = '' ) {
2069
- $lesson_id = $this->get_post_id($lesson_id);
2070
- $user_id = $this->get_user_id($user_id);
2071
 
2072
  if ( $key && $value ) {
2073
- $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
2074
  $lesson_info[ $lesson_id ][ $key ] = $value;
2075
  update_user_meta( $user_id, '_lesson_reading_info', $lesson_info );
2076
  }
@@ -2085,7 +2146,7 @@ class Utils {
2085
  *
2086
  * @since v.1.0.0
2087
  */
2088
- public function get_youtube_video_id( $url = '') {
2089
  if ( ! $url ) {
2090
  return false;
2091
  }
@@ -2110,7 +2171,7 @@ class Utils {
2110
  * @since v.1.0.0
2111
  */
2112
  public function get_vimeo_video_id( $url = '' ) {
2113
- if ( preg_match('%^https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)(?:[?]?.*)$%im', $url, $match ) ) {
2114
  if ( isset( $match[3] ) ) {
2115
  return $match[3];
2116
  }
@@ -2130,7 +2191,7 @@ class Utils {
2130
  $user_id = $this->get_user_id( $user_id );
2131
 
2132
  do_action( 'tutor_mark_lesson_complete_before', $post_id, $user_id );
2133
- update_user_meta( $user_id, '_tutor_completed_lesson_id_'.$post_id, tutor_time() );
2134
  do_action( 'tutor_mark_lesson_complete_after', $post_id, $user_id );
2135
  }
2136
 
@@ -2159,11 +2220,11 @@ class Utils {
2159
 
2160
  do_action( 'tutor_before_enroll', $course_id );
2161
  $user_id = $this->get_user_id( $user_id );
2162
- $title = __( 'Course Enrolled', 'tutor')." &ndash; ".date( get_option('date_format') ) .' @ '.date(get_option('time_format') ) ;
2163
 
2164
  if ( $course_id && $user_id ) {
2165
  if ( $this->is_enrolled( $course_id, $user_id ) ) {
2166
- return ;
2167
  }
2168
  }
2169
 
@@ -2176,13 +2237,14 @@ class Utils {
2176
  $enrolment_status = 'pending';
2177
  }
2178
 
2179
- $enroll_data = apply_filters( 'tutor_enroll_data',
 
2180
  array(
2181
- 'post_type' => 'tutor_enrolled',
2182
- 'post_title' => $title,
2183
- 'post_status' => $enrolment_status,
2184
- 'post_author' => $user_id,
2185
- 'post_parent' => $course_id,
2186
  )
2187
  );
2188
 
@@ -2194,20 +2256,20 @@ class Utils {
2194
  do_action( 'tutor_after_enroll', $course_id, $isEnrolled );
2195
 
2196
  // Run this hook for completed enrollment regardless of payment provider and free/paid mode
2197
- if( $enroll_data['post_status'] == 'completed' ) {
2198
- do_action('tutor_after_enrolled', $course_id, $user_id, $isEnrolled);
2199
  }
2200
 
2201
- //Mark Current User as Students with user meta data
2202
  update_user_meta( $user_id, '_is_tutor_student', tutor_time() );
2203
 
2204
  if ( $order_id ) {
2205
- //Mark order for course and user
2206
  $product_id = $this->get_course_product_id( $course_id );
2207
  update_post_meta( $isEnrolled, '_tutor_enrolled_by_order_id', $order_id );
2208
  update_post_meta( $isEnrolled, '_tutor_enrolled_by_product_id', $product_id );
2209
  update_post_meta( $order_id, '_is_tutor_order_for_course', tutor_time() );
2210
- update_post_meta( $order_id, '_tutor_order_for_course_id_'.$course_id, $isEnrolled );
2211
  }
2212
  return true;
2213
  }
@@ -2215,61 +2277,76 @@ class Utils {
2215
  return false;
2216
  }
2217
 
2218
- /**
2219
- * @param bool $enrol_id
2220
- * @param string $new_status
2221
- *
2222
- * Enrol Status change
2223
- *
2224
- * @since v.1.6.1
2225
- */
2226
  public function course_enrol_status_change( $enrol_id = false, $new_status = '' ) {
2227
- if ( ! $enrol_id ) {
2228
- return;
2229
- }
2230
-
2231
- global $wpdb;
2232
-
2233
- do_action( 'tutor/course/enrol_status_change/before',$enrol_id, $new_status );
2234
- $wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $enrol_id ) );
2235
- do_action( 'tutor/course/enrol_status_change/after',$enrol_id, $new_status );
2236
- }
2237
-
2238
- /**
2239
- * @param int $course_id
2240
- * @param int $user_id
2241
- * @param string $cancel_status
2242
- */
2243
  public function cancel_course_enrol( $course_id = 0, $user_id = 0, $cancel_status = 'canceled' ) {
2244
- $course_id = $this->get_post_id( $course_id );
2245
- $user_id = $this->get_user_id( $user_id );
2246
- $enrolled = $this->is_enrolled($course_id, $user_id);
2247
-
2248
- if ( $enrolled ) {
2249
- global $wpdb;
2250
-
2251
- if ( $cancel_status === 'delete') {
2252
- $wpdb->delete( $wpdb->posts, array( 'post_type' => 'tutor_enrolled', 'post_author' => $user_id, 'post_parent' => $course_id ) );
2253
-
2254
- //Delete Related Meta Data
2255
- delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_product_id' );
2256
- $order_id = get_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id', true );
2257
- if ( $order_id ) {
2258
- delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id' );
2259
- delete_post_meta( $order_id, '_is_tutor_order_for_course' );
2260
- delete_post_meta( $order_id, '_tutor_order_for_course_id_'.$course_id );
2261
-
 
 
 
 
 
 
 
2262
  do_action( 'tutor_enrollment/after/delete', $enrolled->ID );
2263
- }
2264
- } else {
2265
- $wpdb->update( $wpdb->posts, array( 'post_status' => $cancel_status), array('post_type' => 'tutor_enrolled', 'post_author' => $user_id, 'post_parent' => $course_id ) );
2266
-
 
 
 
 
 
 
 
 
2267
  if ( $cancel_status === 'cancel' ) {
2268
  do_action( 'tutor_enrollment/after/cancel', $enrolled->ID );
2269
  }
2270
  }
2271
- }
2272
- }
2273
 
2274
  /**
2275
  * @param $order_id
@@ -2307,24 +2384,26 @@ class Utils {
2307
  public function get_course_enrolled_ids_by_order_id( $order_id ) {
2308
  global $wpdb;
2309
 
2310
- //Getting all of courses ids within this order
2311
- $courses_ids = $wpdb->get_results( $wpdb->prepare(
2312
- "SELECT *
 
2313
  FROM {$wpdb->postmeta}
2314
- WHERE post_id = %d
2315
  AND meta_key LIKE '_tutor_order_for_course_id_%'
2316
- ",
2317
- $order_id
2318
- ) );
 
2319
 
2320
  if ( is_array( $courses_ids ) && count( $courses_ids ) ) {
2321
  $course_enrolled_by_order = array();
2322
  foreach ( $courses_ids as $courses_id ) {
2323
- $course_id = str_replace( '_tutor_order_for_course_id_', '',$courses_id->meta_key );
2324
  $course_enrolled_by_order[] = array(
2325
  'course_id' => $course_id,
2326
  'enrolled_id' => $courses_id->meta_value,
2327
- 'order_id' => $courses_id->post_id
2328
  );
2329
  }
2330
  return $course_enrolled_by_order;
@@ -2345,16 +2424,18 @@ class Utils {
2345
  */
2346
  public function get_wc_products_db() {
2347
  global $wpdb;
2348
- $query = $wpdb->get_results( $wpdb->prepare(
2349
- "SELECT ID,
 
2350
  post_title
2351
  FROM {$wpdb->posts}
2352
  WHERE post_status = %s
2353
  AND post_type = %s;
2354
  ",
2355
- 'publish',
2356
- 'product'
2357
- ) );
 
2358
 
2359
  return $query;
2360
  }
@@ -2366,16 +2447,18 @@ class Utils {
2366
  */
2367
  public function get_edd_products() {
2368
  global $wpdb;
2369
- $query = $wpdb->get_results( $wpdb->prepare(
2370
- "SELECT ID,
 
2371
  post_title
2372
  FROM {$wpdb->posts}
2373
  WHERE post_status = %s
2374
  AND post_type = %s;
2375
  ",
2376
- 'publish',
2377
- 'download'
2378
- ) );
 
2379
 
2380
  return $query;
2381
  }
@@ -2408,17 +2491,19 @@ class Utils {
2408
  public function product_belongs_with_course( $product_id = 0 ) {
2409
  global $wpdb;
2410
 
2411
- $query = $wpdb->get_row( $wpdb->prepare(
2412
- "SELECT *
 
2413
  FROM {$wpdb->postmeta}
2414
- WHERE meta_key = %s
2415
- AND meta_value = %d
2416
  limit 1
2417
  ",
2418
- '_tutor_course_product_id',
2419
- $product_id
2420
- ) );
2421
-
 
2422
  return $query;
2423
  }
2424
 
@@ -2430,7 +2515,7 @@ class Utils {
2430
  public function get_enrolled_statuses() {
2431
  return apply_filters(
2432
  'tutor_get_enrolled_statuses',
2433
- array (
2434
  'pending',
2435
  'processing',
2436
  'on-hold',
@@ -2463,25 +2548,54 @@ class Utils {
2463
  * @since v.1.0.0
2464
  */
2465
  public function tutor_dashboard_pages() {
2466
- $nav_items = apply_filters( 'tutor_dashboard/nav_items', array(
2467
- 'index' => __( 'Dashboard', 'tutor' ),
2468
- 'my-profile' => __( 'My Profile', 'tutor' ),
2469
- 'enrolled-courses' => __( 'Enrolled Courses', 'tutor' ),
2470
- 'wishlist' => __( 'Wishlist', 'tutor' ),
2471
- 'reviews' => __( 'Reviews', 'tutor' ),
2472
- 'my-quiz-attempts' => __( 'My Quiz Attempts', 'tutor' ),
2473
- 'purchase_history' => __( 'Purchase History', 'tutor' ),
2474
- ));
2475
-
2476
- $instructor_nav_items = apply_filters( 'tutor_dashboard/instructor_nav_items', array(
2477
- 'separator-1' => array( 'title' => __( 'Instructor', 'tutor'), 'auth_cap' => tutor()->instructor_role, 'type' => 'separator' ),
2478
- 'create-course' => array( 'title' => __( 'Create Course', 'tutor'), 'show_ui' => false, 'auth_cap' => tutor()->instructor_role ),
2479
- 'my-courses' => array( 'title' => __( 'My Courses', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2480
- 'announcements' => array( 'title' => __( 'Announcements', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2481
- 'withdraw' => array( 'title' => __( 'Withdrawals', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2482
- 'quiz-attempts' => array( 'title' => __( 'Quiz Attempts', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2483
- 'question-answer' => array( 'title' => __( 'Question & Answer', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2484
- ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2485
 
2486
  $disable = get_tutor_option( 'disable_course_review' );
2487
  if ( $disable && isset( $nav_items['reviews'] ) ) {
@@ -2490,11 +2604,17 @@ class Utils {
2490
 
2491
  $nav_items = array_merge( $nav_items, $instructor_nav_items );
2492
 
2493
- $new_navs = apply_filters( 'tutor_dashboard/bottom_nav_items', array(
2494
- 'separator-2' => array( 'title' => '', 'type' => 'separator' ),
2495
- 'settings' => __( 'Settings', 'tutor' ),
2496
- 'logout' => __( 'Logout', 'tutor' ),
2497
- ));
 
 
 
 
 
 
2498
  $all_nav_items = array_merge( $nav_items, $new_navs );
2499
 
2500
  return apply_filters( 'tutor_dashboard/nav_items_all', $all_nav_items );
@@ -2503,9 +2623,15 @@ class Utils {
2503
  public function tutor_dashboard_permalinks() {
2504
  $dashboard_pages = $this->tutor_dashboard_pages();
2505
 
2506
- $dashboard_permalinks = apply_filters( 'tutor_dashboard/permalinks', array(
2507
- 'retrieve-password' => array( 'title' => __( 'Retrieve Password', 'tutor' ), 'login_require' => false ),
2508
- ));
 
 
 
 
 
 
2509
 
2510
  $dashboard_pages = array_merge( $dashboard_pages, $dashboard_permalinks );
2511
 
@@ -2524,23 +2650,23 @@ class Utils {
2524
  $nav_items = $this->tutor_dashboard_pages();
2525
 
2526
  foreach ( $nav_items as $key => $nav_item ) {
2527
- if ( is_array($nav_item) ) {
2528
 
2529
  if ( isset( $nav_item['show_ui'] ) && ! tutor_utils()->array_get( 'show_ui', $nav_item ) ) {
2530
  unset( $nav_items[ $key ] );
2531
  }
2532
- if ( isset($nav_item['auth_cap'] ) && ! current_user_can( $nav_item['auth_cap'] ) ) {
2533
  unset( $nav_items[ $key ] );
2534
  }
2535
  }
2536
  }
2537
 
2538
- return apply_filters('tutor_dashboard/nav_ui_items', $nav_items);
2539
  }
2540
 
2541
  /**
2542
  * @param string $page_key
2543
- * @param int $page_id
2544
  *
2545
  * @return string
2546
  *
@@ -2553,8 +2679,8 @@ class Utils {
2553
  $page_key = '';
2554
  }
2555
  if ( ! $page_id ) {
2556
- $page_id = (int) tutils()->get_option( 'tutor_dashboard_page_id' );
2557
- }
2558
  return trailingslashit( get_permalink( $page_id ) ) . $page_key;
2559
  }
2560
 
@@ -2570,7 +2696,7 @@ class Utils {
2570
  */
2571
  public function input_old( $input = '', $old_data = null ) {
2572
  if ( ! $old_data ) {
2573
- $old_data = $_REQUEST;
2574
  }
2575
  $value = $this->avalue_dot( $input, $old_data );
2576
  if ( $value ) {
@@ -2595,7 +2721,7 @@ class Utils {
2595
  }
2596
 
2597
  /**
2598
- * @param int $user_id
2599
  * @param bool $status_name
2600
  *
2601
  * @return bool|mixed
@@ -2607,19 +2733,22 @@ class Utils {
2607
  public function instructor_status( $user_id = 0, $status_name = true ) {
2608
  $user_id = $this->get_user_id( $user_id );
2609
 
2610
- $instructor_status = apply_filters( 'tutor_instructor_statuses', array(
2611
- 'pending' => __( 'Pending', 'tutor' ),
2612
- 'approved' => __( 'Approved', 'tutor' ),
2613
- 'blocked' => __( 'Blocked', 'tutor' ),
2614
- ));
 
 
 
2615
 
2616
  $status = get_user_meta( $user_id, '_tutor_instructor_status', true );
2617
 
2618
- if ( isset( $instructor_status[$status] ) ) {
2619
  if ( ! $status_name ) {
2620
  return $status;
2621
  }
2622
- return $instructor_status[$status];
2623
  }
2624
  return false;
2625
  }
@@ -2633,32 +2762,34 @@ class Utils {
2633
  *
2634
  * @since v.1.0.0
2635
  */
2636
- public function get_total_instructors( $search_filter = '') {
2637
  global $wpdb;
2638
 
2639
- sanitize_text_field($search_filter);
2640
-
2641
- $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
2642
 
2643
- $count = $wpdb->get_var( $wpdb->prepare(
2644
- "SELECT COUNT(user.ID)
 
 
 
2645
  FROM {$wpdb->users} as user
2646
  INNER JOIN {$wpdb->usermeta} as user_meta
2647
  ON ( user_meta.user_id = user.ID )
2648
-
2649
  WHERE user_meta.meta_key = %s
2650
  AND ( user.display_name LIKE %s OR user.user_email LIKE %s );
2651
  ",
2652
- '_is_tutor_instructor',
2653
- $search_filter,
2654
- $search_filter
2655
- ) );
 
2656
  return $count;
2657
  }
2658
 
2659
  /**
2660
- * @param int $start
2661
- * @param int $limit
2662
  * @param string $search_term
2663
  *
2664
  * @return array|null|object
@@ -2670,38 +2801,44 @@ class Utils {
2670
  public function get_instructors( $start = 0, $limit = 10, $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $status = null, $cat_ids = array() ) {
2671
  global $wpdb;
2672
 
2673
- sanitize_text_field($search_filter);
2674
- sanitize_text_field($course_filter);
2675
- sanitize_text_field($date_filter);
2676
- sanitize_text_field($order_filter);
2677
 
2678
- $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
2679
- $course_filter = $course_filter != '' ? " AND inst_status.meta_key = '_tutor_instructor_course_id' AND inst_status.meta_value = $course_filter " : '' ;
2680
 
2681
  if ( '' != $date_filter ) {
2682
  $date_filter = tutor_get_formated_date( 'Y-m-d', $date_filter );
2683
  }
2684
-
2685
- $date_filter = $date_filter != '' ? " AND DATE(user.user_registered) = '$date_filter' " : '' ;
2686
 
2687
- $category_join = '';
 
 
2688
  $category_where = '';
2689
 
2690
  if ( $status ) {
2691
- !is_array( $status ) ? $status = array( $status ) : 0;
2692
 
2693
- $status = array_map( function($str) {
2694
- return "'{$str}'";
2695
- }, $status);
 
 
 
2696
 
2697
- $status = " AND inst_status.meta_value IN (".implode( ',', $status ).")";
2698
  }
2699
 
2700
- $cat_ids = array_filter($cat_ids, function($id) {
2701
- return is_numeric($id);
2702
- });
 
 
 
2703
 
2704
- if(count( $cat_ids )) {
2705
 
2706
  $category_join =
2707
  "INNER JOIN {$wpdb->posts} course
@@ -2713,17 +2850,18 @@ class Utils {
2713
  INNER JOIN {$wpdb->prefix}terms term
2714
  ON term.term_id=taxonomy.term_id";
2715
 
2716
- $cat_ids = implode(',', $cat_ids);
2717
  $category_where = " AND term.term_id IN ({$cat_ids})";
2718
  }
2719
 
2720
- $instructors = $wpdb->get_results( $wpdb->prepare(
2721
- "SELECT DISTINCT user.*, user_meta.meta_value AS instructor_from_date
 
2722
  FROM {$wpdb->users} user
2723
  INNER JOIN {$wpdb->usermeta} user_meta
2724
- ON ( user.ID = user_meta.user_id )
2725
- INNER JOIN {$wpdb->usermeta} inst_status
2726
- ON ( user.ID = inst_status.user_id )
2727
  {$category_join}
2728
  WHERE user_meta.meta_key = %s
2729
  AND ( user.display_name LIKE %s OR user.user_email LIKE %s )
@@ -2734,13 +2872,13 @@ class Utils {
2734
  ORDER BY user_meta.meta_value {$order_filter}
2735
  LIMIT %d, %d;
2736
  ",
2737
- '_is_tutor_instructor',
2738
- $search_filter,
2739
- $search_filter,
2740
-
2741
- $start,
2742
- $limit
2743
- ) );
2744
 
2745
  return $instructors;
2746
  }
@@ -2758,34 +2896,36 @@ class Utils {
2758
  global $wpdb;
2759
  $course_id = $this->get_post_id( $course_id );
2760
 
2761
- $instructors = $wpdb->get_results( $wpdb->prepare(
2762
- "SELECT ID,
 
2763
  display_name,
2764
  get_course.meta_value AS taught_course_id,
2765
  tutor_job_title.meta_value AS tutor_profile_job_title,
2766
  tutor_bio.meta_value AS tutor_profile_bio,
2767
- tutor_photo.meta_value AS tutor_profile_photo
2768
- FROM {$wpdb->users}
2769
- INNER JOIN {$wpdb->usermeta} get_course
2770
- ON ID = get_course.user_id
2771
- AND get_course.meta_key = %s
2772
- AND get_course.meta_value = %d
2773
- LEFT JOIN {$wpdb->usermeta} tutor_job_title
2774
- ON ID = tutor_job_title.user_id
2775
- AND tutor_job_title.meta_key = %s
2776
- LEFT JOIN {$wpdb->usermeta} tutor_bio
2777
- ON ID = tutor_bio.user_id
2778
- AND tutor_bio.meta_key = %s
2779
- LEFT JOIN {$wpdb->usermeta} tutor_photo
2780
- ON ID = tutor_photo.user_id
2781
  AND tutor_photo.meta_key = %s
2782
  ",
2783
- '_tutor_instructor_course_id',
2784
- $course_id,
2785
- '_tutor_profile_job_title',
2786
- '_tutor_profile_bio',
2787
- '_tutor_profile_photo'
2788
- ) );
 
2789
 
2790
  if ( is_array( $instructors ) && count( $instructors ) ) {
2791
  return $instructors;
@@ -2809,9 +2949,10 @@ class Utils {
2809
 
2810
  $course_post_type = tutor()->course_post_type;
2811
 
2812
- $count = $wpdb->get_var( $wpdb->prepare(
2813
- "SELECT COUNT(enrollment.ID)
2814
- FROM {$wpdb->posts} enrollment
 
2815
  INNER JOIN {$wpdb->posts} course
2816
  ON enrollment.post_parent=course.ID
2817
  WHERE course.post_author = %d
@@ -2820,55 +2961,55 @@ class Utils {
2820
  AND enrollment.post_type = %s
2821
  AND enrollment.post_status = %s;
2822
  ",
2823
- $instructor_id,
2824
- $course_post_type,
2825
- 'publish',
2826
- 'tutor_enrolled',
2827
- 'completed'
2828
-
2829
- ) );
2830
 
2831
  return (int) $count;
2832
  }
2833
 
2834
  /**
2835
  * Get all students by instructor_id
2836
- *
2837
  * @param $instructor_id int | required
2838
- *
2839
  * @param $offset int | required
2840
- *
2841
  * @param $limit int | required
2842
- *
2843
  * @param $search string | optional
2844
- *
2845
  * @param $course_id int | optional
2846
- *
2847
  * @param $date string | optional
2848
- *
2849
  * @return array
2850
- *
2851
  * @since 1.9.9
2852
  */
2853
  public function get_students_by_instructor( int $instructor_id, int $offset, int $limit, $search_filter = '', $course_id = '', $date_filter = '', $order_by = '', $order = '' ): array {
2854
  global $wpdb;
2855
- $instructor_id = sanitize_text_field( $instructor_id );
2856
- $limit = sanitize_text_field( $limit );
2857
- $offset = sanitize_text_field( $offset );
2858
- $course_id = sanitize_text_field( $course_id );
2859
- $date_filter = sanitize_text_field( $date_filter );
2860
- $search_filter = sanitize_text_field( $search_filter );
2861
-
2862
- $order_by = 'user.ID';
2863
  if ( 'registration_date' === $order_by ) {
2864
  $order_by = 'enrollment.post_date';
2865
- } else if ( 'course_taken' === $order_by ) {
2866
  $order_by = 'course_taken';
2867
  } else {
2868
  $order_by = 'user.ID';
2869
  }
2870
 
2871
- $order = sanitize_text_field( $order );
2872
 
2873
  if ( '' !== $date_filter ) {
2874
  $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter );
@@ -2887,9 +3028,10 @@ class Utils {
2887
  $date_query = " AND DATE(user.user_registered) = CAST( '$date_filter' AS DATE ) ";
2888
  }
2889
 
2890
- $students = $wpdb->get_results( $wpdb->prepare(
2891
- "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, (SELECT post_date FROM {$wpdb->posts} WHERE post_author = user.ID LIMIT 1) AS enroll_date
2892
- FROM {$wpdb->posts} enrollment
 
2893
  INNER JOIN {$wpdb->posts} AS course
2894
  ON enrollment.post_parent=course.ID
2895
  INNER JOIN {$wpdb->users} AS user
@@ -2907,23 +3049,25 @@ class Utils {
2907
  ORDER BY {$order_by} {$order}
2908
  LIMIT %d, %d
2909
  ",
2910
- $instructor_id,
2911
- $course_post_type,
2912
- 'publish',
2913
- 'tutor_enrolled',
2914
- 'completed',
2915
- $search_query,
2916
- $search_query,
2917
- $search_query,
2918
- $search_query,
2919
- $offset,
2920
- $limit
2921
- ) );
2922
- $total_students = $wpdb->get_results( $wpdb->prepare(
2923
- "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, enrollment.post_date AS enroll_date
2924
- FROM {$wpdb->posts} enrollment
2925
- INNER JOIN {$wpdb->posts} AS course
2926
- ON enrollment.post_parent=course.ID
 
 
2927
  INNER JOIN {$wpdb->users} AS user
2928
  ON user.ID = enrollment.post_author
2929
  WHERE course.post_author = %d
@@ -2936,42 +3080,44 @@ class Utils {
2936
  {$date_query}
2937
  GROUP BY enrollment.post_author
2938
  ORDER BY {$order_by} {$order}
2939
-
2940
  ",
2941
- $instructor_id,
2942
- $course_post_type,
2943
- 'publish',
2944
- 'tutor_enrolled',
2945
- 'completed',
2946
- $search_query,
2947
- $search_query,
2948
- $search_query,
2949
- $search_query
2950
- ) );
 
2951
 
2952
  return array(
2953
- 'students' => $students,
2954
- 'total_students' => count($total_students)
2955
  );
2956
  }
2957
 
2958
  /**
2959
  * Get all course for a give student & instructor id
2960
- *
2961
  * @param $student_id int | required
2962
- *
2963
  * @param $instructor_id int | required
2964
- *
2965
  * @return array
2966
- *
2967
  * @since 1.9.9
2968
  */
2969
- public function get_courses_by_student_instructor_id (int $student_id, int $instructor_id): array {
2970
  global $wpdb;
2971
  $course_post_type = tutor()->course_post_type;
2972
- $students = $wpdb->get_results( $wpdb->prepare(
2973
- "SELECT course.*
2974
- FROM {$wpdb->posts} enrollment
 
2975
  INNER JOIN {$wpdb->posts} AS course
2976
  ON enrollment.post_parent=course.ID
2977
  WHERE course.post_author = %d
@@ -2982,70 +3128,75 @@ class Utils {
2982
  AND enrollment.post_author = %d
2983
  ORDER BY course.post_date DESC
2984
  ",
2985
- $instructor_id,
2986
- $course_post_type,
2987
- 'publish',
2988
- 'tutor_enrolled',
2989
- 'completed',
2990
- $student_id
2991
- ) );
 
2992
  return $students;
2993
  }
2994
 
2995
  /**
2996
  * Get total number of completed assignment
2997
- *
2998
  * @param $course_id int | required
2999
- *
3000
  * @param $student | required
3001
- *
3002
  * @since 1.9.9
3003
  */
3004
- public function get_completed_assignment(int $course_id, int $student_id): int {
3005
  global $wpdb;
3006
- $course_id = sanitize_text_field( $course_id );
3007
  $student_id = sanitize_text_field( $student_id );
3008
- $count = $wpdb->get_var($wpdb->prepare(
3009
- "SELECT COUNT(ID) FROM wp_posts
 
3010
  INNER JOIN wp_comments c ON c.comment_post_ID = wp_posts.ID AND c.user_id = %d AND c.comment_approved = %s
3011
  WHERE post_parent IN (SELECT ID FROM wp_posts WHERE post_type = %s AND post_parent = %d AND post_status = %s)
3012
- AND post_type =%s
3013
  AND post_status = %s
3014
- ",
3015
- $student_id,
3016
- 'submitted',
3017
- 'topics',
3018
- $course_id,
3019
- 'publish',
3020
- 'tutor_assignments',
3021
- 'publish'
3022
- ));
 
3023
  return (int) $count;
3024
  }
3025
  /**
3026
  * Get total number of completed quiz
3027
- *
3028
  * @param $course_id int | required
3029
- *
3030
  * @param $student | required
3031
- *
3032
  * @since 1.9.9
3033
  */
3034
- public function get_completed_quiz(int $course_id, int $student_id): int {
3035
  global $wpdb;
3036
- $course_id = sanitize_text_field( $course_id );
3037
  $student_id = sanitize_text_field( $student_id );
3038
- $count = $wpdb->get_var($wpdb->prepare(
3039
- "SELECT COUNT(DISTINCT quiz_id) AS total
3040
- FROM {$wpdb->prefix}tutor_quiz_attempts
3041
- WHERE course_id = %d
 
3042
  AND user_id = %d
3043
  AND attempt_status = %s
3044
  ",
3045
- $course_id,
3046
- $student_id,
3047
- 'attempt_ended'
3048
- ));
 
3049
  return (int) $count;
3050
  }
3051
 
@@ -3060,10 +3211,10 @@ class Utils {
3060
  */
3061
  public function get_rating_value( $input = 0.00 ) {
3062
 
3063
- if ( $input > 0) {
3064
- $input = number_format( $input, 2 );
3065
  $int_value = (int) $input;
3066
- $fraction = $input - $int_value;
3067
 
3068
  if ( $fraction == 0 ) {
3069
  $fraction = 0.00;
@@ -3081,7 +3232,7 @@ class Utils {
3081
 
3082
  /**
3083
  * @param float $current_rating
3084
- * @param bool $echo
3085
  *
3086
  * @return string
3087
  *
@@ -3092,26 +3243,26 @@ class Utils {
3092
  public function star_rating_generator( $current_rating = 0.00, $echo = true ) {
3093
  $output = '<div class="tutor-star-rating-group">';
3094
 
3095
- for ( $i = 1; $i <=5 ; $i++ ) {
3096
  $intRating = (int) $current_rating;
3097
 
3098
  if ( $intRating >= $i ) {
3099
- $output.= '<i class="tutor-icon-star-full" data-rating-value="'.$i.'"></i>';
3100
  } else {
3101
- if ( ( $current_rating - $i) == -0.5 ) {
3102
- $output.= '<i class="tutor-icon-star-half" data-rating-value="'.$i.'"></i>';
3103
  } else {
3104
- $output.= '<i class="tutor-icon-star-line" data-rating-value="'.$i.'"></i>';
3105
  }
3106
  }
3107
  }
3108
 
3109
- $output .= "<div class='tutor-rating-gen-input'><input type='hidden' name='tutor_rating_gen_input' value='{$current_rating}' /> </div>";
3110
 
3111
- $output .= "</div>";
3112
 
3113
  if ( $echo ) {
3114
- echo $output;
3115
  }
3116
 
3117
  return $output;
@@ -3123,18 +3274,16 @@ class Utils {
3123
  * @return string
3124
  *
3125
  * Split string regardless of ASCI, Unicode
3126
- *
3127
- *
3128
  */
3129
  public function str_split( $string ) {
3130
  $strlen = mb_strlen( $string );
3131
  while ( $strlen ) {
3132
- $array[] = mb_substr( $string,0,1,"UTF-8" );
3133
- $string = mb_substr( $string,1,$strlen,"UTF-8" );
3134
- $strlen = mb_strlen( $string );
3135
  }
3136
  return $array;
3137
- }
3138
 
3139
  /**
3140
  * @param null $name
@@ -3154,18 +3303,18 @@ class Utils {
3154
 
3155
  $user = $this->get_tutor_user( $user_id );
3156
  if ( $user->tutor_profile_photo ) {
3157
- return '<img src="'.wp_get_attachment_image_url( $user->tutor_profile_photo, $size ).'" class="tutor-image-avatar" alt="" /> ';
3158
  }
3159
 
3160
  $name = $user->display_name;
3161
- $arr = explode( ' ', trim( $name ) );
3162
 
3163
- $first_char = ! empty( $arr[0] ) ? $this->str_split( $arr[0] )[0] : '';
3164
- $second_char = ! empty( $arr[1] ) ? $this->str_split( $arr[1] )[0] : '';
3165
- $initial_avatar = strtoupper( $first_char.$second_char );
3166
 
3167
- $bg_color = '#'.substr( md5( $initial_avatar ), 0, 6);
3168
- $initial_avatar = "<span class='tutor-text-avatar' style='background-color: {$bg_color}; color: #fff8e5'>{$initial_avatar}</span>";
3169
 
3170
  return $initial_avatar;
3171
  }
@@ -3182,15 +3331,16 @@ class Utils {
3182
  public function get_tutor_user( $user_id ) {
3183
  global $wpdb;
3184
 
3185
- $user = $wpdb->get_row( $wpdb->prepare(
3186
- "SELECT ID,
3187
- display_name,
3188
- tutor_job_title.meta_value AS tutor_profile_job_title,
 
3189
  tutor_bio.meta_value AS tutor_profile_bio,
3190
  tutor_photo.meta_value AS tutor_profile_photo
3191
  FROM {$wpdb->users}
3192
- LEFT JOIN {$wpdb->usermeta} tutor_job_title
3193
- ON ID = tutor_job_title.user_id
3194
  AND tutor_job_title.meta_key = '_tutor_profile_job_title'
3195
  LEFT JOIN {$wpdb->usermeta} tutor_bio
3196
  ON ID = tutor_bio.user_id
@@ -3200,8 +3350,9 @@ class Utils {
3200
  AND tutor_photo.meta_key = '_tutor_profile_photo'
3201
  WHERE ID = %d
3202
  ",
3203
- $user_id
3204
- ) );
 
3205
 
3206
  return $user;
3207
  }
@@ -3221,31 +3372,33 @@ class Utils {
3221
  $course_id = $this->get_post_id( $course_id );
3222
  global $wpdb;
3223
 
3224
- $reviews = $wpdb->get_results( $wpdb->prepare(
3225
- "SELECT {$wpdb->comments}.comment_ID,
3226
- {$wpdb->comments}.comment_post_ID,
3227
- {$wpdb->comments}.comment_author,
3228
- {$wpdb->comments}.comment_author_email,
3229
- {$wpdb->comments}.comment_date,
3230
- {$wpdb->comments}.comment_content,
3231
- {$wpdb->comments}.user_id,
 
3232
  {$wpdb->commentmeta}.meta_value AS rating,
3233
- {$wpdb->users}.display_name
3234
-
3235
  FROM {$wpdb->comments}
3236
- INNER JOIN {$wpdb->commentmeta}
3237
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3238
  LEFT JOIN {$wpdb->users}
3239
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3240
- WHERE {$wpdb->comments}.comment_post_ID = %d
3241
  AND comment_type = 'tutor_course_rating' AND meta_key = 'tutor_rating'
3242
  ORDER BY comment_ID DESC
3243
  LIMIT %d, %d;
3244
  ",
3245
- $course_id,
3246
- $offset,
3247
- $limit
3248
- ) );
 
3249
 
3250
  return $reviews;
3251
  }
@@ -3267,11 +3420,18 @@ class Utils {
3267
  'rating_count' => 0,
3268
  'rating_sum' => 0,
3269
  'rating_avg' => 0.00,
3270
- 'count_by_value' => array( 5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0 )
 
 
 
 
 
 
3271
  );
3272
 
3273
- $rating = $wpdb->get_row( $wpdb->prepare(
3274
- "SELECT COUNT(meta_value) AS rating_count,
 
3275
  SUM(meta_value) AS rating_sum
3276
  FROM {$wpdb->comments}
3277
  INNER JOIN {$wpdb->commentmeta}
@@ -3279,42 +3439,51 @@ class Utils {
3279
  WHERE {$wpdb->comments}.comment_post_ID = %d
3280
  AND {$wpdb->comments}.comment_type = %s
3281
  AND meta_key = %s;
3282
- ",
3283
- $course_id,
3284
- 'tutor_course_rating',
3285
- 'tutor_rating'
3286
- ) );
 
3287
 
3288
  if ( $rating->rating_count ) {
3289
  $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
3290
 
3291
- $stars = $wpdb->get_results( $wpdb->prepare(
3292
- "SELECT commentmeta.meta_value AS rating,
3293
- COUNT(commentmeta.meta_value) as rating_count
 
3294
  FROM {$wpdb->comments} comments
3295
  INNER JOIN {$wpdb->commentmeta} commentmeta
3296
  ON comments.comment_ID = commentmeta.comment_id
3297
- WHERE comments.comment_post_ID = %d
3298
  AND comments.comment_type = %s
3299
  AND commentmeta.meta_key = %s
3300
  GROUP BY commentmeta.meta_value;
3301
- ",
3302
- $course_id,
3303
- 'tutor_course_rating',
3304
- 'tutor_rating'
3305
- ) );
 
3306
 
3307
- $ratings = array( 5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0 );
 
 
 
 
 
 
3308
  foreach ( $stars as $star ) {
3309
  $index = (int) $star->rating;
3310
- array_key_exists($index, $ratings) ? $ratings[ $index ] = $star->rating_count : 0;
3311
  }
3312
 
3313
  $ratings = array(
3314
  'rating_count' => $rating->rating_count,
3315
  'rating_sum' => $rating->rating_sum,
3316
  'rating_avg' => $avg_rating,
3317
- 'count_by_value' => $ratings
3318
  );
3319
  }
3320
 
@@ -3336,8 +3505,9 @@ class Utils {
3336
  $user_id = $this->get_user_id( $user_id );
3337
  global $wpdb;
3338
 
3339
- $reviews = $wpdb->get_results( $wpdb->prepare(
3340
- "SELECT {$wpdb->comments}.comment_ID,
 
3341
  {$wpdb->comments}.comment_post_ID,
3342
  {$wpdb->comments}.comment_author,
3343
  {$wpdb->comments}.comment_author_email,
@@ -3346,45 +3516,47 @@ class Utils {
3346
  {$wpdb->comments}.user_id,
3347
  {$wpdb->commentmeta}.meta_value as rating,
3348
  {$wpdb->users}.display_name
3349
-
3350
  FROM {$wpdb->comments}
3351
- INNER JOIN {$wpdb->commentmeta}
3352
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3353
  INNER JOIN {$wpdb->users}
3354
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3355
- WHERE {$wpdb->comments}.user_id = %d
3356
  AND comment_type = %s
3357
  AND meta_key = %s
3358
  ORDER BY comment_ID DESC
3359
  LIMIT %d, %d;
3360
  ",
3361
- $user_id,
3362
- 'tutor_course_rating',
3363
- 'tutor_rating',
3364
- $offset,
3365
- $limit
3366
- ) );
3367
-
3368
 
3369
- if($get_object) {
3370
- $count = (int)$wpdb->get_var( $wpdb->prepare(
3371
- "SELECT COUNT({$wpdb->comments}.comment_ID)
 
3372
  FROM {$wpdb->comments}
3373
- INNER JOIN {$wpdb->commentmeta}
3374
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3375
  INNER JOIN {$wpdb->users}
3376
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3377
- WHERE {$wpdb->comments}.user_id = %d
3378
  AND comment_type = %s
3379
  AND meta_key = %s",
3380
- $user_id,
3381
- 'tutor_course_rating',
3382
- 'tutor_rating'
3383
- ) );
 
3384
 
3385
- return (object)array(
3386
- 'count' => $count,
3387
- 'results' => $reviews
3388
  );
3389
  }
3390
 
@@ -3392,47 +3564,47 @@ class Utils {
3392
  }
3393
 
3394
  /**
3395
- * @param int $user_id
3396
- * @param int $offset
3397
- * @param int $limit
3398
  *
3399
  * @return array|null|object
3400
  *
3401
  * Get reviews by instructor (Received by the instructor)
3402
  *
3403
  * @since v.1.4.0
3404
- *
3405
  * @param $course_id optional
3406
- *
3407
  * @param $date_filter optional
3408
- *
3409
  * Course id & date filter is sorting with specific course and date
3410
- *
3411
  * @since 1.9.9
3412
  */
3413
  public function get_reviews_by_instructor( $instructor_id = 0, $offset = 0, $limit = 150, $course_id = '', $date_filter = '' ) {
3414
  global $wpdb;
3415
- $instructor_id = sanitize_text_field( $instructor_id );
3416
- $offset = sanitize_text_field( $offset );
3417
- $limit = sanitize_text_field( $limit );
3418
- $course_id = sanitize_text_field( $course_id );
3419
- $date_filter = sanitize_text_field( $date_filter );
3420
- $instructor_id = $this->get_user_id( $instructor_id );
3421
 
3422
- $course_query = '';
3423
- $date_query = '';
3424
 
3425
  if ( '' !== $course_id ) {
3426
  $course_query = " AND {$wpdb->comments}.comment_post_ID = {$course_id} ";
3427
- }
3428
  if ( '' !== $date_filter ) {
3429
- $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter);
3430
- $date_query = " AND DATE({$wpdb->comments}.comment_date) = CAST( '$date_filter' AS DATE ) ";
3431
- }
3432
 
3433
  $results = array(
3434
- 'count' => 0,
3435
- 'results' => false,
3436
  );
3437
 
3438
  $cours_ids = (array) $this->get_assigned_courses_ids_by_instructors( $instructor_id );
@@ -3440,45 +3612,48 @@ class Utils {
3440
  if ( $this->count( $cours_ids ) ) {
3441
  $implode_ids = implode( ',', $cours_ids );
3442
 
3443
- //Count
3444
- $results['count'] = $wpdb->get_var( $wpdb->prepare(
3445
- "SELECT COUNT({$wpdb->comments}.comment_ID)
 
3446
  FROM {$wpdb->comments}
3447
  INNER JOIN {$wpdb->commentmeta}
3448
  ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3449
  INNER JOIN {$wpdb->users}
3450
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3451
- WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3452
  AND comment_type = %s
3453
  AND meta_key = %s
3454
  {$course_query}
3455
  {$date_query}
3456
  ",
3457
- 'tutor_course_rating',
3458
- 'tutor_rating'
3459
- ) );
3460
-
3461
- //Results
3462
- $results['results'] = $wpdb->get_results( $wpdb->prepare(
3463
- "SELECT {$wpdb->comments}.comment_ID,
3464
- {$wpdb->comments}.comment_post_ID,
3465
- {$wpdb->comments}.comment_author,
3466
- {$wpdb->comments}.comment_author_email,
3467
- {$wpdb->comments}.comment_date,
3468
- {$wpdb->comments}.comment_content,
3469
- {$wpdb->comments}.user_id,
 
 
3470
  {$wpdb->commentmeta}.meta_value AS rating,
3471
  {$wpdb->users}.display_name,
3472
  {$wpdb->posts}.post_title as course_title
3473
-
3474
  FROM {$wpdb->comments}
3475
- INNER JOIN {$wpdb->commentmeta}
3476
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3477
  INNER JOIN {$wpdb->users}
3478
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3479
  INNER JOIN {$wpdb->posts}
3480
  ON {$wpdb->posts}.ID = {$wpdb->comments}.comment_post_ID
3481
- WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3482
  AND comment_type = %s
3483
  AND meta_key = %s
3484
  {$course_query}
@@ -3486,11 +3661,12 @@ class Utils {
3486
  ORDER BY comment_ID DESC
3487
  LIMIT %d, %d;
3488
  ",
3489
- 'tutor_course_rating',
3490
- 'tutor_rating',
3491
- $offset,
3492
- $limit
3493
- ) );
 
3494
  }
3495
 
3496
  return (object) $results;
@@ -3509,13 +3685,14 @@ class Utils {
3509
  global $wpdb;
3510
 
3511
  $ratings = array(
3512
- 'rating_count' => 0,
3513
- 'rating_sum' => 0,
3514
- 'rating_avg' => 0.00,
3515
  );
3516
 
3517
- $rating = $wpdb->get_row( $wpdb->prepare(
3518
- "SELECT COUNT(rating.meta_value) as rating_count, SUM(rating.meta_value) as rating_sum
 
3519
  FROM {$wpdb->usermeta} courses
3520
  INNER JOIN {$wpdb->comments} reviews
3521
  ON courses.meta_value = reviews.comment_post_ID
@@ -3526,17 +3703,18 @@ class Utils {
3526
  WHERE courses.user_id = %d
3527
  AND courses.meta_key = %s
3528
  ",
3529
- $instructor_id,
3530
- '_tutor_instructor_course_id'
3531
- ) );
 
3532
 
3533
  if ( $rating->rating_count ) {
3534
  $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
3535
 
3536
  $ratings = array(
3537
- 'rating_count' => $rating->rating_count,
3538
- 'rating_sum' => $rating->rating_sum,
3539
- 'rating_avg' => $avg_rating,
3540
  );
3541
  }
3542
 
@@ -3557,27 +3735,29 @@ class Utils {
3557
  global $wpdb;
3558
 
3559
  $course_id = $this->get_post_id( $course_id );
3560
- $user_id = $this->get_user_id( $user_id );
3561
 
3562
  $ratings = array(
3563
  'rating' => 0,
3564
  'review' => '',
3565
  );
3566
 
3567
- $rating = $wpdb->get_row( $wpdb->prepare(
3568
- "SELECT meta_value AS rating,
 
3569
  comment_content AS review
3570
  FROM {$wpdb->comments}
3571
- INNER JOIN {$wpdb->commentmeta}
3572
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3573
  WHERE {$wpdb->comments}.comment_post_ID = %d
3574
  AND user_id = %d
3575
  AND meta_key = %s;
3576
  ",
3577
- $course_id,
3578
- $user_id,
3579
- 'tutor_rating'
3580
- ) );
 
3581
 
3582
  if ( $rating ) {
3583
  $rating_format = number_format( $rating->rating, 2 );
@@ -3601,17 +3781,19 @@ class Utils {
3601
  public function count_reviews_wrote_by_user( $user_id = 0 ) {
3602
  global $wpdb;
3603
 
3604
- $user_id = $this->get_user_id($user_id);
3605
 
3606
- $count_reviews = $wpdb->get_var( $wpdb->prepare(
3607
- "SELECT COUNT(comment_ID)
 
3608
  FROM {$wpdb->comments}
3609
  WHERE user_id = %d
3610
  AND comment_type = %s
3611
  ",
3612
- $user_id,
3613
- 'tutor_course_rating'
3614
- ) );
 
3615
 
3616
  return $count_reviews;
3617
  }
@@ -3633,19 +3815,19 @@ class Utils {
3633
  switch ( strtoupper( $l ) ) {
3634
  case 'P':
3635
  $ret *= 1024;
3636
- // No break.
3637
  case 'T':
3638
  $ret *= 1024;
3639
- // No break.
3640
  case 'G':
3641
  $ret *= 1024;
3642
- // No break.
3643
  case 'M':
3644
  $ret *= 1024;
3645
- // No break.
3646
  case 'K':
3647
  $ret *= 1024;
3648
- // No break.
3649
  }
3650
  return $ret;
3651
  }
@@ -3698,37 +3880,39 @@ class Utils {
3698
  public function get_top_question( $course_id = 0, $user_id = 0, $offset = 0, $limit = 20, $is_author = false ) {
3699
  global $wpdb;
3700
 
3701
- $course_id = $this->get_post_id( $course_id );
3702
- $user_id = $this->get_user_id( $user_id );
3703
 
3704
- $author_sql = $is_author ? "" : "AND {$wpdb->comments}.user_id = {$user_id}";
3705
-
3706
- $questions = $wpdb->get_results( $wpdb->prepare(
3707
- "SELECT {$wpdb->comments}.comment_ID,
3708
- {$wpdb->comments}.comment_post_ID,
3709
- {$wpdb->comments}.comment_author,
3710
- {$wpdb->comments}.comment_date,
3711
- {$wpdb->comments}.comment_date_gmt,
3712
- {$wpdb->comments}.comment_content,
3713
- {$wpdb->comments}.user_id,
3714
- {$wpdb->commentmeta}.meta_value as question_title,
3715
- {$wpdb->users}.display_name
3716
- FROM {$wpdb->comments}
 
3717
  INNER JOIN {$wpdb->commentmeta}
3718
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3719
  INNER JOIN {$wpdb->users}
3720
- ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3721
- WHERE {$wpdb->comments}.comment_post_ID = {$course_id} {$author_sql}
3722
- AND {$wpdb->comments}.comment_type = %s
3723
- AND meta_key = %s
3724
- ORDER BY comment_ID DESC
3725
  LIMIT %d, %d;
3726
  ",
3727
- 'tutor_q_and_a',
3728
- 'tutor_question_title',
3729
- $offset,
3730
- $limit
3731
- ) );
 
3732
 
3733
  return $questions;
3734
  }
@@ -3745,7 +3929,7 @@ class Utils {
3745
  public function get_total_qa_question( $search_term = '' ) {
3746
  global $wpdb;
3747
 
3748
- $user_id = get_current_user_id();
3749
  $course_type = tutor()->course_post_type;
3750
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
3751
 
@@ -3755,32 +3939,36 @@ class Utils {
3755
  */
3756
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
3757
 
3758
- $get_course_ids = $wpdb->get_col( $wpdb->prepare(
3759
- "SELECT ID
 
3760
  FROM {$wpdb->posts}
3761
  WHERE post_author = %d
3762
  AND post_type = %s
3763
  AND post_status = %s
3764
  ",
3765
- $user_id,
3766
- $course_type,
3767
- 'publish'
3768
- ) );
 
3769
 
3770
- $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
3771
- "SELECT meta_value
 
3772
  FROM {$wpdb->usermeta}
3773
  WHERE meta_key = %s
3774
  AND user_id = %d
3775
  ",
3776
- '_tutor_instructor_course_id',
3777
- $user_id
3778
- ) );
 
3779
 
3780
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
3781
 
3782
  if ( $this->count( $my_course_ids ) ) {
3783
- $implode_ids = implode( ',', $my_course_ids );
3784
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
3785
  }
3786
  }
@@ -3790,31 +3978,34 @@ class Utils {
3790
  * could be retained thus total number counted and q & a showing
3791
  * list is not similar
3792
  * now only the q & a will be appeared that is belongs to a user
 
3793
  * @since version 1.9.0
3794
  */
3795
- $count = $wpdb->get_var( $wpdb->prepare(
3796
- "SELECT COUNT({$wpdb->comments}.comment_ID)
 
3797
  FROM {$wpdb->comments}
3798
  INNER JOIN {$wpdb->commentmeta}
3799
  ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3800
 
3801
- INNER JOIN {$wpdb->users}
3802
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3803
 
3804
- WHERE comment_type = %s
3805
  AND comment_parent = 0 {$in_question_id_query}
3806
  AND {$wpdb->commentmeta}.meta_value LIKE %s;
3807
  ",
3808
- 'tutor_q_and_a',
3809
- $search_term
3810
- ) );
 
3811
 
3812
  return (int) $count;
3813
  }
3814
 
3815
  /**
3816
- * @param int $start
3817
- * @param int $limit
3818
  * @param string $search_term
3819
  *
3820
  * @return array|null|object
@@ -3836,49 +4027,54 @@ class Utils {
3836
  * Get only assinged courses questions if current user is a
3837
  */
3838
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
3839
-
3840
- $get_course_ids = $wpdb->get_col( $wpdb->prepare(
3841
- "SELECT ID
 
3842
  FROM {$wpdb->posts}
3843
  WHERE post_author = %d
3844
  AND post_type = %s
3845
  AND post_status = %s
3846
  ",
3847
- $user_id,
3848
- $course_type,
3849
- 'publish'
3850
- ) );
 
3851
 
3852
- $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
3853
- "SELECT meta_value
 
3854
  FROM {$wpdb->usermeta}
3855
  WHERE meta_key = %s
3856
  AND user_id = %d
3857
  ",
3858
- '_tutor_instructor_course_id',
3859
- $user_id
3860
- ) );
 
3861
 
3862
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
3863
 
3864
  if ( $this->count( $my_course_ids ) ) {
3865
- $implode_ids = implode( ',', $my_course_ids );
3866
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
3867
  }
3868
  }
3869
 
3870
- $query = $wpdb->get_results( $wpdb->prepare(
3871
- "SELECT {$wpdb->comments}.comment_ID,
3872
- {$wpdb->comments}.comment_post_ID,
3873
- {$wpdb->comments}.comment_author,
3874
- {$wpdb->comments}.comment_date,
3875
- {$wpdb->comments}.comment_content,
3876
- {$wpdb->comments}.user_id,
3877
- {$wpdb->commentmeta}.meta_value as question_title,
3878
- {$wpdb->users}.display_name,
3879
- {$wpdb->posts}.post_title,
3880
- ( SELECT COUNT(answers_t.comment_ID)
3881
- FROM {$wpdb->comments} answers_t
 
3882
  WHERE answers_t.comment_parent = {$wpdb->comments}.comment_ID
3883
  ) AS answer_count
3884
  FROM {$wpdb->comments}
@@ -3892,14 +4088,15 @@ class Utils {
3892
  AND {$wpdb->comments}.comment_parent = 0
3893
  AND {$wpdb->commentmeta}.meta_value LIKE %s
3894
  {$in_question_id_query}
3895
- ORDER BY {$wpdb->comments}.comment_ID DESC
3896
  LIMIT %d, %d;
3897
  ",
3898
- 'tutor_q_and_a',
3899
- $search_term,
3900
- $start,
3901
- $limit
3902
- ) );
 
3903
 
3904
  return $query;
3905
  }
@@ -3915,30 +4112,32 @@ class Utils {
3915
  */
3916
  public function get_qa_question( $question_id ) {
3917
  global $wpdb;
3918
- $query = $wpdb->get_row( $wpdb->prepare(
3919
- "SELECT {$wpdb->comments}.comment_ID,
3920
- {$wpdb->comments}.comment_post_ID,
3921
- {$wpdb->comments}.comment_author,
3922
- {$wpdb->comments}.comment_date,
3923
- {$wpdb->comments}.comment_date_gmt,
3924
- {$wpdb->comments}.comment_content,
3925
- {$wpdb->comments}.user_id,
3926
- {$wpdb->commentmeta}.meta_value as question_title,
3927
- {$wpdb->users}.display_name,
3928
- {$wpdb->posts}.post_title
3929
- FROM {$wpdb->comments}
3930
- INNER JOIN {$wpdb->commentmeta}
3931
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3932
- INNER JOIN {$wpdb->posts}
3933
- ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
 
3934
  INNER JOIN {$wpdb->users}
3935
- ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3936
- WHERE comment_type = %s
3937
  AND {$wpdb->comments}.comment_ID = %d;
3938
  ",
3939
- 'tutor_q_and_a',
3940
- $question_id
3941
- ) );
 
3942
 
3943
  return $query;
3944
  }
@@ -3952,8 +4151,9 @@ class Utils {
3952
  */
3953
  public function get_qa_answer_by_question( $question_id ) {
3954
  global $wpdb;
3955
- $query = $wpdb->get_results( $wpdb->prepare(
3956
- "SELECT {$wpdb->comments}.comment_ID,
 
3957
  {$wpdb->comments}.comment_post_ID,
3958
  {$wpdb->comments}.comment_author,
3959
  {$wpdb->comments}.comment_date,
@@ -3969,9 +4169,10 @@ class Utils {
3969
  AND {$wpdb->comments}.comment_parent = %d
3970
  ORDER BY {$wpdb->comments}.comment_ID ASC;
3971
  ",
3972
- 'tutor_q_and_a',
3973
- $question_id
3974
- ) );
 
3975
 
3976
  return $query;
3977
  }
@@ -3980,34 +4181,36 @@ class Utils {
3980
  * @param $answer_id
3981
  *
3982
  * @return array|null|object
3983
- *
3984
  * @since v1.6.9
3985
  *
3986
  * Get question and asnwer by answer_id
3987
  */
3988
  public function get_qa_answer_by_answer_id( $answer_id ) {
3989
  global $wpdb;
3990
- $answer = $wpdb->get_row( $wpdb->prepare(
3991
- "SELECT answer.comment_post_ID,
3992
- answer.comment_content,
 
3993
  users.display_name,
3994
  question.user_id AS question_by,
3995
  question.comment_content AS question,
3996
  question_meta.meta_value AS question_title
3997
  FROM {$wpdb->comments} answer
3998
  INNER JOIN {$wpdb->users} users
3999
- ON answer.user_id = users.id
4000
- INNER JOIN {$wpdb->comments} question
4001
- ON answer.comment_parent = question.comment_ID
4002
- INNER JOIN {$wpdb->commentmeta} question_meta
4003
  ON answer.comment_parent = question_meta.comment_id
4004
  AND question_meta.meta_key = 'tutor_question_title'
4005
- WHERE answer.comment_ID = %d
4006
  AND answer.comment_type = %s;
4007
- ",
4008
- $answer_id,
4009
- 'tutor_q_and_a'
4010
- ) );
 
4011
 
4012
  if ( $answer ) {
4013
  return $answer;
@@ -4023,9 +4226,10 @@ class Utils {
4023
  * instructor as it was count unanswered question from all courses
4024
  * from now on it will check if tutor instructor and count
4025
  * from instructor's course
 
4026
  * @since version 1.9.0
4027
  */
4028
- $user_id = get_current_user_id();
4029
  $course_type = tutor()->course_post_type;
4030
 
4031
  $in_question_id_query = '';
@@ -4034,38 +4238,43 @@ class Utils {
4034
  */
4035
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
4036
 
4037
- $get_course_ids = $wpdb->get_col( $wpdb->prepare(
4038
- "SELECT ID
 
4039
  FROM {$wpdb->posts}
4040
  WHERE post_author = %d
4041
  AND post_type = %s
4042
  AND post_status = %s
4043
  ",
4044
- $user_id,
4045
- $course_type,
4046
- 'publish'
4047
- ) );
 
4048
 
4049
- $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
4050
- "SELECT meta_value
 
4051
  FROM {$wpdb->usermeta}
4052
  WHERE meta_key = %s
4053
  AND user_id = %d
4054
  ",
4055
- '_tutor_instructor_course_id',
4056
- $user_id
4057
- ) );
 
4058
 
4059
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4060
 
4061
  if ( $this->count( $my_course_ids ) ) {
4062
- $implode_ids = implode( ',', $my_course_ids );
4063
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4064
  }
4065
  }
4066
 
4067
- $count = $wpdb->get_var( $wpdb->prepare(
4068
- "SELECT COUNT({$wpdb->comments}.comment_ID)
 
4069
  FROM {$wpdb->comments}
4070
  INNER JOIN {$wpdb->posts}
4071
  ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
@@ -4075,9 +4284,10 @@ class Utils {
4075
  AND {$wpdb->comments}.comment_approved = %s
4076
  AND {$wpdb->comments}.comment_parent = 0 {$in_question_id_query};
4077
  ",
4078
- 'tutor_q_and_a',
4079
- 'waiting_for_answer'
4080
- ) );
 
4081
  return (int) $count;
4082
  }
4083
 
@@ -4093,23 +4303,25 @@ class Utils {
4093
  public function get_announcements( $course_id = 0 ) {
4094
  $course_id = $this->get_post_id( $course_id );
4095
  global $wpdb;
4096
- $query = $wpdb->get_results( $wpdb->prepare(
4097
- "SELECT {$wpdb->posts}.ID,
4098
- post_author,
4099
- post_date,
4100
- post_content,
4101
- post_title,
4102
- display_name
4103
- FROM {$wpdb->posts}
4104
- INNER JOIN {$wpdb->users}
4105
- ON post_author = {$wpdb->users}.ID
4106
- WHERE post_type = %s
 
4107
  AND post_parent = %d
4108
  ORDER BY {$wpdb->posts}.ID DESC;
4109
  ",
4110
- 'tutor_announcements',
4111
- $course_id
4112
- ) );
 
4113
  return $query;
4114
  }
4115
 
@@ -4127,7 +4339,7 @@ class Utils {
4127
 
4128
  $user_display_name = 'User';
4129
  if ( is_user_logged_in() ) {
4130
- $user = wp_get_current_user();
4131
  $user_display_name = $user->display_name;
4132
  }
4133
 
@@ -4137,17 +4349,17 @@ class Utils {
4137
  }
4138
 
4139
  /**
4140
- * @param int $post_id
4141
  * @param string $option_key
4142
- * @param bool $default
4143
  *
4144
  * @return array|bool|mixed
4145
  *
4146
  * Get the quiz option from meta
4147
  */
4148
  public function get_quiz_option( $post_id = 0, $option_key = '', $default = false ) {
4149
- $post_id = $this->get_post_id( $post_id );
4150
- $get_option_meta = maybe_unserialize(get_post_meta( $post_id, 'tutor_quiz_option', true ) );
4151
 
4152
  if ( ! $option_key && ! empty( $get_option_meta ) ) {
4153
  return $get_option_meta;
@@ -4172,14 +4384,16 @@ class Utils {
4172
  $quiz_id = $this->get_post_id( $quiz_id );
4173
  global $wpdb;
4174
 
4175
- $questions = $wpdb->get_results( $wpdb->prepare(
4176
- "SELECT *
 
4177
  FROM {$wpdb->prefix}tutor_quiz_questions
4178
  WHERE quiz_id = %d
4179
  ORDER BY question_order ASC
4180
  ",
4181
- $quiz_id
4182
- ) );
 
4183
 
4184
  if ( is_array( $questions ) && count( $questions ) ) {
4185
  return $questions;
@@ -4199,14 +4413,16 @@ class Utils {
4199
  global $wpdb;
4200
 
4201
  if ( $question_id ) {
4202
- $question = $wpdb->get_row( $wpdb->prepare(
4203
- "SELECT *
 
4204
  FROM {$wpdb->prefix}tutor_quiz_questions
4205
  WHERE question_id = %d
4206
  LIMIT 0, 1;
4207
  ",
4208
- $question_id
4209
- ) );
 
4210
 
4211
  return $question;
4212
  }
@@ -4225,40 +4441,82 @@ class Utils {
4225
  */
4226
  public function get_question_types( $type = null ) {
4227
  $types = array(
4228
- 'true_false' => array( 'name' => __('True/False', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="True/False"><i class="tutor-icon-block tutor-icon-yes-no"></i></span>', 'is_pro' => false ),
4229
- 'single_choice' => array( 'name' => __('Single Choice', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Single Choice"><i class="tutor-icon-block tutor-icon-mark"></i></span>', 'is_pro' => false ),
4230
- 'multiple_choice' => array( 'name' => __('Multiple Choice', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Multiple Choicee"><i class="tutor-icon-block tutor-icon-multiple-choice"></i></span>', 'is_pro' => false ),
4231
- 'open_ended' => array( 'name' => __('Open Ended/Essay', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Open/Essay"><i class="tutor-icon-block tutor-icon-open-ended"></i></span>', 'is_pro' => false ),
4232
- 'fill_in_the_blank' => array( 'name' => __('Fill In The Blanks', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Fill In The Blanks"><i class="tutor-icon-block tutor-icon-fill-gaps"></i></span>', 'is_pro' => false ),
4233
- 'short_answer' => array( 'name' => __('Short Answer', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Short Answer"><i class="tutor-icon-block tutor-icon-short-ans"></i></span>', 'is_pro' => true ),
4234
- 'matching' => array( 'name' => __('Matching', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Matching"><i class="tutor-icon-block tutor-icon-matching"></i></span>', 'is_pro' => true ),
4235
- 'image_matching' => array( 'name' => __('Image Matching', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Image Matching"><i class="tutor-icon-block tutor-icon-image-matching"></i></span>', 'is_pro' => true ),
4236
- 'image_answering' => array( 'name' => __('Image Answering', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Image Answering"><i class="tutor-icon-block tutor-icon-image-ans"></i></span>', 'is_pro' => true ),
4237
- 'ordering' => array( 'name' => __('Ordering', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Ordering"><i class="tutor-icon-block tutor-icon-ordering"></i></span>', 'is_pro' => true ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4238
  );
4239
 
4240
  if ( isset( $types[ $type ] ) ) {
4241
  return $types[ $type ];
4242
  }
4243
-
4244
  return $types;
4245
  }
4246
 
4247
  public function get_quiz_answer_options_by_question( $question_id ) {
4248
  global $wpdb;
4249
 
4250
- $answer_options = $wpdb->get_results( $wpdb->prepare(
4251
- "SELECT {$wpdb->comments}.comment_ID,
4252
- {$wpdb->comments}.comment_post_ID,
 
4253
  {$wpdb->comments}.comment_content
4254
  FROM {$wpdb->comments}
4255
- WHERE {$wpdb->comments}.comment_post_ID = %d
4256
  AND {$wpdb->comments}.comment_type = %s
4257
  ORDER BY {$wpdb->comments}.comment_karma ASC;
4258
  ",
4259
- $question_id,
4260
- 'quiz_answer_option'
4261
- ) );
 
4262
 
4263
  if ( is_array( $answer_options ) && count( $answer_options ) ) {
4264
  return $answer_options;
@@ -4278,13 +4536,15 @@ class Utils {
4278
  public function quiz_next_question_order_id( $quiz_id ) {
4279
  global $wpdb;
4280
 
4281
- $last_order = (int) $wpdb->get_var( $wpdb->prepare(
4282
- "SELECT MAX(question_order)
4283
- FROM {$wpdb->prefix}tutor_quiz_questions
 
4284
  WHERE quiz_id = %d ;
4285
  ",
4286
- $quiz_id
4287
- ) );
 
4288
 
4289
  return $last_order + 1;
4290
  }
@@ -4306,13 +4566,15 @@ class Utils {
4306
 
4307
  public function get_quiz_id_by_question( $question_id ) {
4308
  global $wpdb;
4309
- $quiz_id = $wpdb->get_var( $wpdb->prepare(
4310
- "SELECT quiz_id
4311
- FROM {$wpdb->tutor_quiz_questions}
 
4312
  WHERE question_id = %d;
4313
  ",
4314
- $question_id
4315
- ) );
 
4316
  return $quiz_id;
4317
  }
4318
 
@@ -4328,8 +4590,9 @@ class Utils {
4328
 
4329
  $post_id = $this->get_post_id( $post_id );
4330
 
4331
- $questions = $wpdb->get_results( $wpdb->prepare(
4332
- "SELECT ID,
 
4333
  post_content,
4334
  post_title,
4335
  post_parent
@@ -4338,10 +4601,11 @@ class Utils {
4338
  AND post_status = %s
4339
  AND post_parent = %d;
4340
  ",
4341
- 'tutor_quiz',
4342
- 'publish',
4343
- $post_id
4344
- ) );
 
4345
 
4346
  if ( is_array( $questions ) && count( $questions ) ) {
4347
  return $questions;
@@ -4363,13 +4627,13 @@ class Utils {
4363
  global $wpdb;
4364
 
4365
  $quiz_id = $this->get_post_id( $quiz_id );
4366
- $post = get_post( $quiz_id );
4367
 
4368
  if ( $post ) {
4369
  $course_post_type = tutor()->course_post_type;
4370
- $query_string = "SELECT ID, post_author, post_name, post_type, post_parent FROM {$wpdb->posts} where ID = %d";
4371
- $course = $wpdb->get_row( $wpdb->prepare( $query_string, $post->post_parent ) );
4372
-
4373
  if ( $course ) {
4374
  if ( $course->post_type !== $course_post_type ) {
4375
  $course = $wpdb->get_row( $wpdb->prepare( $query_string, $course->post_parent ) );
@@ -4393,15 +4657,17 @@ class Utils {
4393
  global $wpdb;
4394
 
4395
  $max_questions_count = (int) tutor_utils()->get_quiz_option( get_the_ID(), 'max_questions_for_answer' );
4396
- $total_question = (int) $wpdb->get_var( $wpdb->prepare(
4397
- "SELECT count(question_id)
 
4398
  FROM {$wpdb->tutor_quiz_questions}
4399
  WHERE quiz_id = %d;
4400
  ",
4401
- $quiz_id
4402
- ) );
 
4403
 
4404
- return min($max_questions_count, $total_question);
4405
  }
4406
 
4407
  /**
@@ -4419,17 +4685,19 @@ class Utils {
4419
  $quiz_id = $this->get_post_id( $quiz_id );
4420
  $user_id = get_current_user_id();
4421
 
4422
- $is_started = $wpdb->get_row( $wpdb->prepare(
4423
- "SELECT *
 
4424
  FROM {$wpdb->prefix}tutor_quiz_attempts
4425
  WHERE user_id = %d
4426
  AND quiz_id = %d
4427
  AND attempt_status = %s;
4428
  ",
4429
- $user_id,
4430
- $quiz_id,
4431
- 'attempt_started'
4432
- ) );
 
4433
 
4434
  return $is_started;
4435
  }
@@ -4449,13 +4717,15 @@ class Utils {
4449
  $quiz_id = $this->get_post_id( $quiz_id );
4450
  global $wpdb;
4451
 
4452
- $max_questions = (int) $wpdb->get_var( $wpdb->prepare(
4453
- "SELECT count(question_id)
 
4454
  FROM {$wpdb->prefix}tutor_quiz_questions
4455
  WHERE quiz_id = %d;
4456
  ",
4457
- $quiz_id
4458
- ) );
 
4459
 
4460
  $max_mentioned = (int) $this->get_quiz_option( $quiz_id, 'max_questions_for_answer', 10 );
4461
 
@@ -4481,13 +4751,15 @@ class Utils {
4481
  return false;
4482
  }
4483
 
4484
- $attempt = $wpdb->get_row( $wpdb->prepare(
4485
- "SELECT *
 
4486
  FROM {$wpdb->prefix}tutor_quiz_attempts
4487
  WHERE attempt_id = %d;
4488
  ",
4489
- $attempt_id
4490
- ) );
 
4491
 
4492
  return $attempt;
4493
  }
@@ -4507,7 +4779,7 @@ class Utils {
4507
 
4508
  /**
4509
  * @param $quiz_attempt_id
4510
- * @param array $attempt_info
4511
  *
4512
  * @return bool|int
4513
  *
@@ -4516,13 +4788,13 @@ class Utils {
4516
  * @since v.1.0.0
4517
  */
4518
  public function quiz_update_attempt_info( $quiz_attempt_id, $attempt_info = array() ) {
4519
- $answers = tutor_utils()->avalue_dot( 'answers', $attempt_info );
4520
- $total_marks = array_sum( wp_list_pluck( $answers, 'question_mark' ) );
4521
- $earned_marks = tutor_utils()->avalue_dot( 'marks_earned', $attempt_info );
4522
- $earned_mark_percent = $earned_marks > 0 ? ( number_format( ($earned_marks * 100) / $total_marks) ) : 0;
4523
  update_comment_meta( $quiz_attempt_id, 'earned_mark_percent', $earned_mark_percent );
4524
 
4525
- return update_comment_meta( $quiz_attempt_id,'quiz_attempt_info', $attempt_info );
4526
  }
4527
 
4528
  /**
@@ -4537,20 +4809,22 @@ class Utils {
4537
  public function get_random_question_by_quiz( $quiz_id = 0 ) {
4538
  global $wpdb;
4539
 
4540
- $quiz_id = $this->get_post_id( $quiz_id );
4541
  $is_attempt = $this->is_started_quiz( $quiz_id );
4542
 
4543
- $tempSql = " AND question_type = 'matching' ";
4544
- $questions = $wpdb->get_results( $wpdb->prepare(
4545
- "SELECT *
 
4546
  FROM {$wpdb->prefix}tutor_quiz_questions
4547
  WHERE quiz_id = %d
4548
  {$tempSql}
4549
  ORDER BY RAND()
4550
  LIMIT 0, 1
4551
  ",
4552
- $quiz_id
4553
- ) );
 
4554
 
4555
  return $questions;
4556
  }
@@ -4565,8 +4839,8 @@ class Utils {
4565
  public function get_random_questions_by_quiz( $quiz_id = 0 ) {
4566
  global $wpdb;
4567
 
4568
- $quiz_id = $this->get_post_id( $quiz_id );
4569
- $attempt = $this->is_started_quiz( $quiz_id );
4570
  $total_questions = (int) $attempt->total_questions;
4571
  if ( ! $attempt ) {
4572
  return false;
@@ -4574,15 +4848,15 @@ class Utils {
4574
 
4575
  $questions_order = tutor_utils()->get_quiz_option( get_the_ID(), 'questions_order', 'rand' );
4576
 
4577
- $order_by = "";
4578
  if ( $questions_order === 'rand' ) {
4579
- $order_by = "ORDER BY RAND()";
4580
  } elseif ( $questions_order === 'asc' ) {
4581
- $order_by = "ORDER BY question_id ASC";
4582
  } elseif ( $questions_order === 'desc' ) {
4583
- $order_by = "ORDER BY question_id DESC";
4584
  } elseif ( $questions_order === 'sorting' ) {
4585
- $order_by = "ORDER BY question_order ASC";
4586
  }
4587
 
4588
  $limit = '';
@@ -4590,22 +4864,24 @@ class Utils {
4590
  $limit = "LIMIT {$total_questions} ";
4591
  }
4592
 
4593
- $questions = $wpdb->get_results( $wpdb->prepare(
4594
- "SELECT *
 
4595
  FROM {$wpdb->prefix}tutor_quiz_questions
4596
  WHERE quiz_id = %d
4597
  {$order_by}
4598
  {$limit}
4599
  ",
4600
- $quiz_id
4601
- ) );
 
4602
 
4603
  return $questions;
4604
  }
4605
 
4606
  /**
4607
  * @param $question_id
4608
- * @param bool $rand
4609
  *
4610
  * @return array|bool|null|object
4611
  *
@@ -4616,38 +4892,42 @@ class Utils {
4616
  public function get_answers_by_quiz_question( $question_id, $rand = false ) {
4617
  global $wpdb;
4618
 
4619
- $question = $wpdb->get_row( $wpdb->prepare(
4620
- "SELECT *
 
4621
  FROM {$wpdb->prefix}tutor_quiz_questions
4622
  WHERE question_id = %d;
4623
  ",
4624
- $question_id
4625
- ) );
 
4626
 
4627
  if ( ! $question ) {
4628
  return false;
4629
  }
4630
 
4631
- $order = " answer_order ASC ";
4632
  if ( $question->question_type === 'ordering' ) {
4633
- $order = " RAND() ";
4634
  }
4635
 
4636
- if ($rand){
4637
- $order = " RAND() ";
4638
  }
4639
 
4640
- $answers = $wpdb->get_results( $wpdb->prepare(
4641
- "SELECT *
4642
- FROM {$wpdb->prefix}tutor_quiz_question_answers
 
4643
  WHERE belongs_question_id = %d
4644
  AND belongs_question_type = %s
4645
  ORDER BY {$order}
4646
  ",
4647
- $question_id,
4648
- $question->question_type
4649
- ) );
4650
-
 
4651
  return $answers;
4652
  }
4653
 
@@ -4668,16 +4948,18 @@ class Utils {
4668
  $quiz_id = $this->get_post_id( $quiz_id );
4669
  $user_id = $this->get_user_id( $user_id );
4670
 
4671
- $attempts = $wpdb->get_results( $wpdb->prepare(
4672
- "SELECT *
 
4673
  FROM {$wpdb->prefix}tutor_quiz_attempts
4674
  WHERE quiz_id = %d
4675
  AND user_id = %d
4676
- ORDER BY attempt_id DESC
4677
  ",
4678
- $quiz_id,
4679
- $user_id
4680
- ) );
 
4681
 
4682
  if ( is_array( $attempts ) && count( $attempts ) ) {
4683
  return $attempts;
@@ -4702,17 +4984,19 @@ class Utils {
4702
  $quiz_id = $this->get_post_id( $quiz_id );
4703
  $user_id = $this->get_user_id( $user_id );
4704
 
4705
- $attempts = $wpdb->get_results( $wpdb->prepare(
4706
- "SELECT *
 
4707
  FROM {$wpdb->prefix}tutor_quiz_attempts
4708
  WHERE quiz_id = %d
4709
  AND user_id = %d
4710
  AND attempt_status != %s
4711
  ",
4712
- $quiz_id,
4713
- $user_id,
4714
- 'attempt_started'
4715
- ) );
 
4716
 
4717
  if ( is_array( $attempts ) && count( $attempts ) ) {
4718
  return $attempts;
@@ -4735,14 +5019,16 @@ class Utils {
4735
  global $wpdb;
4736
 
4737
  $user_id = $this->get_user_id( $user_id );
4738
- $attempts = $wpdb->get_results( $wpdb->prepare(
4739
- "SELECT *
 
4740
  FROM {$wpdb->prefix}tutor_quiz_attempts
4741
  WHERE user_id = %d
4742
  ORDER BY attempt_id DESC
4743
  ",
4744
- $user_id
4745
- ) );
 
4746
 
4747
  if ( is_array( $attempts ) && count( $attempts ) ) {
4748
  return $attempts;
@@ -4759,21 +5045,21 @@ class Utils {
4759
  * Total number of quiz attempts
4760
  *
4761
  * @since v.1.0.0
4762
- *
4763
  * This method is not being in used
4764
- *
4765
- * to get total number of attempt get_quiz_attempts method is enough
4766
- *
4767
- * @since 1.9.5
4768
  *
 
 
 
4769
  */
4770
  public function get_total_quiz_attempts( $search_term = '' ) {
4771
  global $wpdb;
4772
 
4773
- $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4774
 
4775
- $count = $wpdb->get_var( $wpdb->prepare(
4776
- "SELECT COUNT(attempt_id)
 
4777
  FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4778
  INNER JOIN {$wpdb->posts} quiz
4779
  ON quiz_attempts.quiz_id = quiz.ID
@@ -4782,18 +5068,19 @@ class Utils {
4782
  WHERE attempt_status != %s
4783
  AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4784
  ",
4785
- 'attempt_started',
4786
- $search_term,
4787
- $search_term,
4788
- $search_term
4789
- ) );
 
4790
 
4791
  return (int) $count;
4792
  }
4793
 
4794
  /**
4795
- * @param int $start
4796
- * @param int $limit
4797
  * @param string $search_term
4798
  *
4799
  * @return array|null|object
@@ -4802,21 +5089,22 @@ class Utils {
4802
  * Get the all quiz attempts
4803
  *
4804
  * @since 1.0.0
4805
- *
4806
- * Sorting paramas added
4807
- *
4808
  * @since 1.9.5
4809
  */
4810
- public function get_quiz_attempts( $start = 0, $limit = 10, $search_filter='', $course_filter='', $date_filter='', $order_filter='' ) {
4811
  global $wpdb;
4812
 
4813
- $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
4814
- $course_filter = $course_filter != '' ? " AND quiz_attempts.course_id = $course_filter " : '' ;
4815
- $date_filter = $date_filter != '' ? tutor_get_formated_date( 'Y-m-d', $date_filter ) : '';
4816
- $date_filter = $date_filter != '' ? " AND DATE(quiz_attempts.attempt_started_at) = '$date_filter' " : '' ;
4817
 
4818
- $query = $wpdb->get_results( $wpdb->prepare(
4819
- "SELECT quiz_attempts.*, quiz.*, users.*
 
4820
  FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4821
  INNER JOIN {$wpdb->posts} quiz
4822
  ON quiz_attempts.quiz_id = quiz.ID
@@ -4828,124 +5116,135 @@ class Utils {
4828
  AND ( users.user_email LIKE %s OR users.display_name LIKE %s OR quiz.post_title LIKE %s OR course.post_title LIKE %s )
4829
  {$course_filter}
4830
  {$date_filter}
4831
- ORDER BY quiz_attempts.attempt_ended_at $order_filter
4832
  LIMIT %d, %d;
4833
  ",
4834
- 'attempt_started',
4835
- $search_filter,
4836
- $search_filter,
4837
- $search_filter,
4838
- $search_filter,
4839
- $start,
4840
- $limit
4841
- ) );
 
4842
 
4843
  return $query;
4844
  }
4845
 
4846
  /**
4847
  * Delete quizattempt for user
4848
- *
4849
  * @since v1.9.5
4850
  */
4851
- public function delete_quiz_attempt($attempt_ids) {
4852
  global $wpdb;
4853
 
4854
  // Singlular to array
4855
- !is_array($attempt_ids) ? $attempt_ids = array($attempt_ids) : 0;
4856
 
4857
- if(count($attempt_ids)) {
4858
- $attempt_ids = implode( ',', $attempt_ids);
4859
 
4860
- //Deleting attempt (comment), child attempt and attempt meta (comment meta)
4861
  $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_attempts WHERE attempt_id IN($attempt_ids)" );
4862
  $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE quiz_attempt_id IN($attempt_ids)" );
4863
  }
4864
  }
4865
 
4866
  /**
4867
- * Sorting params added on quiz attempt
4868
- *
4869
  * SQL query updated
4870
- *
4871
  * @since 1.9.5
4872
  */
4873
  public function get_quiz_attempts_by_course_ids( $start = 0, $limit = 10, $course_ids = array(), $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $user_id = null ) {
4874
  global $wpdb;
4875
 
4876
- $course_ids = array_map( function( $id ) {
4877
- return "'" . esc_sql( $id ) . "'";
4878
- }, $course_ids );
 
 
 
4879
 
4880
  $course_ids_in = implode( ', ', $course_ids );
4881
 
4882
- $search_filter = $search_filter ? '%' . $wpdb->esc_like( $search_filter ) . '%' : '';
4883
  $search_filter = $search_filter ? "AND ( users.user_email LIKE {$search_filter} OR users.display_name LIKE {$search_filter} OR quiz.post_title LIKE {$search_filter} OR course.post_title LIKE {$search_filter} )" : '';
4884
 
4885
- $course_filter = $course_filter != '' ? " AND quiz_attempts.course_id = $course_filter " : '' ;
4886
- $date_filter = $date_filter != '' ? tutor_get_formated_date( 'Y-m-d', $date_filter ) : '';
4887
- $date_filter = $date_filter != '' ? " AND DATE(quiz_attempts.attempt_started_at) = '$date_filter' " : '' ;
4888
 
4889
- $query = $wpdb->get_results( $wpdb->prepare(
4890
- "SELECT quiz_attempts.*, users.*, quiz.*
4891
- FROM {$wpdb->prefix}tutor_quiz_attempts AS quiz_attempts
 
4892
  INNER JOIN {$wpdb->posts} AS quiz
4893
- ON quiz_attempts.quiz_id = quiz.ID
4894
  INNER JOIN {$wpdb->users} AS users
4895
- ON quiz_attempts.user_id = users.ID
4896
  INNER JOIN {$wpdb->posts} AS course
4897
- ON course.ID = quiz_attempts.course_id
4898
  WHERE quiz_attempts.course_id IN (" . $course_ids_in . ")
4899
  AND quiz_attempts.attempt_status != %s
4900
  {$search_filter}
4901
  {$course_filter}
4902
  {$date_filter}
4903
- " . ($user_id ? ' AND user_id=\''.esc_sql( $user_id ).'\'' : '') . "
4904
  ORDER BY quiz_attempts.attempt_id $order_filter
4905
  LIMIT %d, %d;
4906
  ",
4907
- 'attempt_started',
4908
- $start,
4909
- $limit
4910
- ) );
 
4911
 
4912
  return $query;
4913
  }
4914
 
4915
  /**
4916
  * This method is not being in used
4917
- *
4918
- * to get total number of attempt above method is enough
4919
- *
4920
  * @since 1.9.5
4921
  */
4922
  public function get_total_quiz_attempts_by_course_ids( $course_ids = array(), $search_term = '' ) {
4923
  global $wpdb;
4924
-
4925
- $course_ids = array_map( function( $id ) {
4926
- return "'" . esc_sql( $id ) . "'";
4927
- }, $course_ids );
 
 
 
4928
 
4929
  $course_ids_in = implode( ', ', $course_ids );
4930
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4931
 
4932
- $count = $wpdb->get_var( $wpdb->prepare(
4933
- "SELECT COUNT(attempt_id)
4934
- FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
 
4935
  INNER JOIN {$wpdb->posts} quiz
4936
- ON quiz_attempts.quiz_id = quiz.ID
4937
  INNER JOIN {$wpdb->users}
4938
- ON quiz_attempts.user_id = {$wpdb->users}.ID
4939
- WHERE quiz_attempts.course_id IN (" . $course_ids_in . ")
4940
- AND attempt_status != %s
4941
  AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4942
- ",
4943
- 'attempt_started',
4944
- $search_term,
4945
- $search_term,
4946
- $search_term
4947
- ) );
4948
-
 
4949
  return (int) $count;
4950
  }
4951
 
@@ -4961,18 +5260,20 @@ class Utils {
4961
  public function get_quiz_answers_by_attempt_id( $attempt_id ) {
4962
  global $wpdb;
4963
 
4964
- $results = $wpdb->get_results( $wpdb->prepare(
4965
- "SELECT answers.*,
4966
- question.question_title,
4967
- question.question_type
4968
- FROM {$wpdb->prefix}tutor_quiz_attempt_answers answers
 
4969
  LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
4970
- ON answers.question_id = question.question_id
4971
- WHERE answers.quiz_attempt_id = %d
4972
  ORDER BY attempt_answer_id ASC;
4973
  ",
4974
- $attempt_id
4975
- ) );
 
4976
 
4977
  return $results;
4978
  }
@@ -4990,25 +5291,30 @@ class Utils {
4990
  global $wpdb;
4991
 
4992
  ! is_array( $answer_id ) ? $answer_id = array( $answer_id ) : 0;
4993
-
4994
- $answer_id = array_map( function( $id ) {
4995
- return "'" . esc_sql( $id ) . "'";
4996
- }, $answer_id );
 
 
 
4997
 
4998
  $in_ids_string = implode( ', ', $answer_id );
4999
-
5000
- $answer = $wpdb->get_results( $wpdb->prepare(
5001
- "SELECT answer.*,
 
5002
  question.question_title,
5003
  question.question_type
5004
  FROM {$wpdb->prefix}tutor_quiz_question_answers answer
5005
  LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
5006
  ON answer.belongs_question_id = question.question_id
5007
- WHERE answer.answer_id IN (" . $in_ids_string . ")
5008
  AND 1 = %d;
5009
- ",
5010
- 1
5011
- ) );
 
5012
 
5013
  return $answer;
5014
  }
@@ -5029,19 +5335,21 @@ class Utils {
5029
  return false;
5030
  }
5031
 
5032
- $in_ids = implode(",", $ids);
5033
 
5034
  global $wpdb;
5035
 
5036
- $query = $wpdb->get_results( $wpdb->prepare(
5037
- "SELECT comment_ID,
 
5038
  comment_content
5039
  FROM {$wpdb->comments}
5040
  WHERE comment_type = %s
5041
  AND comment_ID IN({$in_ids})
5042
  ",
5043
- 'quiz_answer_option'
5044
- ) );
 
5045
 
5046
  if ( is_array( $query ) && count( $query ) ) {
5047
  return $query;
@@ -5060,12 +5368,15 @@ class Utils {
5060
  * @since v.1.0.0
5061
  */
5062
  public function course_levels( $level = null ) {
5063
- $levels = apply_filters( 'tutor_course_level', array(
5064
- 'all_levels' => __( 'All Levels', 'tutor' ),
5065
- 'beginner' => __( 'Beginner', 'tutor' ),
5066
- 'intermediate' => __( 'Intermediate', 'tutor' ),
5067
- 'expert' => __( 'Expert', 'tutor' ),
5068
- ));
 
 
 
5069
 
5070
  if ( $level ) {
5071
  if ( isset( $levels[ $level ] ) ) {
@@ -5087,7 +5398,7 @@ class Utils {
5087
  */
5088
  public function user_profile_permalinks() {
5089
  $permalinks = array(
5090
- 'courses_taken' => __( 'Courses Taken', 'tutor' ),
5091
  );
5092
 
5093
  $show_enrolled_course = tutor_utils()->get_option( 'show_courses_completed_by_student' );
@@ -5143,7 +5454,7 @@ class Utils {
5143
  *
5144
  * Get frontend dashboard URL
5145
  */
5146
- public function tutor_dashboard_url($sub_url = '') {
5147
  $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
5148
  $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
5149
  return trailingslashit( get_the_permalink( $page_id ) ) . $sub_url;
@@ -5153,7 +5464,6 @@ class Utils {
5153
  * Get the tutor dashboard page ID
5154
  *
5155
  * @return int
5156
- *
5157
  */
5158
  public function dashboard_page_id() {
5159
  $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
@@ -5173,22 +5483,24 @@ class Utils {
5173
  */
5174
  public function is_wishlisted( $course_id = 0, $user_id = 0 ) {
5175
  $course_id = $this->get_post_id( $course_id );
5176
- $user_id = $this->get_user_id( $user_id );
5177
  if ( ! $user_id ) {
5178
  return false;
5179
  }
5180
 
5181
  global $wpdb;
5182
- $if_added_to_list = (bool) $wpdb->get_row( $wpdb->prepare(
5183
- "SELECT *
5184
- FROM {$wpdb->usermeta}
 
5185
  WHERE user_id = %d
5186
  AND meta_key = '_tutor_course_wishlist'
5187
  AND meta_value = %d;
5188
  ",
5189
- $user_id,
5190
- $course_id
5191
- ) );
 
5192
 
5193
  return $if_added_to_list;
5194
  }
@@ -5208,8 +5520,9 @@ class Utils {
5208
  $user_id = $this->get_user_id( $user_id );
5209
  $course_post_type = tutor()->course_post_type;
5210
 
5211
- $pageposts = $wpdb->get_results( $wpdb->prepare(
5212
- "SELECT $wpdb->posts.*
 
5213
  FROM $wpdb->posts
5214
  LEFT JOIN $wpdb->usermeta
5215
  ON ($wpdb->posts.ID = $wpdb->usermeta.meta_value)
@@ -5219,11 +5532,13 @@ class Utils {
5219
  AND $wpdb->usermeta.user_id = %d
5220
  ORDER BY $wpdb->usermeta.umeta_id DESC;
5221
  ",
5222
- $course_post_type,
5223
- 'publish',
5224
- '_tutor_course_wishlist',
5225
- $user_id
5226
- ), OBJECT );
 
 
5227
 
5228
  return $pageposts;
5229
  }
@@ -5239,21 +5554,22 @@ class Utils {
5239
  */
5240
  public function most_popular_courses( $limit = 10, $user_id = '' ) {
5241
  global $wpdb;
5242
- $limit = sanitize_text_field( $limit );
5243
- $user_id = sanitize_text_field( $user_id );
5244
 
5245
  $author_query = '';
5246
  if ( '' !== $user_id ) {
5247
  $author_query = "AND course.post_author = $user_id";
5248
  }
5249
 
5250
- $courses = $wpdb->get_results( $wpdb->prepare(
5251
- "SELECT COUNT(enrolled.ID) AS total_enrolled,
 
5252
  enrolled.post_parent as course_id,
5253
  course.*
5254
  FROM {$wpdb->posts} enrolled
5255
  INNER JOIN {$wpdb->posts} course
5256
- ON enrolled.post_parent = course.ID
5257
  WHERE enrolled.post_type = %s
5258
  AND enrolled.post_status = %s
5259
  {$author_query}
@@ -5261,10 +5577,11 @@ class Utils {
5261
  ORDER BY total_enrolled DESC
5262
  LIMIT 0, %d;
5263
  ",
5264
- 'tutor_enrolled',
5265
- 'completed',
5266
- $limit
5267
- ) );
 
5268
 
5269
  return $courses;
5270
  }
@@ -5281,8 +5598,9 @@ class Utils {
5281
  public function most_rated_courses( $limit = 10 ) {
5282
  global $wpdb;
5283
 
5284
- $result = $wpdb->get_results( $wpdb->prepare(
5285
- "SELECT COUNT(comment_ID) AS total_rating,
 
5286
  comment_ID,
5287
  comment_post_ID,
5288
  course.*
@@ -5295,10 +5613,11 @@ class Utils {
5295
  ORDER BY total_rating DESC
5296
  LIMIT 0, %d
5297
  ;",
5298
- 'tutor_course_rating',
5299
- 'approved',
5300
- $limit
5301
- ) );
 
5302
 
5303
  if ( is_array( $result ) && count( $result ) ) {
5304
  return $result;
@@ -5339,20 +5658,21 @@ class Utils {
5339
  */
5340
  function get_ip() {
5341
  $ipaddress = '';
5342
- if ( getenv( 'HTTP_CLIENT_IP') )
5343
  $ipaddress = getenv( 'HTTP_CLIENT_IP' );
5344
- else if( getenv( 'HTTP_X_FORWARDED_FOR' ) )
5345
  $ipaddress = getenv( 'HTTP_X_FORWARDED_FOR' );
5346
- else if( getenv( 'HTTP_X_FORWARDED' ) )
5347
  $ipaddress = getenv( 'HTTP_X_FORWARDED' );
5348
- else if( getenv( 'HTTP_FORWARDED_FOR' ) )
5349
  $ipaddress = getenv( 'HTTP_FORWARDED_FOR' );
5350
- else if( getenv( 'HTTP_FORWARDED' ) )
5351
  $ipaddress = getenv( 'HTTP_FORWARDED' );
5352
- else if( getenv( 'REMOTE_ADDR' ) )
5353
  $ipaddress = getenv( 'REMOTE_ADDR' );
5354
- else
5355
  $ipaddress = 'UNKNOWN';
 
5356
  return $ipaddress;
5357
  }
5358
 
@@ -5365,10 +5685,22 @@ class Utils {
5365
  */
5366
  public function tutor_social_share_icons() {
5367
  $icons = array(
5368
- 'facebook' => array( 'share_class' => 's_facebook', 'icon_html' => '<i class="tutor-icon-facebook"></i>' ),
5369
- 'twitter' => array( 'share_class' => 's_twitter', 'icon_html' => '<i class="tutor-icon-twitter"></i>' ),
5370
- 'linkedin' => array( 'share_class' => 's_linkedin', 'icon_html' => '<i class="tutor-icon-linkedin"></i>' ),
5371
- 'tumblr' => array( 'share_class' => 's_tumblr', 'icon_html' => '<i class="tutor-icon-tumblr"></i>' ),
 
 
 
 
 
 
 
 
 
 
 
 
5372
  );
5373
 
5374
  return apply_filters( 'tutor_social_share_icons', $icons );
@@ -5384,29 +5716,29 @@ class Utils {
5384
  public function tutor_user_social_icons() {
5385
  $icons = array(
5386
  '_tutor_profile_website' => array(
5387
- 'label' => __('Website URL', 'tutor'),
5388
  'placeholder' => 'https://example.com/',
5389
- 'icon_classes' => 'tutor-icon-earth'
5390
  ),
5391
- '_tutor_profile_github' => array(
5392
- 'label' => __('Github URL', 'tutor'),
5393
  'placeholder' => 'https://github.com/username',
5394
- 'icon_classes' => 'tutor-icon-github-logo'
5395
  ),
5396
- '_tutor_profile_facebook' => array(
5397
- 'label' => __('Facebook URL', 'tutor'),
5398
  'placeholder' => 'https://facebook.com/username',
5399
- 'icon_classes' => 'tutor-icon-facebook'
5400
  ),
5401
  '_tutor_profile_twitter' => array(
5402
- 'label' => __('Twitter URL', 'tutor'),
5403
  'placeholder' => 'https://twitter.com/username',
5404
- 'icon_classes' => 'tutor-icon-twitter'
5405
  ),
5406
- '_tutor_profile_linkedin' => array(
5407
- 'label' => __('Linkedin URL', 'tutor'),
5408
  'placeholder' => 'https://linkedin.com/username',
5409
- 'icon_classes' => 'tutor-icon-linkedin'
5410
  ),
5411
  );
5412
 
@@ -5439,19 +5771,19 @@ class Utils {
5439
  */
5440
  public function tutor_get_screen_ids() {
5441
  $screen_ids = array(
5442
- "edit-course",
5443
- "course",
5444
- "edit-course-category",
5445
- "edit-course-tag",
5446
- "tutor-lms_page_tutor-students",
5447
- "tutor-lms_page_tutor-instructors",
5448
- "tutor-lms_page_question_answer",
5449
- "tutor-lms_page_tutor_quiz_attempts",
5450
- "tutor-lms_page_tutor-addons",
5451
- "tutor-lms_page_tutor-status",
5452
- "tutor-lms_page_tutor_report",
5453
- "tutor-lms_page_tutor_settings",
5454
- "tutor-lms_page_tutor_emails",
5455
  );
5456
 
5457
  return apply_filters( 'tutor_get_screen_ids', $screen_ids );
@@ -5467,7 +5799,7 @@ class Utils {
5467
  public function get_earnings_completed_statuses() {
5468
  return apply_filters(
5469
  'tutor_get_earnings_completed_statuses',
5470
- array (
5471
  'wc-completed',
5472
  'completed',
5473
  'complete',
@@ -5476,7 +5808,7 @@ class Utils {
5476
  }
5477
 
5478
  /**
5479
- * @param int $user_id
5480
  * @param array $date_filter
5481
  *
5482
  * @return array|null|object
@@ -5488,7 +5820,7 @@ class Utils {
5488
  public function get_earning_sum( $user_id = 0, $date_filter = array() ) {
5489
  global $wpdb;
5490
 
5491
- $user_id = $this->get_user_id( $user_id );
5492
  $date_query = '';
5493
 
5494
  if ( $this->count( $date_filter ) ) {
@@ -5509,39 +5841,41 @@ class Utils {
5509
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
5510
  $complete_status = "'" . implode( "','", $complete_status ) . "'";
5511
 
5512
- $earning_sum = $wpdb->get_row( $wpdb->prepare(
5513
- "SELECT SUM(course_price_total) AS course_price_total,
5514
- SUM(course_price_grand_total) AS course_price_grand_total,
5515
- SUM(instructor_amount) AS instructor_amount,
 
5516
  (SELECT SUM(amount)
5517
  FROM {$wpdb->prefix}tutor_withdraws
5518
  WHERE user_id = {$user_id}
5519
  AND status != 'rejected'
5520
  ) AS withdraws_amount,
5521
- SUM(admin_amount) AS admin_amount,
5522
  SUM(deduct_fees_amount) AS deduct_fees_amount
5523
- FROM {$wpdb->prefix}tutor_earnings
5524
  WHERE user_id = %d
5525
  AND order_status IN({$complete_status})
5526
  {$date_query}
5527
  ",
5528
- $user_id
5529
- ) );
 
5530
 
5531
- //TODO: need to check
5532
  // (SUM(instructor_amount) - (SELECT withdraws_amount) ) as balance,
5533
 
5534
  if ( $earning_sum->course_price_total ) {
5535
  $earning_sum->balance = $earning_sum->instructor_amount - $earning_sum->withdraws_amount;
5536
  } else {
5537
  $earning_sum = (object) array(
5538
- 'course_price_total' => 0,
5539
- 'course_price_grand_total' => 0,
5540
- 'instructor_amount' => 0,
5541
- 'withdraws_amount' => 0,
5542
- 'balance' => 0,
5543
- 'admin_amount' => 0,
5544
- 'deduct_fees_amount' => 0,
5545
  );
5546
  }
5547
 
@@ -5549,7 +5883,7 @@ class Utils {
5549
  }
5550
 
5551
  /**
5552
- * @param int $user_id
5553
  * @param array $date_filter
5554
  *
5555
  * @return array|null|object
@@ -5561,13 +5895,13 @@ class Utils {
5561
  public function get_earning_statements( $user_id = 0, $filter_data = array() ) {
5562
  global $wpdb;
5563
 
5564
- $user_sql = "";
5565
- if ($user_id){
5566
  $user_sql = " AND user_id='{$user_id}' ";
5567
  }
5568
 
5569
- $date_query = '';
5570
- $query_by_status = '';
5571
  $pagination_query = '';
5572
 
5573
  /**
@@ -5604,40 +5938,40 @@ class Utils {
5604
  }
5605
 
5606
  if ( ! empty( $per_page ) ) {
5607
- $offset = (int) ! empty($offset) ? $offset : 0;
5608
  $pagination_query = " LIMIT {$offset}, {$per_page} ";
5609
  }
5610
  }
5611
 
5612
-
5613
  /**
5614
  * Delete duplicated earning rows that were created due to not checking if already added while creating new.
5615
  * New entries will check before insert.
5616
- *
5617
  * @since v1.9.7
5618
  */
5619
- if(!get_option( 'tutor_duplicated_earning_deleted', false )) {
5620
 
5621
  // Get the duplicated order IDs
5622
- $del_rows = array();
5623
  $order_ids = $wpdb->get_col(
5624
- "SELECT order_id
5625
- FROM (SELECT order_id, COUNT(order_id) AS cnt
5626
- FROM {$wpdb->prefix}tutor_earnings
5627
- GROUP BY order_id) t
5628
  WHERE cnt>1"
5629
  );
5630
 
5631
- if(is_array($order_ids) && count($order_ids)) {
5632
- $order_ids_string = implode(',', $order_ids);
5633
- $earnings = $wpdb->get_results(
5634
  "SELECT earning_id, course_id FROM {$wpdb->prefix}tutor_earnings
5635
- WHERE order_id IN ({$order_ids_string})
5636
- ORDER BY earning_id ASC");
 
5637
 
5638
  $excluded_first = array();
5639
- foreach($earnings as $earning) {
5640
- if(!in_array($earning->course_id, $excluded_first)) {
5641
  // Exclude first course ID from deletion
5642
  $excluded_first[] = $earning->course_id;
5643
  continue;
@@ -5647,16 +5981,17 @@ class Utils {
5647
  }
5648
  }
5649
 
5650
- if(count($del_rows)) {
5651
- $ids = implode(',', $del_rows);
5652
- $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_earnings WHERE earning_id IN ({$ids})");
5653
  }
5654
-
5655
  update_option( 'tutor_duplicated_earning_deleted', true );
5656
  }
5657
 
5658
- $query = $wpdb->get_results( $wpdb->prepare(
5659
- "SELECT earning_tbl.*,
 
5660
  course.post_title AS course_title
5661
  FROM {$wpdb->prefix}tutor_earnings earning_tbl
5662
  LEFT JOIN {$wpdb->posts} course
@@ -5664,17 +5999,20 @@ class Utils {
5664
  WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
5665
  ORDER BY created_at DESC {$pagination_query}
5666
  ",
5667
- 1
5668
- ) );
 
5669
 
5670
- $query_count = (int) $wpdb->get_var( $wpdb->prepare(
5671
- "SELECT COUNT(earning_tbl.earning_id)
 
5672
  FROM {$wpdb->prefix}tutor_earnings earning_tbl
5673
  WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
5674
  ORDER BY created_at DESC
5675
  ",
5676
- 1
5677
- ) );
 
5678
 
5679
  return (object) array(
5680
  'count' => $query_count,
@@ -5692,11 +6030,11 @@ class Utils {
5692
  * @since v.1.1.2
5693
  */
5694
  public function tutor_price( $price = 0 ) {
5695
- if ( function_exists( 'wc_price') ) {
5696
  return wc_price( $price );
5697
  } elseif ( function_exists( 'edd_currency_filter' ) ) {
5698
  return edd_currency_filter( edd_format_amount( $price ) );
5699
- }else{
5700
  return number_format_i18n( $price );
5701
  }
5702
  }
@@ -5710,7 +6048,7 @@ class Utils {
5710
  */
5711
  public function currency_symbol() {
5712
  $enable_tutor_edd = tutor_utils()->get_option( 'enable_tutor_edd' );
5713
- $monetize_by = $this->get_option('monetize_by');
5714
 
5715
  $symbol = '&#36;';
5716
  if ( $enable_tutor_edd && function_exists( 'edd_currency_symbol' ) ) {
@@ -5743,7 +6081,7 @@ class Utils {
5743
  }
5744
 
5745
  /**
5746
- * @param int $user_id
5747
  * @param array $filter
5748
  *
5749
  * get withdrawal history
@@ -5754,11 +6092,11 @@ class Utils {
5754
  global $wpdb;
5755
 
5756
  $filter = (array) $filter;
5757
- extract($filter);
5758
 
5759
- $query_by_status_sql = "";
5760
- $query_by_user_sql = "";
5761
- $query_by_pagination = "";
5762
 
5763
  if ( ! empty( $status ) ) {
5764
  $status = (array) $status;
@@ -5768,8 +6106,9 @@ class Utils {
5768
  }
5769
 
5770
  if ( ! empty( $per_page ) ) {
5771
- if ( empty( $start ) )
5772
  $start = 0;
 
5773
 
5774
  $query_by_pagination = " LIMIT {$start}, {$per_page} ";
5775
  }
@@ -5778,31 +6117,35 @@ class Utils {
5778
  $query_by_user_sql = " AND user_id = {$user_id} ";
5779
  }
5780
 
5781
- $count = (int) $wpdb->get_var( $wpdb->prepare(
5782
- "SELECT COUNT(withdraw_id)
 
5783
  FROM {$wpdb->prefix}tutor_withdraws
5784
  WHERE 1 = %d
5785
  {$query_by_user_sql}
5786
  {$query_by_status_sql}
5787
  ",
5788
- 1
5789
- ) );
5790
-
5791
- $results = $wpdb->get_results( $wpdb->prepare(
5792
- "SELECT withdraw_tbl.*,
5793
- user_tbl.display_name AS user_name,
5794
- user_tbl.user_email
5795
- FROM {$wpdb->prefix}tutor_withdraws withdraw_tbl
 
 
5796
  INNER JOIN {$wpdb->users} user_tbl
5797
  ON withdraw_tbl.user_id = user_tbl.ID
5798
  WHERE 1 = %d
5799
- {$query_by_user_sql}
5800
  {$query_by_status_sql}
5801
  ORDER BY created_at DESC
5802
  {$query_by_pagination}
5803
  ",
5804
- 1
5805
- ) );
 
5806
 
5807
  $withdraw_history = array(
5808
  'count' => 0,
@@ -5870,12 +6213,12 @@ class Utils {
5870
  public function set_flash_msg( $msg = '', $name = 'success' ) {
5871
  global $wp_filesystem;
5872
  if ( ! $wp_filesystem ) {
5873
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
5874
  }
5875
 
5876
- $filename = "tutor_flash_msg_{$name}.txt";
5877
  $upload_dir = wp_upload_dir();
5878
- $dir = trailingslashit( $upload_dir['basedir'] ) . 'tutor/';
5879
 
5880
  WP_Filesystem( false, $upload_dir['basedir'], true );
5881
 
@@ -5900,10 +6243,10 @@ class Utils {
5900
 
5901
  $upload_dir = wp_get_upload_dir();
5902
  $upload_dir = trailingslashit( $upload_dir['basedir'] );
5903
- $msg_name = 'tutor_flash_msg_'.$name;
5904
 
5905
- $msg = '';
5906
- $flash_msg_file_name = $upload_dir."tutor/{$msg_name}.txt";
5907
  if ( file_exists( $flash_msg_file_name ) ) {
5908
  $msg = file_get_contents( $flash_msg_file_name );
5909
  unlink( $flash_msg_file_name );
@@ -5925,19 +6268,20 @@ class Utils {
5925
  $user_id = $this->get_user_id();
5926
  $monetize_by = tutils()->get_option( 'monetize_by' );
5927
 
5928
- $post_type = "";
5929
- $user_meta = "";
5930
 
5931
  if ( $monetize_by === 'wc' ) {
5932
- $post_type = "shop_order";
5933
- $user_meta = "_customer_user";
5934
- } else if ( $monetize_by === 'edd' ) {
5935
- $post_type = "edd_payment";
5936
- $user_meta = "_edd_payment_user_id";
5937
  }
5938
 
5939
- $orders = $wpdb->get_results( $wpdb->prepare(
5940
- "SELECT {$wpdb->posts}.*
 
5941
  FROM {$wpdb->posts}
5942
  INNER JOIN {$wpdb->postmeta} customer
5943
  ON id = customer.post_id
@@ -5946,12 +6290,13 @@ class Utils {
5946
  ON id = tutor_order.post_id
5947
  AND tutor_order.meta_key = '_is_tutor_order_for_course'
5948
  WHERE post_type = %s
5949
- AND customer.meta_value = %d
5950
  ORDER BY {$wpdb->posts}.id DESC
5951
  ",
5952
- $post_type,
5953
- $user_id
5954
- ) );
 
5955
 
5956
  return $orders;
5957
  }
@@ -5969,22 +6314,22 @@ class Utils {
5969
  $status = str_replace( 'wc-', '', $status );
5970
  $status_name = ucwords( str_replace( '-', ' ', $status ) );
5971
 
5972
- return "<span class='label-order-status label-status-{$status}'>$status_name</span>";
5973
  }
5974
 
5975
  /**
5976
- * Depricated since v1.9.8
5977
  * This function is redundant and will be removed later
5978
  */
5979
  public function get_course_id_by_assignment( $assignment_id = 0 ) {
5980
  $assignment_id = $this->get_post_id( $assignment_id );
5981
- return $this->get_course_id_by('assignment', $assignment_id);
5982
  }
5983
 
5984
  /**
5985
- * @param int $assignment_id
5986
  * @param string $option_key
5987
- * @param bool $default
5988
  *
5989
  * @return array|bool|mixed
5990
  *
@@ -5994,7 +6339,7 @@ class Utils {
5994
  */
5995
  public function get_assignment_option( $assignment_id = 0, $option_key = '', $default = false ) {
5996
  $assignment_id = $this->get_post_id( $assignment_id );
5997
- $get_option_meta = maybe_unserialize( get_post_meta($assignment_id, 'assignment_option', true ) );
5998
 
5999
  if ( ! $option_key && ! empty( $get_option_meta ) ) {
6000
  return $get_option_meta;
@@ -6023,21 +6368,23 @@ class Utils {
6023
  global $wpdb;
6024
 
6025
  $assignment_id = $this->get_post_id( $assignment_id );
6026
- $user_id = $this->get_user_id( $user_id );
6027
 
6028
- $is_running_submit = (int) $wpdb->get_var( $wpdb->prepare(
6029
- "SELECT comment_ID
 
6030
  FROM {$wpdb->comments}
6031
- WHERE comment_type = %s
6032
- AND comment_approved = %s
6033
  AND user_id = %d
6034
  AND comment_post_ID = %d;
6035
  ",
6036
- 'tutor_assignment',
6037
- 'submitting',
6038
- $user_id,
6039
- $assignment_id
6040
- ) );
 
6041
 
6042
  return $is_running_submit;
6043
  }
@@ -6058,19 +6405,21 @@ class Utils {
6058
  $assignment_id = $this->get_post_id( $assignment_id );
6059
  $user_id = $this->get_user_id( $user_id );
6060
 
6061
- $has_submitted = $wpdb->get_row( $wpdb->prepare(
6062
- "SELECT *
 
6063
  FROM {$wpdb->comments}
6064
  WHERE comment_type = %s
6065
  AND comment_approved = %s
6066
  AND user_id = %d
6067
  AND comment_post_ID = %d;
6068
  ",
6069
- 'tutor_assignment',
6070
- 'submitted',
6071
- $user_id,
6072
- $assignment_id
6073
- ) );
 
6074
 
6075
  return $has_submitted;
6076
  }
@@ -6080,17 +6429,19 @@ class Utils {
6080
 
6081
  $assignment_submitted_id = $this->get_post_id( $assignment_submitted_id );
6082
 
6083
- $submitted_info = $wpdb->get_row( $wpdb->prepare(
6084
- "SELECT *
 
6085
  FROM {$wpdb->comments}
6086
  WHERE comment_ID = %d
6087
  AND comment_type = %s
6088
  AND comment_approved = %s;
6089
  ",
6090
- $assignment_submitted_id,
6091
- 'tutor_assignment',
6092
- 'submitted'
6093
- ) );
 
6094
 
6095
  return $submitted_info;
6096
  }
@@ -6102,15 +6453,17 @@ class Utils {
6102
  public function get_total_assignments() {
6103
  global $wpdb;
6104
 
6105
- $count = $wpdb->get_var( $wpdb->prepare(
6106
- "SELECT COUNT(comment_ID)
 
6107
  FROM {$wpdb->comments}
6108
  WHERE comment_type = %s
6109
  AND comment_approved = %s;
6110
  ",
6111
- 'tutor_assignment',
6112
- 'submitted'
6113
- ) );
 
6114
 
6115
  return (int) $count;
6116
  }
@@ -6122,15 +6475,17 @@ class Utils {
6122
  public function get_assignments() {
6123
  global $wpdb;
6124
 
6125
- $results = $wpdb->get_results( $wpdb->prepare(
6126
- "SELECT *
 
6127
  FROM {$wpdb->comments}
6128
  WHERE comment_type = %s
6129
  AND comment_approved = %s;
6130
  ",
6131
- 'tutor_assignment',
6132
- 'submitted'
6133
- ) );
 
6134
 
6135
  return $results;
6136
  }
@@ -6149,14 +6504,16 @@ class Utils {
6149
  $user_id = $this->get_user_id( $user_id );
6150
  $course_post_type = tutor()->course_post_type;
6151
 
6152
- $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
6153
- "SELECT meta.meta_value
6154
- FROM {$wpdb->usermeta} meta
6155
- INNER JOIN {$wpdb->posts} course ON meta.meta_value=course.ID
6156
- WHERE meta.meta_key = '_tutor_instructor_course_id'
 
6157
  AND meta.user_id = %d GROUP BY meta_value",
6158
- $user_id
6159
- ) );
 
6160
 
6161
  return $get_assigned_courses_ids;
6162
  }
@@ -6171,17 +6528,20 @@ class Utils {
6171
  * @since v.1.3.4
6172
  */
6173
  public function get_course_categories( $parent = 0 ) {
6174
- $args = apply_filters( 'tutor_get_course_categories_args', array(
6175
- 'taxonomy' => 'course-category',
6176
- 'hide_empty' => false,
6177
- 'parent' => $parent,
6178
- ));
 
 
 
6179
 
6180
  $terms = get_terms( $args );
6181
 
6182
  $children = array();
6183
  foreach ( $terms as $term ) {
6184
- $term->children = $this->get_course_categories( $term->term_id );
6185
  $children[ $term->term_id ] = $term;
6186
  }
6187
 
@@ -6197,17 +6557,20 @@ class Utils {
6197
  *
6198
  * @since v.1.9.3
6199
  */
6200
- public function get_course_tags( ) {
6201
- $args = apply_filters( 'tutor_get_course_tags_args', array(
6202
- 'taxonomy' => 'course-tag',
6203
- 'hide_empty' => false
6204
- ));
 
 
 
6205
 
6206
  $terms = get_terms( $args );
6207
 
6208
  $children = array();
6209
  foreach ( $terms as $term ) {
6210
- $term->children = array();
6211
  $children[ $term->term_id ] = $term;
6212
  }
6213
 
@@ -6224,11 +6587,14 @@ class Utils {
6224
  * @since v.1.3.5
6225
  */
6226
  public function get_course_categories_term( $parent_id = 0 ) {
6227
- $args = apply_filters( 'tutor_get_course_categories_terms_args', array(
6228
- 'taxonomy' => 'course-category',
6229
- 'parent' => $parent_id,
6230
- 'hide_empty' => false,
6231
- ));
 
 
 
6232
 
6233
  $terms = get_terms( $args );
6234
 
@@ -6258,9 +6624,9 @@ class Utils {
6258
  public function course_edit_link( $course_id = 0 ) {
6259
  $course_id = $this->get_post_id( $course_id );
6260
 
6261
- $url = admin_url("post.php?post={$course_id}&action=edit");
6262
  if ( tutor()->has_pro ) {
6263
- $url = $this->tutor_dashboard_url( "create-course/?course_ID=" . $course_id );
6264
  }
6265
 
6266
  return $url;
@@ -6276,7 +6642,7 @@ class Utils {
6276
  $in_course_ids = implode( "','", $course_ids );
6277
 
6278
  $pagination_query = $date_query = '';
6279
- $sort_query = 'ORDER BY ID DESC';
6280
  if ( $this->count( $filter_data ) ) {
6281
  extract( $filter_data );
6282
 
@@ -6285,7 +6651,7 @@ class Utils {
6285
  }
6286
  if ( ! empty( $date_filter ) ) {
6287
  $date_filter = tutor_get_formated_date( 'Y-m-d', $date_filter );
6288
- $date_query = " AND DATE(post_date) = '{$date_filter}'";
6289
  }
6290
  if ( ! empty( $order_filter ) ) {
6291
  $sort_query = " ORDER BY ID {$order_filter} ";
@@ -6296,8 +6662,9 @@ class Utils {
6296
  }
6297
  }
6298
 
6299
- $count = (int) $wpdb->get_var( $wpdb->prepare(
6300
- "SELECT COUNT(ID)
 
6301
  FROM {$wpdb->postmeta} post_meta
6302
  INNER JOIN {$wpdb->posts} assignment
6303
  ON post_meta.post_id = assignment.ID
@@ -6306,25 +6673,31 @@ class Utils {
6306
  AND post_meta.meta_value IN('$in_course_ids')
6307
  {$date_query}
6308
  ",
6309
- $assignment_post_type
6310
- ) );
 
6311
 
6312
- $query = $wpdb->get_results( $wpdb->prepare(
6313
- "SELECT *
 
6314
  FROM {$wpdb->postmeta} post_meta
6315
  INNER JOIN {$wpdb->posts} assignment
6316
  ON post_meta.post_id = assignment.ID
6317
  AND post_meta.meta_key = '_tutor_course_id_for_assignments'
6318
  WHERE post_type = %s
6319
- AND post_meta.meta_value IN('$in_course_ids')
6320
  {$date_query}
6321
  {$sort_query}
6322
  {$pagination_query}
6323
  ",
6324
- $assignment_post_type
6325
- ) );
 
6326
 
6327
- return (object) array( 'count' => $count, 'results' => $query );
 
 
 
6328
  }
6329
 
6330
  /**
@@ -6342,8 +6715,9 @@ class Utils {
6342
 
6343
  $assignment_post_type = 'tutor_assignments';
6344
 
6345
- $count = (int) $wpdb->get_var( $wpdb->prepare(
6346
- "SELECT COUNT(ID)
 
6347
  FROM {$wpdb->postmeta} post_meta
6348
  INNER JOIN {$wpdb->posts} assignment
6349
  ON post_meta.post_id = assignment.ID
@@ -6352,12 +6726,14 @@ class Utils {
6352
  AND post_meta.meta_value = %d
6353
  ORDER BY ID DESC;
6354
  ",
6355
- $assignment_post_type,
6356
- $course_id
6357
- ) );
 
6358
 
6359
- $query = $wpdb->get_results( $wpdb->prepare(
6360
- "SELECT *
 
6361
  FROM {$wpdb->postmeta} post_meta
6362
  INNER JOIN {$wpdb->posts} assignment
6363
  ON post_meta.post_id = assignment.ID
@@ -6366,11 +6742,15 @@ class Utils {
6366
  AND post_meta.meta_value = %d
6367
  ORDER BY ID DESC;
6368
  ",
6369
- $assignment_post_type,
6370
- $course_id
6371
- ) );
 
6372
 
6373
- return (object) array( 'count' => $count, 'results' => $query );
 
 
 
6374
  }
6375
 
6376
  /**
@@ -6408,6 +6788,7 @@ class Utils {
6408
 
6409
  /**
6410
  * Get total Enrolments
 
6411
  * @since v.1.4.0
6412
  */
6413
  public function get_total_enrolments( $search_term = '' ) {
@@ -6415,8 +6796,9 @@ class Utils {
6415
 
6416
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
6417
 
6418
- $count = $wpdb->get_var( $wpdb->prepare(
6419
- "SELECT COUNT(enrol.ID)
 
6420
  FROM {$wpdb->posts} enrol
6421
  INNER JOIN {$wpdb->posts} course
6422
  ON enrol.post_parent = course.ID
@@ -6425,12 +6807,13 @@ class Utils {
6425
  WHERE enrol.post_type = %s
6426
  AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s );
6427
  ",
6428
- 'tutor_enrolled',
6429
- $search_term,
6430
- $search_term,
6431
- $search_term,
6432
- $search_term
6433
- ) );
 
6434
 
6435
  return (int) $count;
6436
  }
@@ -6440,8 +6823,9 @@ class Utils {
6440
 
6441
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
6442
 
6443
- $enrolments = $wpdb->get_results( $wpdb->prepare(
6444
- "SELECT enrol.ID AS enrol_id,
 
6445
  enrol.post_author AS student_id,
6446
  enrol.post_date AS enrol_date,
6447
  enrol.post_title AS enrol_title,
@@ -6458,17 +6842,18 @@ class Utils {
6458
  ON enrol.post_author = student.ID
6459
  WHERE enrol.post_type = %s
6460
  AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s )
6461
- ORDER BY enrol_id DESC
6462
  LIMIT %d, %d;
6463
  ",
6464
- 'tutor_enrolled',
6465
- $search_term,
6466
- $search_term,
6467
- $search_term,
6468
- $search_term,
6469
- $start,
6470
- $limit
6471
- ) );
 
6472
 
6473
  return $enrolments;
6474
  }
@@ -6510,30 +6895,32 @@ class Utils {
6510
  'review' => '',
6511
  );
6512
 
6513
- $rating = $wpdb->get_row( $wpdb->prepare(
6514
- "SELECT meta_value AS rating,
 
6515
  comment_content AS review
6516
  FROM {$wpdb->comments}
6517
- INNER JOIN {$wpdb->commentmeta}
6518
- ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
6519
  WHERE {$wpdb->comments}.comment_ID = %d;
6520
- ",
6521
- $rating_id
6522
- ) );
 
6523
 
6524
  if ( $rating ) {
6525
  $rating_format = number_format( $rating->rating, 2 );
6526
 
6527
  $ratings = array(
6528
- 'rating' => $rating_format,
6529
- 'review' => $rating->review,
6530
  );
6531
  }
6532
  return (object) $ratings;
6533
  }
6534
 
6535
  /**
6536
- * @param int $course_id
6537
  * @param null $key
6538
  * @param bool $default
6539
  *
@@ -6550,7 +6937,7 @@ class Utils {
6550
  }
6551
 
6552
  /**
6553
- * @param int $lesson_id
6554
  * @param null $key
6555
  * @param bool $default
6556
  *
@@ -6585,7 +6972,7 @@ class Utils {
6585
  while ( $topics->have_posts() ) {
6586
  $topics->the_post();
6587
  $topic_id = get_the_ID();
6588
- $lessons = tutor_utils()->get_course_contents_by_topic( $topic_id, -1 );
6589
  if ( $lessons->have_posts() ) {
6590
  while ( $lessons->have_posts() ) {
6591
  $lessons->the_post();
@@ -6593,15 +6980,14 @@ class Utils {
6593
  $contents[] = $post;
6594
  }
6595
  }
6596
-
6597
  }
6598
  }
6599
 
6600
- if ( tutils()->count( $contents) ) {
6601
  foreach ( $contents as $key => $content ) {
6602
  if ( $current_item->ID == $content->ID ) {
6603
- if ( ! empty( $contents[ $key-1 ]->ID ) ) {
6604
- return $contents[ $key-1 ]->ID;
6605
  }
6606
  }
6607
  }
@@ -6621,15 +7007,17 @@ class Utils {
6621
  global $wpdb;
6622
  $post = get_post( $post );
6623
 
6624
- $course_id = $wpdb->get_var( $wpdb->prepare(
6625
- "SELECT post_parent
 
6626
  FROM {$wpdb->posts}
6627
  WHERE ID = %d
6628
  AND post_type = %s
6629
  ",
6630
- $post->post_parent,
6631
- 'topics'
6632
- ) );
 
6633
 
6634
  return (int) $course_id;
6635
  }
@@ -6648,8 +7036,9 @@ class Utils {
6648
 
6649
  $course_id = $this->get_post_id( $course_id );
6650
 
6651
- $contents = $wpdb->get_results( $wpdb->prepare(
6652
- "SELECT items.*
 
6653
  FROM {$wpdb->posts} topic
6654
  INNER JOIN {$wpdb->posts} items
6655
  ON topic.ID = items.post_parent
@@ -6658,9 +7047,10 @@ class Utils {
6658
  ORDER BY topic.menu_order ASC,
6659
  items.menu_order ASC;
6660
  ",
6661
- $course_id,
6662
- 'publish'
6663
- ) );
 
6664
 
6665
  return $contents;
6666
  }
@@ -6676,7 +7066,7 @@ class Utils {
6676
  */
6677
  public function get_gradebooks() {
6678
  global $wpdb;
6679
- $results = $wpdb->get_results("SELECT * FROM {$wpdb->tutor_gradebooks} ORDER BY grade_point DESC ");
6680
  return $results;
6681
  }
6682
 
@@ -6700,23 +7090,25 @@ class Utils {
6700
  $attempt = false;
6701
 
6702
  $quiz_grade_method = get_tutor_option( 'quiz_grade_method', 'highest_grade' );
6703
- $from_string = "FROM {$wpdb->tutor_quiz_attempts} WHERE quiz_id = %d AND user_id = %d AND attempt_status != 'attempt_started' ";
6704
 
6705
- if ( $quiz_grade_method === 'highest_grade') {
6706
 
6707
  $attempt = $wpdb->get_row( $wpdb->prepare( "SELECT * {$from_string} ORDER BY earned_marks DESC LIMIT 1; ", $quiz_id, $user_id ) );
6708
 
6709
- } elseif ($quiz_grade_method === 'average_grade' ) {
6710
 
6711
- $attempt = $wpdb->get_row( $wpdb->prepare(
6712
- "SELECT {$wpdb->tutor_quiz_attempts}.*,
 
6713
  COUNT(attempt_id) AS attempt_count,
6714
  AVG(total_marks) AS total_marks,
6715
  AVG(earned_marks) AS earned_marks {$from_string}
6716
  ",
6717
- $quiz_id,
6718
- $user_id
6719
- ) );
 
6720
 
6721
  } elseif ( $quiz_grade_method === 'first_attempt' ) {
6722
 
@@ -6747,13 +7139,13 @@ class Utils {
6747
 
6748
  $html = '';
6749
  if ( $is_completed ) {
6750
- $html = '<span class="course-completion-status course-completed"><i class="tutor-icon-mark"></i> '.__('Completed', 'tutor').' </span>';
6751
  } else {
6752
  $is_in_progress = tutor_utils()->get_completed_lesson_count_by_course( $course_id, $user_id );
6753
  if ( $is_in_progress ) {
6754
- $html = '<span class="course-completion-status course-inprogress"><i class="tutor-icon-refresh-button-1"></i> '.__('In Progress', 'tutor').' </span>';
6755
  } else {
6756
- $html = '<span class="course-completion-status course-not-taken"><i class="tutor-icon-spinner"></i> '.__('Not Taken', 'tutor').' </span>';
6757
  }
6758
  }
6759
  return $html;
@@ -6787,11 +7179,14 @@ class Utils {
6787
  * @since v.1.4.3
6788
  */
6789
  public function tutor_pages() {
6790
- $pages = apply_filters( 'tutor_pages', array(
6791
- 'tutor_dashboard_page_id' => __( 'Dashboard Page', 'tutor' ),
6792
- 'instructor_register_page' => __( 'Instructor Registration Page', 'tutor' ),
6793
- 'student_register_page' => __( 'Student Registration Page', 'tutor' ),
6794
- ));
 
 
 
6795
 
6796
  $new_pages = array();
6797
  foreach ( $pages as $key => $page ) {
@@ -6808,12 +7203,12 @@ class Utils {
6808
  }
6809
 
6810
  $new_pages[] = array(
6811
- 'option_key' => $key,
6812
- 'page_name' => $page,
6813
- 'wp_page_name' => $wp_page_name,
6814
- 'page_id' => $page_id,
6815
- 'page_exists' => $page_exists,
6816
- 'page_visible' => $page_visible,
6817
  );
6818
  }
6819
 
@@ -6831,15 +7226,15 @@ class Utils {
6831
  */
6832
  public function get_course_prev_next_contents_by_id( $content_id = 0 ) {
6833
 
6834
- $course_id = $this->get_course_id_by_content($content_id);
6835
- $course_contents = $this->get_course_contents_by_id($course_id);
6836
  $previous_id = 0;
6837
  $next_id = 0;
6838
 
6839
  if ( $this->count( $course_contents ) ) {
6840
  $ids = wp_list_pluck( $course_contents, 'ID' );
6841
 
6842
- $i=0;
6843
  foreach ( $ids as $key => $id ) {
6844
  $previous_i = $key - 1;
6845
  $next_i = $key + 1;
@@ -6856,14 +7251,17 @@ class Utils {
6856
  }
6857
  }
6858
 
6859
- return (object) [ 'previous_id' => $previous_id, 'next_id' => $next_id ];
 
 
 
6860
  }
6861
 
6862
  /**
6863
  * Get a subset of the items from the given array.
6864
  *
6865
- * @param array $array
6866
- * @param array|string $keys
6867
  *
6868
  * @return array|bool
6869
  *
@@ -6887,28 +7285,30 @@ class Utils {
6887
  *
6888
  * @since v.1.6.4
6889
  */
6890
- public function is_instructor_of_this_course( $instructor_id=0, $course_id=0 ) {
6891
  global $wpdb;
6892
 
6893
- $instructor_id = $this->get_user_id( $instructor_id );
6894
- $course_id = $this->get_post_id( $course_id );
6895
 
6896
  if ( ! $instructor_id || ! $course_id ) {
6897
  return false;
6898
  }
6899
 
6900
- $instructor = $wpdb->get_col( $wpdb->prepare(
6901
- "SELECT umeta_id
 
6902
  FROM {$wpdb->usermeta}
6903
  WHERE user_id = %d
6904
  AND meta_key = '_tutor_instructor_course_id'
6905
  AND meta_value = %d
6906
  ",
6907
- $instructor_id,
6908
- $course_id
6909
- ) );
6910
-
6911
- if (is_array($instructor) && count($instructor)) {
 
6912
  return $instructor;
6913
  }
6914
 
@@ -6925,29 +7325,32 @@ class Utils {
6925
  * @since v.1.6.6
6926
  */
6927
  public function user_profile_completion( $user_id = 0 ) {
6928
- $user_id = $this->get_user_id( $user_id );
6929
- $instructor = $this->is_instructor( $user_id );
6930
  $instructor_status = get_user_meta( $user_id, '_tutor_instructor_status', true );
6931
 
6932
- $required_fields = apply_filters( 'tutor_profile_required_fields', array(
6933
- 'first_name' => __( 'First Name', 'tutor' ),
6934
- 'last_name' => __( 'Last Name', 'tutor' ),
6935
- '_tutor_profile_photo' => __( 'Profile Photo', 'tutor' ),
6936
- '_tutor_withdraw_method_data' => __( 'Withdraw Method', 'tutor' ),
6937
- ));
 
 
 
6938
 
6939
- if ( 'approved' !== $instructor_status && array_key_exists( "_tutor_withdraw_method_data", $required_fields ) ) {
6940
- unset( $required_fields[ '_tutor_withdraw_method_data' ] );
6941
  }
6942
 
6943
  $empty_fields = array();
6944
  foreach ( $required_fields as $key => $field ) {
6945
  $value = get_user_meta( $user_id, $key, true );
6946
- if ( !$value ) {
6947
  array_push( $empty_fields, $field );
6948
  }
6949
  }
6950
-
6951
  $total_empty_fields = count( $empty_fields );
6952
  $total_required_fields = count( $required_fields );
6953
  $signup_point = apply_filters( 'tutor_profile_completion_signup_point', 50 );
@@ -6955,9 +7358,9 @@ class Utils {
6955
  if ( $total_empty_fields == 0 ) {
6956
  $progress = 100;
6957
  } else {
6958
- $completed_field = $total_required_fields-$total_empty_fields;
6959
  $per_field_point = $signup_point / $total_required_fields;
6960
- $progress = $signup_point + ceil($per_field_point * $completed_field);
6961
  }
6962
 
6963
  $return = array(
@@ -6980,8 +7383,9 @@ class Utils {
6980
  public function get_enrolment_by_enrol_id( $enrol_id = 0 ) {
6981
  global $wpdb;
6982
 
6983
- $enrolment = $wpdb->get_row( $wpdb->prepare(
6984
- "SELECT enrol.id AS enrol_id,
 
6985
  enrol.post_author AS student_id,
6986
  enrol.post_date AS enrol_date,
6987
  enrol.post_title AS enrol_title,
@@ -6997,7 +7401,10 @@ class Utils {
6997
  INNER JOIN {$wpdb->users} student
6998
  ON enrol.post_author = student.id
6999
  WHERE enrol.id = %d;
7000
- ", $enrol_id));
 
 
 
7001
 
7002
  if ( $enrolment ) {
7003
  return $enrolment;
@@ -7011,19 +7418,21 @@ class Utils {
7011
  global $wpdb;
7012
  $course_id = $this->get_post_id( $course_id );
7013
 
7014
- $student_data = $wpdb->get_results( $wpdb->prepare(
7015
- "SELECT student.{$field_name}
 
7016
  FROM {$wpdb->posts} enrol
7017
  INNER JOIN {$wpdb->users} student
7018
  ON enrol.post_author = student.id
7019
  WHERE enrol.post_type = %s
7020
  AND enrol.post_parent = %d
7021
- AND enrol.post_status = %s;
7022
  ",
7023
- 'tutor_enrolled',
7024
- $course_id,
7025
- 'completed'
7026
- ) );
 
7027
 
7028
  return array_column( $student_data, $field_name );
7029
  }
@@ -7032,7 +7441,7 @@ class Utils {
7032
  * @param int $course_id
7033
  *
7034
  * @return array
7035
- *
7036
  * @since v1.6.9
7037
  *
7038
  * Get students email by course id
@@ -7045,38 +7454,40 @@ class Utils {
7045
  *requie post id & user id
7046
  *return single comment post
7047
  */
7048
- public function get_single_comment_user_post_id( $post_id,$user_id ) {
7049
  global $wpdb;
7050
- $table = $wpdb->prefix . "comments";
7051
- $query = $wpdb->get_row( $wpdb->prepare(
7052
- "SELECT *
 
7053
  FROM $table
7054
  WHERE comment_post_ID = %d
7055
  AND user_id = %d
7056
  LIMIT 1
7057
  ",
7058
- $post_id,
7059
- $user_id
7060
- ) );
 
7061
  return $query ? $query : false;
7062
  }
7063
-
7064
  /**
7065
  * @param int $course_id
7066
  *
7067
  * @return bool
7068
- *
7069
  * @since v1.7.5
7070
  *
7071
  * Check if course is in wc cart
7072
  */
7073
- public function is_course_added_to_cart( $course_or_product_id = 0, $is_product_id=false ) {
7074
-
7075
- switch( $this->get_option( 'monetize_by' ) ) {
7076
  case 'wc':
7077
  global $woocommerce;
7078
  $product_id = $is_product_id ? $course_or_product_id : $this->get_course_product_id( $course_or_product_id );
7079
-
7080
  if ( $woocommerce->cart ) {
7081
  foreach ( $woocommerce->cart->get_cart() as $key => $val ) {
7082
  if ( $product_id == $val['product_id'] ) {
@@ -7092,7 +7503,7 @@ class Utils {
7092
  * @param int $user_id
7093
  *
7094
  * @return bool
7095
- *
7096
  * @since v1.7.5
7097
  *
7098
  * Get profile pic url
@@ -7101,7 +7512,7 @@ class Utils {
7101
  $cover_photo_src = tutor()->url . 'assets/images/cover-photo.jpg';
7102
  $cover_photo_id = get_user_meta( $user_id, '_tutor_cover_photo', true );
7103
  if ( $cover_photo_id ) {
7104
- $url = wp_get_attachment_image_url( $cover_photo_id, 'full' );
7105
  ! empty( $url ) ? $cover_photo_src = $url : 0;
7106
  }
7107
 
@@ -7110,7 +7521,7 @@ class Utils {
7110
 
7111
  /**
7112
  * @return int
7113
- *
7114
  * @since v1.7.9
7115
  *
7116
  * Return the course ID by lession, quiz, answer etc.
@@ -7120,49 +7531,57 @@ class Utils {
7120
  $course_id = null;
7121
 
7122
  switch ( $content ) {
7123
- case 'course' :
7124
  $course_id = $object_id;
7125
  break;
7126
 
7127
- case 'topic' :
7128
- case 'announcement' :
7129
- $course_id = $wpdb->get_var( $wpdb->prepare(
7130
- "SELECT post_parent
7131
- FROM {$wpdb->posts}
 
7132
  WHERE ID=%d
7133
  LIMIT 1",
7134
- $object_id ) );
 
 
7135
  break;
7136
-
7137
- case 'lesson' :
7138
- case 'quiz' :
7139
- case 'assignment' :
7140
- $course_id = $wpdb->get_var( $wpdb->prepare(
7141
- "SELECT post_parent
7142
- FROM {$wpdb->posts}
 
7143
  WHERE ID = (SELECT post_parent FROM {$wpdb->posts} WHERE ID = %d);
7144
  ",
7145
- $object_id
7146
- ) );
 
7147
  break;
7148
-
7149
- case 'question' :
7150
- $course_id = $wpdb->get_var( $wpdb->prepare(
7151
- "SELECT topic.post_parent
 
7152
  FROM {$wpdb->posts} topic
7153
- INNER JOIN {$wpdb->posts} quiz
7154
  ON quiz.post_parent=topic.ID
7155
  INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
7156
  ON question.quiz_id=quiz.ID
7157
  WHERE question.question_id = %d;
7158
  ",
7159
- $object_id
7160
- ) );
 
7161
  break;
7162
-
7163
- case 'quiz_answer' :
7164
- $course_id = $wpdb->get_var( $wpdb->prepare(
7165
- "SELECT topic.post_parent
 
7166
  FROM {$wpdb->posts} topic
7167
  INNER JOIN {$wpdb->posts} quiz
7168
  ON quiz.post_parent=topic.ID
@@ -7172,39 +7591,46 @@ class Utils {
7172
  ON answer.belongs_question_id=question.question_id
7173
  WHERE answer.answer_id = %d;
7174
  ",
7175
- $object_id
7176
- ) );
 
7177
  break;
7178
-
7179
- case 'attempt' :
7180
- $course_id = $wpdb->get_var( $wpdb->prepare(
7181
- "SELECT course_id
 
7182
  FROM {$wpdb->prefix}tutor_quiz_attempts
7183
  WHERE attempt_id=%d;
7184
  ",
7185
- $object_id
7186
- ) );
 
7187
  break;
7188
 
7189
- case 'attempt_answer' :
7190
- $course_id = $wpdb->get_var( $wpdb->prepare(
7191
- "SELECT course_id
7192
- FROM {$wpdb->prefix}tutor_quiz_attempts
 
7193
  WHERE attempt_id = (SELECT quiz_attempt_id FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id=%d)
7194
  ",
7195
- $object_id
7196
- ) );
 
7197
  break;
7198
 
7199
- case 'review' :
7200
- case 'qa_question' :
7201
- $course_id = $wpdb->get_var( $wpdb->prepare(
7202
- "SELECT comment_post_ID
 
7203
  FROM {$wpdb->comments}
7204
  WHERE comment_ID = %d;
7205
  ",
7206
- $object_id
7207
- ) );
 
7208
  break;
7209
  }
7210
 
@@ -7213,28 +7639,31 @@ class Utils {
7213
 
7214
  /**
7215
  * @return bool
7216
- *
7217
  * @since v1.7.7
7218
  *
7219
- * Check if user can create, edit, delete various tutor contents such as lesson, quiz, answer etc.
7220
  */
7221
- public function can_user_manage( $content, $object_id, $user_id=0, $allow_current_admin=true ) {
7222
-
7223
- if( $allow_current_admin && current_user_can( 'administrator' ) ) {
7224
  // Admin has access to everything
7225
  return true;
7226
  }
7227
 
7228
  $course_id = $this->get_course_id_by( $content, $object_id );
7229
 
7230
- if( $course_id ) {
7231
-
7232
  $instructors = $this->get_instructors_by_course( $course_id );
7233
- $instructor_ids = is_array( $instructors ) ? array_map( function($instructor) {
7234
- return (int)$instructor->ID;
7235
- }, $instructors) : array();
7236
-
7237
- $user_id = (int)$this->get_user_id( $user_id );
 
 
 
7238
  $is_listed = in_array( $user_id, $instructor_ids );
7239
 
7240
  return $is_listed;
@@ -7245,15 +7674,15 @@ class Utils {
7245
 
7246
  /**
7247
  * @return bool
7248
- *
7249
  * @since v1.7.9
7250
  *
7251
  * Check if user has access for content like lesson, quiz, assignment etc.
7252
  */
7253
- public function has_enrolled_content_access( $content, $object_id=0, $user_id=0 ) {
7254
- $user_id = $this->get_user_id( $user_id );
7255
- $object_id = $this->get_post_id( $object_id );
7256
- $course_id = $this->get_course_id_by( $content, $object_id );
7257
  $course_content_access = (bool) get_tutor_option( 'course_content_access_for_ia' );
7258
 
7259
  do_action( 'tutor_before_enrolment_check', $course_id, $user_id );
@@ -7264,8 +7693,8 @@ class Utils {
7264
  if ( $course_content_access && ( current_user_can( 'administrator' ) || current_user_can( tutor()->instructor_role ) ) ) {
7265
  return true;
7266
  }
7267
- //Check Lesson edit access to support page builders (eg: Oxygen)
7268
- if ( current_user_can(tutor()->instructor_role) && tutils()->has_lesson_edit_access() ) {
7269
  return true;
7270
  }
7271
 
@@ -7274,19 +7703,19 @@ class Utils {
7274
 
7275
  /**
7276
  * @return date
7277
- *
7278
  * @since v1.8.0
7279
  *
7280
  * Return the assignment deadline date based on duration and assignment creation date
7281
  */
7282
- public function get_assignment_deadline_date( $assignment_id, $format=null, $fallback=null ) {
7283
-
7284
- ! $format ? $format='j F, Y, g:i a' : 0;
7285
 
7286
  $value = $this->get_assignment_option( $assignment_id, 'time_duration.value' );
7287
  $time = $this->get_assignment_option( $assignment_id, 'time_duration.time' );
7288
-
7289
- if ( !$value ) {
7290
  return $fallback;
7291
  }
7292
 
@@ -7300,7 +7729,7 @@ class Utils {
7300
 
7301
  /**
7302
  * @return array
7303
- *
7304
  * @since v1.8.2
7305
  *
7306
  * Get earning chart data
@@ -7318,28 +7747,30 @@ class Utils {
7318
 
7319
  $datesPeriod = array();
7320
  foreach ( $period as $dt ) {
7321
- $datesPeriod[ $dt->format( "Y-m-d" ) ] = 0;
7322
  }
7323
 
7324
  // Get statuses
7325
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
7326
  $statuses = $complete_status;
7327
- $complete_status = "'" . implode( "','", $complete_status) . "'";
7328
-
7329
- $salesQuery = $wpdb->get_results( $wpdb->prepare(
7330
- "SELECT SUM(instructor_amount) AS total_earning,
7331
- DATE(created_at) AS date_format
7332
- FROM {$wpdb->prefix}tutor_earnings
7333
- WHERE user_id = %d
7334
- AND order_status IN({$complete_status})
 
7335
  AND (created_at BETWEEN %s AND %s)
7336
  GROUP BY date_format
7337
  ORDER BY created_at ASC;
7338
- ",
7339
- $user_id,
7340
- $start_date,
7341
- $end_date
7342
- ) );
 
7343
 
7344
  $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
7345
  $queried_date = wp_list_pluck( $salesQuery, 'date_format' );
@@ -7348,27 +7779,27 @@ class Utils {
7348
 
7349
  foreach ( $chartData as $key => $salesCount ) {
7350
  unset( $chartData[ $key ] );
7351
- $formatDate = date('d M', strtotime($key));
7352
  $chartData[ $formatDate ] = $salesCount;
7353
  }
7354
 
7355
- $statements = tutor_utils()->get_earning_statements( $user_id, compact('start_date', 'end_date', 'statuses' ) );
7356
  $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'start_date', 'end_date' ) );
7357
 
7358
  return array(
7359
- 'chartData' => $chartData,
7360
  'statements' => $statements,
7361
  'statuses' => $statuses,
7362
  'begin' => $begin,
7363
  'end' => $end,
7364
  'earning_sum' => $earning_sum,
7365
- 'datesPeriod' => $datesPeriod
7366
  );
7367
  }
7368
 
7369
  /**
7370
  * @return array
7371
- *
7372
  * @since v1.8.2
7373
  *
7374
  * Get earning chart data yearly
@@ -7378,21 +7809,23 @@ class Utils {
7378
 
7379
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
7380
  $statuses = $complete_status;
7381
- $complete_status = "'" . implode( "','", $complete_status) . "'";
7382
-
7383
- $salesQuery = $wpdb->get_results( $wpdb->prepare(
7384
- "SELECT SUM(instructor_amount) AS total_earning,
7385
- MONTHNAME(created_at) AS month_name
7386
- FROM {$wpdb->prefix}tutor_earnings
7387
- WHERE user_id = %d
7388
- AND order_status IN({$complete_status})
7389
- AND YEAR(created_at) = %s
7390
- GROUP BY MONTH (created_at)
 
7391
  ORDER BY MONTH(created_at) ASC;
7392
- ",
7393
- $user_id,
7394
- $year
7395
- ) );
 
7396
 
7397
  $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
7398
  $months = wp_list_pluck( $salesQuery, 'month_name' );
@@ -7404,24 +7837,24 @@ class Utils {
7404
  * Format yearly
7405
  */
7406
  $emptyMonths = array();
7407
- for ( $m=1; $m <= 12; $m++ ) {
7408
- $emptyMonths[ date('F', mktime( 0, 0, 0, $m, 1, date( 'Y' ) ) ) ] = 0;
7409
  }
7410
 
7411
  $chartData = array_merge( $emptyMonths, $monthWiseSales );
7412
- $statements = tutor_utils()->get_earning_statements( $user_id, compact('year', 'dataFor', 'statuses' ) );
7413
  $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'year', 'dataFor' ) );
7414
 
7415
- return [
7416
  'chartData' => $chartData,
7417
  'statements' => $statements,
7418
- 'earning_sum' => $earning_sum
7419
- ];
7420
  }
7421
 
7422
  /**
7423
  * @return object
7424
- *
7425
  * @since v1.8.4
7426
  *
7427
  * Return object from vendor package
@@ -7429,163 +7862,164 @@ class Utils {
7429
  function get_package_object() {
7430
 
7431
  $params = func_get_args();
7432
-
7433
- $is_pro = $params[0];
7434
- $class = $params[1];
7435
  $class_args = array_slice( $params, 2 );
7436
- $root_path = $is_pro ? tutor_pro()->path : tutor()->path;
7437
 
7438
  require_once $root_path . '/vendor/autoload.php';
7439
-
7440
  $reflector = new \ReflectionClass( $class );
7441
- $object = $reflector->newInstanceArgs( $class_args );
7442
 
7443
  return $object;
7444
  }
7445
 
7446
  /**
7447
  * @return boolean
7448
- *
7449
  * @since v1.8.9
7450
- *
7451
  * Check if user has specific role
7452
  */
7453
- public function has_user_role($roles, $user_id = 0) {
7454
-
7455
- !$user_id ? $user_id = get_current_user_id() : 0;
7456
- !is_array($roles) ? $roles = array($roles) : 0;
7457
-
7458
- $user = get_userdata($user_id);
7459
- $role_list = (is_object($user) && is_array($user->roles)) ? $user->roles : array();
7460
 
7461
- $without_roles = array_diff($roles, $role_list);
 
7462
 
7463
- return count($roles) > count($without_roles);
 
 
7464
  }
7465
 
7466
  /**
7467
  * @return boolean
7468
- *
7469
  * @since v1.8.9
7470
- *
7471
  * Check if user can edit course
7472
  */
7473
- public function can_user_edit_course($user_id, $course_id)
7474
- {
7475
- return $this->has_user_role(array('administrator', 'editor')) || $this->is_instructor_of_this_course($user_id, $course_id);
7476
  }
7477
 
7478
-
7479
  /**
7480
  * @return boolean
7481
- *
7482
  * @since v1.9.0
7483
- *
7484
  * Check if course member limit full
7485
  */
7486
- public function is_course_fully_booked($course_id = 0) {
 
 
 
7487
 
7488
- $total_enrolled = $this->count_enrolled_users_by_course($course_id);
7489
- $maximum_students = (int) $this->get_course_settings($course_id, 'maximum_students');
7490
-
7491
  return $maximum_students && $maximum_students <= $total_enrolled;
7492
  }
7493
 
7494
  /**
7495
  * @return boolean
7496
- *
7497
  * @since v1.9.2
7498
- *
7499
  * Check if current screen is under tutor dashboard
7500
  */
7501
- public function is_tutor_dashboard($subpage = null) {
7502
 
7503
  // To Do: Add subpage check later
7504
 
7505
- if(function_exists('is_admin') && is_admin()) {
7506
  $screen = get_current_screen();
7507
  return is_object( $screen ) && $screen->parent_base == 'tutor';
7508
  }
7509
-
7510
  return false;
7511
  }
7512
 
7513
  /**
7514
  * @return boolean
7515
- *
7516
  * @since v1.9.4
7517
- *
7518
  * Check if current screen tutor frontend dashboard
7519
  */
7520
- public function is_tutor_frontend_dashboard($subpage = null) {
7521
 
7522
  global $wp_query;
7523
- if ($wp_query->is_page) {
7524
- $dashboard_page = tutor_utils()->array_get('tutor_dashboard_page', $wp_query->query_vars);
7525
 
7526
- if($subpage && $dashboard_page == $subpage) {
7527
  return true;
7528
  }
7529
 
7530
- if($wp_query->queried_object && $wp_query->queried_object->ID) {
7531
- return $wp_query->queried_object->ID == tutor_utils()->get_option('tutor_dashboard_page_id');
7532
  }
7533
  }
7534
 
7535
  return false;
7536
  }
7537
 
7538
- public function get_unique_slug($slug, $post_type=null, $num_assigned=false) {
7539
 
7540
  global $wpdb;
7541
- $existing_slug = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM {$wpdb->posts} WHERE post_name=%s" . ($post_type ? " AND post_type='{$post_type}' LIMIT 1" : ""), $slug));
7542
 
7543
- if(!$existing_slug) {
7544
  return $slug;
7545
  }
7546
 
7547
- if(!$num_assigned) {
7548
  $new_slug = $slug . '-' . 2;
7549
  } else {
7550
- $new_slug = explode('-', $slug);
7551
- $number = end( $new_slug ) + 1;
7552
-
7553
- array_pop($new_slug);
7554
 
7555
- $new_slug = implode('-', $new_slug) . '-' . $number;
 
 
7556
  }
7557
 
7558
- return $this->get_unique_slug($new_slug, $post_type, true);
7559
  }
7560
 
7561
- public function get_course_content_ids_by($content_type, $ancestor_type, $ancestor_ids) {
7562
- global $wpdb;
7563
  $ids = array();
7564
 
7565
  // Convert single id to array
7566
- !is_array($ancestor_ids) ? $ancestor_ids=array($ancestor_ids) : 0;
7567
- $ancestor_ids = implode(',', $ancestor_ids);
7568
 
7569
- switch($content_type) {
7570
 
7571
  // Get lesson, quiz, assignment IDs
7572
- case tutor()->lesson_post_type :
7573
- case 'tutor_quiz' :
7574
- case 'tutor_assignments' :
7575
- switch($ancestor_type) {
7576
 
7577
  // Get lesson, quiz, assignment IDs by course ID
7578
- case tutor()->course_post_type :
7579
- $content_ids = $wpdb->get_col($wpdb->prepare(
7580
- "SELECT content.ID FROM {$wpdb->posts} course
7581
- INNER JOIN {$wpdb->posts} topic ON course.ID=topic.post_parent
 
7582
  INNER JOIN {$wpdb->posts} content ON topic.ID=content.post_parent
7583
  WHERE course.ID IN ({$ancestor_ids}) AND content.post_type=%s",
7584
- $content_type
7585
- ));
 
7586
 
7587
  // Assign id array to the variable
7588
- is_array($content_ids) ? $ids=$content_ids : 0;
7589
  break 2;
7590
  }
7591
  }
@@ -7595,82 +8029,88 @@ class Utils {
7595
 
7596
  /**
7597
  * Custom Pagination for Tutor Shortcode
7598
- *
7599
  * @param int $total_num_pages
7600
- *
7601
  * @return void
7602
  */
7603
  public function tutor_custom_pagination( $total_num_pages = 1 ) {
7604
 
7605
  do_action( 'tutor_course/archive/pagination/before' ); ?>
7606
-
7607
  <div class="tutor-pagination-wrap">
7608
  <?php
7609
  $big = 999999999; // need an unlikely integer
7610
-
7611
- echo paginate_links( array(
7612
- 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
7613
- 'format' => '?paged=%#%',
7614
- 'current' => max( 1, get_query_var( 'paged' ) ),
7615
- 'total' => $total_num_pages
7616
- ) );
 
 
7617
  ?>
7618
  </div>
7619
-
7620
- <?php do_action( 'tutor_course/archive/pagination/after' );
 
7621
  }
7622
 
7623
  /**
7624
  * Get all courses along with topics & course materials for current student
7625
- *
7626
  * @since 1.9.10
7627
- *
7628
  * @return array
7629
  */
7630
  public function course_with_materials(): array {
7631
- $user_id = get_current_user_id();
7632
  $enrolled_courses = $this->get_enrolled_courses_by_user( $user_id );
7633
 
7634
  if ( false === $enrolled_courses ) {
7635
- return [];
7636
  }
7637
- $data = [];
7638
  foreach ( $enrolled_courses->posts as $key => $course ) {
7639
- //push courses
7640
- array_push($data, ['course' => array('title' => $course->post_title)]);
7641
  $topics = $this->get_topics( $course->ID );
7642
 
7643
- if ( !is_null( $topics) || count( $topics->posts ) ) {
7644
  foreach ( $topics->posts as $topic_key => $topic ) {
7645
  $materials = $this->get_course_contents_by_topic( $topic->ID, -1 );
7646
- if ( count( $materials->posts ) || !is_null( $materials->posts ) ) {
7647
  $topic->materials = $materials->posts;
7648
  }
7649
- //push topics
7650
- array_push( $data[$key]['course'], ['topics' => $topic] );
7651
  }
7652
  }
7653
-
7654
  }
7655
  return $data;
7656
  }
7657
 
7658
- public function get_course_duration($course_id, $return_array, $texts = array('h'=>'hr', 'm'=>'min', 's'=>'sec')) {
7659
- $duration = maybe_unserialize(get_post_meta($course_id, '_course_duration', true));
7660
- $durationHours = tutor_utils()->avalue_dot('hours', $duration);
7661
- $durationMinutes = tutor_utils()->avalue_dot('minutes', $duration);
7662
- $durationSeconds = tutor_utils()->avalue_dot('seconds', $duration);
 
 
 
 
7663
 
7664
- if($return_array) {
7665
  return array(
7666
- 'duration' => $duration,
7667
- 'durationHours' => $durationHours,
7668
  'durationMinutes' => $durationMinutes,
7669
  'durationSeconds' => $durationSeconds,
7670
  );
7671
  }
7672
 
7673
- if(!$durationHours && !$durationMinutes && !$durationSeconds) {
7674
  return '';
7675
  }
7676
 
@@ -7678,4 +8118,4 @@ class Utils {
7678
  $durationMinutes . $texts['m'] . ' ' .
7679
  $durationSeconds . $texts['s'];
7680
  }
7681
- }
1
  <?php
2
  /**
3
  * Tutor Utils Helper functions
4
+ *
5
  * @package TUTOR
6
  *
7
  * @since v.1.0.0
9
 
10
  namespace TUTOR;
11
 
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
  class Utils {
17
  /**
25
  * @since v.1.0.0
26
  */
27
  public function get_option( $key = null, $default = false ) {
28
+ $option = (array) maybe_unserialize( get_option( 'tutor_option' ) );
29
 
30
  if ( empty( $option ) || ! is_array( $option ) ) {
31
  return $default;
34
  return $option;
35
  }
36
  if ( array_key_exists( $key, $option ) ) {
37
+ return apply_filters( $key, $option[ $key ] );
38
  }
39
+ // Access array value via dot notation, such as option->get('value.subvalue')
40
+ if ( strpos( $key, '.' ) ) {
41
  $option_key_array = explode( '.', $key );
42
 
43
  $new_option = $option;
44
  foreach ( $option_key_array as $dotKey ) {
45
+ if ( isset( $new_option[ $dotKey ] ) ) {
46
+ $new_option = $new_option[ $dotKey ];
47
+ } else {
48
  return $default;
49
  }
50
  }
63
  * @since v.1.0.0
64
  */
65
  public function update_option( $key = null, $value = false ) {
66
+ $option = (array) maybe_unserialize( get_option( 'tutor_option' ) );
67
+ $option[ $key ] = $value;
68
  update_option( 'tutor_option', $option );
69
  }
70
 
71
  /**
72
+ * @param null $key
73
  * @param array $array
74
  *
75
  * @return array|bool|mixed
82
  */
83
  public function avalue_dot( $key = null, $array = array(), $default = false ) {
84
  $array = (array) $array;
85
+ if ( ! $key || ! count( $array ) ) {
86
  return $default;
87
  }
88
  $option_key_array = explode( '.', $key );
90
  $value = $array;
91
 
92
  foreach ( $option_key_array as $dotKey ) {
93
+ if ( isset( $value[ $dotKey ] ) ) {
94
+ $value = $value[ $dotKey ];
95
  } else {
96
  return $default;
97
  }
100
  }
101
 
102
  /**
103
+ * @param null $key
104
  * @param array $array
105
  *
106
  * @return array|bool|mixed
128
 
129
  do_action( 'tutor_utils/get_pages/before' );
130
 
131
+ $pages = array();
132
  $wp_pages = get_pages();
133
 
134
+ if ( is_array( $wp_pages ) && count( $wp_pages ) ) {
135
+ foreach ( $wp_pages as $page ) {
136
+ $pages[ $page->ID ] = $page->post_title;
137
  }
138
  }
139
+
140
  do_action( 'tutor_utils/get_pages/after' );
141
 
142
  return $pages;
153
  $course_post_type = tutor()->course_post_type;
154
  $course_page_url = trailingslashit( home_url() ) . $course_post_type;
155
 
156
+ $course_archive_page = $this->get_option( 'course_archive_page' );
157
  if ( $course_archive_page && $course_archive_page !== '-1' ) {
158
  $course_page_url = get_permalink( $course_archive_page );
159
  }
175
  $user_name = '';
176
  if ( $student_id ) {
177
  global $wpdb;
178
+ $user = $wpdb->get_row(
179
+ $wpdb->prepare(
180
+ "SELECT user_nicename
181
+ FROM {$wpdb->users}
182
  WHERE ID = %d;
183
+ ",
184
+ $student_id
185
+ )
186
+ );
187
 
188
+ if ( $user ) {
189
  $user_name = $user->user_nicename;
190
  }
 
191
  } else {
192
  $user_name = 'user_name';
193
  }
194
 
195
+ return $site_url . $user_name;
196
  }
197
 
198
  /**
206
  */
207
  public function get_user_by_login( $user_nicename = '' ) {
208
  global $wpdb;
209
+ $user_nicename = sanitize_text_field( $user_nicename );
210
+ $user = $wpdb->get_row(
211
+ $wpdb->prepare(
212
+ "SELECT *
213
  FROM {$wpdb->users}
214
  WHERE user_nicename = %s;
215
  ",
216
+ $user_nicename
217
+ )
218
+ );
219
  return $user;
220
  }
221
 
225
  * Check if WooCommerce Activated
226
  *
227
  * @since v.1.0.0
228
+ * @updated @1.5.9
229
  */
230
  public function has_wc() {
231
  return class_exists( 'WooCommerce' );
252
  *
253
  * @since v.1.3.6
254
  */
255
+ public function has_pmpro( $check_monetization = false ) {
256
+ $has_pmpro = $this->is_plugin_active( 'paid-memberships-pro/paid-memberships-pro.php' );
257
+ return $has_pmpro && ( ! $check_monetization || get_tutor_option( 'monetize_by' ) == 'pmpro' );
258
  }
259
 
260
+ public function is_plugin_active( $plugin_path ) {
261
  $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
262
+ $depends = is_array( $plugin_path ) ? $plugin_path : array( $plugin_path );
263
  $has_plugin = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
264
+
265
  return $has_plugin;
266
  }
267
 
268
+ public function has_wcs() {
269
+ $has_wcs = $this->is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' );
270
  return $has_wcs;
271
  }
272
 
273
+ public function is_addon_enabled( $basename ) {
274
+ if ( $this->is_plugin_active( 'tutor-pro/tutor-pro.php' ) ) {
275
+ $addonConfig = $this->get_addon_config( $basename );
276
+
277
+ return (bool) $this->avalue_dot( 'is_enable', $addonConfig );
278
  }
279
  }
280
 
285
  *
286
  * @since v.1.4.8
287
  */
288
+ public function has_bp() {
289
  $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
290
  $depends = array( 'buddypress/bp-loader.php' );
291
  $has_bp = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
299
  */
300
  public function languages() {
301
  $language_codes = array(
302
+ 'en' => 'English',
303
+ 'aa' => 'Afar',
304
+ 'ab' => 'Abkhazian',
305
+ 'af' => 'Afrikaans',
306
+ 'am' => 'Amharic',
307
+ 'ar' => 'Arabic',
308
+ 'as' => 'Assamese',
309
+ 'ay' => 'Aymara',
310
+ 'az' => 'Azerbaijani',
311
+ 'ba' => 'Bashkir',
312
+ 'be' => 'Byelorussian',
313
+ 'bg' => 'Bulgarian',
314
+ 'bh' => 'Bihari',
315
+ 'bi' => 'Bislama',
316
+ 'bn' => 'Bengali/Bangla',
317
+ 'bo' => 'Tibetan',
318
+ 'br' => 'Breton',
319
+ 'ca' => 'Catalan',
320
+ 'co' => 'Corsican',
321
+ 'cs' => 'Czech',
322
+ 'cy' => 'Welsh',
323
+ 'da' => 'Danish',
324
+ 'de' => 'German',
325
+ 'dz' => 'Bhutani',
326
+ 'el' => 'Greek',
327
+ 'eo' => 'Esperanto',
328
+ 'es' => 'Spanish',
329
+ 'et' => 'Estonian',
330
+ 'eu' => 'Basque',
331
+ 'fa' => 'Persian',
332
+ 'fi' => 'Finnish',
333
+ 'fj' => 'Fiji',
334
+ 'fo' => 'Faeroese',
335
+ 'fr' => 'French',
336
+ 'fy' => 'Frisian',
337
+ 'ga' => 'Irish',
338
+ 'gd' => 'Scots/Gaelic',
339
+ 'gl' => 'Galician',
340
+ 'gn' => 'Guarani',
341
+ 'gu' => 'Gujarati',
342
+ 'ha' => 'Hausa',
343
+ 'hi' => 'Hindi',
344
+ 'hr' => 'Croatian',
345
+ 'hu' => 'Hungarian',
346
+ 'hy' => 'Armenian',
347
+ 'ia' => 'Interlingua',
348
+ 'ie' => 'Interlingue',
349
+ 'ik' => 'Inupiak',
350
+ 'in' => 'Indonesian',
351
+ 'is' => 'Icelandic',
352
+ 'it' => 'Italian',
353
+ 'iw' => 'Hebrew',
354
+ 'ja' => 'Japanese',
355
+ 'ji' => 'Yiddish',
356
+ 'jw' => 'Javanese',
357
+ 'ka' => 'Georgian',
358
+ 'kk' => 'Kazakh',
359
+ 'kl' => 'Greenlandic',
360
+ 'km' => 'Cambodian',
361
+ 'kn' => 'Kannada',
362
+ 'ko' => 'Korean',
363
+ 'ks' => 'Kashmiri',
364
+ 'ku' => 'Kurdish',
365
+ 'ky' => 'Kirghiz',
366
+ 'la' => 'Latin',
367
+ 'ln' => 'Lingala',
368
+ 'lo' => 'Laothian',
369
+ 'lt' => 'Lithuanian',
370
+ 'lv' => 'Latvian/Lettish',
371
+ 'mg' => 'Malagasy',
372
+ 'mi' => 'Maori',
373
+ 'mk' => 'Macedonian',
374
+ 'ml' => 'Malayalam',
375
+ 'mn' => 'Mongolian',
376
+ 'mo' => 'Moldavian',
377
+ 'mr' => 'Marathi',
378
+ 'ms' => 'Malay',
379
+ 'mt' => 'Maltese',
380
+ 'my' => 'Burmese',
381
+ 'na' => 'Nauru',
382
+ 'ne' => 'Nepali',
383
+ 'nl' => 'Dutch',
384
+ 'no' => 'Norwegian',
385
+ 'oc' => 'Occitan',
386
+ 'om' => '(Afan)/Oromoor/Oriya',
387
+ 'pa' => 'Punjabi',
388
+ 'pl' => 'Polish',
389
+ 'ps' => 'Pashto/Pushto',
390
+ 'pt' => 'Portuguese',
391
+ 'qu' => 'Quechua',
392
+ 'rm' => 'Rhaeto-Romance',
393
+ 'rn' => 'Kirundi',
394
+ 'ro' => 'Romanian',
395
+ 'ru' => 'Russian',
396
+ 'rw' => 'Kinyarwanda',
397
+ 'sa' => 'Sanskrit',
398
+ 'sd' => 'Sindhi',
399
+ 'sg' => 'Sangro',
400
+ 'sh' => 'Serbo-Croatian',
401
+ 'si' => 'Singhalese',
402
+ 'sk' => 'Slovak',
403
+ 'sl' => 'Slovenian',
404
+ 'sm' => 'Samoan',
405
+ 'sn' => 'Shona',
406
+ 'so' => 'Somali',
407
+ 'sq' => 'Albanian',
408
+ 'sr' => 'Serbian',
409
+ 'ss' => 'Siswati',
410
+ 'st' => 'Sesotho',
411
+ 'su' => 'Sundanese',
412
+ 'sv' => 'Swedish',
413
+ 'sw' => 'Swahili',
414
+ 'ta' => 'Tamil',
415
+ 'te' => 'Tegulu',
416
+ 'tg' => 'Tajik',
417
+ 'th' => 'Thai',
418
+ 'ti' => 'Tigrinya',
419
+ 'tk' => 'Turkmen',
420
+ 'tl' => 'Tagalog',
421
+ 'tn' => 'Setswana',
422
+ 'to' => 'Tonga',
423
+ 'tr' => 'Turkish',
424
+ 'ts' => 'Tsonga',
425
+ 'tt' => 'Tatar',
426
+ 'tw' => 'Twi',
427
+ 'uk' => 'Ukrainian',
428
+ 'ur' => 'Urdu',
429
+ 'uz' => 'Uzbek',
430
+ 'vi' => 'Vietnamese',
431
+ 'vo' => 'Volapuk',
432
+ 'wo' => 'Wolof',
433
+ 'xh' => 'Xhosa',
434
+ 'yo' => 'Yoruba',
435
+ 'zh' => 'Chinese',
436
+ 'zu' => 'Zulu',
437
  );
438
 
439
  return apply_filters( 'tutor/utils/languages', $language_codes );
448
  */
449
  public function print_view( $value = '' ) {
450
  echo '<pre>';
451
+ print_r( $value );
452
  echo '</pre>';
453
  }
454
 
471
  $exclude_query = implode( "','", $excludes );
472
  }
473
 
474
+ $post_status = array_map(
475
+ function( $element ) {
476
+ return "'" . $element . "'";
477
+ },
478
+ $post_status
479
+ );
480
 
481
  $post_status = implode( ',', $post_status );
482
  $course_post_type = tutor()->course_post_type;
483
 
484
+ $query = $wpdb->get_results(
485
+ $wpdb->prepare(
486
+ "SELECT ID,
487
  post_author,
488
  post_title,
489
  post_name,
490
  post_status,
491
+ menu_order
492
+ FROM {$wpdb->posts}
493
  WHERE post_status IN ({$post_status})
494
  AND ID NOT IN('$exclude_query')
495
  AND post_type = %s;
496
  ",
497
+ $course_post_type
498
+ )
499
+ );
500
 
501
  return $query;
502
  }
517
  $course_post_type = tutor()->course_post_type;
518
 
519
  global $current_user;
520
+ $courses = get_posts(
521
+ array(
522
+ 'post_type' => $course_post_type,
523
+ 'author' => $instructor_id,
524
+ 'post_status' => array( 'publish', 'pending' ),
525
+ 'posts_per_page' => -1,
526
+ )
527
+ );
528
+
529
  return $courses;
530
  }
531
 
543
 
544
  $course_post_type = tutor()->course_post_type;
545
 
546
+ $count = $wpdb->get_var(
547
+ $wpdb->prepare(
548
+ "SELECT COUNT(ID)
549
  FROM {$wpdb->posts}
550
  INNER JOIN {$wpdb->usermeta}
551
  ON user_id = %d
552
  AND meta_key = %s
553
  AND meta_value = ID
554
+ WHERE post_status = %s
555
  AND post_type = %s;
556
  ",
557
+ $instructor_id,
558
+ '_tutor_instructor_course_id',
559
+ 'publish',
560
+ $course_post_type
561
+ )
562
+ );
563
 
564
  return $count;
565
  }
576
  public function get_courses_by_instructor( $instructor_id = 0, $post_status = array( 'publish' ) ) {
577
  global $wpdb;
578
 
579
+ $instructor_id = $this->get_user_id( $instructor_id );
580
  $course_post_type = tutor()->course_post_type;
581
 
582
  if ( $post_status === 'any' ) {
583
+ $where_post_status = '';
584
  } else {
585
  $post_status = (array) $post_status;
586
  $statuses = "'" . implode( "','", $post_status ) . "'";
587
  $where_post_status = "AND $wpdb->posts.post_status IN({$statuses}) ";
588
  }
589
 
590
+ $pageposts = $wpdb->get_results(
591
+ $wpdb->prepare(
592
+ "SELECT $wpdb->posts.*
593
  FROM $wpdb->posts
594
  INNER JOIN {$wpdb->usermeta}
595
  ON $wpdb->usermeta.user_id = %d
596
  AND $wpdb->usermeta.meta_key = %s
597
+ AND $wpdb->usermeta.meta_value = $wpdb->posts.ID
598
  WHERE 1 = 1 {$where_post_status}
599
  AND $wpdb->posts.post_type = %s
600
  ORDER BY $wpdb->posts.post_date DESC;
601
  ",
602
+ $instructor_id,
603
+ '_tutor_instructor_course_id',
604
+ $course_post_type
605
+ ),
606
+ OBJECT
607
+ );
608
 
609
  return $pageposts;
610
  }
633
 
634
  $course_post_type = tutor()->course_post_type;
635
 
636
+ $count = $wpdb->get_var(
637
+ $wpdb->prepare(
638
+ "SELECT COUNT(ID)
639
  FROM {$wpdb->posts}
640
  WHERE post_status = %s
641
  AND post_type = %s;
642
  ",
643
+ 'publish',
644
+ $course_post_type
645
+ )
646
+ );
647
+
648
  return $count;
649
  }
650
 
660
 
661
  $lesson_post_type = tutor()->lesson_post_type;
662
 
663
+ $count = $wpdb->get_var(
664
+ $wpdb->prepare(
665
+ "SELECT COUNT(ID)
666
  FROM {$wpdb->posts}
667
  WHERE post_status = %s
668
  AND post_type = %s;
669
  ",
670
+ 'publish',
671
+ $lesson_post_type
672
+ )
673
+ );
674
+
675
  return $count;
676
  }
677
 
736
  $user_id = $this->get_user_id( $user_id );
737
 
738
  $lesson_ids = $this->get_course_content_ids_by( tutor()->lesson_post_type, tutor()->course_post_type, $course_id );
739
+
740
  $count = 0;
741
+ if ( count( $lesson_ids ) ) {
742
  $completed_lesson_meta_ids = array();
743
  foreach ( $lesson_ids as $lesson_id ) {
744
  $completed_lesson_meta_ids[] = '_tutor_completed_lesson_id_' . $lesson_id;
745
  }
746
  $in_ids = implode( "','", $completed_lesson_meta_ids );
747
 
748
+ $count = (int) $wpdb->get_var(
749
+ $wpdb->prepare(
750
+ "SELECT count(umeta_id)
751
  FROM {$wpdb->usermeta}
752
  WHERE user_id = %d
753
  AND meta_key IN ('{$in_ids}')
754
  ",
755
+ $user_id
756
+ )
757
+ );
758
  }
759
 
760
  return $count;
767
  * @return float|int
768
  *
769
  * @since v.1.0.0
770
+ * @updated v.1.6.1
771
  */
772
  public function get_course_completed_percent( $course_id = 0, $user_id = 0 ) {
773
+ $course_id = $this->get_post_id( $course_id );
774
+ $user_id = $this->get_user_id( $user_id );
775
+ $completed_lesson = $this->get_completed_lesson_count_by_course( $course_id, $user_id );
776
+ $course_contents = tutils()->get_course_contents_by_id( $course_id );
777
+ $totalContents = $this->count( $course_contents );
778
+ $totalContents = $totalContents ? $totalContents : 0;
779
+ $completedCount = $completed_lesson;
780
+
781
+ if ( tutils()->count( $course_contents ) ) {
782
+ foreach ( $course_contents as $content ) {
783
+ if ( $content->post_type === 'tutor_quiz' ) {
784
+ $attempt = $this->get_quiz_attempt( $content->ID, $user_id );
785
+ if ( $attempt ) {
786
+ $completedCount++;
787
+ }
788
+ } elseif ( $content->post_type === 'tutor_assignments' ) {
789
+ $isSubmitted = $this->is_assignment_submitted( $content->ID, $user_id );
790
+ if ( $isSubmitted ) {
791
+ $completedCount++;
792
+ }
793
+ }
794
+ }
795
+ }
796
 
797
  if ( $totalContents > 0 && $completedCount > 0 ) {
798
  return number_format( ( $completedCount * 100 ) / $totalContents );
838
  public function get_next_topic_order_id( $course_ID ) {
839
  global $wpdb;
840
 
841
+ $last_order = (int) $wpdb->get_var(
842
+ $wpdb->prepare(
843
+ "SELECT MAX(menu_order)
844
  FROM {$wpdb->posts}
845
  WHERE post_parent = %d
846
  AND post_type = %s;
847
  ",
848
+ $course_ID,
849
+ 'topics'
850
+ )
851
+ );
852
+
853
  return $last_order + 1;
854
  }
855
 
865
  public function get_next_course_content_order_id( $topic_ID ) {
866
  global $wpdb;
867
 
868
+ $last_order = (int) $wpdb->get_var(
869
+ $wpdb->prepare(
870
+ "SELECT MAX(menu_order)
871
  FROM {$wpdb->posts}
872
  WHERE post_parent = %d;
873
  ",
874
+ $topic_ID
875
+ )
876
+ );
877
 
878
+ return is_numeric( $last_order ) ? $last_order + 1 : 0;
879
  }
880
 
881
  /**
891
  public function get_lessons_by_topic( $topics_id = 0, $limit = 10 ) {
892
  $topics_id = $this->get_post_id( $topics_id );
893
  $lesson_post_type = tutor()->lesson_post_type;
894
+
895
  $args = array(
896
  'post_type' => $lesson_post_type,
897
  'post_parent' => $topics_id,
916
  * @since v.1.0.0
917
  */
918
  public function get_course_contents_by_topic( $topics_id = 0, $limit = 10 ) {
919
+ $topics_id = $this->get_post_id( $topics_id );
920
  $lesson_post_type = tutor()->lesson_post_type;
921
  $post_type = apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) );
922
 
942
  */
943
  public function checking_nonce( $request_method = 'post' ) {
944
 
945
+ $data = $request_method === 'post' ? $_POST : $_GET;
946
+ $nonce_value = sanitize_text_field( tutils()->array_get( tutor()->nonce, $data, null ) );
947
+ $matched = $nonce_value && wp_verify_nonce( $nonce_value, tutor()->nonce_action );
948
 
949
+ ! $matched ? exit( __( 'Nonce not matched', 'tutor' ) ) : 0;
950
  }
951
 
952
  /**
984
  $course_id = $this->get_post_id( $course_id );
985
 
986
  if ( $this->is_course_purchasable() ) {
987
+ $monetize_by = $this->get_option( 'monetize_by' );
988
 
989
  if ( $this->has_wc() && $monetize_by === 'wc' ) {
990
  $product_id = tutor_utils()->get_course_product_id( $course_id );
1020
  'sale_price' => 0,
1021
  );
1022
 
1023
+ $monetize_by = $this->get_option( 'monetize_by' );
1024
 
1025
  $product_id = $this->get_course_product_id( $course_id );
1026
  if ( $product_id ) {
1069
 
1070
  do_action( 'tutor_is_enrolled_before', $course_id, $user_id );
1071
 
1072
+ $getEnrolledInfo = $wpdb->get_row(
1073
+ $wpdb->prepare(
1074
+ "SELECT ID,
1075
  post_author,
1076
  post_date,
1077
  post_date_gmt,
1082
  AND post_author = %d
1083
  AND post_status = %s;
1084
  ",
1085
+ 'tutor_enrolled',
1086
+ $course_id,
1087
+ $user_id,
1088
+ 'completed'
1089
+ )
1090
+ );
1091
 
1092
  if ( $getEnrolledInfo ) {
1093
  return apply_filters( 'tutor_is_enrolled', $getEnrolledInfo, $course_id, $user_id );
1112
  $user_id = $this->get_user_id( $user_id );
1113
 
1114
  // Delete Quiz submissions
1115
+ $attempts = $this->get_quiz_attempts_by_course_ids( $start = 0, $limit = 99999999, $course_ids = array( $course_id ), $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $user_id = $user_id );
1116
+
1117
+ if ( is_array( $attempts ) ) {
1118
+ $attempt_ids = array_map(
1119
+ function( $attempt ) {
1120
+ return is_object( $attempt ) ? $attempt->attempt_id : 0;
1121
+ },
1122
+ $attempts
1123
+ );
1124
 
1125
+ $this->delete_quiz_attempt( $attempt_ids );
1126
  }
1127
 
1128
  // Delete Course completion row
1129
  $del_where = array(
1130
+ 'user_id' => $user_id,
1131
  'comment_post_ID' => $course_id,
1132
+ 'comment_type' => 'course_completed',
1133
+ 'comment_agent' => 'TutorLMSPlugin',
1134
  );
1135
+ $wpdb->delete( $wpdb->comments, $del_where );
1136
 
1137
  // Delete Completed lesson count
1138
+ $lesson_ids = $this->get_course_content_ids_by( tutor()->lesson_post_type, tutor()->course_post_type, $course_id );
1139
+ foreach ( $lesson_ids as $id ) {
1140
+ delete_user_meta( $user_id, '_tutor_completed_lesson_id_' . $id );
1141
  }
1142
 
1143
  // Delete other addon-wise stuffs by hook, specially assignment.
1161
  if ( is_user_logged_in() ) {
1162
  global $wpdb;
1163
 
1164
+ $getEnrolledInfo = $wpdb->get_row(
1165
+ $wpdb->prepare(
1166
+ "SELECT ID,
1167
  post_author,
1168
  post_date,
1169
  post_date_gmt,
1170
  post_title
1171
  FROM {$wpdb->posts}
1172
+ WHERE post_type = %s
1173
  AND post_parent = %d
1174
  AND post_author = %d;
1175
  ",
1176
+ 'tutor_enrolled',
1177
+ $course_id,
1178
+ $user_id
1179
+ )
1180
+ );
1181
 
1182
  if ( $getEnrolledInfo ) {
1183
  return $getEnrolledInfo;
1188
  }
1189
 
1190
 
1191
+ /**
1192
+ * @param int $enrol_id
1193
+ * @return array|bool|\WP_Post|null
1194
+ *
1195
+ * Get course by enrol id
1196
+ *
1197
+ * @since v.1.6.1
1198
+ */
1199
  public function get_course_by_enrol_id( $enrol_id = 0 ) {
1200
+ if ( ! $enrol_id ) {
1201
+ return false;
1202
+ }
1203
 
1204
+ global $wpdb;
1205
 
1206
+ $course_id = (int) $wpdb->get_var(
1207
+ $wpdb->prepare(
1208
+ "SELECT post_parent
1209
  FROM {$wpdb->posts}
1210
  WHERE post_type = %s
1211
  AND ID = %d
1212
  ",
1213
+ 'tutor_enrolled',
1214
+ $enrol_id
1215
+ )
1216
+ );
1217
 
1218
+ if ( $course_id ) {
1219
+ return get_post( $course_id );
1220
+ }
1221
 
1222
+ return null;
1223
+ }
1224
 
1225
  /**
1226
  * @param int $lesson_id
1254
  */
1255
  public function get_course_id_by_lesson( $lesson_id = 0 ) {
1256
  $lesson_id = $this->get_post_id( $lesson_id );
1257
+ $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
1258
 
1259
  if ( ! $course_id ) {
1260
  $course_id = $this->get_course_id_by_content( $lesson_id );
1275
  *
1276
  * @since v.1.0.0
1277
  */
1278
+ public function get_course_first_lesson( $course_id = 0, $post_type = null ) {
1279
  global $wpdb;
1280
 
1281
  $course_id = $this->get_post_id( $course_id );
1282
  $user_id = get_current_user_id();
1283
 
1284
+ $lessons = $wpdb->get_results(
1285
+ $wpdb->prepare(
1286
+ "SELECT items.ID
1287
  FROM {$wpdb->posts} topic
1288
  INNER JOIN {$wpdb->posts} items
1289
  ON topic.ID = items.post_parent
1290
  WHERE topic.post_parent = %d
1291
  AND items.post_status = %s
1292
+ " . ( $post_type ? " AND items.post_type='{$post_type}' " : '' ) . '
1293
  ORDER BY topic.menu_order ASC,
1294
  items.menu_order ASC;
1295
+ ',
1296
+ $course_id,
1297
+ 'publish'
1298
+ )
1299
+ );
1300
 
1301
  $first_lesson = false;
1302
 
1303
  if ( tutils()->count( $lessons ) ) {
1304
+ if ( ! empty( $lessons[0] ) ) {
1305
+ $first_lesson = $lessons[0];
1306
+ }
1307
 
1308
  foreach ( $lessons as $lesson ) {
1309
  $is_complete = get_user_meta( $user_id, "_tutor_completed_lesson_id_{$lesson->ID}", true );
1313
  }
1314
  }
1315
 
1316
+ if ( ! empty( $first_lesson->ID ) ) {
1317
  return get_permalink( $first_lesson->ID );
1318
  }
1319
  }
1329
  */
1330
  public function course_sub_pages() {
1331
  $nav_items = array(
1332
+ 'questions' => __( 'Q&A', 'tutor' ),
1333
+ 'announcements' => __( 'Announcements', 'tutor' ),
1334
  );
1335
 
1336
  return apply_filters( 'tutor_course/single/enrolled/nav_items', $nav_items );
1353
  }
1354
 
1355
  /**
1356
+ * @param int $post_id
1357
  * @param array $video_data
1358
  *
1359
  * @return bool
1380
  $attachments = maybe_unserialize( get_post_meta( $post_id, '_tutor_attachments', true ) );
1381
  $attachments_arr = array();
1382
 
1383
+ $font_icons = apply_filters(
1384
+ 'tutor_file_types_icon',
1385
+ array(
1386
+ 'archive',
1387
+ 'audio',
1388
+ 'code',
1389
+ 'default',
1390
+ 'document',
1391
+ 'interactive',
1392
+ 'spreadsheet',
1393
+ 'text',
1394
+ 'video',
1395
+ 'image',
1396
+ )
1397
+ );
1398
 
1399
  if ( is_array( $attachments ) && count( $attachments ) ) {
1400
  foreach ( $attachments as $attachment ) {
1401
  $url = wp_get_attachment_url( $attachment );
1402
  $file_type = wp_check_filetype( $url );
1403
  $ext = $file_type['ext'];
1404
+ $title = get_the_title( $attachment );
1405
 
1406
  $file_path = get_attached_file( $attachment );
1407
+ $size_bytes = file_exists( $file_path ) ? filesize( $file_path ) : 0;
1408
  $size = size_format( $size_bytes, 2 );
1409
  $type = wp_ext2type( $ext );
1410
 
1443
  * @since v.1.0.0
1444
  */
1445
  public function playtime_string( $seconds ) {
1446
+ $sign = ( ( $seconds < 0 ) ? '-' : '' );
1447
  $seconds = round( abs( $seconds ) );
1448
+ $H = (int) floor( $seconds / 3600 );
1449
+ $M = (int) floor( ( $seconds - ( 3600 * $H ) ) / 60 );
1450
+ $S = (int) round( $seconds - ( 3600 * $H ) - ( 60 * $M ) );
1451
+ return $sign . ( $H ? $H . ':' : '' ) . ( $H ? str_pad( $M, 2, '0', STR_PAD_LEFT ) : intval( $M ) ) . ':' . str_pad( $S, 2, 0, STR_PAD_LEFT );
1452
  }
1453
 
1454
  /**
1467
  'seconds' => '00',
1468
  );
1469
 
1470
+ if ( $seconds <= 0 ) {
1471
  return $run_time_format;
1472
  }
1473
 
1474
  $playTimeString = $this->playtime_string( $seconds );
1475
  $timeInArray = explode( ':', $playTimeString );
1476
 
1477
+ $run_time_size = count( $timeInArray );
1478
  if ( $run_time_size === 3 ) {
1479
+ $run_time_format['hours'] = $timeInArray[0];
1480
+ $run_time_format['minutes'] = $timeInArray[1];
1481
+ $run_time_format['seconds'] = $timeInArray[2];
1482
  } elseif ( $run_time_size === 2 ) {
1483
+ $run_time_format['minutes'] = $timeInArray[0];
1484
+ $run_time_format['seconds'] = $timeInArray[1];
1485
  }
1486
 
1487
  return $run_time_format;
1497
  * @since v.1.0.0
1498
  */
1499
  public function seconds_to_time_context( $seconds ) {
1500
+ $sign = ( ( $seconds < 0 ) ? '-' : '' );
1501
  $seconds = round( abs( $seconds ) );
1502
+ $H = (int) floor( $seconds / 3600 );
1503
+ $M = (int) floor( ( $seconds - ( 3600 * $H ) ) / 60 );
1504
+ $S = (int) round( $seconds - ( 3600 * $H ) - ( 60 * $M ) );
1505
 
1506
+ return $sign . ( $H ? $H . 'h ' : '' ) . ( $H ? str_pad( $M, 2, '0', STR_PAD_LEFT ) : intval( $M ) ) . 'm ' . str_pad( $S, 2, 0, STR_PAD_LEFT ) . 's';
1507
  }
1508
 
1509
  /**
1525
  'playtime' => '00:00',
1526
  );
1527
 
1528
+ $types = apply_filters(
1529
+ 'tutor_video_types',
1530
+ array(
1531
+ 'mp4' => 'video/mp4',
1532
+ 'webm' => 'video/webm',
1533
+ 'ogg' => 'video/ogg',
1534
+ )
1535
+ );
1536
 
1537
+ $videoSource = $this->avalue_dot( 'source', $video );
1538
 
1539
  if ( $videoSource === 'html5' ) {
1540
  $sourceVideoID = $this->avalue_dot( 'source_video_id', $video );
1541
  $video_info = get_post_meta( $sourceVideoID, '_wp_attachment_metadata', true );
1542
 
1543
+ if ( $video_info && in_array( $this->array_get( 'mime_type', $video_info ), $types ) ) {
1544
  $path = get_attached_file( $sourceVideoID );
1545
  $info['playtime'] = $video_info['length_formatted'];
1546
  $info['path'] = $path;
1569
  }
1570
 
1571
  public function get_optimized_duration( $duration ) {
1572
+ /*
1573
+ if(is_string($duration)){
1574
  strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove Empty hour
1575
  strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove empty minute
1576
  } */
1604
  *
1605
  * return lesson type icon
1606
  *
1607
+ * @param int $lesson_id
1608
  * @param bool $html
1609
  * @param bool $echo
1610
  *
1628
  }
1629
 
1630
  if ( $echo ) {
1631
+ echo $tutor_lesson_type_icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1632
  }
1633
 
1634
  return $tutor_lesson_type_icon;
1645
  public function is_completed_lesson( $lesson_id = 0, $user_id = 0 ) {
1646
  $lesson_id = $this->get_post_id( $lesson_id );
1647
  $user_id = $this->get_user_id( $user_id );
1648
+ $is_completed = get_user_meta( $user_id, '_tutor_completed_lesson_id_' . $lesson_id, true );
1649
 
1650
  if ( $is_completed ) {
1651
  return $is_completed;
1667
  * @updated v.1.4.9
1668
  */
1669
  public function is_completed_course( $course_id = 0, $user_id = 0 ) {
1670
+
1671
  global $wpdb;
1672
+ $course_id = $this->get_post_id( $course_id );
1673
+ $user_id = $this->get_user_id( $user_id );
1674
+
1675
+ $is_completed = $wpdb->get_row(
1676
+ $wpdb->prepare(
1677
+ "SELECT comment_ID,
1678
+ comment_post_ID AS course_id,
1679
+ comment_author AS completed_user_id,
1680
+ comment_date AS completion_date,
1681
+ comment_content AS completed_hash
1682
+ FROM {$wpdb->comments}
1683
+ WHERE comment_agent = %s
1684
+ AND comment_type = %s
1685
+ AND comment_post_ID = %d
1686
  AND user_id = %d;
1687
  ",
1688
+ 'TutorLMSPlugin',
1689
+ 'course_completed',
1690
+ $course_id,
1691
+ $user_id
1692
+ )
1693
+ );
1694
 
1695
  if ( $is_completed ) {
1696
  return apply_filters( 'is_completed_course', $is_completed, $course_id, $user_id );
1713
 
1714
  if ( is_array( $input ) && count( $input ) ) {
1715
  foreach ( $input as $key => $value ) {
1716
+ if ( is_array( $value ) ) {
1717
+ $array[ $key ] = $this->sanitize_array( $value );
1718
  } else {
1719
+ $key = sanitize_text_field( $key );
1720
+ $value = sanitize_text_field( $value );
1721
+ $array[ $key ] = $value;
1722
  }
1723
  }
1724
  }
1738
  public function has_video_in_single( $post_id = 0 ) {
1739
  if ( is_single() ) {
1740
  $post_id = $this->get_post_id( $post_id );
1741
+
1742
  $video = $this->get_video( $post_id );
1743
  if ( $video && $this->array_get( 'source', $video ) !== '-1' ) {
1744
+
1745
+ $not_empty = ! empty( $video['source_video_id'] ) ||
1746
+ ! empty( $video['source_external_url'] ) ||
1747
+ ! empty( $video['source_youtube'] ) ||
1748
+ ! empty( $video['source_vimeo'] ) ||
1749
+ ! empty( $video['source_embedded'] );
1750
+
1751
  return $not_empty ? $video : false;
1752
  }
1753
  }
1755
  }
1756
 
1757
  /**
1758
+ * @param int $start
1759
+ * @param int $limit
1760
  * @param string $search_term
1761
+ * @param int $course_id
1762
  *
1763
  * @return array|null|object
1764
  *
1774
 
1775
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
1776
 
1777
+ $students = $wpdb->get_results(
1778
+ $wpdb->prepare(
1779
+ "SELECT SQL_CALC_FOUND_ROWS {$wpdb->users}.*
1780
  FROM {$wpdb->users}
1781
  INNER JOIN {$wpdb->usermeta}
1782
  ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
1785
  ORDER BY {$wpdb->usermeta}.meta_value DESC
1786
  LIMIT {$start}, {$limit};
1787
  ",
1788
+ '_is_tutor_student',
1789
+ $search_term,
1790
+ $search_term
1791
+ )
1792
+ );
1793
 
1794
  return $students;
1795
  }
1809
 
1810
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
1811
 
1812
+ $count = $wpdb->get_var(
1813
+ $wpdb->prepare(
1814
+ "SELECT COUNT({$wpdb->users}.ID)
1815
  FROM {$wpdb->users}
1816
  INNER JOIN {$wpdb->usermeta}
1817
  ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
1818
  WHERE {$wpdb->usermeta}.meta_key = %s
1819
  AND ( {$wpdb->users}.display_name LIKE %s OR {$wpdb->users}.user_email LIKE %s );
1820
  ",
1821
+ '_is_tutor_student',
1822
+ $search_term,
1823
+ $search_term
1824
+ )
1825
+ );
1826
 
1827
  return (int) $count;
1828
  }
1841
 
1842
  $user_id = $this->get_user_id( $user_id );
1843
 
1844
+ $course_ids = (array) $wpdb->get_col(
1845
+ $wpdb->prepare(
1846
+ "SELECT comment_post_ID AS course_id
1847
+ FROM {$wpdb->comments}
1848
+ WHERE comment_agent = %s
1849
  AND comment_type = %s
1850
  AND user_id = %d
1851
  ",
1852
+ 'TutorLMSPlugin',
1853
+ 'course_completed',
1854
+ $user_id
1855
+ )
1856
+ );
1857
 
1858
  return $course_ids;
1859
  }
1871
  $user_id = $this->get_user_id( $user_id );
1872
  $course_ids = $this->get_completed_courses_ids_by_user( $user_id );
1873
 
1874
+ if ( count( $course_ids ) ) {
1875
  $course_post_type = tutor()->course_post_type;
1876
+ $course_args = array(
1877
  'post_type' => $course_post_type,
1878
  'post_status' => 'publish',
1879
  'post__in' => $course_ids,
1880
+ 'posts_per_page' => -1,
1881
  );
1882
 
1883
  return new \WP_Query( $course_args );
1903
 
1904
  if ( count( $active_courses ) ) {
1905
  $course_post_type = tutor()->course_post_type;
1906
+ $course_args = array(
1907
  'post_type' => $course_post_type,
1908
  'post_status' => 'publish',
1909
  'post__in' => $active_courses,
1910
+ 'posts_per_page' => -1,
1911
  );
1912
 
1913
  return new \WP_Query( $course_args );
1927
  */
1928
  public function get_enrolled_courses_ids_by_user( $user_id = 0 ) {
1929
  global $wpdb;
1930
+ $user_id = $this->get_user_id( $user_id );
1931
+ $course_ids = $wpdb->get_col(
1932
+ $wpdb->prepare(
1933
+ "SELECT DISTINCT post_parent
1934
  FROM {$wpdb->posts}
1935
  WHERE post_type = %s
1936
  AND post_status = %s
1937
  AND post_author = %d;
1938
  ",
1939
+ 'tutor_enrolled',
1940
+ 'completed',
1941
+ $user_id
1942
+ )
1943
+ );
1944
 
1945
  return $course_ids;
1946
  }
1947
 
1948
  /**
1949
  * Get total enrolled students by course id
1950
+ *
1951
+ * @param int $course_id
1952
  *
1953
  * @param $period string | optional added since 1.9.9
1954
+ *
1955
  * @return int
1956
+ *
1957
  * @since 1.9.9
1958
  */
1959
+ public function count_enrolled_users_by_course( $course_id = 0, $period = '' ) {
1960
  global $wpdb;
1961
 
1962
  $course_id = $this->get_post_id( $course_id );
1963
+ // set period wise query
1964
  $period_filter = '';
1965
  if ( 'today' === $period ) {
1966
+ $period_filter = 'AND DATE(post_date) = CURDATE()';
1967
+ }
1968
  if ( 'monthly' === $period ) {
1969
+ $period_filter = 'AND MONTH(post_date) = MONTH(CURDATE()) ';
1970
  }
1971
  if ( 'yearly' === $period ) {
1972
+ $period_filter = 'AND YEAR(post_date) = YEAR(CURDATE()) ';
1973
  }
1974
 
1975
+ $course_ids = $wpdb->get_var(
1976
+ $wpdb->prepare(
1977
+ "SELECT COUNT(ID)
1978
+ FROM {$wpdb->posts}
1979
  WHERE post_type = %s
1980
  AND post_status = %s
1981
  AND post_parent = %d;
1982
  {$period_filter}
1983
  ",
1984
+ 'tutor_enrolled',
1985
+ 'completed',
1986
+ $course_id
1987
+ )
1988
+ );
1989
 
1990
  return (int) $course_ids;
1991
  }
1997
  *
1998
  * Get the enrolled courses by user
1999
  */
2000
+ public function get_enrolled_courses_by_user( $user_id = 0, $post_status = 'publish' ) {
2001
  global $wpdb;
2002
 
2003
+ $user_id = $this->get_user_id( $user_id );
2004
  $course_ids = $this->get_enrolled_courses_ids_by_user( $user_id );
2005
 
2006
  if ( count( $course_ids ) ) {
2007
  $course_post_type = tutor()->course_post_type;
2008
+ $course_args = array(
2009
  'post_type' => $course_post_type,
2010
  'post_status' => $post_status,
2011
  'post__in' => $course_ids,
2012
+ 'posts_per_page' => -1,
2013
  );
2014
  return new \WP_Query( $course_args );
2015
  }
2032
  $video_url = trailingslashit( home_url() ) . 'video-url/' . $post->post_name;
2033
  } else {
2034
  $video_info = tutor_utils()->get_video_info( $post_id );
2035
+ $video_url = $video_info->url;
2036
  }
2037
 
2038
  return $video_url;
2050
  */
2051
  public function get_lesson_reading_info_full( $lesson_id = 0, $user_id = 0 ) {
2052
  $lesson_id = $this->get_post_id( $lesson_id );
2053
+ $user_id = $this->get_user_id( $user_id );
2054
 
2055
  $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
2056
  return $this->avalue_dot( $lesson_id, $lesson_info );
2065
  *
2066
  * @since v.1.0.0
2067
  */
2068
+ public function get_post_id( $post_id = 0 ) {
2069
  if ( ! $post_id ) {
2070
  $post_id = get_the_ID();
2071
  if ( ! $post_id ) {
2086
  * @since v.1.0.0
2087
  */
2088
  public function get_user_id( $user_id = 0 ) {
2089
+ if ( ! $user_id ) {
2090
  $user_id = get_current_user_id();
2091
  if ( ! $user_id ) {
2092
  return false;
2097
  }
2098
 
2099
  /**
2100
+ * @param int $lesson_id
2101
+ * @param int $user_id
2102
  * @param string $key
2103
  *
2104
  * @return array|bool|mixed
2112
  $user_id = $this->get_user_id( $user_id );
2113
  $lesson_info = $this->get_lesson_reading_info_full( $lesson_id, $user_id );
2114
 
2115
+ return $this->avalue_dot( $key, $lesson_info );
2116
  }
2117
 
2118
  /**
2119
+ * @param int $lesson_id
2120
+ * @param int $user_id
2121
  * @param array $data
2122
  *
2123
  * @return bool
2127
  * @since v.1.0.0
2128
  */
2129
  public function update_lesson_reading_info( $lesson_id = 0, $user_id = 0, $key = '', $value = '' ) {
2130
+ $lesson_id = $this->get_post_id( $lesson_id );
2131
+ $user_id = $this->get_user_id( $user_id );
2132
 
2133
  if ( $key && $value ) {
2134
+ $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
2135
  $lesson_info[ $lesson_id ][ $key ] = $value;
2136
  update_user_meta( $user_id, '_lesson_reading_info', $lesson_info );
2137
  }
2146
  *
2147
  * @since v.1.0.0
2148
  */
2149
+ public function get_youtube_video_id( $url = '' ) {
2150
  if ( ! $url ) {
2151
  return false;
2152
  }
2171
  * @since v.1.0.0
2172
  */
2173
  public function get_vimeo_video_id( $url = '' ) {
2174
+ if ( preg_match( '%^https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)(?:[?]?.*)$%im', $url, $match ) ) {
2175
  if ( isset( $match[3] ) ) {
2176
  return $match[3];
2177
  }
2191
  $user_id = $this->get_user_id( $user_id );
2192
 
2193
  do_action( 'tutor_mark_lesson_complete_before', $post_id, $user_id );
2194
+ update_user_meta( $user_id, '_tutor_completed_lesson_id_' . $post_id, tutor_time() );
2195
  do_action( 'tutor_mark_lesson_complete_after', $post_id, $user_id );
2196
  }
2197
 
2220
 
2221
  do_action( 'tutor_before_enroll', $course_id );
2222
  $user_id = $this->get_user_id( $user_id );
2223
+ $title = __( 'Course Enrolled', 'tutor' ) . ' &ndash; ' . date( get_option( 'date_format' ) ) . ' @ ' . date( get_option( 'time_format' ) );
2224
 
2225
  if ( $course_id && $user_id ) {
2226
  if ( $this->is_enrolled( $course_id, $user_id ) ) {
2227
+ return;
2228
  }
2229
  }
2230
 
2237
  $enrolment_status = 'pending';
2238
  }
2239
 
2240
+ $enroll_data = apply_filters(
2241
+ 'tutor_enroll_data',
2242
  array(
2243
+ 'post_type' => 'tutor_enrolled',
2244
+ 'post_title' => $title,
2245
+ 'post_status' => $enrolment_status,
2246
+ 'post_author' => $user_id,
2247
+ 'post_parent' => $course_id,
2248
  )
2249
  );
2250
 
2256
  do_action( 'tutor_after_enroll', $course_id, $isEnrolled );
2257
 
2258
  // Run this hook for completed enrollment regardless of payment provider and free/paid mode
2259
+ if ( $enroll_data['post_status'] == 'completed' ) {
2260
+ do_action( 'tutor_after_enrolled', $course_id, $user_id, $isEnrolled );
2261
  }
2262
 
2263
+ // Mark Current User as Students with user meta data
2264
  update_user_meta( $user_id, '_is_tutor_student', tutor_time() );
2265
 
2266
  if ( $order_id ) {
2267
+ // Mark order for course and user
2268
  $product_id = $this->get_course_product_id( $course_id );
2269
  update_post_meta( $isEnrolled, '_tutor_enrolled_by_order_id', $order_id );
2270
  update_post_meta( $isEnrolled, '_tutor_enrolled_by_product_id', $product_id );
2271
  update_post_meta( $order_id, '_is_tutor_order_for_course', tutor_time() );
2272
+ update_post_meta( $order_id, '_tutor_order_for_course_id_' . $course_id, $isEnrolled );
2273
  }
2274
  return true;
2275
  }
2277
  return false;
2278
  }
2279
 
2280
+ /**
2281
+ * @param bool $enrol_id
2282
+ * @param string $new_status
2283
+ *
2284
+ * Enrol Status change
2285
+ *
2286
+ * @since v.1.6.1
2287
+ */
2288
  public function course_enrol_status_change( $enrol_id = false, $new_status = '' ) {
2289
+ if ( ! $enrol_id ) {
2290
+ return;
2291
+ }
2292
+
2293
+ global $wpdb;
2294
+
2295
+ do_action( 'tutor/course/enrol_status_change/before', $enrol_id, $new_status );
2296
+ $wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $enrol_id ) );
2297
+ do_action( 'tutor/course/enrol_status_change/after', $enrol_id, $new_status );
2298
+ }
2299
+
2300
+ /**
2301
+ * @param int $course_id
2302
+ * @param int $user_id
2303
+ * @param string $cancel_status
2304
+ */
2305
  public function cancel_course_enrol( $course_id = 0, $user_id = 0, $cancel_status = 'canceled' ) {
2306
+ $course_id = $this->get_post_id( $course_id );
2307
+ $user_id = $this->get_user_id( $user_id );
2308
+ $enrolled = $this->is_enrolled( $course_id, $user_id );
2309
+
2310
+ if ( $enrolled ) {
2311
+ global $wpdb;
2312
+
2313
+ if ( $cancel_status === 'delete' ) {
2314
+ $wpdb->delete(
2315
+ $wpdb->posts,
2316
+ array(
2317
+ 'post_type' => 'tutor_enrolled',
2318
+ 'post_author' => $user_id,
2319
+ 'post_parent' => $course_id,
2320
+ )
2321
+ );
2322
+
2323
+ // Delete Related Meta Data
2324
+ delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_product_id' );
2325
+ $order_id = get_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id', true );
2326
+ if ( $order_id ) {
2327
+ delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id' );
2328
+ delete_post_meta( $order_id, '_is_tutor_order_for_course' );
2329
+ delete_post_meta( $order_id, '_tutor_order_for_course_id_' . $course_id );
2330
+
2331
  do_action( 'tutor_enrollment/after/delete', $enrolled->ID );
2332
+ }
2333
+ } else {
2334
+ $wpdb->update(
2335
+ $wpdb->posts,
2336
+ array( 'post_status' => $cancel_status ),
2337
+ array(
2338
+ 'post_type' => 'tutor_enrolled',
2339
+ 'post_author' => $user_id,
2340
+ 'post_parent' => $course_id,
2341
+ )
2342
+ );
2343
+
2344
  if ( $cancel_status === 'cancel' ) {
2345
  do_action( 'tutor_enrollment/after/cancel', $enrolled->ID );
2346
  }
2347
  }
2348
+ }
2349
+ }
2350
 
2351
  /**
2352
  * @param $order_id
2384
  public function get_course_enrolled_ids_by_order_id( $order_id ) {
2385
  global $wpdb;
2386
 
2387
+ // Getting all of courses ids within this order
2388
+ $courses_ids = $wpdb->get_results(
2389
+ $wpdb->prepare(
2390
+ "SELECT *
2391
  FROM {$wpdb->postmeta}
2392
+ WHERE post_id = %d
2393
  AND meta_key LIKE '_tutor_order_for_course_id_%'
2394
+ ",
2395
+ $order_id
2396
+ )
2397
+ );
2398
 
2399
  if ( is_array( $courses_ids ) && count( $courses_ids ) ) {
2400
  $course_enrolled_by_order = array();
2401
  foreach ( $courses_ids as $courses_id ) {
2402
+ $course_id = str_replace( '_tutor_order_for_course_id_', '', $courses_id->meta_key );
2403
  $course_enrolled_by_order[] = array(
2404
  'course_id' => $course_id,
2405
  'enrolled_id' => $courses_id->meta_value,
2406
+ 'order_id' => $courses_id->post_id,
2407
  );
2408
  }
2409
  return $course_enrolled_by_order;
2424
  */
2425
  public function get_wc_products_db() {
2426
  global $wpdb;
2427
+ $query = $wpdb->get_results(
2428
+ $wpdb->prepare(
2429
+ "SELECT ID,
2430
  post_title
2431
  FROM {$wpdb->posts}
2432
  WHERE post_status = %s
2433
  AND post_type = %s;
2434
  ",
2435
+ 'publish',
2436
+ 'product'
2437
+ )
2438
+ );
2439
 
2440
  return $query;
2441
  }
2447
  */
2448
  public function get_edd_products() {
2449
  global $wpdb;
2450
+ $query = $wpdb->get_results(
2451
+ $wpdb->prepare(
2452
+ "SELECT ID,
2453
  post_title
2454
  FROM {$wpdb->posts}
2455
  WHERE post_status = %s
2456
  AND post_type = %s;
2457
  ",
2458
+ 'publish',
2459
+ 'download'
2460
+ )
2461
+ );
2462
 
2463
  return $query;
2464
  }
2491
  public function product_belongs_with_course( $product_id = 0 ) {
2492
  global $wpdb;
2493
 
2494
+ $query = $wpdb->get_row(
2495
+ $wpdb->prepare(
2496
+ "SELECT *
2497
  FROM {$wpdb->postmeta}
2498
+ WHERE meta_key = %s
2499
+ AND meta_value = %d
2500
  limit 1
2501
  ",
2502
+ '_tutor_course_product_id',
2503
+ $product_id
2504
+ )
2505
+ );
2506
+
2507
  return $query;
2508
  }
2509
 
2515
  public function get_enrolled_statuses() {
2516
  return apply_filters(
2517
  'tutor_get_enrolled_statuses',
2518
+ array(
2519
  'pending',
2520
  'processing',
2521
  'on-hold',
2548
  * @since v.1.0.0
2549
  */
2550
  public function tutor_dashboard_pages() {
2551
+ $nav_items = apply_filters(
2552
+ 'tutor_dashboard/nav_items',
2553
+ array(
2554
+ 'index' => __( 'Dashboard', 'tutor' ),
2555
+ 'my-profile' => __( 'My Profile', 'tutor' ),
2556
+ 'enrolled-courses' => __( 'Enrolled Courses', 'tutor' ),
2557
+ 'wishlist' => __( 'Wishlist', 'tutor' ),
2558
+ 'reviews' => __( 'Reviews', 'tutor' ),
2559
+ 'my-quiz-attempts' => __( 'My Quiz Attempts', 'tutor' ),
2560
+ 'purchase_history' => __( 'Purchase History', 'tutor' ),
2561
+ )
2562
+ );
2563
+
2564
+ $instructor_nav_items = apply_filters(
2565
+ 'tutor_dashboard/instructor_nav_items',
2566
+ array(
2567
+ 'separator-1' => array(
2568
+ 'title' => __( 'Instructor', 'tutor' ),
2569
+ 'auth_cap' => tutor()->instructor_role,
2570
+ 'type' => 'separator',
2571
+ ),
2572
+ 'create-course' => array(
2573
+ 'title' => __( 'Create Course', 'tutor' ),
2574
+ 'show_ui' => false,
2575
+ 'auth_cap' => tutor()->instructor_role,
2576
+ ),
2577
+ 'my-courses' => array(
2578
+ 'title' => __( 'My Courses', 'tutor' ),
2579
+ 'auth_cap' => tutor()->instructor_role,
2580
+ ),
2581
+ 'announcements' => array(
2582
+ 'title' => __( 'Announcements', 'tutor' ),
2583
+ 'auth_cap' => tutor()->instructor_role,
2584
+ ),
2585
+ 'withdraw' => array(
2586
+ 'title' => __( 'Withdrawals', 'tutor' ),
2587
+ 'auth_cap' => tutor()->instructor_role,
2588
+ ),
2589
+ 'quiz-attempts' => array(
2590
+ 'title' => __( 'Quiz Attempts', 'tutor' ),
2591
+ 'auth_cap' => tutor()->instructor_role,
2592
+ ),
2593
+ 'question-answer' => array(
2594
+ 'title' => __( 'Question & Answer', 'tutor' ),
2595
+ 'auth_cap' => tutor()->instructor_role,
2596
+ ),
2597
+ )
2598
+ );
2599
 
2600
  $disable = get_tutor_option( 'disable_course_review' );
2601
  if ( $disable && isset( $nav_items['reviews'] ) ) {
2604
 
2605
  $nav_items = array_merge( $nav_items, $instructor_nav_items );
2606
 
2607
+ $new_navs = apply_filters(
2608
+ 'tutor_dashboard/bottom_nav_items',
2609
+ array(
2610
+ 'separator-2' => array(
2611
+ 'title' => '',
2612
+ 'type' => 'separator',
2613
+ ),
2614
+ 'settings' => __( 'Settings', 'tutor' ),
2615
+ 'logout' => __( 'Logout', 'tutor' ),
2616
+ )
2617
+ );
2618
  $all_nav_items = array_merge( $nav_items, $new_navs );
2619
 
2620
  return apply_filters( 'tutor_dashboard/nav_items_all', $all_nav_items );
2623
  public function tutor_dashboard_permalinks() {
2624
  $dashboard_pages = $this->tutor_dashboard_pages();
2625
 
2626
+ $dashboard_permalinks = apply_filters(
2627
+ 'tutor_dashboard/permalinks',
2628
+ array(
2629
+ 'retrieve-password' => array(
2630
+ 'title' => __( 'Retrieve Password', 'tutor' ),
2631
+ 'login_require' => false,
2632
+ ),
2633
+ )
2634
+ );
2635
 
2636
  $dashboard_pages = array_merge( $dashboard_pages, $dashboard_permalinks );
2637
 
2650
  $nav_items = $this->tutor_dashboard_pages();
2651
 
2652
  foreach ( $nav_items as $key => $nav_item ) {
2653
+ if ( is_array( $nav_item ) ) {
2654
 
2655
  if ( isset( $nav_item['show_ui'] ) && ! tutor_utils()->array_get( 'show_ui', $nav_item ) ) {
2656
  unset( $nav_items[ $key ] );
2657
  }
2658
+ if ( isset( $nav_item['auth_cap'] ) && ! current_user_can( $nav_item['auth_cap'] ) ) {
2659
  unset( $nav_items[ $key ] );
2660
  }
2661
  }
2662
  }
2663
 
2664
+ return apply_filters( 'tutor_dashboard/nav_ui_items', $nav_items );
2665
  }
2666
 
2667
  /**
2668
  * @param string $page_key
2669
+ * @param int $page_id
2670
  *
2671
  * @return string
2672
  *
2679
  $page_key = '';
2680
  }
2681
  if ( ! $page_id ) {
2682
+ $page_id = (int) tutils()->get_option( 'tutor_dashboard_page_id' );
2683
+ }
2684
  return trailingslashit( get_permalink( $page_id ) ) . $page_key;
2685
  }
2686
 
2696
  */
2697
  public function input_old( $input = '', $old_data = null ) {
2698
  if ( ! $old_data ) {
2699
+ $old_data = tutor_sanitize_data( $_REQUEST );
2700
  }
2701
  $value = $this->avalue_dot( $input, $old_data );
2702
  if ( $value ) {
2721
  }
2722
 
2723
  /**
2724
+ * @param int $user_id
2725
  * @param bool $status_name
2726
  *
2727
  * @return bool|mixed
2733
  public function instructor_status( $user_id = 0, $status_name = true ) {
2734
  $user_id = $this->get_user_id( $user_id );
2735
 
2736
+ $instructor_status = apply_filters(
2737
+ 'tutor_instructor_statuses',
2738
+ array(
2739
+ 'pending' => __( 'Pending', 'tutor' ),
2740
+ 'approved' => __( 'Approved', 'tutor' ),
2741
+ 'blocked' => __( 'Blocked', 'tutor' ),
2742
+ )
2743
+ );
2744
 
2745
  $status = get_user_meta( $user_id, '_tutor_instructor_status', true );
2746
 
2747
+ if ( isset( $instructor_status[ $status ] ) ) {
2748
  if ( ! $status_name ) {
2749
  return $status;
2750
  }
2751
+ return $instructor_status[ $status ];
2752
  }
2753
  return false;
2754
  }
2762
  *
2763
  * @since v.1.0.0
2764
  */
2765
+ public function get_total_instructors( $search_filter = '' ) {
2766
  global $wpdb;
2767
 
2768
+ sanitize_text_field( $search_filter );
 
 
2769
 
2770
+ $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
2771
+
2772
+ $count = $wpdb->get_var(
2773
+ $wpdb->prepare(
2774
+ "SELECT COUNT(user.ID)
2775
  FROM {$wpdb->users} as user
2776
  INNER JOIN {$wpdb->usermeta} as user_meta
2777
  ON ( user_meta.user_id = user.ID )
2778
+
2779
  WHERE user_meta.meta_key = %s
2780
  AND ( user.display_name LIKE %s OR user.user_email LIKE %s );
2781
  ",
2782
+ '_is_tutor_instructor',
2783
+ $search_filter,
2784
+ $search_filter
2785
+ )
2786
+ );
2787
  return $count;
2788
  }
2789
 
2790
  /**
2791
+ * @param int $start
2792
+ * @param int $limit
2793
  * @param string $search_term
2794
  *
2795
  * @return array|null|object
2801
  public function get_instructors( $start = 0, $limit = 10, $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $status = null, $cat_ids = array() ) {
2802
  global $wpdb;
2803
 
2804
+ sanitize_text_field( $search_filter );
2805
+ sanitize_text_field( $course_filter );
2806
+ sanitize_text_field( $date_filter );
2807
+ sanitize_text_field( $order_filter );
2808
 
2809
+ $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
2810
+ $course_filter = $course_filter != '' ? " AND inst_status.meta_key = '_tutor_instructor_course_id' AND inst_status.meta_value = $course_filter " : '';
2811
 
2812
  if ( '' != $date_filter ) {
2813
  $date_filter = tutor_get_formated_date( 'Y-m-d', $date_filter );
2814
  }
 
 
2815
 
2816
+ $date_filter = $date_filter != '' ? " AND DATE(user.user_registered) = '$date_filter' " : '';
2817
+
2818
+ $category_join = '';
2819
  $category_where = '';
2820
 
2821
  if ( $status ) {
2822
+ ! is_array( $status ) ? $status = array( $status ) : 0;
2823
 
2824
+ $status = array_map(
2825
+ function( $str ) {
2826
+ return "'{$str}'";
2827
+ },
2828
+ $status
2829
+ );
2830
 
2831
+ $status = ' AND inst_status.meta_value IN (' . implode( ',', $status ) . ')';
2832
  }
2833
 
2834
+ $cat_ids = array_filter(
2835
+ $cat_ids,
2836
+ function( $id ) {
2837
+ return is_numeric( $id );
2838
+ }
2839
+ );
2840
 
2841
+ if ( count( $cat_ids ) ) {
2842
 
2843
  $category_join =
2844
  "INNER JOIN {$wpdb->posts} course
2850
  INNER JOIN {$wpdb->prefix}terms term
2851
  ON term.term_id=taxonomy.term_id";
2852
 
2853
+ $cat_ids = implode( ',', $cat_ids );
2854
  $category_where = " AND term.term_id IN ({$cat_ids})";
2855
  }
2856
 
2857
+ $instructors = $wpdb->get_results(
2858
+ $wpdb->prepare(
2859
+ "SELECT DISTINCT user.*, user_meta.meta_value AS instructor_from_date
2860
  FROM {$wpdb->users} user
2861
  INNER JOIN {$wpdb->usermeta} user_meta
2862
+ ON ( user.ID = user_meta.user_id )
2863
+ INNER JOIN {$wpdb->usermeta} inst_status
2864
+ ON ( user.ID = inst_status.user_id )
2865
  {$category_join}
2866
  WHERE user_meta.meta_key = %s
2867
  AND ( user.display_name LIKE %s OR user.user_email LIKE %s )
2872
  ORDER BY user_meta.meta_value {$order_filter}
2873
  LIMIT %d, %d;
2874
  ",
2875
+ '_is_tutor_instructor',
2876
+ $search_filter,
2877
+ $search_filter,
2878
+ $start,
2879
+ $limit
2880
+ )
2881
+ );
2882
 
2883
  return $instructors;
2884
  }
2896
  global $wpdb;
2897
  $course_id = $this->get_post_id( $course_id );
2898
 
2899
+ $instructors = $wpdb->get_results(
2900
+ $wpdb->prepare(
2901
+ "SELECT ID,
2902
  display_name,
2903
  get_course.meta_value AS taught_course_id,
2904
  tutor_job_title.meta_value AS tutor_profile_job_title,
2905
  tutor_bio.meta_value AS tutor_profile_bio,
2906
+ tutor_photo.meta_value AS tutor_profile_photo
2907
+ FROM {$wpdb->users}
2908
+ INNER JOIN {$wpdb->usermeta} get_course
2909
+ ON ID = get_course.user_id
2910
+ AND get_course.meta_key = %s
2911
+ AND get_course.meta_value = %d
2912
+ LEFT JOIN {$wpdb->usermeta} tutor_job_title
2913
+ ON ID = tutor_job_title.user_id
2914
+ AND tutor_job_title.meta_key = %s
2915
+ LEFT JOIN {$wpdb->usermeta} tutor_bio
2916
+ ON ID = tutor_bio.user_id
2917
+ AND tutor_bio.meta_key = %s
2918
+ LEFT JOIN {$wpdb->usermeta} tutor_photo
2919
+ ON ID = tutor_photo.user_id
2920
  AND tutor_photo.meta_key = %s
2921
  ",
2922
+ '_tutor_instructor_course_id',
2923
+ $course_id,
2924
+ '_tutor_profile_job_title',
2925
+ '_tutor_profile_bio',
2926
+ '_tutor_profile_photo'
2927
+ )
2928
+ );
2929
 
2930
  if ( is_array( $instructors ) && count( $instructors ) ) {
2931
  return $instructors;
2949
 
2950
  $course_post_type = tutor()->course_post_type;
2951
 
2952
+ $count = $wpdb->get_var(
2953
+ $wpdb->prepare(
2954
+ "SELECT COUNT(enrollment.ID)
2955
+ FROM {$wpdb->posts} enrollment
2956
  INNER JOIN {$wpdb->posts} course
2957
  ON enrollment.post_parent=course.ID
2958
  WHERE course.post_author = %d
2961
  AND enrollment.post_type = %s
2962
  AND enrollment.post_status = %s;
2963
  ",
2964
+ $instructor_id,
2965
+ $course_post_type,
2966
+ 'publish',
2967
+ 'tutor_enrolled',
2968
+ 'completed'
2969
+ )
2970
+ );
2971
 
2972
  return (int) $count;
2973
  }
2974
 
2975
  /**
2976
  * Get all students by instructor_id
2977
+ *
2978
  * @param $instructor_id int | required
2979
+ *
2980
  * @param $offset int | required
2981
+ *
2982
  * @param $limit int | required
2983
+ *
2984
  * @param $search string | optional
2985
+ *
2986
  * @param $course_id int | optional
2987
+ *
2988
  * @param $date string | optional
2989
+ *
2990
  * @return array
2991
+ *
2992
  * @since 1.9.9
2993
  */
2994
  public function get_students_by_instructor( int $instructor_id, int $offset, int $limit, $search_filter = '', $course_id = '', $date_filter = '', $order_by = '', $order = '' ): array {
2995
  global $wpdb;
2996
+ $instructor_id = sanitize_text_field( $instructor_id );
2997
+ $limit = sanitize_text_field( $limit );
2998
+ $offset = sanitize_text_field( $offset );
2999
+ $course_id = sanitize_text_field( $course_id );
3000
+ $date_filter = sanitize_text_field( $date_filter );
3001
+ $search_filter = sanitize_text_field( $search_filter );
3002
+
3003
+ $order_by = 'user.ID';
3004
  if ( 'registration_date' === $order_by ) {
3005
  $order_by = 'enrollment.post_date';
3006
+ } elseif ( 'course_taken' === $order_by ) {
3007
  $order_by = 'course_taken';
3008
  } else {
3009
  $order_by = 'user.ID';
3010
  }
3011
 
3012
+ $order = sanitize_text_field( $order );
3013
 
3014
  if ( '' !== $date_filter ) {
3015
  $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter );
3028
  $date_query = " AND DATE(user.user_registered) = CAST( '$date_filter' AS DATE ) ";
3029
  }
3030
 
3031
+ $students = $wpdb->get_results(
3032
+ $wpdb->prepare(
3033
+ "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, (SELECT post_date FROM {$wpdb->posts} WHERE post_author = user.ID LIMIT 1) AS enroll_date
3034
+ FROM {$wpdb->posts} enrollment
3035
  INNER JOIN {$wpdb->posts} AS course
3036
  ON enrollment.post_parent=course.ID
3037
  INNER JOIN {$wpdb->users} AS user
3049
  ORDER BY {$order_by} {$order}
3050
  LIMIT %d, %d
3051
  ",
3052
+ $instructor_id,
3053
+ $course_post_type,
3054
+ 'publish',
3055
+ 'tutor_enrolled',
3056
+ 'completed',
3057
+ $search_query,
3058
+ $search_query,
3059
+ $search_query,
3060
+ $search_query,
3061
+ $offset,
3062
+ $limit
3063
+ )
3064
+ );
3065
+ $total_students = $wpdb->get_results(
3066
+ $wpdb->prepare(
3067
+ "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, enrollment.post_date AS enroll_date
3068
+ FROM {$wpdb->posts} enrollment
3069
+ INNER JOIN {$wpdb->posts} AS course
3070
+ ON enrollment.post_parent=course.ID
3071
  INNER JOIN {$wpdb->users} AS user
3072
  ON user.ID = enrollment.post_author
3073
  WHERE course.post_author = %d
3080
  {$date_query}
3081
  GROUP BY enrollment.post_author
3082
  ORDER BY {$order_by} {$order}
3083
+
3084
  ",
3085
+ $instructor_id,
3086
+ $course_post_type,
3087
+ 'publish',
3088
+ 'tutor_enrolled',
3089
+ 'completed',
3090
+ $search_query,
3091
+ $search_query,
3092
+ $search_query,
3093
+ $search_query
3094
+ )
3095
+ );
3096
 
3097
  return array(
3098
+ 'students' => $students,
3099
+ 'total_students' => count( $total_students ),
3100
  );
3101
  }
3102
 
3103
  /**
3104
  * Get all course for a give student & instructor id
3105
+ *
3106
  * @param $student_id int | required
3107
+ *
3108
  * @param $instructor_id int | required
3109
+ *
3110
  * @return array
3111
+ *
3112
  * @since 1.9.9
3113
  */
3114
+ public function get_courses_by_student_instructor_id( int $student_id, int $instructor_id ): array {
3115
  global $wpdb;
3116
  $course_post_type = tutor()->course_post_type;
3117
+ $students = $wpdb->get_results(
3118
+ $wpdb->prepare(
3119
+ "SELECT course.*
3120
+ FROM {$wpdb->posts} enrollment
3121
  INNER JOIN {$wpdb->posts} AS course
3122
  ON enrollment.post_parent=course.ID
3123
  WHERE course.post_author = %d
3128
  AND enrollment.post_author = %d
3129
  ORDER BY course.post_date DESC
3130
  ",
3131
+ $instructor_id,
3132
+ $course_post_type,
3133
+ 'publish',
3134
+ 'tutor_enrolled',
3135
+ 'completed',
3136
+ $student_id
3137
+ )
3138
+ );
3139
  return $students;
3140
  }
3141
 
3142
  /**
3143
  * Get total number of completed assignment
3144
+ *
3145
  * @param $course_id int | required
3146
+ *
3147
  * @param $student | required
3148
+ *
3149
  * @since 1.9.9
3150
  */
3151
+ public function get_completed_assignment( int $course_id, int $student_id ): int {
3152
  global $wpdb;
3153
+ $course_id = sanitize_text_field( $course_id );
3154
  $student_id = sanitize_text_field( $student_id );
3155
+ $count = $wpdb->get_var(
3156
+ $wpdb->prepare(
3157
+ 'SELECT COUNT(ID) FROM wp_posts
3158
  INNER JOIN wp_comments c ON c.comment_post_ID = wp_posts.ID AND c.user_id = %d AND c.comment_approved = %s
3159
  WHERE post_parent IN (SELECT ID FROM wp_posts WHERE post_type = %s AND post_parent = %d AND post_status = %s)
3160
+ AND post_type =%s
3161
  AND post_status = %s
3162
+ ',
3163
+ $student_id,
3164
+ 'submitted',
3165
+ 'topics',
3166
+ $course_id,
3167
+ 'publish',
3168
+ 'tutor_assignments',
3169
+ 'publish'
3170
+ )
3171
+ );
3172
  return (int) $count;
3173
  }
3174
  /**
3175
  * Get total number of completed quiz
3176
+ *
3177
  * @param $course_id int | required
3178
+ *
3179
  * @param $student | required
3180
+ *
3181
  * @since 1.9.9
3182
  */
3183
+ public function get_completed_quiz( int $course_id, int $student_id ): int {
3184
  global $wpdb;
3185
+ $course_id = sanitize_text_field( $course_id );
3186
  $student_id = sanitize_text_field( $student_id );
3187
+ $count = $wpdb->get_var(
3188
+ $wpdb->prepare(
3189
+ "SELECT COUNT(DISTINCT quiz_id) AS total
3190
+ FROM {$wpdb->prefix}tutor_quiz_attempts
3191
+ WHERE course_id = %d
3192
  AND user_id = %d
3193
  AND attempt_status = %s
3194
  ",
3195
+ $course_id,
3196
+ $student_id,
3197
+ 'attempt_ended'
3198
+ )
3199
+ );
3200
  return (int) $count;
3201
  }
3202
 
3211
  */
3212
  public function get_rating_value( $input = 0.00 ) {
3213
 
3214
+ if ( $input > 0 ) {
3215
+ $input = number_format( $input, 2 );
3216
  $int_value = (int) $input;
3217
+ $fraction = $input - $int_value;
3218
 
3219
  if ( $fraction == 0 ) {
3220
  $fraction = 0.00;
3232
 
3233
  /**
3234
  * @param float $current_rating
3235
+ * @param bool $echo
3236
  *
3237
  * @return string
3238
  *
3243
  public function star_rating_generator( $current_rating = 0.00, $echo = true ) {
3244
  $output = '<div class="tutor-star-rating-group">';
3245
 
3246
+ for ( $i = 1; $i <= 5; $i++ ) {
3247
  $intRating = (int) $current_rating;
3248
 
3249
  if ( $intRating >= $i ) {
3250
+ $output .= '<i class="tutor-icon-star-full" data-rating-value="' . $i . '"></i>';
3251
  } else {
3252
+ if ( ( $current_rating - $i ) == -0.5 ) {
3253
+ $output .= '<i class="tutor-icon-star-half" data-rating-value="' . $i . '"></i>';
3254
  } else {
3255
+ $output .= '<i class="tutor-icon-star-line" data-rating-value="' . $i . '"></i>';
3256
  }
3257
  }
3258
  }
3259
 
3260
+ $output .= '<div class="tutor-rating-gen-input"><input type="hidden" name="tutor_rating_gen_input" value="' . $current_rating . '" /></div>';
3261
 
3262
+ $output .= '</div>';
3263
 
3264
  if ( $echo ) {
3265
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
3266
  }
3267
 
3268
  return $output;
3274
  * @return string
3275
  *
3276
  * Split string regardless of ASCI, Unicode
 
 
3277
  */
3278
  public function str_split( $string ) {
3279
  $strlen = mb_strlen( $string );
3280
  while ( $strlen ) {
3281
+ $array[] = mb_substr( $string, 0, 1, 'UTF-8' );
3282
+ $string = mb_substr( $string, 1, $strlen, 'UTF-8' );
3283
+ $strlen = mb_strlen( $string );
3284
  }
3285
  return $array;
3286
+ }
3287
 
3288
  /**
3289
  * @param null $name
3303
 
3304
  $user = $this->get_tutor_user( $user_id );
3305
  if ( $user->tutor_profile_photo ) {
3306
+ return '<img src="' . wp_get_attachment_image_url( $user->tutor_profile_photo, $size ) . '" class="tutor-image-avatar" alt="" /> ';
3307
  }
3308
 
3309
  $name = $user->display_name;
3310
+ $arr = explode( ' ', trim( $name ) );
3311
 
3312
+ $first_char = ! empty( $arr[0] ) ? $this->str_split( $arr[0] )[0] : '';
3313
+ $second_char = ! empty( $arr[1] ) ? $this->str_split( $arr[1] )[0] : '';
3314
+ $initial_avatar = strtoupper( $first_char . $second_char );
3315
 
3316
+ $bg_color = '#' . substr( md5( $initial_avatar ), 0, 6 );
3317
+ $initial_avatar = '<span class="tutor-text-avatar" style="background-color: ' . $bg_color . '; color: #fff8e5">' . $initial_avatar . '</span>';
3318
 
3319
  return $initial_avatar;
3320
  }
3331
  public function get_tutor_user( $user_id ) {
3332
  global $wpdb;
3333
 
3334
+ $user = $wpdb->get_row(
3335
+ $wpdb->prepare(
3336
+ "SELECT ID,
3337
+ display_name,
3338
+ tutor_job_title.meta_value AS tutor_profile_job_title,
3339
  tutor_bio.meta_value AS tutor_profile_bio,
3340
  tutor_photo.meta_value AS tutor_profile_photo
3341
  FROM {$wpdb->users}
3342
+ LEFT JOIN {$wpdb->usermeta} tutor_job_title
3343
+ ON ID = tutor_job_title.user_id
3344
  AND tutor_job_title.meta_key = '_tutor_profile_job_title'
3345
  LEFT JOIN {$wpdb->usermeta} tutor_bio
3346
  ON ID = tutor_bio.user_id
3350
  AND tutor_photo.meta_key = '_tutor_profile_photo'
3351
  WHERE ID = %d
3352
  ",
3353
+ $user_id
3354
+ )
3355
+ );
3356
 
3357
  return $user;
3358
  }
3372
  $course_id = $this->get_post_id( $course_id );
3373
  global $wpdb;
3374
 
3375
+ $reviews = $wpdb->get_results(
3376
+ $wpdb->prepare(
3377
+ "SELECT {$wpdb->comments}.comment_ID,
3378
+ {$wpdb->comments}.comment_post_ID,
3379
+ {$wpdb->comments}.comment_author,
3380
+ {$wpdb->comments}.comment_author_email,
3381
+ {$wpdb->comments}.comment_date,
3382
+ {$wpdb->comments}.comment_content,
3383
+ {$wpdb->comments}.user_id,
3384
  {$wpdb->commentmeta}.meta_value AS rating,
3385
+ {$wpdb->users}.display_name
3386
+
3387
  FROM {$wpdb->comments}
3388
+ INNER JOIN {$wpdb->commentmeta}
3389
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3390
  LEFT JOIN {$wpdb->users}
3391
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3392
+ WHERE {$wpdb->comments}.comment_post_ID = %d
3393
  AND comment_type = 'tutor_course_rating' AND meta_key = 'tutor_rating'
3394
  ORDER BY comment_ID DESC
3395
  LIMIT %d, %d;
3396
  ",
3397
+ $course_id,
3398
+ $offset,
3399
+ $limit
3400
+ )
3401
+ );
3402
 
3403
  return $reviews;
3404
  }
3420
  'rating_count' => 0,
3421
  'rating_sum' => 0,
3422
  'rating_avg' => 0.00,
3423
+ 'count_by_value' => array(
3424
+ 5 => 0,
3425
+ 4 => 0,
3426
+ 3 => 0,
3427
+ 2 => 0,
3428
+ 1 => 0,
3429
+ ),
3430
  );
3431
 
3432
+ $rating = $wpdb->get_row(
3433
+ $wpdb->prepare(
3434
+ "SELECT COUNT(meta_value) AS rating_count,
3435
  SUM(meta_value) AS rating_sum
3436
  FROM {$wpdb->comments}
3437
  INNER JOIN {$wpdb->commentmeta}
3439
  WHERE {$wpdb->comments}.comment_post_ID = %d
3440
  AND {$wpdb->comments}.comment_type = %s
3441
  AND meta_key = %s;
3442
+ ",
3443
+ $course_id,
3444
+ 'tutor_course_rating',
3445
+ 'tutor_rating'
3446
+ )
3447
+ );
3448
 
3449
  if ( $rating->rating_count ) {
3450
  $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
3451
 
3452
+ $stars = $wpdb->get_results(
3453
+ $wpdb->prepare(
3454
+ "SELECT commentmeta.meta_value AS rating,
3455
+ COUNT(commentmeta.meta_value) as rating_count
3456
  FROM {$wpdb->comments} comments
3457
  INNER JOIN {$wpdb->commentmeta} commentmeta
3458
  ON comments.comment_ID = commentmeta.comment_id
3459
+ WHERE comments.comment_post_ID = %d
3460
  AND comments.comment_type = %s
3461
  AND commentmeta.meta_key = %s
3462
  GROUP BY commentmeta.meta_value;
3463
+ ",
3464
+ $course_id,
3465
+ 'tutor_course_rating',
3466
+ 'tutor_rating'
3467
+ )
3468
+ );
3469
 
3470
+ $ratings = array(
3471
+ 5 => 0,
3472
+ 4 => 0,
3473
+ 3 => 0,
3474
+ 2 => 0,
3475
+ 1 => 0,
3476
+ );
3477
  foreach ( $stars as $star ) {
3478
  $index = (int) $star->rating;
3479
+ array_key_exists( $index, $ratings ) ? $ratings[ $index ] = $star->rating_count : 0;
3480
  }
3481
 
3482
  $ratings = array(
3483
  'rating_count' => $rating->rating_count,
3484
  'rating_sum' => $rating->rating_sum,
3485
  'rating_avg' => $avg_rating,
3486
+ 'count_by_value' => $ratings,
3487
  );
3488
  }
3489
 
3505
  $user_id = $this->get_user_id( $user_id );
3506
  global $wpdb;
3507
 
3508
+ $reviews = $wpdb->get_results(
3509
+ $wpdb->prepare(
3510
+ "SELECT {$wpdb->comments}.comment_ID,
3511
  {$wpdb->comments}.comment_post_ID,
3512
  {$wpdb->comments}.comment_author,
3513
  {$wpdb->comments}.comment_author_email,
3516
  {$wpdb->comments}.user_id,
3517
  {$wpdb->commentmeta}.meta_value as rating,
3518
  {$wpdb->users}.display_name
3519
+
3520
  FROM {$wpdb->comments}
3521
+ INNER JOIN {$wpdb->commentmeta}
3522
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3523
  INNER JOIN {$wpdb->users}
3524
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3525
+ WHERE {$wpdb->comments}.user_id = %d
3526
  AND comment_type = %s
3527
  AND meta_key = %s
3528
  ORDER BY comment_ID DESC
3529
  LIMIT %d, %d;
3530
  ",
3531
+ $user_id,
3532
+ 'tutor_course_rating',
3533
+ 'tutor_rating',
3534
+ $offset,
3535
+ $limit
3536
+ )
3537
+ );
3538
 
3539
+ if ( $get_object ) {
3540
+ $count = (int) $wpdb->get_var(
3541
+ $wpdb->prepare(
3542
+ "SELECT COUNT({$wpdb->comments}.comment_ID)
3543
  FROM {$wpdb->comments}
3544
+ INNER JOIN {$wpdb->commentmeta}
3545
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3546
  INNER JOIN {$wpdb->users}
3547
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3548
+ WHERE {$wpdb->comments}.user_id = %d
3549
  AND comment_type = %s
3550
  AND meta_key = %s",
3551
+ $user_id,
3552
+ 'tutor_course_rating',
3553
+ 'tutor_rating'
3554
+ )
3555
+ );
3556
 
3557
+ return (object) array(
3558
+ 'count' => $count,
3559
+ 'results' => $reviews,
3560
  );
3561
  }
3562
 
3564
  }
3565
 
3566
  /**
3567
+ * @param int $user_id
3568
+ * @param int $offset
3569
+ * @param int $limit
3570
  *
3571
  * @return array|null|object
3572
  *
3573
  * Get reviews by instructor (Received by the instructor)
3574
  *
3575
  * @since v.1.4.0
3576
+ *
3577
  * @param $course_id optional
3578
+ *
3579
  * @param $date_filter optional
3580
+ *
3581
  * Course id & date filter is sorting with specific course and date
3582
+ *
3583
  * @since 1.9.9
3584
  */
3585
  public function get_reviews_by_instructor( $instructor_id = 0, $offset = 0, $limit = 150, $course_id = '', $date_filter = '' ) {
3586
  global $wpdb;
3587
+ $instructor_id = sanitize_text_field( $instructor_id );
3588
+ $offset = sanitize_text_field( $offset );
3589
+ $limit = sanitize_text_field( $limit );
3590
+ $course_id = sanitize_text_field( $course_id );
3591
+ $date_filter = sanitize_text_field( $date_filter );
3592
+ $instructor_id = $this->get_user_id( $instructor_id );
3593
 
3594
+ $course_query = '';
3595
+ $date_query = '';
3596
 
3597
  if ( '' !== $course_id ) {
3598
  $course_query = " AND {$wpdb->comments}.comment_post_ID = {$course_id} ";
3599
+ }
3600
  if ( '' !== $date_filter ) {
3601
+ $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter );
3602
+ $date_query = " AND DATE({$wpdb->comments}.comment_date) = CAST( '$date_filter' AS DATE ) ";
3603
+ }
3604
 
3605
  $results = array(
3606
+ 'count' => 0,
3607
+ 'results' => false,
3608
  );
3609
 
3610
  $cours_ids = (array) $this->get_assigned_courses_ids_by_instructors( $instructor_id );
3612
  if ( $this->count( $cours_ids ) ) {
3613
  $implode_ids = implode( ',', $cours_ids );
3614
 
3615
+ // Count
3616
+ $results['count'] = $wpdb->get_var(
3617
+ $wpdb->prepare(
3618
+ "SELECT COUNT({$wpdb->comments}.comment_ID)
3619
  FROM {$wpdb->comments}
3620
  INNER JOIN {$wpdb->commentmeta}
3621
  ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3622
  INNER JOIN {$wpdb->users}
3623
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3624
+ WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3625
  AND comment_type = %s
3626
  AND meta_key = %s
3627
  {$course_query}
3628
  {$date_query}
3629
  ",
3630
+ 'tutor_course_rating',
3631
+ 'tutor_rating'
3632
+ )
3633
+ );
3634
+
3635
+ // Results
3636
+ $results['results'] = $wpdb->get_results(
3637
+ $wpdb->prepare(
3638
+ "SELECT {$wpdb->comments}.comment_ID,
3639
+ {$wpdb->comments}.comment_post_ID,
3640
+ {$wpdb->comments}.comment_author,
3641
+ {$wpdb->comments}.comment_author_email,
3642
+ {$wpdb->comments}.comment_date,
3643
+ {$wpdb->comments}.comment_content,
3644
+ {$wpdb->comments}.user_id,
3645
  {$wpdb->commentmeta}.meta_value AS rating,
3646
  {$wpdb->users}.display_name,
3647
  {$wpdb->posts}.post_title as course_title
3648
+
3649
  FROM {$wpdb->comments}
3650
+ INNER JOIN {$wpdb->commentmeta}
3651
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3652
  INNER JOIN {$wpdb->users}
3653
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3654
  INNER JOIN {$wpdb->posts}
3655
  ON {$wpdb->posts}.ID = {$wpdb->comments}.comment_post_ID
3656
+ WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3657
  AND comment_type = %s
3658
  AND meta_key = %s
3659
  {$course_query}
3661
  ORDER BY comment_ID DESC
3662
  LIMIT %d, %d;
3663
  ",
3664
+ 'tutor_course_rating',
3665
+ 'tutor_rating',
3666
+ $offset,
3667
+ $limit
3668
+ )
3669
+ );
3670
  }
3671
 
3672
  return (object) $results;
3685
  global $wpdb;
3686
 
3687
  $ratings = array(
3688
+ 'rating_count' => 0,
3689
+ 'rating_sum' => 0,
3690
+ 'rating_avg' => 0.00,
3691
  );
3692
 
3693
+ $rating = $wpdb->get_row(
3694
+ $wpdb->prepare(
3695
+ "SELECT COUNT(rating.meta_value) as rating_count, SUM(rating.meta_value) as rating_sum
3696
  FROM {$wpdb->usermeta} courses
3697
  INNER JOIN {$wpdb->comments} reviews
3698
  ON courses.meta_value = reviews.comment_post_ID
3703
  WHERE courses.user_id = %d
3704
  AND courses.meta_key = %s
3705
  ",
3706
+ $instructor_id,
3707
+ '_tutor_instructor_course_id'
3708
+ )
3709
+ );
3710
 
3711
  if ( $rating->rating_count ) {
3712
  $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
3713
 
3714
  $ratings = array(
3715
+ 'rating_count' => $rating->rating_count,
3716
+ 'rating_sum' => $rating->rating_sum,
3717
+ 'rating_avg' => $avg_rating,
3718
  );
3719
  }
3720
 
3735
  global $wpdb;
3736
 
3737
  $course_id = $this->get_post_id( $course_id );
3738
+ $user_id = $this->get_user_id( $user_id );
3739
 
3740
  $ratings = array(
3741
  'rating' => 0,
3742
  'review' => '',
3743
  );
3744
 
3745
+ $rating = $wpdb->get_row(
3746
+ $wpdb->prepare(
3747
+ "SELECT meta_value AS rating,
3748
  comment_content AS review
3749
  FROM {$wpdb->comments}
3750
+ INNER JOIN {$wpdb->commentmeta}
3751
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3752
  WHERE {$wpdb->comments}.comment_post_ID = %d
3753
  AND user_id = %d
3754
  AND meta_key = %s;
3755
  ",
3756
+ $course_id,
3757
+ $user_id,
3758
+ 'tutor_rating'
3759
+ )
3760
+ );
3761
 
3762
  if ( $rating ) {
3763
  $rating_format = number_format( $rating->rating, 2 );
3781
  public function count_reviews_wrote_by_user( $user_id = 0 ) {
3782
  global $wpdb;
3783
 
3784
+ $user_id = $this->get_user_id( $user_id );
3785
 
3786
+ $count_reviews = $wpdb->get_var(
3787
+ $wpdb->prepare(
3788
+ "SELECT COUNT(comment_ID)
3789
  FROM {$wpdb->comments}
3790
  WHERE user_id = %d
3791
  AND comment_type = %s
3792
  ",
3793
+ $user_id,
3794
+ 'tutor_course_rating'
3795
+ )
3796
+ );
3797
 
3798
  return $count_reviews;
3799
  }
3815
  switch ( strtoupper( $l ) ) {
3816
  case 'P':
3817
  $ret *= 1024;
3818
+ // No break.
3819
  case 'T':
3820
  $ret *= 1024;
3821
+ // No break.
3822
  case 'G':
3823
  $ret *= 1024;
3824
+ // No break.
3825
  case 'M':
3826
  $ret *= 1024;
3827
+ // No break.
3828
  case 'K':
3829
  $ret *= 1024;
3830
+ // No break.
3831
  }
3832
  return $ret;
3833
  }
3880
  public function get_top_question( $course_id = 0, $user_id = 0, $offset = 0, $limit = 20, $is_author = false ) {
3881
  global $wpdb;
3882
 
3883
+ $course_id = $this->get_post_id( $course_id );
3884
+ $user_id = $this->get_user_id( $user_id );
3885
 
3886
+ $author_sql = $is_author ? '' : "AND {$wpdb->comments}.user_id = {$user_id}";
3887
+
3888
+ $questions = $wpdb->get_results(
3889
+ $wpdb->prepare(
3890
+ "SELECT {$wpdb->comments}.comment_ID,
3891
+ {$wpdb->comments}.comment_post_ID,
3892
+ {$wpdb->comments}.comment_author,
3893
+ {$wpdb->comments}.comment_date,
3894
+ {$wpdb->comments}.comment_date_gmt,
3895
+ {$wpdb->comments}.comment_content,
3896
+ {$wpdb->comments}.user_id,
3897
+ {$wpdb->commentmeta}.meta_value as question_title,
3898
+ {$wpdb->users}.display_name
3899
+ FROM {$wpdb->comments}
3900
  INNER JOIN {$wpdb->commentmeta}
3901
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3902
  INNER JOIN {$wpdb->users}
3903
+ ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3904
+ WHERE {$wpdb->comments}.comment_post_ID = {$course_id} {$author_sql}
3905
+ AND {$wpdb->comments}.comment_type = %s
3906
+ AND meta_key = %s
3907
+ ORDER BY comment_ID DESC
3908
  LIMIT %d, %d;
3909
  ",
3910
+ 'tutor_q_and_a',
3911
+ 'tutor_question_title',
3912
+ $offset,
3913
+ $limit
3914
+ )
3915
+ );
3916
 
3917
  return $questions;
3918
  }
3929
  public function get_total_qa_question( $search_term = '' ) {
3930
  global $wpdb;
3931
 
3932
+ $user_id = get_current_user_id();
3933
  $course_type = tutor()->course_post_type;
3934
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
3935
 
3939
  */
3940
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
3941
 
3942
+ $get_course_ids = $wpdb->get_col(
3943
+ $wpdb->prepare(
3944
+ "SELECT ID
3945
  FROM {$wpdb->posts}
3946
  WHERE post_author = %d
3947
  AND post_type = %s
3948
  AND post_status = %s
3949
  ",
3950
+ $user_id,
3951
+ $course_type,
3952
+ 'publish'
3953
+ )
3954
+ );
3955
 
3956
+ $get_assigned_courses_ids = $wpdb->get_col(
3957
+ $wpdb->prepare(
3958
+ "SELECT meta_value
3959
  FROM {$wpdb->usermeta}
3960
  WHERE meta_key = %s
3961
  AND user_id = %d
3962
  ",
3963
+ '_tutor_instructor_course_id',
3964
+ $user_id
3965
+ )
3966
+ );
3967
 
3968
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
3969
 
3970
  if ( $this->count( $my_course_ids ) ) {
3971
+ $implode_ids = implode( ',', $my_course_ids );
3972
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
3973
  }
3974
  }
3978
  * could be retained thus total number counted and q & a showing
3979
  * list is not similar
3980
  * now only the q & a will be appeared that is belongs to a user
3981
+ *
3982
  * @since version 1.9.0
3983
  */
3984
+ $count = $wpdb->get_var(
3985
+ $wpdb->prepare(
3986
+ "SELECT COUNT({$wpdb->comments}.comment_ID)
3987
  FROM {$wpdb->comments}
3988
  INNER JOIN {$wpdb->commentmeta}
3989
  ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3990
 
3991
+ INNER JOIN {$wpdb->users}
3992
  ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3993
 
3994
+ WHERE comment_type = %s
3995
  AND comment_parent = 0 {$in_question_id_query}
3996
  AND {$wpdb->commentmeta}.meta_value LIKE %s;
3997
  ",
3998
+ 'tutor_q_and_a',
3999
+ $search_term
4000
+ )
4001
+ );
4002
 
4003
  return (int) $count;
4004
  }
4005
 
4006
  /**
4007
+ * @param int $start
4008
+ * @param int $limit
4009
  * @param string $search_term
4010
  *
4011
  * @return array|null|object
4027
  * Get only assinged courses questions if current user is a
4028
  */
4029
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
4030
+
4031
+ $get_course_ids = $wpdb->get_col(
4032
+ $wpdb->prepare(
4033
+ "SELECT ID
4034
  FROM {$wpdb->posts}
4035
  WHERE post_author = %d
4036
  AND post_type = %s
4037
  AND post_status = %s
4038
  ",
4039
+ $user_id,
4040
+ $course_type,
4041
+ 'publish'
4042
+ )
4043
+ );
4044
 
4045
+ $get_assigned_courses_ids = $wpdb->get_col(
4046
+ $wpdb->prepare(
4047
+ "SELECT meta_value
4048
  FROM {$wpdb->usermeta}
4049
  WHERE meta_key = %s
4050
  AND user_id = %d
4051
  ",
4052
+ '_tutor_instructor_course_id',
4053
+ $user_id
4054
+ )
4055
+ );
4056
 
4057
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4058
 
4059
  if ( $this->count( $my_course_ids ) ) {
4060
+ $implode_ids = implode( ',', $my_course_ids );
4061
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4062
  }
4063
  }
4064
 
4065
+ $query = $wpdb->get_results(
4066
+ $wpdb->prepare(
4067
+ "SELECT {$wpdb->comments}.comment_ID,
4068
+ {$wpdb->comments}.comment_post_ID,
4069
+ {$wpdb->comments}.comment_author,
4070
+ {$wpdb->comments}.comment_date,
4071
+ {$wpdb->comments}.comment_content,
4072
+ {$wpdb->comments}.user_id,
4073
+ {$wpdb->commentmeta}.meta_value as question_title,
4074
+ {$wpdb->users}.display_name,
4075
+ {$wpdb->posts}.post_title,
4076
+ ( SELECT COUNT(answers_t.comment_ID)
4077
+ FROM {$wpdb->comments} answers_t
4078
  WHERE answers_t.comment_parent = {$wpdb->comments}.comment_ID
4079
  ) AS answer_count
4080
  FROM {$wpdb->comments}
4088
  AND {$wpdb->comments}.comment_parent = 0
4089
  AND {$wpdb->commentmeta}.meta_value LIKE %s
4090
  {$in_question_id_query}
4091
+ ORDER BY {$wpdb->comments}.comment_ID DESC
4092
  LIMIT %d, %d;
4093
  ",
4094
+ 'tutor_q_and_a',
4095
+ $search_term,
4096
+ $start,
4097
+ $limit
4098
+ )
4099
+ );
4100
 
4101
  return $query;
4102
  }
4112
  */
4113
  public function get_qa_question( $question_id ) {
4114
  global $wpdb;
4115
+ $query = $wpdb->get_row(
4116
+ $wpdb->prepare(
4117
+ "SELECT {$wpdb->comments}.comment_ID,
4118
+ {$wpdb->comments}.comment_post_ID,
4119
+ {$wpdb->comments}.comment_author,
4120
+ {$wpdb->comments}.comment_date,
4121
+ {$wpdb->comments}.comment_date_gmt,
4122
+ {$wpdb->comments}.comment_content,
4123
+ {$wpdb->comments}.user_id,
4124
+ {$wpdb->commentmeta}.meta_value as question_title,
4125
+ {$wpdb->users}.display_name,
4126
+ {$wpdb->posts}.post_title
4127
+ FROM {$wpdb->comments}
4128
+ INNER JOIN {$wpdb->commentmeta}
4129
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4130
+ INNER JOIN {$wpdb->posts}
4131
+ ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
4132
  INNER JOIN {$wpdb->users}
4133
+ ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
4134
+ WHERE comment_type = %s
4135
  AND {$wpdb->comments}.comment_ID = %d;
4136
  ",
4137
+ 'tutor_q_and_a',
4138
+ $question_id
4139
+ )
4140
+ );
4141
 
4142
  return $query;
4143
  }
4151
  */
4152
  public function get_qa_answer_by_question( $question_id ) {
4153
  global $wpdb;
4154
+ $query = $wpdb->get_results(
4155
+ $wpdb->prepare(
4156
+ "SELECT {$wpdb->comments}.comment_ID,
4157
  {$wpdb->comments}.comment_post_ID,
4158
  {$wpdb->comments}.comment_author,
4159
  {$wpdb->comments}.comment_date,
4169
  AND {$wpdb->comments}.comment_parent = %d
4170
  ORDER BY {$wpdb->comments}.comment_ID ASC;
4171
  ",
4172
+ 'tutor_q_and_a',
4173
+ $question_id
4174
+ )
4175
+ );
4176
 
4177
  return $query;
4178
  }
4181
  * @param $answer_id
4182
  *
4183
  * @return array|null|object
4184
+ *
4185
  * @since v1.6.9
4186
  *
4187
  * Get question and asnwer by answer_id
4188
  */
4189
  public function get_qa_answer_by_answer_id( $answer_id ) {
4190
  global $wpdb;
4191
+ $answer = $wpdb->get_row(
4192
+ $wpdb->prepare(
4193
+ "SELECT answer.comment_post_ID,
4194
+ answer.comment_content,
4195
  users.display_name,
4196
  question.user_id AS question_by,
4197
  question.comment_content AS question,
4198
  question_meta.meta_value AS question_title
4199
  FROM {$wpdb->comments} answer
4200
  INNER JOIN {$wpdb->users} users
4201
+ ON answer.user_id = users.id
4202
+ INNER JOIN {$wpdb->comments} question
4203
+ ON answer.comment_parent = question.comment_ID
4204
+ INNER JOIN {$wpdb->commentmeta} question_meta
4205
  ON answer.comment_parent = question_meta.comment_id
4206
  AND question_meta.meta_key = 'tutor_question_title'
4207
+ WHERE answer.comment_ID = %d
4208
  AND answer.comment_type = %s;
4209
+ ",
4210
+ $answer_id,
4211
+ 'tutor_q_and_a'
4212
+ )
4213
+ );
4214
 
4215
  if ( $answer ) {
4216
  return $answer;
4226
  * instructor as it was count unanswered question from all courses
4227
  * from now on it will check if tutor instructor and count
4228
  * from instructor's course
4229
+ *
4230
  * @since version 1.9.0
4231
  */
4232
+ $user_id = get_current_user_id();
4233
  $course_type = tutor()->course_post_type;
4234
 
4235
  $in_question_id_query = '';
4238
  */
4239
  if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
4240
 
4241
+ $get_course_ids = $wpdb->get_col(
4242
+ $wpdb->prepare(
4243
+ "SELECT ID
4244
  FROM {$wpdb->posts}
4245
  WHERE post_author = %d
4246
  AND post_type = %s
4247
  AND post_status = %s
4248
  ",
4249
+ $user_id,
4250
+ $course_type,
4251
+ 'publish'
4252
+ )
4253
+ );
4254
 
4255
+ $get_assigned_courses_ids = $wpdb->get_col(
4256
+ $wpdb->prepare(
4257
+ "SELECT meta_value
4258
  FROM {$wpdb->usermeta}
4259
  WHERE meta_key = %s
4260
  AND user_id = %d
4261
  ",
4262
+ '_tutor_instructor_course_id',
4263
+ $user_id
4264
+ )
4265
+ );
4266
 
4267
  $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4268
 
4269
  if ( $this->count( $my_course_ids ) ) {
4270
+ $implode_ids = implode( ',', $my_course_ids );
4271
  $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4272
  }
4273
  }
4274
 
4275
+ $count = $wpdb->get_var(
4276
+ $wpdb->prepare(
4277
+ "SELECT COUNT({$wpdb->comments}.comment_ID)
4278
  FROM {$wpdb->comments}
4279
  INNER JOIN {$wpdb->posts}
4280
  ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
4284
  AND {$wpdb->comments}.comment_approved = %s
4285
  AND {$wpdb->comments}.comment_parent = 0 {$in_question_id_query};
4286
  ",
4287
+ 'tutor_q_and_a',
4288
+ 'waiting_for_answer'
4289
+ )
4290
+ );
4291
  return (int) $count;
4292
  }
4293
 
4303
  public function get_announcements( $course_id = 0 ) {
4304
  $course_id = $this->get_post_id( $course_id );
4305
  global $wpdb;
4306
+ $query = $wpdb->get_results(
4307
+ $wpdb->prepare(
4308
+ "SELECT {$wpdb->posts}.ID,
4309
+ post_author,
4310
+ post_date,
4311
+ post_content,
4312
+ post_title,
4313
+ display_name
4314
+ FROM {$wpdb->posts}
4315
+ INNER JOIN {$wpdb->users}
4316
+ ON post_author = {$wpdb->users}.ID
4317
+ WHERE post_type = %s
4318
  AND post_parent = %d
4319
  ORDER BY {$wpdb->posts}.ID DESC;
4320
  ",
4321
+ 'tutor_announcements',
4322
+ $course_id
4323
+ )
4324
+ );
4325
  return $query;
4326
  }
4327
 
4339
 
4340
  $user_display_name = 'User';
4341
  if ( is_user_logged_in() ) {
4342
+ $user = wp_get_current_user();
4343
  $user_display_name = $user->display_name;
4344
  }
4345
 
4349
  }
4350
 
4351
  /**
4352
+ * @param int $post_id
4353
  * @param string $option_key
4354
+ * @param bool $default
4355
  *
4356
  * @return array|bool|mixed
4357
  *
4358
  * Get the quiz option from meta
4359
  */
4360
  public function get_quiz_option( $post_id = 0, $option_key = '', $default = false ) {
4361
+ $post_id = $this->get_post_id( $post_id );
4362
+ $get_option_meta = maybe_unserialize( get_post_meta( $post_id, 'tutor_quiz_option', true ) );
4363
 
4364
  if ( ! $option_key && ! empty( $get_option_meta ) ) {
4365
  return $get_option_meta;
4384
  $quiz_id = $this->get_post_id( $quiz_id );
4385
  global $wpdb;
4386
 
4387
+ $questions = $wpdb->get_results(
4388
+ $wpdb->prepare(
4389
+ "SELECT *
4390
  FROM {$wpdb->prefix}tutor_quiz_questions
4391
  WHERE quiz_id = %d
4392
  ORDER BY question_order ASC
4393
  ",
4394
+ $quiz_id
4395
+ )
4396
+ );
4397
 
4398
  if ( is_array( $questions ) && count( $questions ) ) {
4399
  return $questions;
4413
  global $wpdb;
4414
 
4415
  if ( $question_id ) {
4416
+ $question = $wpdb->get_row(
4417
+ $wpdb->prepare(
4418
+ "SELECT *
4419
  FROM {$wpdb->prefix}tutor_quiz_questions
4420
  WHERE question_id = %d
4421
  LIMIT 0, 1;
4422
  ",
4423
+ $question_id
4424
+ )
4425
+ );
4426
 
4427
  return $question;
4428
  }
4441
  */
4442
  public function get_question_types( $type = null ) {
4443
  $types = array(
4444
+ 'true_false' => array(
4445
+ 'name' => __( 'True/False', 'tutor' ),
4446
+ 'icon' => '<span class="tooltip-btn" data-tooltip="True/False"><i class="tutor-icon-block tutor-icon-yes-no"></i></span>',
4447
+ 'is_pro' => false,
4448
+ ),
4449
+ 'single_choice' => array(
4450
+ 'name' => __( 'Single Choice', 'tutor' ),
4451
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Single Choice"><i class="tutor-icon-block tutor-icon-mark"></i></span>',
4452
+ 'is_pro' => false,
4453
+ ),
4454
+ 'multiple_choice' => array(
4455
+ 'name' => __( 'Multiple Choice', 'tutor' ),
4456
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Multiple Choicee"><i class="tutor-icon-block tutor-icon-multiple-choice"></i></span>',
4457
+ 'is_pro' => false,
4458
+ ),
4459
+ 'open_ended' => array(
4460
+ 'name' => __( 'Open Ended/Essay', 'tutor' ),
4461
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Open/Essay"><i class="tutor-icon-block tutor-icon-open-ended"></i></span>',
4462
+ 'is_pro' => false,
4463
+ ),
4464
+ 'fill_in_the_blank' => array(
4465
+ 'name' => __( 'Fill In The Blanks', 'tutor' ),
4466
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Fill In The Blanks"><i class="tutor-icon-block tutor-icon-fill-gaps"></i></span>',
4467
+ 'is_pro' => false,
4468
+ ),
4469
+ 'short_answer' => array(
4470
+ 'name' => __( 'Short Answer', 'tutor' ),
4471
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Short Answer"><i class="tutor-icon-block tutor-icon-short-ans"></i></span>',
4472
+ 'is_pro' => true,
4473
+ ),
4474
+ 'matching' => array(
4475
+ 'name' => __( 'Matching', 'tutor' ),
4476
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Matching"><i class="tutor-icon-block tutor-icon-matching"></i></span>',
4477
+ 'is_pro' => true,
4478
+ ),
4479
+ 'image_matching' => array(
4480
+ 'name' => __( 'Image Matching', 'tutor' ),
4481
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Image Matching"><i class="tutor-icon-block tutor-icon-image-matching"></i></span>',
4482
+ 'is_pro' => true,
4483
+ ),
4484
+ 'image_answering' => array(
4485
+ 'name' => __( 'Image Answering', 'tutor' ),
4486
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Image Answering"><i class="tutor-icon-block tutor-icon-image-ans"></i></span>',
4487
+ 'is_pro' => true,
4488
+ ),
4489
+ 'ordering' => array(
4490
+ 'name' => __( 'Ordering', 'tutor' ),
4491
+ 'icon' => '<span class="tooltip-btn" data-tooltip="Ordering"><i class="tutor-icon-block tutor-icon-ordering"></i></span>',
4492
+ 'is_pro' => true,
4493
+ ),
4494
  );
4495
 
4496
  if ( isset( $types[ $type ] ) ) {
4497
  return $types[ $type ];
4498
  }
4499
+
4500
  return $types;
4501
  }
4502
 
4503
  public function get_quiz_answer_options_by_question( $question_id ) {
4504
  global $wpdb;
4505
 
4506
+ $answer_options = $wpdb->get_results(
4507
+ $wpdb->prepare(
4508
+ "SELECT {$wpdb->comments}.comment_ID,
4509
+ {$wpdb->comments}.comment_post_ID,
4510
  {$wpdb->comments}.comment_content
4511
  FROM {$wpdb->comments}
4512
+ WHERE {$wpdb->comments}.comment_post_ID = %d
4513
  AND {$wpdb->comments}.comment_type = %s
4514
  ORDER BY {$wpdb->comments}.comment_karma ASC;
4515
  ",
4516
+ $question_id,
4517
+ 'quiz_answer_option'
4518
+ )
4519
+ );
4520
 
4521
  if ( is_array( $answer_options ) && count( $answer_options ) ) {
4522
  return $answer_options;
4536
  public function quiz_next_question_order_id( $quiz_id ) {
4537
  global $wpdb;
4538
 
4539
+ $last_order = (int) $wpdb->get_var(
4540
+ $wpdb->prepare(
4541
+ "SELECT MAX(question_order)
4542
+ FROM {$wpdb->prefix}tutor_quiz_questions
4543
  WHERE quiz_id = %d ;
4544
  ",
4545
+ $quiz_id
4546
+ )
4547
+ );
4548
 
4549
  return $last_order + 1;
4550
  }
4566
 
4567
  public function get_quiz_id_by_question( $question_id ) {
4568
  global $wpdb;
4569
+ $quiz_id = $wpdb->get_var(
4570
+ $wpdb->prepare(
4571
+ "SELECT quiz_id
4572
+ FROM {$wpdb->tutor_quiz_questions}
4573
  WHERE question_id = %d;
4574
  ",
4575
+ $question_id
4576
+ )
4577
+ );
4578
  return $quiz_id;
4579
  }
4580
 
4590
 
4591
  $post_id = $this->get_post_id( $post_id );
4592
 
4593
+ $questions = $wpdb->get_results(
4594
+ $wpdb->prepare(
4595
+ "SELECT ID,
4596
  post_content,
4597
  post_title,
4598
  post_parent
4601
  AND post_status = %s
4602
  AND post_parent = %d;
4603
  ",
4604
+ 'tutor_quiz',
4605
+ 'publish',
4606
+ $post_id
4607
+ )
4608
+ );
4609
 
4610
  if ( is_array( $questions ) && count( $questions ) ) {
4611
  return $questions;
4627
  global $wpdb;
4628
 
4629
  $quiz_id = $this->get_post_id( $quiz_id );
4630
+ $post = get_post( $quiz_id );
4631
 
4632
  if ( $post ) {
4633
  $course_post_type = tutor()->course_post_type;
4634
+ $query_string = "SELECT ID, post_author, post_name, post_type, post_parent FROM {$wpdb->posts} where ID = %d";
4635
+ $course = $wpdb->get_row( $wpdb->prepare( $query_string, $post->post_parent ) );
4636
+
4637
  if ( $course ) {
4638
  if ( $course->post_type !== $course_post_type ) {
4639
  $course = $wpdb->get_row( $wpdb->prepare( $query_string, $course->post_parent ) );
4657
  global $wpdb;
4658
 
4659
  $max_questions_count = (int) tutor_utils()->get_quiz_option( get_the_ID(), 'max_questions_for_answer' );
4660
+ $total_question = (int) $wpdb->get_var(
4661
+ $wpdb->prepare(
4662
+ "SELECT count(question_id)
4663
  FROM {$wpdb->tutor_quiz_questions}
4664
  WHERE quiz_id = %d;
4665
  ",
4666
+ $quiz_id
4667
+ )
4668
+ );
4669
 
4670
+ return min( $max_questions_count, $total_question );
4671
  }
4672
 
4673
  /**
4685
  $quiz_id = $this->get_post_id( $quiz_id );
4686
  $user_id = get_current_user_id();
4687
 
4688
+ $is_started = $wpdb->get_row(
4689
+ $wpdb->prepare(
4690
+ "SELECT *
4691
  FROM {$wpdb->prefix}tutor_quiz_attempts
4692
  WHERE user_id = %d
4693
  AND quiz_id = %d
4694
  AND attempt_status = %s;
4695
  ",
4696
+ $user_id,
4697
+ $quiz_id,
4698
+ 'attempt_started'
4699
+ )
4700
+ );
4701
 
4702
  return $is_started;
4703
  }
4717
  $quiz_id = $this->get_post_id( $quiz_id );
4718
  global $wpdb;
4719
 
4720
+ $max_questions = (int) $wpdb->get_var(
4721
+ $wpdb->prepare(
4722
+ "SELECT count(question_id)
4723
  FROM {$wpdb->prefix}tutor_quiz_questions
4724
  WHERE quiz_id = %d;
4725
  ",
4726
+ $quiz_id
4727
+ )
4728
+ );
4729
 
4730
  $max_mentioned = (int) $this->get_quiz_option( $quiz_id, 'max_questions_for_answer', 10 );
4731
 
4751
  return false;
4752
  }
4753
 
4754
+ $attempt = $wpdb->get_row(
4755
+ $wpdb->prepare(
4756
+ "SELECT *
4757
  FROM {$wpdb->prefix}tutor_quiz_attempts
4758
  WHERE attempt_id = %d;
4759
  ",
4760
+ $attempt_id
4761
+ )
4762
+ );
4763
 
4764
  return $attempt;
4765
  }
4779
 
4780
  /**
4781
  * @param $quiz_attempt_id
4782
+ * @param array $attempt_info
4783
  *
4784
  * @return bool|int
4785
  *
4788
  * @since v.1.0.0
4789
  */
4790
  public function quiz_update_attempt_info( $quiz_attempt_id, $attempt_info = array() ) {
4791
+ $answers = tutor_utils()->avalue_dot( 'answers', $attempt_info );
4792
+ $total_marks = array_sum( wp_list_pluck( $answers, 'question_mark' ) );
4793
+ $earned_marks = tutor_utils()->avalue_dot( 'marks_earned', $attempt_info );
4794
+ $earned_mark_percent = $earned_marks > 0 ? ( number_format( ( $earned_marks * 100 ) / $total_marks ) ) : 0;
4795
  update_comment_meta( $quiz_attempt_id, 'earned_mark_percent', $earned_mark_percent );
4796
 
4797
+ return update_comment_meta( $quiz_attempt_id, 'quiz_attempt_info', $attempt_info );
4798
  }
4799
 
4800
  /**
4809
  public function get_random_question_by_quiz( $quiz_id = 0 ) {
4810
  global $wpdb;
4811
 
4812
+ $quiz_id = $this->get_post_id( $quiz_id );
4813
  $is_attempt = $this->is_started_quiz( $quiz_id );
4814
 
4815
+ $tempSql = " AND question_type = 'matching' ";
4816
+ $questions = $wpdb->get_results(
4817
+ $wpdb->prepare(
4818
+ "SELECT *
4819
  FROM {$wpdb->prefix}tutor_quiz_questions
4820
  WHERE quiz_id = %d
4821
  {$tempSql}
4822
  ORDER BY RAND()
4823
  LIMIT 0, 1
4824
  ",
4825
+ $quiz_id
4826
+ )
4827
+ );
4828
 
4829
  return $questions;
4830
  }
4839
  public function get_random_questions_by_quiz( $quiz_id = 0 ) {
4840
  global $wpdb;
4841
 
4842
+ $quiz_id = $this->get_post_id( $quiz_id );
4843
+ $attempt = $this->is_started_quiz( $quiz_id );
4844
  $total_questions = (int) $attempt->total_questions;
4845
  if ( ! $attempt ) {
4846
  return false;
4848
 
4849
  $questions_order = tutor_utils()->get_quiz_option( get_the_ID(), 'questions_order', 'rand' );
4850
 
4851
+ $order_by = '';
4852
  if ( $questions_order === 'rand' ) {
4853
+ $order_by = 'ORDER BY RAND()';
4854
  } elseif ( $questions_order === 'asc' ) {
4855
+ $order_by = 'ORDER BY question_id ASC';
4856
  } elseif ( $questions_order === 'desc' ) {
4857
+ $order_by = 'ORDER BY question_id DESC';
4858
  } elseif ( $questions_order === 'sorting' ) {
4859
+ $order_by = 'ORDER BY question_order ASC';
4860
  }
4861
 
4862
  $limit = '';
4864
  $limit = "LIMIT {$total_questions} ";
4865
  }
4866
 
4867
+ $questions = $wpdb->get_results(
4868
+ $wpdb->prepare(
4869
+ "SELECT *
4870
  FROM {$wpdb->prefix}tutor_quiz_questions
4871
  WHERE quiz_id = %d
4872
  {$order_by}
4873
  {$limit}
4874
  ",
4875
+ $quiz_id
4876
+ )
4877
+ );
4878
 
4879
  return $questions;
4880
  }
4881
 
4882
  /**
4883
  * @param $question_id
4884
+ * @param bool $rand
4885
  *
4886
  * @return array|bool|null|object
4887
  *
4892
  public function get_answers_by_quiz_question( $question_id, $rand = false ) {
4893
  global $wpdb;
4894
 
4895
+ $question = $wpdb->get_row(
4896
+ $wpdb->prepare(
4897
+ "SELECT *
4898
  FROM {$wpdb->prefix}tutor_quiz_questions
4899
  WHERE question_id = %d;
4900
  ",
4901
+ $question_id
4902
+ )
4903
+ );
4904
 
4905
  if ( ! $question ) {
4906
  return false;
4907
  }
4908
 
4909
+ $order = ' answer_order ASC ';
4910
  if ( $question->question_type === 'ordering' ) {
4911
+ $order = ' RAND() ';
4912
  }
4913
 
4914
+ if ( $rand ) {
4915
+ $order = ' RAND() ';
4916
  }
4917
 
4918
+ $answers = $wpdb->get_results(
4919
+ $wpdb->prepare(
4920
+ "SELECT *
4921
+ FROM {$wpdb->prefix}tutor_quiz_question_answers
4922
  WHERE belongs_question_id = %d
4923
  AND belongs_question_type = %s
4924
  ORDER BY {$order}
4925
  ",
4926
+ $question_id,
4927
+ $question->question_type
4928
+ )
4929
+ );
4930
+
4931
  return $answers;
4932
  }
4933
 
4948
  $quiz_id = $this->get_post_id( $quiz_id );
4949
  $user_id = $this->get_user_id( $user_id );
4950
 
4951
+ $attempts = $wpdb->get_results(
4952
+ $wpdb->prepare(
4953
+ "SELECT *
4954
  FROM {$wpdb->prefix}tutor_quiz_attempts
4955
  WHERE quiz_id = %d
4956
  AND user_id = %d
4957
+ ORDER BY attempt_id DESC
4958
  ",
4959
+ $quiz_id,
4960
+ $user_id
4961
+ )
4962
+ );
4963
 
4964
  if ( is_array( $attempts ) && count( $attempts ) ) {
4965
  return $attempts;
4984
  $quiz_id = $this->get_post_id( $quiz_id );
4985
  $user_id = $this->get_user_id( $user_id );
4986
 
4987
+ $attempts = $wpdb->get_results(
4988
+ $wpdb->prepare(
4989
+ "SELECT *
4990
  FROM {$wpdb->prefix}tutor_quiz_attempts
4991
  WHERE quiz_id = %d
4992
  AND user_id = %d
4993
  AND attempt_status != %s
4994
  ",
4995
+ $quiz_id,
4996
+ $user_id,
4997
+ 'attempt_started'
4998
+ )
4999
+ );
5000
 
5001
  if ( is_array( $attempts ) && count( $attempts ) ) {
5002
  return $attempts;
5019
  global $wpdb;
5020
 
5021
  $user_id = $this->get_user_id( $user_id );
5022
+ $attempts = $wpdb->get_results(
5023
+ $wpdb->prepare(
5024
+ "SELECT *
5025
  FROM {$wpdb->prefix}tutor_quiz_attempts
5026
  WHERE user_id = %d
5027
  ORDER BY attempt_id DESC
5028
  ",
5029
+ $user_id
5030
+ )
5031
+ );
5032
 
5033
  if ( is_array( $attempts ) && count( $attempts ) ) {
5034
  return $attempts;
5045
  * Total number of quiz attempts
5046
  *
5047
  * @since v.1.0.0
5048
+ *
5049
  * This method is not being in used
 
 
 
 
5050
  *
5051
+ * to get total number of attempt get_quiz_attempts method is enough
5052
+ *
5053
+ * @since 1.9.5
5054
  */
5055
  public function get_total_quiz_attempts( $search_term = '' ) {
5056
  global $wpdb;
5057
 
5058
+ $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5059
 
5060
+ $count = $wpdb->get_var(
5061
+ $wpdb->prepare(
5062
+ "SELECT COUNT(attempt_id)
5063
  FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
5064
  INNER JOIN {$wpdb->posts} quiz
5065
  ON quiz_attempts.quiz_id = quiz.ID
5068
  WHERE attempt_status != %s
5069
  AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
5070
  ",
5071
+ 'attempt_started',
5072
+ $search_term,
5073
+ $search_term,
5074
+ $search_term
5075
+ )
5076
+ );
5077
 
5078
  return (int) $count;
5079
  }
5080
 
5081
  /**
5082
+ * @param int $start
5083
+ * @param int $limit
5084
  * @param string $search_term
5085
  *
5086
  * @return array|null|object
5089
  * Get the all quiz attempts
5090
  *
5091
  * @since 1.0.0
5092
+ *
5093
+ * Sorting paramas added
5094
+ *
5095
  * @since 1.9.5
5096
  */
5097
+ public function get_quiz_attempts( $start = 0, $limit = 10, $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '' ) {
5098
  global $wpdb;
5099
 
5100
+ $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
5101
+ $course_filter = $course_filter != '' ? " AND quiz_attempts.course_id = $course_filter " : '';
5102
+ $date_filter = $date_filter != '' ? tutor_get_formated_date( 'Y-m-d', $date_filter ) : '';
5103
+ $date_filter = $date_filter != '' ? " AND DATE(quiz_attempts.attempt_started_at) = '$date_filter' " : '';
5104
 
5105
+ $query = $wpdb->get_results(
5106
+ $wpdb->prepare(
5107
+ "SELECT quiz_attempts.*, quiz.*, users.*
5108
  FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
5109
  INNER JOIN {$wpdb->posts} quiz
5110
  ON quiz_attempts.quiz_id = quiz.ID
5116
  AND ( users.user_email LIKE %s OR users.display_name LIKE %s OR quiz.post_title LIKE %s OR course.post_title LIKE %s )
5117
  {$course_filter}
5118
  {$date_filter}
5119
+ ORDER BY quiz_attempts.attempt_ended_at $order_filter
5120
  LIMIT %d, %d;
5121
  ",
5122
+ 'attempt_started',
5123
+ $search_filter,
5124
+ $search_filter,
5125
+ $search_filter,
5126
+ $search_filter,
5127
+ $start,
5128
+ $limit
5129
+ )
5130
+ );
5131
 
5132
  return $query;
5133
  }
5134
 
5135
  /**
5136
  * Delete quizattempt for user
5137
+ *
5138
  * @since v1.9.5
5139
  */
5140
+ public function delete_quiz_attempt( $attempt_ids ) {
5141
  global $wpdb;
5142
 
5143
  // Singlular to array
5144
+ ! is_array( $attempt_ids ) ? $attempt_ids = array( $attempt_ids ) : 0;
5145
 
5146
+ if ( count( $attempt_ids ) ) {
5147
+ $attempt_ids = implode( ',', $attempt_ids );
5148
 
5149
+ // Deleting attempt (comment), child attempt and attempt meta (comment meta)
5150
  $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_attempts WHERE attempt_id IN($attempt_ids)" );
5151
  $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE quiz_attempt_id IN($attempt_ids)" );
5152
  }
5153
  }
5154
 
5155
  /**
5156
+ * Sorting params added on quiz attempt
5157
+ *
5158
  * SQL query updated
5159
+ *
5160
  * @since 1.9.5
5161
  */
5162
  public function get_quiz_attempts_by_course_ids( $start = 0, $limit = 10, $course_ids = array(), $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $user_id = null ) {
5163
  global $wpdb;
5164
 
5165
+ $course_ids = array_map(
5166
+ function( $id ) {
5167
+ return "'" . esc_sql( $id ) . "'";
5168
+ },
5169
+ $course_ids
5170
+ );
5171
 
5172
  $course_ids_in = implode( ', ', $course_ids );
5173
 
5174
+ $search_filter = $search_filter ? '%' . $wpdb->esc_like( $search_filter ) . '%' : '';
5175
  $search_filter = $search_filter ? "AND ( users.user_email LIKE {$search_filter} OR users.display_name LIKE {$search_filter} OR quiz.post_title LIKE {$search_filter} OR course.post_title LIKE {$search_filter} )" : '';
5176
 
5177
+ $course_filter = $course_filter != '' ? " AND quiz_attempts.course_id = $course_filter " : '';
5178
+ $date_filter = $date_filter != '' ? tutor_get_formated_date( 'Y-m-d', $date_filter ) : '';
5179
+ $date_filter = $date_filter != '' ? " AND DATE(quiz_attempts.attempt_started_at) = '$date_filter' " : '';
5180
 
5181
+ $query = $wpdb->get_results(
5182
+ $wpdb->prepare(
5183
+ "SELECT quiz_attempts.*, users.*, quiz.*
5184
+ FROM {$wpdb->prefix}tutor_quiz_attempts AS quiz_attempts
5185
  INNER JOIN {$wpdb->posts} AS quiz
5186
+ ON quiz_attempts.quiz_id = quiz.ID
5187
  INNER JOIN {$wpdb->users} AS users
5188
+ ON quiz_attempts.user_id = users.ID
5189
  INNER JOIN {$wpdb->posts} AS course
5190
+ ON course.ID = quiz_attempts.course_id
5191
  WHERE quiz_attempts.course_id IN (" . $course_ids_in . ")
5192
  AND quiz_attempts.attempt_status != %s
5193
  {$search_filter}
5194
  {$course_filter}
5195
  {$date_filter}
5196
+ " . ( $user_id ? ' AND user_id=\'' . esc_sql( $user_id ) . '\'' : '' ) . "
5197
  ORDER BY quiz_attempts.attempt_id $order_filter
5198
  LIMIT %d, %d;
5199
  ",
5200
+ 'attempt_started',
5201
+ $start,
5202
+ $limit
5203
+ )
5204
+ );
5205
 
5206
  return $query;
5207
  }
5208
 
5209
  /**
5210
  * This method is not being in used
5211
+ *
5212
+ * to get total number of attempt above method is enough
5213
+ *
5214
  * @since 1.9.5
5215
  */
5216
  public function get_total_quiz_attempts_by_course_ids( $course_ids = array(), $search_term = '' ) {
5217
  global $wpdb;
5218
+
5219
+ $course_ids = array_map(
5220
+ function( $id ) {
5221
+ return "'" . esc_sql( $id ) . "'";
5222
+ },
5223
+ $course_ids
5224
+ );
5225
 
5226
  $course_ids_in = implode( ', ', $course_ids );
5227
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5228
 
5229
+ $count = $wpdb->get_var(
5230
+ $wpdb->prepare(
5231
+ "SELECT COUNT(attempt_id)
5232
+ FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
5233
  INNER JOIN {$wpdb->posts} quiz
5234
+ ON quiz_attempts.quiz_id = quiz.ID
5235
  INNER JOIN {$wpdb->users}
5236
+ ON quiz_attempts.user_id = {$wpdb->users}.ID
5237
+ WHERE quiz_attempts.course_id IN (" . $course_ids_in . ')
5238
+ AND attempt_status != %s
5239
  AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
5240
+ ',
5241
+ 'attempt_started',
5242
+ $search_term,
5243
+ $search_term,
5244
+ $search_term
5245
+ )
5246
+ );
5247
+
5248
  return (int) $count;
5249
  }
5250
 
5260
  public function get_quiz_answers_by_attempt_id( $attempt_id ) {
5261
  global $wpdb;
5262
 
5263
+ $results = $wpdb->get_results(
5264
+ $wpdb->prepare(
5265
+ "SELECT answers.*,
5266
+ question.question_title,
5267
+ question.question_type
5268
+ FROM {$wpdb->prefix}tutor_quiz_attempt_answers answers
5269
  LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
5270
+ ON answers.question_id = question.question_id
5271
+ WHERE answers.quiz_attempt_id = %d
5272
  ORDER BY attempt_answer_id ASC;
5273
  ",
5274
+ $attempt_id
5275
+ )
5276
+ );
5277
 
5278
  return $results;
5279
  }
5291
  global $wpdb;
5292
 
5293
  ! is_array( $answer_id ) ? $answer_id = array( $answer_id ) : 0;
5294
+
5295
+ $answer_id = array_map(
5296
+ function( $id ) {
5297
+ return "'" . esc_sql( $id ) . "'";
5298
+ },
5299
+ $answer_id
5300
+ );
5301
 
5302
  $in_ids_string = implode( ', ', $answer_id );
5303
+
5304
+ $answer = $wpdb->get_results(
5305
+ $wpdb->prepare(
5306
+ "SELECT answer.*,
5307
  question.question_title,
5308
  question.question_type
5309
  FROM {$wpdb->prefix}tutor_quiz_question_answers answer
5310
  LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
5311
  ON answer.belongs_question_id = question.question_id
5312
+ WHERE answer.answer_id IN (" . $in_ids_string . ')
5313
  AND 1 = %d;
5314
+ ',
5315
+ 1
5316
+ )
5317
+ );
5318
 
5319
  return $answer;
5320
  }
5335
  return false;
5336
  }
5337
 
5338
+ $in_ids = implode( ',', $ids );
5339
 
5340
  global $wpdb;
5341
 
5342
+ $query = $wpdb->get_results(
5343
+ $wpdb->prepare(
5344
+ "SELECT comment_ID,
5345
  comment_content
5346
  FROM {$wpdb->comments}
5347
  WHERE comment_type = %s
5348
  AND comment_ID IN({$in_ids})
5349
  ",
5350
+ 'quiz_answer_option'
5351
+ )
5352
+ );
5353
 
5354
  if ( is_array( $query ) && count( $query ) ) {
5355
  return $query;
5368
  * @since v.1.0.0
5369
  */
5370
  public function course_levels( $level = null ) {
5371
+ $levels = apply_filters(
5372
+ 'tutor_course_level',
5373
+ array(
5374
+ 'all_levels' => __( 'All Levels', 'tutor' ),
5375
+ 'beginner' => __( 'Beginner', 'tutor' ),
5376
+ 'intermediate' => __( 'Intermediate', 'tutor' ),
5377
+ 'expert' => __( 'Expert', 'tutor' ),
5378
+ )
5379
+ );
5380
 
5381
  if ( $level ) {
5382
  if ( isset( $levels[ $level ] ) ) {
5398
  */
5399
  public function user_profile_permalinks() {
5400
  $permalinks = array(
5401
+ 'courses_taken' => __( 'Courses Taken', 'tutor' ),
5402
  );
5403
 
5404
  $show_enrolled_course = tutor_utils()->get_option( 'show_courses_completed_by_student' );
5454
  *
5455
  * Get frontend dashboard URL
5456
  */
5457
+ public function tutor_dashboard_url( $sub_url = '' ) {
5458
  $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
5459
  $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
5460
  return trailingslashit( get_the_permalink( $page_id ) ) . $sub_url;
5464
  * Get the tutor dashboard page ID
5465
  *
5466
  * @return int
 
5467
  */
5468
  public function dashboard_page_id() {
5469
  $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
5483
  */
5484
  public function is_wishlisted( $course_id = 0, $user_id = 0 ) {
5485
  $course_id = $this->get_post_id( $course_id );
5486
+ $user_id = $this->get_user_id( $user_id );
5487
  if ( ! $user_id ) {
5488
  return false;
5489
  }
5490
 
5491
  global $wpdb;
5492
+ $if_added_to_list = (bool) $wpdb->get_row(
5493
+ $wpdb->prepare(
5494
+ "SELECT *
5495
+ FROM {$wpdb->usermeta}
5496
  WHERE user_id = %d
5497
  AND meta_key = '_tutor_course_wishlist'
5498
  AND meta_value = %d;
5499
  ",
5500
+ $user_id,
5501
+ $course_id
5502
+ )
5503
+ );
5504
 
5505
  return $if_added_to_list;
5506
  }
5520
  $user_id = $this->get_user_id( $user_id );
5521
  $course_post_type = tutor()->course_post_type;
5522
 
5523
+ $pageposts = $wpdb->get_results(
5524
+ $wpdb->prepare(
5525
+ "SELECT $wpdb->posts.*
5526
  FROM $wpdb->posts
5527
  LEFT JOIN $wpdb->usermeta
5528
  ON ($wpdb->posts.ID = $wpdb->usermeta.meta_value)
5532
  AND $wpdb->usermeta.user_id = %d
5533
  ORDER BY $wpdb->usermeta.umeta_id DESC;
5534
  ",
5535
+ $course_post_type,
5536
+ 'publish',
5537
+ '_tutor_course_wishlist',
5538
+ $user_id
5539
+ ),
5540
+ OBJECT
5541
+ );
5542
 
5543
  return $pageposts;
5544
  }
5554
  */
5555
  public function most_popular_courses( $limit = 10, $user_id = '' ) {
5556
  global $wpdb;
5557
+ $limit = sanitize_text_field( $limit );
5558
+ $user_id = sanitize_text_field( $user_id );
5559
 
5560
  $author_query = '';
5561
  if ( '' !== $user_id ) {
5562
  $author_query = "AND course.post_author = $user_id";
5563
  }
5564
 
5565
+ $courses = $wpdb->get_results(
5566
+ $wpdb->prepare(
5567
+ "SELECT COUNT(enrolled.ID) AS total_enrolled,
5568
  enrolled.post_parent as course_id,
5569
  course.*
5570
  FROM {$wpdb->posts} enrolled
5571
  INNER JOIN {$wpdb->posts} course
5572
+ ON enrolled.post_parent = course.ID
5573
  WHERE enrolled.post_type = %s
5574
  AND enrolled.post_status = %s
5575
  {$author_query}
5577
  ORDER BY total_enrolled DESC
5578
  LIMIT 0, %d;
5579
  ",
5580
+ 'tutor_enrolled',
5581
+ 'completed',
5582
+ $limit
5583
+ )
5584
+ );
5585
 
5586
  return $courses;
5587
  }
5598
  public function most_rated_courses( $limit = 10 ) {
5599
  global $wpdb;
5600
 
5601
+ $result = $wpdb->get_results(
5602
+ $wpdb->prepare(
5603
+ "SELECT COUNT(comment_ID) AS total_rating,
5604
  comment_ID,
5605
  comment_post_ID,
5606
  course.*
5613
  ORDER BY total_rating DESC
5614
  LIMIT 0, %d
5615
  ;",
5616
+ 'tutor_course_rating',
5617
+ 'approved',
5618
+ $limit
5619
+ )
5620
+ );
5621
 
5622
  if ( is_array( $result ) && count( $result ) ) {
5623
  return $result;
5658
  */
5659
  function get_ip() {
5660
  $ipaddress = '';
5661
+ if ( getenv( 'HTTP_CLIENT_IP' ) ) {
5662
  $ipaddress = getenv( 'HTTP_CLIENT_IP' );
5663
+ } elseif ( getenv( 'HTTP_X_FORWARDED_FOR' ) ) {
5664
  $ipaddress = getenv( 'HTTP_X_FORWARDED_FOR' );
5665
+ } elseif ( getenv( 'HTTP_X_FORWARDED' ) ) {
5666
  $ipaddress = getenv( 'HTTP_X_FORWARDED' );
5667
+ } elseif ( getenv( 'HTTP_FORWARDED_FOR' ) ) {
5668
  $ipaddress = getenv( 'HTTP_FORWARDED_FOR' );
5669
+ } elseif ( getenv( 'HTTP_FORWARDED' ) ) {
5670
  $ipaddress = getenv( 'HTTP_FORWARDED' );
5671
+ } elseif ( getenv( 'REMOTE_ADDR' ) ) {
5672
  $ipaddress = getenv( 'REMOTE_ADDR' );
5673
+ } else {
5674
  $ipaddress = 'UNKNOWN';
5675
+ }
5676
  return $ipaddress;
5677
  }
5678
 
5685
  */
5686
  public function tutor_social_share_icons() {
5687
  $icons = array(
5688
+ 'facebook' => array(
5689
+ 'share_class' => 's_facebook',
5690
+ 'icon_html' => '<i class="tutor-icon-facebook"></i>',
5691
+ ),
5692
+ 'twitter' => array(
5693
+ 'share_class' => 's_twitter',
5694
+ 'icon_html' => '<i class="tutor-icon-twitter"></i>',
5695
+ ),
5696
+ 'linkedin' => array(
5697
+ 'share_class' => 's_linkedin',
5698
+ 'icon_html' => '<i class="tutor-icon-linkedin"></i>',
5699
+ ),
5700
+ 'tumblr' => array(
5701
+ 'share_class' => 's_tumblr',
5702
+ 'icon_html' => '<i class="tutor-icon-tumblr"></i>',
5703
+ ),
5704
  );
5705
 
5706
  return apply_filters( 'tutor_social_share_icons', $icons );
5716
  public function tutor_user_social_icons() {
5717
  $icons = array(
5718
  '_tutor_profile_website' => array(
5719
+ 'label' => __( 'Website URL', 'tutor' ),
5720
  'placeholder' => 'https://example.com/',
5721
+ 'icon_classes' => 'tutor-icon-earth',
5722
  ),
5723
+ '_tutor_profile_github' => array(
5724
+ 'label' => __( 'Github URL', 'tutor' ),
5725
  'placeholder' => 'https://github.com/username',
5726
+ 'icon_classes' => 'tutor-icon-github-logo',
5727
  ),
5728
+ '_tutor_profile_facebook' => array(
5729
+ 'label' => __( 'Facebook URL', 'tutor' ),
5730
  'placeholder' => 'https://facebook.com/username',
5731
+ 'icon_classes' => 'tutor-icon-facebook',
5732
  ),
5733
  '_tutor_profile_twitter' => array(
5734
+ 'label' => __( 'Twitter URL', 'tutor' ),
5735
  'placeholder' => 'https://twitter.com/username',
5736
+ 'icon_classes' => 'tutor-icon-twitter',
5737
  ),
5738
+ '_tutor_profile_linkedin' => array(
5739
+ 'label' => __( 'Linkedin URL', 'tutor' ),
5740
  'placeholder' => 'https://linkedin.com/username',
5741
+ 'icon_classes' => 'tutor-icon-linkedin',
5742
  ),
5743
  );
5744
 
5771
  */
5772
  public function tutor_get_screen_ids() {
5773
  $screen_ids = array(
5774
+ 'edit-course',
5775
+ 'course',
5776
+ 'edit-course-category',
5777
+ 'edit-course-tag',
5778
+ 'tutor-lms_page_tutor-students',
5779
+ 'tutor-lms_page_tutor-instructors',
5780
+ 'tutor-lms_page_question_answer',
5781
+ 'tutor-lms_page_tutor_quiz_attempts',
5782
+ 'tutor-lms_page_tutor-addons',
5783
+ 'tutor-lms_page_tutor-status',
5784
+ 'tutor-lms_page_tutor_report',
5785
+ 'tutor-lms_page_tutor_settings',
5786
+ 'tutor-lms_page_tutor_emails',
5787
  );
5788
 
5789
  return apply_filters( 'tutor_get_screen_ids', $screen_ids );
5799
  public function get_earnings_completed_statuses() {
5800
  return apply_filters(
5801
  'tutor_get_earnings_completed_statuses',
5802
+ array(
5803
  'wc-completed',
5804
  'completed',
5805
  'complete',
5808
  }
5809
 
5810
  /**
5811
+ * @param int $user_id
5812
  * @param array $date_filter
5813
  *
5814
  * @return array|null|object
5820
  public function get_earning_sum( $user_id = 0, $date_filter = array() ) {
5821
  global $wpdb;
5822
 
5823
+ $user_id = $this->get_user_id( $user_id );
5824
  $date_query = '';
5825
 
5826
  if ( $this->count( $date_filter ) ) {
5841
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
5842
  $complete_status = "'" . implode( "','", $complete_status ) . "'";
5843
 
5844
+ $earning_sum = $wpdb->get_row(
5845
+ $wpdb->prepare(
5846
+ "SELECT SUM(course_price_total) AS course_price_total,
5847
+ SUM(course_price_grand_total) AS course_price_grand_total,
5848
+ SUM(instructor_amount) AS instructor_amount,
5849
  (SELECT SUM(amount)
5850
  FROM {$wpdb->prefix}tutor_withdraws
5851
  WHERE user_id = {$user_id}
5852
  AND status != 'rejected'
5853
  ) AS withdraws_amount,
5854
+ SUM(admin_amount) AS admin_amount,
5855
  SUM(deduct_fees_amount) AS deduct_fees_amount
5856
+ FROM {$wpdb->prefix}tutor_earnings
5857
  WHERE user_id = %d
5858
  AND order_status IN({$complete_status})
5859
  {$date_query}
5860
  ",
5861
+ $user_id
5862
+ )
5863
+ );
5864
 
5865
+ // TODO: need to check
5866
  // (SUM(instructor_amount) - (SELECT withdraws_amount) ) as balance,
5867
 
5868
  if ( $earning_sum->course_price_total ) {
5869
  $earning_sum->balance = $earning_sum->instructor_amount - $earning_sum->withdraws_amount;
5870
  } else {
5871
  $earning_sum = (object) array(
5872
+ 'course_price_total' => 0,
5873
+ 'course_price_grand_total' => 0,
5874
+ 'instructor_amount' => 0,
5875
+ 'withdraws_amount' => 0,
5876
+ 'balance' => 0,
5877
+ 'admin_amount' => 0,
5878
+ 'deduct_fees_amount' => 0,
5879
  );
5880
  }
5881
 
5883
  }
5884
 
5885
  /**
5886
+ * @param int $user_id
5887
  * @param array $date_filter
5888
  *
5889
  * @return array|null|object
5895
  public function get_earning_statements( $user_id = 0, $filter_data = array() ) {
5896
  global $wpdb;
5897
 
5898
+ $user_sql = '';
5899
+ if ( $user_id ) {
5900
  $user_sql = " AND user_id='{$user_id}' ";
5901
  }
5902
 
5903
+ $date_query = '';
5904
+ $query_by_status = '';
5905
  $pagination_query = '';
5906
 
5907
  /**
5938
  }
5939
 
5940
  if ( ! empty( $per_page ) ) {
5941
+ $offset = (int) ! empty( $offset ) ? $offset : 0;
5942
  $pagination_query = " LIMIT {$offset}, {$per_page} ";
5943
  }
5944
  }
5945
 
 
5946
  /**
5947
  * Delete duplicated earning rows that were created due to not checking if already added while creating new.
5948
  * New entries will check before insert.
5949
+ *
5950
  * @since v1.9.7
5951
  */
5952
+ if ( ! get_option( 'tutor_duplicated_earning_deleted', false ) ) {
5953
 
5954
  // Get the duplicated order IDs
5955
+ $del_rows = array();
5956
  $order_ids = $wpdb->get_col(
5957
+ "SELECT order_id
5958
+ FROM (SELECT order_id, COUNT(order_id) AS cnt
5959
+ FROM {$wpdb->prefix}tutor_earnings
5960
+ GROUP BY order_id) t
5961
  WHERE cnt>1"
5962
  );
5963
 
5964
+ if ( is_array( $order_ids ) && count( $order_ids ) ) {
5965
+ $order_ids_string = implode( ',', $order_ids );
5966
+ $earnings = $wpdb->get_results(
5967
  "SELECT earning_id, course_id FROM {$wpdb->prefix}tutor_earnings
5968
+ WHERE order_id IN ({$order_ids_string})
5969
+ ORDER BY earning_id ASC"
5970
+ );
5971
 
5972
  $excluded_first = array();
5973
+ foreach ( $earnings as $earning ) {
5974
+ if ( ! in_array( $earning->course_id, $excluded_first ) ) {
5975
  // Exclude first course ID from deletion
5976
  $excluded_first[] = $earning->course_id;
5977
  continue;
5981
  }
5982
  }
5983
 
5984
+ if ( count( $del_rows ) ) {
5985
+ $ids = implode( ',', $del_rows );
5986
+ $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_earnings WHERE earning_id IN ({$ids})" );
5987
  }
5988
+
5989
  update_option( 'tutor_duplicated_earning_deleted', true );
5990
  }
5991
 
5992
+ $query = $wpdb->get_results(
5993
+ $wpdb->prepare(
5994
+ "SELECT earning_tbl.*,
5995
  course.post_title AS course_title
5996
  FROM {$wpdb->prefix}tutor_earnings earning_tbl
5997
  LEFT JOIN {$wpdb->posts} course
5999
  WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
6000
  ORDER BY created_at DESC {$pagination_query}
6001
  ",
6002
+ 1
6003
+ )
6004
+ );
6005
 
6006
+ $query_count = (int) $wpdb->get_var(
6007
+ $wpdb->prepare(
6008
+ "SELECT COUNT(earning_tbl.earning_id)
6009
  FROM {$wpdb->prefix}tutor_earnings earning_tbl
6010
  WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
6011
  ORDER BY created_at DESC
6012
  ",
6013
+ 1
6014
+ )
6015
+ );
6016
 
6017
  return (object) array(
6018
  'count' => $query_count,
6030
  * @since v.1.1.2
6031
  */
6032
  public function tutor_price( $price = 0 ) {
6033
+ if ( function_exists( 'wc_price' ) ) {
6034
  return wc_price( $price );
6035
  } elseif ( function_exists( 'edd_currency_filter' ) ) {
6036
  return edd_currency_filter( edd_format_amount( $price ) );
6037
+ } else {
6038
  return number_format_i18n( $price );
6039
  }
6040
  }
6048
  */
6049
  public function currency_symbol() {
6050
  $enable_tutor_edd = tutor_utils()->get_option( 'enable_tutor_edd' );
6051
+ $monetize_by = $this->get_option( 'monetize_by' );
6052
 
6053
  $symbol = '&#36;';
6054
  if ( $enable_tutor_edd && function_exists( 'edd_currency_symbol' ) ) {
6081
  }
6082
 
6083
  /**
6084
+ * @param int $user_id
6085
  * @param array $filter
6086
  *
6087
  * get withdrawal history
6092
  global $wpdb;
6093
 
6094
  $filter = (array) $filter;
6095
+ extract( $filter );
6096
 
6097
+ $query_by_status_sql = '';
6098
+ $query_by_user_sql = '';
6099
+ $query_by_pagination = '';
6100
 
6101
  if ( ! empty( $status ) ) {
6102
  $status = (array) $status;
6106
  }
6107
 
6108
  if ( ! empty( $per_page ) ) {
6109
+ if ( empty( $start ) ) {
6110
  $start = 0;
6111
+ }
6112
 
6113
  $query_by_pagination = " LIMIT {$start}, {$per_page} ";
6114
  }
6117
  $query_by_user_sql = " AND user_id = {$user_id} ";
6118
  }
6119
 
6120
+ $count = (int) $wpdb->get_var(
6121
+ $wpdb->prepare(
6122
+ "SELECT COUNT(withdraw_id)
6123
  FROM {$wpdb->prefix}tutor_withdraws
6124
  WHERE 1 = %d
6125
  {$query_by_user_sql}
6126
  {$query_by_status_sql}
6127
  ",
6128
+ 1
6129
+ )
6130
+ );
6131
+
6132
+ $results = $wpdb->get_results(
6133
+ $wpdb->prepare(
6134
+ "SELECT withdraw_tbl.*,
6135
+ user_tbl.display_name AS user_name,
6136
+ user_tbl.user_email
6137
+ FROM {$wpdb->prefix}tutor_withdraws withdraw_tbl
6138
  INNER JOIN {$wpdb->users} user_tbl
6139
  ON withdraw_tbl.user_id = user_tbl.ID
6140
  WHERE 1 = %d
6141
+ {$query_by_user_sql}
6142
  {$query_by_status_sql}
6143
  ORDER BY created_at DESC
6144
  {$query_by_pagination}
6145
  ",
6146
+ 1
6147
+ )
6148
+ );
6149
 
6150
  $withdraw_history = array(
6151
  'count' => 0,
6213
  public function set_flash_msg( $msg = '', $name = 'success' ) {
6214
  global $wp_filesystem;
6215
  if ( ! $wp_filesystem ) {
6216
+ require_once ABSPATH . 'wp-admin/includes/file.php';
6217
  }
6218
 
6219
+ $filename = "tutor_flash_msg_{$name}.txt";
6220
  $upload_dir = wp_upload_dir();
6221
+ $dir = trailingslashit( $upload_dir['basedir'] ) . 'tutor/';
6222
 
6223
  WP_Filesystem( false, $upload_dir['basedir'], true );
6224
 
6243
 
6244
  $upload_dir = wp_get_upload_dir();
6245
  $upload_dir = trailingslashit( $upload_dir['basedir'] );
6246
+ $msg_name = 'tutor_flash_msg_' . $name;
6247
 
6248
+ $msg = '';
6249
+ $flash_msg_file_name = $upload_dir . "tutor/{$msg_name}.txt";
6250
  if ( file_exists( $flash_msg_file_name ) ) {
6251
  $msg = file_get_contents( $flash_msg_file_name );
6252
  unlink( $flash_msg_file_name );
6268
  $user_id = $this->get_user_id();
6269
  $monetize_by = tutils()->get_option( 'monetize_by' );
6270
 
6271
+ $post_type = '';
6272
+ $user_meta = '';
6273
 
6274
  if ( $monetize_by === 'wc' ) {
6275
+ $post_type = 'shop_order';
6276
+ $user_meta = '_customer_user';
6277
+ } elseif ( $monetize_by === 'edd' ) {
6278
+ $post_type = 'edd_payment';
6279
+ $user_meta = '_edd_payment_user_id';
6280
  }
6281
 
6282
+ $orders = $wpdb->get_results(
6283
+ $wpdb->prepare(
6284
+ "SELECT {$wpdb->posts}.*
6285
  FROM {$wpdb->posts}
6286
  INNER JOIN {$wpdb->postmeta} customer
6287
  ON id = customer.post_id
6290
  ON id = tutor_order.post_id
6291
  AND tutor_order.meta_key = '_is_tutor_order_for_course'
6292
  WHERE post_type = %s
6293
+ AND customer.meta_value = %d
6294
  ORDER BY {$wpdb->posts}.id DESC
6295
  ",
6296
+ $post_type,
6297
+ $user_id
6298
+ )
6299
+ );
6300
 
6301
  return $orders;
6302
  }
6314
  $status = str_replace( 'wc-', '', $status );
6315
  $status_name = ucwords( str_replace( '-', ' ', $status ) );
6316
 
6317
+ return '<span class="label-order-status label-status-' . $status . '">' . $status_name . '</span>';
6318
  }
6319
 
6320
  /**
6321
+ * Depricated since v1.9.8
6322
  * This function is redundant and will be removed later
6323
  */
6324
  public function get_course_id_by_assignment( $assignment_id = 0 ) {
6325
  $assignment_id = $this->get_post_id( $assignment_id );
6326
+ return $this->get_course_id_by( 'assignment', $assignment_id );
6327
  }
6328
 
6329
  /**
6330
+ * @param int $assignment_id
6331
  * @param string $option_key
6332
+ * @param bool $default
6333
  *
6334
  * @return array|bool|mixed
6335
  *
6339
  */
6340
  public function get_assignment_option( $assignment_id = 0, $option_key = '', $default = false ) {
6341
  $assignment_id = $this->get_post_id( $assignment_id );
6342
+ $get_option_meta = maybe_unserialize( get_post_meta( $assignment_id, 'assignment_option', true ) );
6343
 
6344
  if ( ! $option_key && ! empty( $get_option_meta ) ) {
6345
  return $get_option_meta;
6368
  global $wpdb;
6369
 
6370
  $assignment_id = $this->get_post_id( $assignment_id );
6371
+ $user_id = $this->get_user_id( $user_id );
6372
 
6373
+ $is_running_submit = (int) $wpdb->get_var(
6374
+ $wpdb->prepare(
6375
+ "SELECT comment_ID
6376
  FROM {$wpdb->comments}
6377
+ WHERE comment_type = %s
6378
+ AND comment_approved = %s
6379
  AND user_id = %d
6380
  AND comment_post_ID = %d;
6381
  ",
6382
+ 'tutor_assignment',
6383
+ 'submitting',
6384
+ $user_id,
6385
+ $assignment_id
6386
+ )
6387
+ );
6388
 
6389
  return $is_running_submit;
6390
  }
6405
  $assignment_id = $this->get_post_id( $assignment_id );
6406
  $user_id = $this->get_user_id( $user_id );
6407
 
6408
+ $has_submitted = $wpdb->get_row(
6409
+ $wpdb->prepare(
6410
+ "SELECT *
6411
  FROM {$wpdb->comments}
6412
  WHERE comment_type = %s
6413
  AND comment_approved = %s
6414
  AND user_id = %d
6415
  AND comment_post_ID = %d;
6416
  ",
6417
+ 'tutor_assignment',
6418
+ 'submitted',
6419
+ $user_id,
6420
+ $assignment_id
6421
+ )
6422
+ );
6423
 
6424
  return $has_submitted;
6425
  }
6429
 
6430
  $assignment_submitted_id = $this->get_post_id( $assignment_submitted_id );
6431
 
6432
+ $submitted_info = $wpdb->get_row(
6433
+ $wpdb->prepare(
6434
+ "SELECT *
6435
  FROM {$wpdb->comments}
6436
  WHERE comment_ID = %d
6437
  AND comment_type = %s
6438
  AND comment_approved = %s;
6439
  ",
6440
+ $assignment_submitted_id,
6441
+ 'tutor_assignment',
6442
+ 'submitted'
6443
+ )
6444
+ );
6445
 
6446
  return $submitted_info;
6447
  }
6453
  public function get_total_assignments() {
6454
  global $wpdb;
6455
 
6456
+ $count = $wpdb->get_var(
6457
+ $wpdb->prepare(
6458
+ "SELECT COUNT(comment_ID)
6459
  FROM {$wpdb->comments}
6460
  WHERE comment_type = %s
6461
  AND comment_approved = %s;
6462
  ",
6463
+ 'tutor_assignment',
6464
+ 'submitted'
6465
+ )
6466
+ );
6467
 
6468
  return (int) $count;
6469
  }
6475
  public function get_assignments() {
6476
  global $wpdb;
6477
 
6478
+ $results = $wpdb->get_results(
6479
+ $wpdb->prepare(
6480
+ "SELECT *
6481
  FROM {$wpdb->comments}
6482
  WHERE comment_type = %s
6483
  AND comment_approved = %s;
6484
  ",
6485
+ 'tutor_assignment',
6486
+ 'submitted'
6487
+ )
6488
+ );
6489
 
6490
  return $results;
6491
  }
6504
  $user_id = $this->get_user_id( $user_id );
6505
  $course_post_type = tutor()->course_post_type;
6506
 
6507
+ $get_assigned_courses_ids = $wpdb->get_col(
6508
+ $wpdb->prepare(
6509
+ "SELECT meta.meta_value
6510
+ FROM {$wpdb->usermeta} meta
6511
+ INNER JOIN {$wpdb->posts} course ON meta.meta_value=course.ID
6512
+ WHERE meta.meta_key = '_tutor_instructor_course_id'
6513
  AND meta.user_id = %d GROUP BY meta_value",
6514
+ $user_id
6515
+ )
6516
+ );
6517
 
6518
  return $get_assigned_courses_ids;
6519
  }
6528
  * @since v.1.3.4
6529
  */
6530
  public function get_course_categories( $parent = 0 ) {
6531
+ $args = apply_filters(
6532
+ 'tutor_get_course_categories_args',
6533
+ array(
6534
+ 'taxonomy' => 'course-category',
6535
+ 'hide_empty' => false,
6536
+ 'parent' => $parent,
6537
+ )
6538
+ );
6539
 
6540
  $terms = get_terms( $args );
6541
 
6542
  $children = array();
6543
  foreach ( $terms as $term ) {
6544
+ $term->children = $this->get_course_categories( $term->term_id );
6545
  $children[ $term->term_id ] = $term;
6546
  }
6547
 
6557
  *
6558
  * @since v.1.9.3
6559
  */
6560
+ public function get_course_tags() {
6561
+ $args = apply_filters(
6562
+ 'tutor_get_course_tags_args',
6563
+ array(
6564
+ 'taxonomy' => 'course-tag',
6565
+ 'hide_empty' => false,
6566
+ )
6567
+ );
6568
 
6569
  $terms = get_terms( $args );
6570
 
6571
  $children = array();
6572
  foreach ( $terms as $term ) {
6573
+ $term->children = array();
6574
  $children[ $term->term_id ] = $term;
6575
  }
6576
 
6587
  * @since v.1.3.5
6588
  */
6589
  public function get_course_categories_term( $parent_id = 0 ) {
6590
+ $args = apply_filters(
6591
+ 'tutor_get_course_categories_terms_args',
6592
+ array(
6593
+ 'taxonomy' => 'course-category',
6594
+ 'parent' => $parent_id,
6595
+ 'hide_empty' => false,
6596
+ )
6597
+ );
6598
 
6599
  $terms = get_terms( $args );
6600
 
6624
  public function course_edit_link( $course_id = 0 ) {
6625
  $course_id = $this->get_post_id( $course_id );
6626
 
6627
+ $url = admin_url( "post.php?post={$course_id}&action=edit" );
6628
  if ( tutor()->has_pro ) {
6629
+ $url = $this->tutor_dashboard_url( 'create-course/?course_ID=' . $course_id );
6630
  }
6631
 
6632
  return $url;
6642
  $in_course_ids = implode( "','", $course_ids );
6643
 
6644
  $pagination_query = $date_query = '';
6645
+ $sort_query = 'ORDER BY ID DESC';
6646
  if ( $this->count( $filter_data ) ) {
6647
  extract( $filter_data );
6648
 
6651
  }
6652
  if ( ! empty( $date_filter ) ) {
6653
  $date_filter = tutor_get_formated_date( 'Y-m-d', $date_filter );
6654
+ $date_query = " AND DATE(post_date) = '{$date_filter}'";
6655
  }
6656
  if ( ! empty( $order_filter ) ) {
6657
  $sort_query = " ORDER BY ID {$order_filter} ";
6662
  }
6663
  }
6664
 
6665
+ $count = (int) $wpdb->get_var(
6666
+ $wpdb->prepare(
6667
+ "SELECT COUNT(ID)
6668
  FROM {$wpdb->postmeta} post_meta
6669
  INNER JOIN {$wpdb->posts} assignment
6670
  ON post_meta.post_id = assignment.ID
6673
  AND post_meta.meta_value IN('$in_course_ids')
6674
  {$date_query}
6675
  ",
6676
+ $assignment_post_type
6677
+ )
6678
+ );
6679
 
6680
+ $query = $wpdb->get_results(
6681
+ $wpdb->prepare(
6682
+ "SELECT *
6683
  FROM {$wpdb->postmeta} post_meta
6684
  INNER JOIN {$wpdb->posts} assignment
6685
  ON post_meta.post_id = assignment.ID
6686
  AND post_meta.meta_key = '_tutor_course_id_for_assignments'
6687
  WHERE post_type = %s
6688
+ AND post_meta.meta_value IN('$in_course_ids')
6689
  {$date_query}
6690
  {$sort_query}
6691
  {$pagination_query}
6692
  ",
6693
+ $assignment_post_type
6694
+ )
6695
+ );
6696
 
6697
+ return (object) array(
6698
+ 'count' => $count,
6699
+ 'results' => $query,
6700
+ );
6701
  }
6702
 
6703
  /**
6715
 
6716
  $assignment_post_type = 'tutor_assignments';
6717
 
6718
+ $count = (int) $wpdb->get_var(
6719
+ $wpdb->prepare(
6720
+ "SELECT COUNT(ID)
6721
  FROM {$wpdb->postmeta} post_meta
6722
  INNER JOIN {$wpdb->posts} assignment
6723
  ON post_meta.post_id = assignment.ID
6726
  AND post_meta.meta_value = %d
6727
  ORDER BY ID DESC;
6728
  ",
6729
+ $assignment_post_type,
6730
+ $course_id
6731
+ )
6732
+ );
6733
 
6734
+ $query = $wpdb->get_results(
6735
+ $wpdb->prepare(
6736
+ "SELECT *
6737
  FROM {$wpdb->postmeta} post_meta
6738
  INNER JOIN {$wpdb->posts} assignment
6739
  ON post_meta.post_id = assignment.ID
6742
  AND post_meta.meta_value = %d
6743
  ORDER BY ID DESC;
6744
  ",
6745
+ $assignment_post_type,
6746
+ $course_id
6747
+ )
6748
+ );
6749
 
6750
+ return (object) array(
6751
+ 'count' => $count,
6752
+ 'results' => $query,
6753
+ );
6754
  }
6755
 
6756
  /**
6788
 
6789
  /**
6790
  * Get total Enrolments
6791
+ *
6792
  * @since v.1.4.0
6793
  */
6794
  public function get_total_enrolments( $search_term = '' ) {
6796
 
6797
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
6798
 
6799
+ $count = $wpdb->get_var(
6800
+ $wpdb->prepare(
6801
+ "SELECT COUNT(enrol.ID)
6802
  FROM {$wpdb->posts} enrol
6803
  INNER JOIN {$wpdb->posts} course
6804
  ON enrol.post_parent = course.ID
6807
  WHERE enrol.post_type = %s
6808
  AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s );
6809
  ",
6810
+ 'tutor_enrolled',
6811
+ $search_term,
6812
+ $search_term,
6813
+ $search_term,
6814
+ $search_term
6815
+ )
6816
+ );
6817
 
6818
  return (int) $count;
6819
  }
6823
 
6824
  $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
6825
 
6826
+ $enrolments = $wpdb->get_results(
6827
+ $wpdb->prepare(
6828
+ "SELECT enrol.ID AS enrol_id,
6829
  enrol.post_author AS student_id,
6830
  enrol.post_date AS enrol_date,
6831
  enrol.post_title AS enrol_title,
6842
  ON enrol.post_author = student.ID
6843
  WHERE enrol.post_type = %s
6844
  AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s )
6845
+ ORDER BY enrol_id DESC
6846
  LIMIT %d, %d;
6847
  ",
6848
+ 'tutor_enrolled',
6849
+ $search_term,
6850
+ $search_term,
6851
+ $search_term,
6852
+ $search_term,
6853
+ $start,
6854
+ $limit
6855
+ )
6856
+ );
6857
 
6858
  return $enrolments;
6859
  }
6895
  'review' => '',
6896
  );
6897
 
6898
+ $rating = $wpdb->get_row(
6899
+ $wpdb->prepare(
6900
+ "SELECT meta_value AS rating,
6901
  comment_content AS review
6902
  FROM {$wpdb->comments}
6903
+ INNER JOIN {$wpdb->commentmeta}
6904
+ ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
6905
  WHERE {$wpdb->comments}.comment_ID = %d;
6906
+ ",
6907
+ $rating_id
6908
+ )
6909
+ );
6910
 
6911
  if ( $rating ) {
6912
  $rating_format = number_format( $rating->rating, 2 );
6913
 
6914
  $ratings = array(
6915
+ 'rating' => $rating_format,
6916
+ 'review' => $rating->review,
6917
  );
6918
  }
6919
  return (object) $ratings;
6920
  }
6921
 
6922
  /**
6923
+ * @param int $course_id
6924
  * @param null $key
6925
  * @param bool $default
6926
  *
6937
  }
6938
 
6939
  /**
6940
+ * @param int $lesson_id
6941
  * @param null $key
6942
  * @param bool $default
6943
  *
6972
  while ( $topics->have_posts() ) {
6973
  $topics->the_post();
6974
  $topic_id = get_the_ID();
6975
+ $lessons = tutor_utils()->get_course_contents_by_topic( $topic_id, -1 );
6976
  if ( $lessons->have_posts() ) {
6977
  while ( $lessons->have_posts() ) {
6978
  $lessons->the_post();
6980
  $contents[] = $post;
6981
  }
6982
  }
 
6983
  }
6984
  }
6985
 
6986
+ if ( tutils()->count( $contents ) ) {
6987
  foreach ( $contents as $key => $content ) {
6988
  if ( $current_item->ID == $content->ID ) {
6989
+ if ( ! empty( $contents[ $key - 1 ]->ID ) ) {
6990
+ return $contents[ $key - 1 ]->ID;
6991
  }
6992
  }
6993
  }
7007
  global $wpdb;
7008
  $post = get_post( $post );
7009
 
7010
+ $course_id = $wpdb->get_var(
7011
+ $wpdb->prepare(
7012
+ "SELECT post_parent
7013
  FROM {$wpdb->posts}
7014
  WHERE ID = %d
7015
  AND post_type = %s
7016
  ",
7017
+ $post->post_parent,
7018
+ 'topics'
7019
+ )
7020
+ );
7021
 
7022
  return (int) $course_id;
7023
  }
7036
 
7037
  $course_id = $this->get_post_id( $course_id );
7038
 
7039
+ $contents = $wpdb->get_results(
7040
+ $wpdb->prepare(
7041
+ "SELECT items.*
7042
  FROM {$wpdb->posts} topic
7043
  INNER JOIN {$wpdb->posts} items
7044
  ON topic.ID = items.post_parent
7047
  ORDER BY topic.menu_order ASC,
7048
  items.menu_order ASC;
7049
  ",
7050
+ $course_id,
7051
+ 'publish'
7052
+ )
7053
+ );
7054
 
7055
  return $contents;
7056
  }
7066
  */
7067
  public function get_gradebooks() {
7068
  global $wpdb;
7069
+ $results = $wpdb->get_results( "SELECT * FROM {$wpdb->tutor_gradebooks} ORDER BY grade_point DESC " );
7070
  return $results;
7071
  }
7072
 
7090
  $attempt = false;
7091
 
7092
  $quiz_grade_method = get_tutor_option( 'quiz_grade_method', 'highest_grade' );
7093
+ $from_string = "FROM {$wpdb->tutor_quiz_attempts} WHERE quiz_id = %d AND user_id = %d AND attempt_status != 'attempt_started' ";
7094
 
7095
+ if ( $quiz_grade_method === 'highest_grade' ) {
7096
 
7097
  $attempt = $wpdb->get_row( $wpdb->prepare( "SELECT * {$from_string} ORDER BY earned_marks DESC LIMIT 1; ", $quiz_id, $user_id ) );
7098
 
7099
+ } elseif ( $quiz_grade_method === 'average_grade' ) {
7100
 
7101
+ $attempt = $wpdb->get_row(
7102
+ $wpdb->prepare(
7103
+ "SELECT {$wpdb->tutor_quiz_attempts}.*,
7104
  COUNT(attempt_id) AS attempt_count,
7105
  AVG(total_marks) AS total_marks,
7106
  AVG(earned_marks) AS earned_marks {$from_string}
7107
  ",
7108
+ $quiz_id,
7109
+ $user_id
7110
+ )
7111
+ );
7112
 
7113
  } elseif ( $quiz_grade_method === 'first_attempt' ) {
7114
 
7139
 
7140
  $html = '';
7141
  if ( $is_completed ) {
7142
+ $html = '<span class="course-completion-status course-completed"><i class="tutor-icon-mark"></i> ' . __( 'Completed', 'tutor' ) . ' </span>';
7143
  } else {
7144
  $is_in_progress = tutor_utils()->get_completed_lesson_count_by_course( $course_id, $user_id );
7145
  if ( $is_in_progress ) {
7146
+ $html = '<span class="course-completion-status course-inprogress"><i class="tutor-icon-refresh-button-1"></i> ' . __( 'In Progress', 'tutor' ) . ' </span>';
7147
  } else {
7148
+ $html = '<span class="course-completion-status course-not-taken"><i class="tutor-icon-spinner"></i> ' . __( 'Not Taken', 'tutor' ) . ' </span>';
7149
  }
7150
  }
7151
  return $html;
7179
  * @since v.1.4.3
7180
  */
7181
  public function tutor_pages() {
7182
+ $pages = apply_filters(
7183
+ 'tutor_pages',
7184
+ array(
7185
+ 'tutor_dashboard_page_id' => __( 'Dashboard Page', 'tutor' ),
7186
+ 'instructor_register_page' => __( 'Instructor Registration Page', 'tutor' ),
7187
+ 'student_register_page' => __( 'Student Registration Page', 'tutor' ),
7188
+ )
7189
+ );
7190
 
7191
  $new_pages = array();
7192
  foreach ( $pages as $key => $page ) {
7203
  }
7204
 
7205
  $new_pages[] = array(
7206
+ 'option_key' => $key,
7207
+ 'page_name' => $page,
7208
+ 'wp_page_name' => $wp_page_name,
7209
+ 'page_id' => $page_id,
7210
+ 'page_exists' => $page_exists,
7211
+ 'page_visible' => $page_visible,
7212
  );
7213
  }
7214
 
7226
  */
7227
  public function get_course_prev_next_contents_by_id( $content_id = 0 ) {
7228
 
7229
+ $course_id = $this->get_course_id_by_content( $content_id );
7230
+ $course_contents = $this->get_course_contents_by_id( $course_id );
7231
  $previous_id = 0;
7232
  $next_id = 0;
7233
 
7234
  if ( $this->count( $course_contents ) ) {
7235
  $ids = wp_list_pluck( $course_contents, 'ID' );
7236
 
7237
+ $i = 0;
7238
  foreach ( $ids as $key => $id ) {
7239
  $previous_i = $key - 1;
7240
  $next_i = $key + 1;
7251
  }
7252
  }
7253
 
7254
+ return (object) array(
7255
+ 'previous_id' => $previous_id,
7256
+ 'next_id' => $next_id,
7257
+ );
7258
  }
7259
 
7260
  /**
7261
  * Get a subset of the items from the given array.
7262
  *
7263
+ * @param array $array
7264
+ * @param array|string $keys
7265
  *
7266
  * @return array|bool
7267
  *
7285
  *
7286
  * @since v.1.6.4
7287
  */
7288
+ public function is_instructor_of_this_course( $instructor_id = 0, $course_id = 0 ) {
7289
  global $wpdb;
7290
 
7291
+ $instructor_id = $this->get_user_id( $instructor_id );
7292
+ $course_id = $this->get_post_id( $course_id );
7293
 
7294
  if ( ! $instructor_id || ! $course_id ) {
7295
  return false;
7296
  }
7297
 
7298
+ $instructor = $wpdb->get_col(
7299
+ $wpdb->prepare(
7300
+ "SELECT umeta_id
7301
  FROM {$wpdb->usermeta}
7302
  WHERE user_id = %d
7303
  AND meta_key = '_tutor_instructor_course_id'
7304
  AND meta_value = %d
7305
  ",
7306
+ $instructor_id,
7307
+ $course_id
7308
+ )
7309
+ );
7310
+
7311
+ if ( is_array( $instructor ) && count( $instructor ) ) {
7312
  return $instructor;
7313
  }
7314
 
7325
  * @since v.1.6.6
7326
  */
7327
  public function user_profile_completion( $user_id = 0 ) {
7328
+ $user_id = $this->get_user_id( $user_id );
7329
+ $instructor = $this->is_instructor( $user_id );
7330
  $instructor_status = get_user_meta( $user_id, '_tutor_instructor_status', true );
7331
 
7332
+ $required_fields = apply_filters(
7333
+ 'tutor_profile_required_fields',
7334
+ array(
7335
+ 'first_name' => __( 'First Name', 'tutor' ),
7336
+ 'last_name' => __( 'Last Name', 'tutor' ),
7337
+ '_tutor_profile_photo' => __( 'Profile Photo', 'tutor' ),
7338
+ '_tutor_withdraw_method_data' => __( 'Withdraw Method', 'tutor' ),
7339
+ )
7340
+ );
7341
 
7342
+ if ( 'approved' !== $instructor_status && array_key_exists( '_tutor_withdraw_method_data', $required_fields ) ) {
7343
+ unset( $required_fields['_tutor_withdraw_method_data'] );
7344
  }
7345
 
7346
  $empty_fields = array();
7347
  foreach ( $required_fields as $key => $field ) {
7348
  $value = get_user_meta( $user_id, $key, true );
7349
+ if ( ! $value ) {
7350
  array_push( $empty_fields, $field );
7351
  }
7352
  }
7353
+
7354
  $total_empty_fields = count( $empty_fields );
7355
  $total_required_fields = count( $required_fields );
7356
  $signup_point = apply_filters( 'tutor_profile_completion_signup_point', 50 );
7358
  if ( $total_empty_fields == 0 ) {
7359
  $progress = 100;
7360
  } else {
7361
+ $completed_field = $total_required_fields - $total_empty_fields;
7362
  $per_field_point = $signup_point / $total_required_fields;
7363
+ $progress = $signup_point + ceil( $per_field_point * $completed_field );
7364
  }
7365
 
7366
  $return = array(
7383
  public function get_enrolment_by_enrol_id( $enrol_id = 0 ) {
7384
  global $wpdb;
7385
 
7386
+ $enrolment = $wpdb->get_row(
7387
+ $wpdb->prepare(
7388
+ "SELECT enrol.id AS enrol_id,
7389
  enrol.post_author AS student_id,
7390
  enrol.post_date AS enrol_date,
7391
  enrol.post_title AS enrol_title,
7401
  INNER JOIN {$wpdb->users} student
7402
  ON enrol.post_author = student.id
7403
  WHERE enrol.id = %d;
7404
+ ",
7405
+ $enrol_id
7406
+ )
7407
+ );
7408
 
7409
  if ( $enrolment ) {
7410
  return $enrolment;
7418
  global $wpdb;
7419
  $course_id = $this->get_post_id( $course_id );
7420
 
7421
+ $student_data = $wpdb->get_results(
7422
+ $wpdb->prepare(
7423
+ "SELECT student.{$field_name}
7424
  FROM {$wpdb->posts} enrol
7425
  INNER JOIN {$wpdb->users} student
7426
  ON enrol.post_author = student.id
7427
  WHERE enrol.post_type = %s
7428
  AND enrol.post_parent = %d
7429
+ AND enrol.post_status = %s;
7430
  ",
7431
+ 'tutor_enrolled',
7432
+ $course_id,
7433
+ 'completed'
7434
+ )
7435
+ );
7436
 
7437
  return array_column( $student_data, $field_name );
7438
  }
7441
  * @param int $course_id
7442
  *
7443
  * @return array
7444
+ *
7445
  * @since v1.6.9
7446
  *
7447
  * Get students email by course id
7454
  *requie post id & user id
7455
  *return single comment post
7456
  */
7457
+ public function get_single_comment_user_post_id( $post_id, $user_id ) {
7458
  global $wpdb;
7459
+ $table = $wpdb->prefix . 'comments';
7460
+ $query = $wpdb->get_row(
7461
+ $wpdb->prepare(
7462
+ "SELECT *
7463
  FROM $table
7464
  WHERE comment_post_ID = %d
7465
  AND user_id = %d
7466
  LIMIT 1
7467
  ",
7468
+ $post_id,
7469
+ $user_id
7470
+ )
7471
+ );
7472
  return $query ? $query : false;
7473
  }
7474
+
7475
  /**
7476
  * @param int $course_id
7477
  *
7478
  * @return bool
7479
+ *
7480
  * @since v1.7.5
7481
  *
7482
  * Check if course is in wc cart
7483
  */
7484
+ public function is_course_added_to_cart( $course_or_product_id = 0, $is_product_id = false ) {
7485
+
7486
+ switch ( $this->get_option( 'monetize_by' ) ) {
7487
  case 'wc':
7488
  global $woocommerce;
7489
  $product_id = $is_product_id ? $course_or_product_id : $this->get_course_product_id( $course_or_product_id );
7490
+
7491
  if ( $woocommerce->cart ) {
7492
  foreach ( $woocommerce->cart->get_cart() as $key => $val ) {
7493
  if ( $product_id == $val['product_id'] ) {
7503
  * @param int $user_id
7504
  *
7505
  * @return bool
7506
+ *
7507
  * @since v1.7.5
7508
  *
7509
  * Get profile pic url
7512
  $cover_photo_src = tutor()->url . 'assets/images/cover-photo.jpg';
7513
  $cover_photo_id = get_user_meta( $user_id, '_tutor_cover_photo', true );
7514
  if ( $cover_photo_id ) {
7515
+ $url = wp_get_attachment_image_url( $cover_photo_id, 'full' );
7516
  ! empty( $url ) ? $cover_photo_src = $url : 0;
7517
  }
7518
 
7521
 
7522
  /**
7523
  * @return int
7524
+ *
7525
  * @since v1.7.9
7526
  *
7527
  * Return the course ID by lession, quiz, answer etc.
7531
  $course_id = null;
7532
 
7533
  switch ( $content ) {
7534
+ case 'course':
7535
  $course_id = $object_id;
7536
  break;
7537
 
7538
+ case 'topic':
7539
+ case 'announcement':
7540
+ $course_id = $wpdb->get_var(
7541
+ $wpdb->prepare(
7542
+ "SELECT post_parent
7543
+ FROM {$wpdb->posts}
7544
  WHERE ID=%d
7545
  LIMIT 1",
7546
+ $object_id
7547
+ )
7548
+ );
7549
  break;
7550
+
7551
+ case 'lesson':
7552
+ case 'quiz':
7553
+ case 'assignment':
7554
+ $course_id = $wpdb->get_var(
7555
+ $wpdb->prepare(
7556
+ "SELECT post_parent
7557
+ FROM {$wpdb->posts}
7558
  WHERE ID = (SELECT post_parent FROM {$wpdb->posts} WHERE ID = %d);
7559
  ",
7560
+ $object_id
7561
+ )
7562
+ );
7563
  break;
7564
+
7565
+ case 'question':
7566
+ $course_id = $wpdb->get_var(
7567
+ $wpdb->prepare(
7568
+ "SELECT topic.post_parent
7569
  FROM {$wpdb->posts} topic
7570
+ INNER JOIN {$wpdb->posts} quiz
7571
  ON quiz.post_parent=topic.ID
7572
  INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
7573
  ON question.quiz_id=quiz.ID
7574
  WHERE question.question_id = %d;
7575
  ",
7576
+ $object_id
7577
+ )
7578
+ );
7579
  break;
7580
+
7581
+ case 'quiz_answer':
7582
+ $course_id = $wpdb->get_var(
7583
+ $wpdb->prepare(
7584
+ "SELECT topic.post_parent
7585
  FROM {$wpdb->posts} topic
7586
  INNER JOIN {$wpdb->posts} quiz
7587
  ON quiz.post_parent=topic.ID
7591
  ON answer.belongs_question_id=question.question_id
7592
  WHERE answer.answer_id = %d;
7593
  ",
7594
+ $object_id
7595
+ )
7596
+ );
7597
  break;
7598
+
7599
+ case 'attempt':
7600
+ $course_id = $wpdb->get_var(
7601
+ $wpdb->prepare(
7602
+ "SELECT course_id
7603
  FROM {$wpdb->prefix}tutor_quiz_attempts
7604
  WHERE attempt_id=%d;
7605
  ",
7606
+ $object_id
7607
+ )
7608
+ );
7609
  break;
7610
 
7611
+ case 'attempt_answer':
7612
+ $course_id = $wpdb->get_var(
7613
+ $wpdb->prepare(
7614
+ "SELECT course_id
7615
+ FROM {$wpdb->prefix}tutor_quiz_attempts
7616
  WHERE attempt_id = (SELECT quiz_attempt_id FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id=%d)
7617
  ",
7618
+ $object_id
7619
+ )
7620
+ );
7621
  break;
7622
 
7623
+ case 'review':
7624
+ case 'qa_question':
7625
+ $course_id = $wpdb->get_var(
7626
+ $wpdb->prepare(
7627
+ "SELECT comment_post_ID
7628
  FROM {$wpdb->comments}
7629
  WHERE comment_ID = %d;
7630
  ",
7631
+ $object_id
7632
+ )
7633
+ );
7634
  break;
7635
  }
7636
 
7639
 
7640
  /**
7641
  * @return bool
7642
+ *
7643
  * @since v1.7.7
7644
  *
7645
+ * Check if user can create, edit, delete various tutor contents such as lesson, quiz, answer etc.
7646
  */
7647
+ public function can_user_manage( $content, $object_id, $user_id = 0, $allow_current_admin = true ) {
7648
+
7649
+ if ( $allow_current_admin && current_user_can( 'administrator' ) ) {
7650
  // Admin has access to everything
7651
  return true;
7652
  }
7653
 
7654
  $course_id = $this->get_course_id_by( $content, $object_id );
7655
 
7656
+ if ( $course_id ) {
7657
+
7658
  $instructors = $this->get_instructors_by_course( $course_id );
7659
+ $instructor_ids = is_array( $instructors ) ? array_map(
7660
+ function( $instructor ) {
7661
+ return (int) $instructor->ID;
7662
+ },
7663
+ $instructors
7664
+ ) : array();
7665
+
7666
+ $user_id = (int) $this->get_user_id( $user_id );
7667
  $is_listed = in_array( $user_id, $instructor_ids );
7668
 
7669
  return $is_listed;
7674
 
7675
  /**
7676
  * @return bool
7677
+ *
7678
  * @since v1.7.9
7679
  *
7680
  * Check if user has access for content like lesson, quiz, assignment etc.
7681
  */
7682
+ public function has_enrolled_content_access( $content, $object_id = 0, $user_id = 0 ) {
7683
+ $user_id = $this->get_user_id( $user_id );
7684
+ $object_id = $this->get_post_id( $object_id );
7685
+ $course_id = $this->get_course_id_by( $content, $object_id );
7686
  $course_content_access = (bool) get_tutor_option( 'course_content_access_for_ia' );
7687
 
7688
  do_action( 'tutor_before_enrolment_check', $course_id, $user_id );
7693
  if ( $course_content_access && ( current_user_can( 'administrator' ) || current_user_can( tutor()->instructor_role ) ) ) {
7694
  return true;
7695
  }
7696
+ // Check Lesson edit access to support page builders (eg: Oxygen)
7697
+ if ( current_user_can( tutor()->instructor_role ) && tutils()->has_lesson_edit_access() ) {
7698
  return true;
7699
  }
7700
 
7703
 
7704
  /**
7705
  * @return date
7706
+ *
7707
  * @since v1.8.0
7708
  *
7709
  * Return the assignment deadline date based on duration and assignment creation date
7710
  */
7711
+ public function get_assignment_deadline_date( $assignment_id, $format = null, $fallback = null ) {
7712
+
7713
+ ! $format ? $format = 'j F, Y, g:i a' : 0;
7714
 
7715
  $value = $this->get_assignment_option( $assignment_id, 'time_duration.value' );
7716
  $time = $this->get_assignment_option( $assignment_id, 'time_duration.time' );
7717
+
7718
+ if ( ! $value ) {
7719
  return $fallback;
7720
  }
7721
 
7729
 
7730
  /**
7731
  * @return array
7732
+ *
7733
  * @since v1.8.2
7734
  *
7735
  * Get earning chart data
7747
 
7748
  $datesPeriod = array();
7749
  foreach ( $period as $dt ) {
7750
+ $datesPeriod[ $dt->format( 'Y-m-d' ) ] = 0;
7751
  }
7752
 
7753
  // Get statuses
7754
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
7755
  $statuses = $complete_status;
7756
+ $complete_status = "'" . implode( "','", $complete_status ) . "'";
7757
+
7758
+ $salesQuery = $wpdb->get_results(
7759
+ $wpdb->prepare(
7760
+ "SELECT SUM(instructor_amount) AS total_earning,
7761
+ DATE(created_at) AS date_format
7762
+ FROM {$wpdb->prefix}tutor_earnings
7763
+ WHERE user_id = %d
7764
+ AND order_status IN({$complete_status})
7765
  AND (created_at BETWEEN %s AND %s)
7766
  GROUP BY date_format
7767
  ORDER BY created_at ASC;
7768
+ ",
7769
+ $user_id,
7770
+ $start_date,
7771
+ $end_date
7772
+ )
7773
+ );
7774
 
7775
  $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
7776
  $queried_date = wp_list_pluck( $salesQuery, 'date_format' );
7779
 
7780
  foreach ( $chartData as $key => $salesCount ) {
7781
  unset( $chartData[ $key ] );
7782
+ $formatDate = date( 'd M', strtotime( $key ) );
7783
  $chartData[ $formatDate ] = $salesCount;
7784
  }
7785
 
7786
+ $statements = tutor_utils()->get_earning_statements( $user_id, compact( 'start_date', 'end_date', 'statuses' ) );
7787
  $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'start_date', 'end_date' ) );
7788
 
7789
  return array(
7790
+ 'chartData' => $chartData,
7791
  'statements' => $statements,
7792
  'statuses' => $statuses,
7793
  'begin' => $begin,
7794
  'end' => $end,
7795
  'earning_sum' => $earning_sum,
7796
+ 'datesPeriod' => $datesPeriod,
7797
  );
7798
  }
7799
 
7800
  /**
7801
  * @return array
7802
+ *
7803
  * @since v1.8.2
7804
  *
7805
  * Get earning chart data yearly
7809
 
7810
  $complete_status = tutor_utils()->get_earnings_completed_statuses();
7811
  $statuses = $complete_status;
7812
+ $complete_status = "'" . implode( "','", $complete_status ) . "'";
7813
+
7814
+ $salesQuery = $wpdb->get_results(
7815
+ $wpdb->prepare(
7816
+ "SELECT SUM(instructor_amount) AS total_earning,
7817
+ MONTHNAME(created_at) AS month_name
7818
+ FROM {$wpdb->prefix}tutor_earnings
7819
+ WHERE user_id = %d
7820
+ AND order_status IN({$complete_status})
7821
+ AND YEAR(created_at) = %s
7822
+ GROUP BY MONTH (created_at)
7823
  ORDER BY MONTH(created_at) ASC;
7824
+ ",
7825
+ $user_id,
7826
+ $year
7827
+ )
7828
+ );
7829
 
7830
  $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
7831
  $months = wp_list_pluck( $salesQuery, 'month_name' );
7837
  * Format yearly
7838
  */
7839
  $emptyMonths = array();
7840
+ for ( $m = 1; $m <= 12; $m++ ) {
7841
+ $emptyMonths[ date( 'F', mktime( 0, 0, 0, $m, 1, date( 'Y' ) ) ) ] = 0;
7842
  }
7843
 
7844
  $chartData = array_merge( $emptyMonths, $monthWiseSales );
7845
+ $statements = tutor_utils()->get_earning_statements( $user_id, compact( 'year', 'dataFor', 'statuses' ) );
7846
  $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'year', 'dataFor' ) );
7847
 
7848
+ return array(
7849
  'chartData' => $chartData,
7850
  'statements' => $statements,
7851
+ 'earning_sum' => $earning_sum,
7852
+ );
7853
  }
7854
 
7855
  /**
7856
  * @return object
7857
+ *
7858
  * @since v1.8.4
7859
  *
7860
  * Return object from vendor package
7862
  function get_package_object() {
7863
 
7864
  $params = func_get_args();
7865
+
7866
+ $is_pro = $params[0];
7867
+ $class = $params[1];
7868
  $class_args = array_slice( $params, 2 );
7869
+ $root_path = $is_pro ? tutor_pro()->path : tutor()->path;
7870
 
7871
  require_once $root_path . '/vendor/autoload.php';
7872
+
7873
  $reflector = new \ReflectionClass( $class );
7874
+ $object = $reflector->newInstanceArgs( $class_args );
7875
 
7876
  return $object;
7877
  }
7878
 
7879
  /**
7880
  * @return boolean
7881
+ *
7882
  * @since v1.8.9
7883
+ *
7884
  * Check if user has specific role
7885
  */
7886
+ public function has_user_role( $roles, $user_id = 0 ) {
7887
+
7888
+ ! $user_id ? $user_id = get_current_user_id() : 0;
7889
+ ! is_array( $roles ) ? $roles = array( $roles ) : 0;
 
 
 
7890
 
7891
+ $user = get_userdata( $user_id );
7892
+ $role_list = ( is_object( $user ) && is_array( $user->roles ) ) ? $user->roles : array();
7893
 
7894
+ $without_roles = array_diff( $roles, $role_list );
7895
+
7896
+ return count( $roles ) > count( $without_roles );
7897
  }
7898
 
7899
  /**
7900
  * @return boolean
7901
+ *
7902
  * @since v1.8.9
7903
+ *
7904
  * Check if user can edit course
7905
  */
7906
+ public function can_user_edit_course( $user_id, $course_id ) {
7907
+ return $this->has_user_role( array( 'administrator', 'editor' ) ) || $this->is_instructor_of_this_course( $user_id, $course_id );
 
7908
  }
7909
 
7910
+
7911
  /**
7912
  * @return boolean
7913
+ *
7914
  * @since v1.9.0
7915
+ *
7916
  * Check if course member limit full
7917
  */
7918
+ public function is_course_fully_booked( $course_id = 0 ) {
7919
+
7920
+ $total_enrolled = $this->count_enrolled_users_by_course( $course_id );
7921
+ $maximum_students = (int) $this->get_course_settings( $course_id, 'maximum_students' );
7922
 
 
 
 
7923
  return $maximum_students && $maximum_students <= $total_enrolled;
7924
  }
7925
 
7926
  /**
7927
  * @return boolean
7928
+ *
7929
  * @since v1.9.2
7930
+ *
7931
  * Check if current screen is under tutor dashboard
7932
  */
7933
+ public function is_tutor_dashboard( $subpage = null ) {
7934
 
7935
  // To Do: Add subpage check later
7936
 
7937
+ if ( function_exists( 'is_admin' ) && is_admin() ) {
7938
  $screen = get_current_screen();
7939
  return is_object( $screen ) && $screen->parent_base == 'tutor';
7940
  }
7941
+
7942
  return false;
7943
  }
7944
 
7945
  /**
7946
  * @return boolean
7947
+ *
7948
  * @since v1.9.4
7949
+ *
7950
  * Check if current screen tutor frontend dashboard
7951
  */
7952
+ public function is_tutor_frontend_dashboard( $subpage = null ) {
7953
 
7954
  global $wp_query;
7955
+ if ( $wp_query->is_page ) {
7956
+ $dashboard_page = tutor_utils()->array_get( 'tutor_dashboard_page', $wp_query->query_vars );
7957
 
7958
+ if ( $subpage && $dashboard_page == $subpage ) {
7959
  return true;
7960
  }
7961
 
7962
+ if ( $wp_query->queried_object && $wp_query->queried_object->ID ) {
7963
+ return $wp_query->queried_object->ID == tutor_utils()->get_option( 'tutor_dashboard_page_id' );
7964
  }
7965
  }
7966
 
7967
  return false;
7968
  }
7969
 
7970
+ public function get_unique_slug( $slug, $post_type = null, $num_assigned = false ) {
7971
 
7972
  global $wpdb;
7973
+ $existing_slug = $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM {$wpdb->posts} WHERE post_name=%s" . ( $post_type ? " AND post_type='{$post_type}' LIMIT 1" : '' ), $slug ) );
7974
 
7975
+ if ( ! $existing_slug ) {
7976
  return $slug;
7977
  }
7978
 
7979
+ if ( ! $num_assigned ) {
7980
  $new_slug = $slug . '-' . 2;
7981
  } else {
7982
+ $new_slug = explode( '-', $slug );
7983
+ $number = end( $new_slug ) + 1;
 
 
7984
 
7985
+ array_pop( $new_slug );
7986
+
7987
+ $new_slug = implode( '-', $new_slug ) . '-' . $number;
7988
  }
7989
 
7990
+ return $this->get_unique_slug( $new_slug, $post_type, true );
7991
  }
7992
 
7993
+ public function get_course_content_ids_by( $content_type, $ancestor_type, $ancestor_ids ) {
7994
+ global $wpdb;
7995
  $ids = array();
7996
 
7997
  // Convert single id to array
7998
+ ! is_array( $ancestor_ids ) ? $ancestor_ids = array( $ancestor_ids ) : 0;
7999
+ $ancestor_ids = implode( ',', $ancestor_ids );
8000
 
8001
+ switch ( $content_type ) {
8002
 
8003
  // Get lesson, quiz, assignment IDs
8004
+ case tutor()->lesson_post_type:
8005
+ case 'tutor_quiz':
8006
+ case 'tutor_assignments':
8007
+ switch ( $ancestor_type ) {
8008
 
8009
  // Get lesson, quiz, assignment IDs by course ID
8010
+ case tutor()->course_post_type:
8011
+ $content_ids = $wpdb->get_col(
8012
+ $wpdb->prepare(
8013
+ "SELECT content.ID FROM {$wpdb->posts} course
8014
+ INNER JOIN {$wpdb->posts} topic ON course.ID=topic.post_parent
8015
  INNER JOIN {$wpdb->posts} content ON topic.ID=content.post_parent
8016
  WHERE course.ID IN ({$ancestor_ids}) AND content.post_type=%s",
8017
+ $content_type
8018
+ )
8019
+ );
8020
 
8021
  // Assign id array to the variable
8022
+ is_array( $content_ids ) ? $ids = $content_ids : 0;
8023
  break 2;
8024
  }
8025
  }
8029
 
8030
  /**
8031
  * Custom Pagination for Tutor Shortcode
8032
+ *
8033
  * @param int $total_num_pages
8034
+ *
8035
  * @return void
8036
  */
8037
  public function tutor_custom_pagination( $total_num_pages = 1 ) {
8038
 
8039
  do_action( 'tutor_course/archive/pagination/before' ); ?>
8040
+
8041
  <div class="tutor-pagination-wrap">
8042
  <?php
8043
  $big = 999999999; // need an unlikely integer
8044
+
8045
+ echo paginate_links(
8046
+ array(
8047
+ 'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
8048
+ 'format' => '?paged=%#%',
8049
+ 'current' => max( 1, get_query_var( 'paged' ) ),
8050
+ 'total' => $total_num_pages,
8051
+ )
8052
+ );
8053
  ?>
8054
  </div>
8055
+
8056
+ <?php
8057
+ do_action( 'tutor_course/archive/pagination/after' );
8058
  }
8059
 
8060
  /**
8061
  * Get all courses along with topics & course materials for current student
8062
+ *
8063
  * @since 1.9.10
8064
+ *
8065
  * @return array
8066
  */
8067
  public function course_with_materials(): array {
8068
+ $user_id = get_current_user_id();
8069
  $enrolled_courses = $this->get_enrolled_courses_by_user( $user_id );
8070
 
8071
  if ( false === $enrolled_courses ) {
8072
+ return array();
8073
  }
8074
+ $data = array();
8075
  foreach ( $enrolled_courses->posts as $key => $course ) {
8076
+ // push courses
8077
+ array_push( $data, array( 'course' => array( 'title' => $course->post_title ) ) );
8078
  $topics = $this->get_topics( $course->ID );
8079
 
8080
+ if ( ! is_null( $topics ) || count( $topics->posts ) ) {
8081
  foreach ( $topics->posts as $topic_key => $topic ) {
8082
  $materials = $this->get_course_contents_by_topic( $topic->ID, -1 );
8083
+ if ( count( $materials->posts ) || ! is_null( $materials->posts ) ) {
8084
  $topic->materials = $materials->posts;
8085
  }
8086
+ // push topics
8087
+ array_push( $data[ $key ]['course'], array( 'topics' => $topic ) );
8088
  }
8089
  }
 
8090
  }
8091
  return $data;
8092
  }
8093
 
8094
+ public function get_course_duration( $course_id, $return_array, $texts = array(
8095
+ 'h' => 'hr',
8096
+ 'm' => 'min',
8097
+ 's' => 'sec',
8098
+ ) ) {
8099
+ $duration = maybe_unserialize( get_post_meta( $course_id, '_course_duration', true ) );
8100
+ $durationHours = tutor_utils()->avalue_dot( 'hours', $duration );
8101
+ $durationMinutes = tutor_utils()->avalue_dot( 'minutes', $duration );
8102
+ $durationSeconds = tutor_utils()->avalue_dot( 'seconds', $duration );
8103
 
8104
+ if ( $return_array ) {
8105
  return array(
8106
+ 'duration' => $duration,
8107
+ 'durationHours' => $durationHours,
8108
  'durationMinutes' => $durationMinutes,
8109
  'durationSeconds' => $durationSeconds,
8110
  );
8111
  }
8112
 
8113
+ if ( ! $durationHours && ! $durationMinutes && ! $durationSeconds ) {
8114
  return '';
8115
  }
8116
 
8118
  $durationMinutes . $texts['m'] . ' ' .
8119
  $durationSeconds . $texts['s'];
8120
  }
8121
+ }
classes/Video_Stream.php CHANGED
@@ -8,12 +8,14 @@
8
 
9
  namespace TUTOR;
10
 
11
- if ( ! defined( 'ABSPATH' ) )
12
  exit;
 
13
 
14
 
15
  /**
16
  * Class Video_Stream
 
17
  * @package TUTOR
18
  *
19
  * TUTOR Video Stream Class
@@ -22,8 +24,8 @@ if ( ! defined( 'ABSPATH' ) )
22
 
23
  class Video_Stream {
24
 
25
- private $path = "";
26
- private $stream = "";
27
  private $buffer = 102400;
28
  private $start = -1;
29
  private $end = -1;
@@ -31,17 +33,24 @@ class Video_Stream {
31
 
32
  private $videoFormats;
33
 
34
- function __construct($filePath) {
35
- $this->videoFormats = apply_filters('tutor_video_types', array("mp4"=>"video/mp4", "webm"=>"video/webm", "ogg"=>"video/ogg")) ;
36
- $this->path = $filePath;
 
 
 
 
 
 
 
37
  }
38
 
39
  /**
40
  * Open stream
41
  */
42
  private function open() {
43
- if (!($this->stream = fopen($this->path, 'rb'))) {
44
- die('Could not open stream for reading');
45
  }
46
  }
47
 
@@ -51,43 +60,42 @@ class Video_Stream {
51
  private function setHeader() {
52
  ob_get_clean();
53
 
54
- header("Content-Type: {$this->videoFormats[strtolower(pathinfo($this->path, PATHINFO_EXTENSION))]}");
55
- header("Cache-Control: max-age=2592000, public");
56
- header("Expires: ".gmdate('D, d M Y H:i:s', tutor_time()+2592000) . ' GMT');
57
- header("Last-Modified: ".gmdate('D, d M Y H:i:s', @filemtime($this->path)) . ' GMT' );
58
  $this->start = 0;
59
- $this->size = filesize($this->path);
60
  $this->end = $this->size - 1;
61
- header("Accept-Ranges: 0-".$this->end);
62
 
63
- if (isset($_SERVER['HTTP_RANGE'])) {
64
- $c_end = $this->end;
65
- list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
66
 
67
- if ($range == '-') {
68
- $c_start = $this->size - substr($range, 1);
69
- }else{
70
- $range = explode('-', $range);
71
  $c_start = $range[0];
72
 
73
- $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $c_end;
74
  }
75
- $c_end = ($c_end > $this->end) ? $this->end : $c_end;
76
- if ($c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size) {
77
- header('HTTP/1.1 416 Requested Range Not Satisfiable');
78
- header("Content-Range: bytes $this->start-$this->end/$this->size");
79
  exit;
80
  }
81
  $this->start = $c_start;
82
- $this->end = $c_end;
83
- $length = $this->end - $this->start + 1;
84
- header('HTTP/1.1 206 Partial Content');
85
- header("Content-Length: ".$length);
86
- header("Content-Range: bytes $this->start-$this->end/".$this->size);
87
- header("Accept-Ranges: bytes");
88
- }
89
- else {
90
- header("Content-Length: ".$this->size);
91
  }
92
 
93
  }
@@ -96,7 +104,7 @@ class Video_Stream {
96
  * close currently opened stream
97
  */
98
  private function end() {
99
- fclose($this->stream);
100
  exit;
101
  }
102
 
@@ -105,15 +113,15 @@ class Video_Stream {
105
  */
106
  private function stream() {
107
  $i = $this->start;
108
- set_time_limit(0);
109
- while(!feof($this->stream) && $i <= $this->end) {
110
  $bytesToRead = $this->buffer;
111
- if(($i+$bytesToRead) > $this->end) {
112
  $bytesToRead = $this->end - $i + 1;
113
  }
114
- //$data = fread($this->stream, $bytesToRead);
115
- $data = @stream_get_contents($this->stream, $bytesToRead, $i);
116
- echo $data;
117
  flush();
118
  $i += $bytesToRead;
119
  }
@@ -128,4 +136,4 @@ class Video_Stream {
128
  $this->stream();
129
  $this->end();
130
  }
131
- }
8
 
9
  namespace TUTOR;
10
 
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
13
+ }
14
 
15
 
16
  /**
17
  * Class Video_Stream
18
+ *
19
  * @package TUTOR
20
  *
21
  * TUTOR Video Stream Class
24
 
25
  class Video_Stream {
26
 
27
+ private $path = '';
28
+ private $stream = '';
29
  private $buffer = 102400;
30
  private $start = -1;
31
  private $end = -1;
33
 
34
  private $videoFormats;
35
 
36
+ function __construct( $filePath ) {
37
+ $this->videoFormats = apply_filters(
38
+ 'tutor_video_types',
39
+ array(
40
+ 'mp4' => 'video/mp4',
41
+ 'webm' => 'video/webm',
42
+ 'ogg' => 'video/ogg',
43
+ )
44
+ );
45
+ $this->path = $filePath;
46
  }
47
 
48
  /**
49
  * Open stream
50
  */
51
  private function open() {
52
+ if ( ! ( $this->stream = fopen( $this->path, 'rb' ) ) ) {
53
+ die( 'Could not open stream for reading' );
54
  }
55
  }
56
 
60
  private function setHeader() {
61
  ob_get_clean();
62
 
63
+ header( 'Content-Type: ' . $this->videoFormats[ strtolower( pathinfo( $this->path, PATHINFO_EXTENSION ) ) ] );
64
+ header( 'Cache-Control: max-age=2592000, public' );
65
+ header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', tutor_time() + 2592000 ) . ' GMT' );
66
+ header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', @filemtime( $this->path ) ) . ' GMT' );
67
  $this->start = 0;
68
+ $this->size = filesize( $this->path );
69
  $this->end = $this->size - 1;
70
+ header( 'Accept-Ranges: 0-' . $this->end );
71
 
72
+ if ( isset( $_SERVER['HTTP_RANGE'] ) ) {
73
+ $c_end = $this->end;
74
+ list(, $range) = explode( '=', $_SERVER['HTTP_RANGE'], 2 );
75
 
76
+ if ( $range == '-' ) {
77
+ $c_start = $this->size - substr( $range, 1 );
78
+ } else {
79
+ $range = explode( '-', $range );
80
  $c_start = $range[0];
81
 
82
+ $c_end = ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? $range[1] : $c_end;
83
  }
84
+ $c_end = ( $c_end > $this->end ) ? $this->end : $c_end;
85
+ if ( $c_start > $c_end || $c_start > $this->size - 1 || $c_end >= $this->size ) {
86
+ header( 'HTTP/1.1 416 Requested Range Not Satisfiable' );
87
+ header( "Content-Range: bytes $this->start-$this->end/$this->size" );
88
  exit;
89
  }
90
  $this->start = $c_start;
91
+ $this->end = $c_end;
92
+ $length = $this->end - $this->start + 1;
93
+ header( 'HTTP/1.1 206 Partial Content' );
94
+ header( 'Content-Length: ' . $length );
95
+ header( "Content-Range: bytes $this->start-$this->end/" . $this->size );
96
+ header( 'Accept-Ranges: bytes' );
97
+ } else {
98
+ header( 'Content-Length: ' . $this->size );
 
99
  }
100
 
101
  }
104
  * close currently opened stream
105
  */
106
  private function end() {
107
+ fclose( $this->stream );
108
  exit;
109
  }
110
 
113
  */
114
  private function stream() {
115
  $i = $this->start;
116
+ set_time_limit( 0 );
117
+ while ( ! feof( $this->stream ) && $i <= $this->end ) {
118
  $bytesToRead = $this->buffer;
119
+ if ( ( $i + $bytesToRead ) > $this->end ) {
120
  $bytesToRead = $this->end - $i + 1;
121
  }
122
+ // $data = fread($this->stream, $bytesToRead);
123
+ $data = @stream_get_contents( $this->stream, $bytesToRead, $i );
124
+ echo $data; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
125
  flush();
126
  $i += $bytesToRead;
127
  }
136
  $this->stream();
137
  $this->end();
138
  }
139
+ }
classes/Withdraw.php CHANGED
@@ -10,8 +10,9 @@
10
 
11
  namespace TUTOR;
12
 
13
- if ( ! defined( 'ABSPATH' ) )
14
  exit;
 
15
 
16
  class Withdraw {
17
 
@@ -20,79 +21,79 @@ class Withdraw {
20
  public $withdraw_methods;
21
 
22
  public function __construct() {
23
- $this->get_options = $this->get_options();
24
- $this->withdraw_methods = $this->withdraw_methods();
25
  $this->available_withdraw_methods = $this->available_withdraw_methods();
26
 
27
- add_action('tutor_options_tutor_withdraw_withdraw_methods_before', array($this, 'withdraw_admin_options'));
28
- add_action('tutor_option_save_after', array($this, 'withdraw_option_save'));
29
 
30
- add_action('wp_ajax_tutor_save_withdraw_account', array($this, 'tutor_save_withdraw_account'));
31
- add_action('wp_ajax_tutor_make_an_withdraw', array($this, 'tutor_make_an_withdraw'));
32
  }
33
 
34
- public function withdraw_methods(){
35
  $methods = array(
36
  'bank_transfer_withdraw' => array(
37
- 'method_name' => __('Bank Transfer', 'tutor'),
38
- 'image' => tutor()->url . 'assets/images/payment-bank.png',
39
- 'desc' => __('Get your payment directly into your bank account', 'tutor'),
40
 
41
- 'admin_form_fields' => array(
42
  'instruction' => array(
43
- 'type' => 'textarea',
44
- 'label' => __('Instruction', 'tutor'),
45
- 'desc' => __('Write instruction for the instructor to fill bank information', 'tutor'),
46
  ),
47
  ),
48
 
49
- 'form_fields' => array(
50
- 'account_name' => array(
51
- 'type' => 'text',
52
- 'label' => __('Account Name', 'tutor'),
53
  ),
54
 
55
  'account_number' => array(
56
- 'type' => 'text',
57
- 'label' => __('Account Number', 'tutor'),
58
  ),
59
 
60
- 'bank_name' => array(
61
- 'type' => 'text',
62
- 'label' => __('Bank Name', 'tutor'),
63
  ),
64
- 'iban' => array(
65
- 'type' => 'text',
66
- 'label' => __('IBAN', 'tutor'),
67
  ),
68
- 'swift' => array(
69
- 'type' => 'text',
70
- 'label' => __('BIC / SWIFT', 'tutor'),
71
  ),
72
 
73
  ),
74
  ),
75
 
76
- 'echeck_withdraw' => array(
77
- 'method_name' => __('E-Check', 'tutor'),
78
- 'image' => tutor()->url . 'assets/images/payment-echeck.png',
79
- 'form_fields' => array(
80
  'physical_address' => array(
81
- 'type' => 'textarea',
82
- 'label' => __('Your Physical Address', 'tutor'),
83
- 'desc' => __('We will send you an E-Check to this address directly.', 'tutor'),
84
  ),
85
  ),
86
  ),
87
 
88
- 'paypal_withdraw' => array(
89
- 'method_name' => __('PayPal', 'tutor'),
90
- 'image' => tutor()->url . 'assets/images/payment-paypal.png',
91
- 'form_fields' => array(
92
  'paypal_email' => array(
93
- 'type' => 'email',
94
- 'label' => __('PayPal E-Mail Address', 'tutor'),
95
- 'desc' => __('We will use this email address to send the money to your Paypal account', 'tutor'),
96
  ),
97
 
98
  ),
@@ -100,7 +101,7 @@ class Withdraw {
100
 
101
  );
102
 
103
- $withdraw_methods = apply_filters('tutor_withdraw_methods', $methods);
104
 
105
  return $withdraw_methods;
106
  }
@@ -110,27 +111,27 @@ class Withdraw {
110
  *
111
  * Return only enabled methods
112
  */
113
- public function available_withdraw_methods(){
114
  $withdraw_options = $this->get_options();
115
- $methods = $this->withdraw_methods();
116
 
117
- foreach ($methods as $method_id => $method){
118
- $is_enable = (bool) tutor_utils()->avalue_dot($method_id.".enabled", $withdraw_options);
119
 
120
- if ( ! $is_enable){
121
- unset($methods[$method_id]);
122
  }
123
  }
124
 
125
  return $methods;
126
  }
127
 
128
- public function get_options(){
129
- return (array) maybe_unserialize(get_option('tutor_withdraw_options'));
130
  }
131
 
132
- public function withdraw_admin_options(){
133
- include tutor()->path.'views/options/withdraw/withdraw_admin_options_generator.php';
134
  }
135
 
136
 
@@ -139,14 +140,14 @@ class Withdraw {
139
  *
140
  * @since v.1.2.0
141
  */
142
- public function withdraw_option_save(){
143
- do_action('tutor_withdraw_options_save_before');
144
 
145
- $option = (array) isset($_POST['tutor_withdraw_options']) ? $_POST['tutor_withdraw_options'] : array();
146
- $option = apply_filters('tutor_withdraw_options_input', $option);
147
- update_option('tutor_withdraw_options', $option);
148
 
149
- do_action('tutor_withdraw_options_save_after');
150
  }
151
 
152
  /**
@@ -155,106 +156,109 @@ class Withdraw {
155
  * @since v.1.2.0
156
  */
157
 
158
- public function tutor_save_withdraw_account(){
159
- //Checking nonce
160
  tutor_utils()->checking_nonce();
161
 
162
  $user_id = get_current_user_id();
163
- $post = $_POST;
164
 
165
- $method = tutor_utils()->avalue_dot('tutor_selected_withdraw_method', $post);
166
- if ( ! $method){
167
  wp_send_json_error();
168
  }
169
 
170
- $method_data = tutor_utils()->avalue_dot("withdraw_method_field.".$method, $post);
171
  $available_withdraw_method = tutor_withdrawal_methods();
172
 
173
- if (tutor_utils()->count($method_data)){
174
- $saved_data = array();
175
- $saved_data['withdraw_method_key'] = $method;
176
- $saved_data['withdraw_method_name'] = tutor_utils()->avalue_dot($method.".method_name", $available_withdraw_method);
177
 
178
- foreach ($method_data as $input_name => $value){
179
- $saved_data[$input_name]['value'] = esc_sql( sanitize_text_field($value) ) ;
180
- $saved_data[$input_name]['label'] = tutor_utils()->avalue_dot($method.".form_fields.{$input_name}.label", $available_withdraw_method);
181
  }
182
 
183
- update_user_meta($user_id, '_tutor_withdraw_method_data', $saved_data);
184
  }
185
 
186
- $msg = apply_filters('tutor_withdraw_method_set_success_msg', __('Withdrawal account information saved successfully!', 'tutor'));
187
- wp_send_json_success(array('msg' => $msg ));
188
  }
189
 
190
- public function tutor_make_an_withdraw(){
191
  global $wpdb;
192
 
193
- //Checking nonce
194
  tutor_utils()->checking_nonce();
195
 
196
- do_action('tutor_withdraw_before');
197
-
198
 
199
  $user_id = get_current_user_id();
200
- $post = $_POST;
201
-
202
- $withdraw_amount = sanitize_text_field(tutor_utils()->avalue_dot('tutor_withdraw_amount', $post));
203
 
204
- $earning_sum = tutor_utils()->get_earning_sum();
205
- $min_withdraw = tutor_utils()->get_option('min_withdraw_amount');
206
 
207
- $saved_withdraw_account = tutor_utils()->get_user_withdraw_method();
208
- $formatted_balance = tutor_utils()->tutor_price($earning_sum->balance);
209
- $formatted_min_withdraw_amount = tutor_utils()->tutor_price($min_withdraw);
210
 
 
 
 
211
 
212
- if ( ! tutor_utils()->count($saved_withdraw_account)){
213
- $no_withdraw_method = apply_filters('tutor_no_withdraw_method_msg', __('Please save withdraw method ', 'tutor') );
214
- wp_send_json_error(array('msg' => $no_withdraw_method ));
215
  }
216
 
217
- if ((!is_numeric($withdraw_amount) && !is_float($withdraw_amount)) || $withdraw_amount < $min_withdraw){
218
- $required_min_withdraw = apply_filters('tutor_required_min_amount_msg', sprintf(__('Minimum withdrawal amount is %s %s %s ', 'tutor') , '<strong>', $formatted_min_withdraw_amount, '</strong>' ) );
219
- wp_send_json_error(array('msg' => $required_min_withdraw ));
220
  }
221
 
222
- if ($earning_sum->balance < $withdraw_amount){
223
- $insufficient_balence = apply_filters('tutor_withdraw_insufficient_balance_msg', __('Insufficient balance.', 'tutor'));
224
 
225
- wp_send_json_error(array('msg' => $insufficient_balence ));
226
  }
227
 
 
 
 
 
 
 
 
 
 
 
 
 
228
 
229
- $date = date("Y-m-d H:i:s", tutor_time());
230
-
231
- $withdraw_data = apply_filters('tutor_pre_withdraw_data', array(
232
- 'user_id' => $user_id,
233
- 'amount' => $withdraw_amount,
234
- 'method_data' => maybe_serialize($saved_withdraw_account),
235
- 'status' => 'pending',
236
- 'created_at' => $date,
237
- ));
238
-
239
- do_action('tutor_insert_withdraw_before', $withdraw_data);
240
 
241
- $wpdb->insert($wpdb->prefix."tutor_withdraws", $withdraw_data);
242
  $withdraw_id = $wpdb->insert_id;
243
 
244
- do_action('tutor_insert_withdraw_after', $withdraw_id, $withdraw_data);
245
-
246
 
247
  /**
248
  * Getting earning and balance data again
249
  */
250
- $earning = tutor_utils()->get_earning_sum();
251
- $new_available_balance = tutor_utils()->tutor_price($earning->balance);
252
 
 
253
 
254
- do_action('tutor_withdraw_after');
255
-
256
- $withdraw_successfull_msg = apply_filters('tutor_withdraw_successful_msg', __('Withdrawal Request Sent!', 'tutor'));
257
- wp_send_json_success(array('msg' => $withdraw_successfull_msg, 'available_balance' => $new_available_balance ));
 
 
 
258
  }
259
 
260
 
10
 
11
  namespace TUTOR;
12
 
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
15
+ }
16
 
17
  class Withdraw {
18
 
21
  public $withdraw_methods;
22
 
23
  public function __construct() {
24
+ $this->get_options = $this->get_options();
25
+ $this->withdraw_methods = $this->withdraw_methods();
26
  $this->available_withdraw_methods = $this->available_withdraw_methods();
27
 
28
+ add_action( 'tutor_options_tutor_withdraw_withdraw_methods_before', array( $this, 'withdraw_admin_options' ) );
29
+ add_action( 'tutor_option_save_after', array( $this, 'withdraw_option_save' ) );
30
 
31
+ add_action( 'wp_ajax_tutor_save_withdraw_account', array( $this, 'tutor_save_withdraw_account' ) );
32
+ add_action( 'wp_ajax_tutor_make_an_withdraw', array( $this, 'tutor_make_an_withdraw' ) );
33
  }
34
 
35
+ public function withdraw_methods() {
36
  $methods = array(
37
  'bank_transfer_withdraw' => array(
38
+ 'method_name' => __( 'Bank Transfer', 'tutor' ),
39
+ 'image' => tutor()->url . 'assets/images/payment-bank.png',
40
+ 'desc' => __( 'Get your payment directly into your bank account', 'tutor' ),
41
 
42
+ 'admin_form_fields' => array(
43
  'instruction' => array(
44
+ 'type' => 'textarea',
45
+ 'label' => __( 'Instruction', 'tutor' ),
46
+ 'desc' => __( 'Write instruction for the instructor to fill bank information', 'tutor' ),
47
  ),
48
  ),
49
 
50
+ 'form_fields' => array(
51
+ 'account_name' => array(
52
+ 'type' => 'text',
53
+ 'label' => __( 'Account Name', 'tutor' ),
54
  ),
55
 
56
  'account_number' => array(
57
+ 'type' => 'text',
58
+ 'label' => __( 'Account Number', 'tutor' ),
59
  ),
60
 
61
+ 'bank_name' => array(
62
+ 'type' => 'text',
63
+ 'label' => __( 'Bank Name', 'tutor' ),
64
  ),
65
+ 'iban' => array(
66
+ 'type' => 'text',
67
+ 'label' => __( 'IBAN', 'tutor' ),
68
  ),
69
+ 'swift' => array(
70
+ 'type' => 'text',
71
+ 'label' => __( 'BIC / SWIFT', 'tutor' ),
72
  ),
73
 
74
  ),
75
  ),
76
 
77
+ 'echeck_withdraw' => array(
78
+ 'method_name' => __( 'E-Check', 'tutor' ),
79
+ 'image' => tutor()->url . 'assets/images/payment-echeck.png',
80
+ 'form_fields' => array(
81
  'physical_address' => array(
82
+ 'type' => 'textarea',
83
+ 'label' => __( 'Your Physical Address', 'tutor' ),
84
+ 'desc' => __( 'We will send you an E-Check to this address directly.', 'tutor' ),
85
  ),
86
  ),
87
  ),
88
 
89
+ 'paypal_withdraw' => array(
90
+ 'method_name' => __( 'PayPal', 'tutor' ),
91
+ 'image' => tutor()->url . 'assets/images/payment-paypal.png',
92
+ 'form_fields' => array(
93
  'paypal_email' => array(
94
+ 'type' => 'email',
95
+ 'label' => __( 'PayPal E-Mail Address', 'tutor' ),
96
+ 'desc' => __( 'We will use this email address to send the money to your Paypal account', 'tutor' ),
97
  ),
98
 
99
  ),
101
 
102
  );
103
 
104
+ $withdraw_methods = apply_filters( 'tutor_withdraw_methods', $methods );
105
 
106
  return $withdraw_methods;
107
  }
111
  *
112
  * Return only enabled methods
113
  */
114
+ public function available_withdraw_methods() {
115
  $withdraw_options = $this->get_options();
116
+ $methods = $this->withdraw_methods();
117
 
118
+ foreach ( $methods as $method_id => $method ) {
119
+ $is_enable = (bool) tutor_utils()->avalue_dot( $method_id . '.enabled', $withdraw_options );
120
 
121
+ if ( ! $is_enable ) {
122
+ unset( $methods[ $method_id ] );
123
  }
124
  }
125
 
126
  return $methods;
127
  }
128
 
129
+ public function get_options() {
130
+ return (array) maybe_unserialize( get_option( 'tutor_withdraw_options' ) );
131
  }
132
 
133
+ public function withdraw_admin_options() {
134
+ include tutor()->path . 'views/options/withdraw/withdraw_admin_options_generator.php';
135
  }
136
 
137
 
140
  *
141
  * @since v.1.2.0
142
  */
143
+ public function withdraw_option_save() {
144
+ do_action( 'tutor_withdraw_options_save_before' );
145
 
146
+ $option = (array) isset( $_POST['tutor_withdraw_options'] ) ? tutor_sanitize_data($_POST['tutor_withdraw_options']) : array();
147
+ $option = apply_filters( 'tutor_withdraw_options_input', $option );
148
+ update_option( 'tutor_withdraw_options', $option );
149
 
150
+ do_action( 'tutor_withdraw_options_save_after' );
151
  }
152
 
153
  /**
156
  * @since v.1.2.0
157
  */
158
 
159
+ public function tutor_save_withdraw_account() {
160
+ // Checking nonce
161
  tutor_utils()->checking_nonce();
162
 
163
  $user_id = get_current_user_id();
164
+ $post = tutor_sanitize_data($_POST);
165
 
166
+ $method = tutor_utils()->avalue_dot( 'tutor_selected_withdraw_method', $post );
167
+ if ( ! $method ) {
168
  wp_send_json_error();
169
  }
170
 
171
+ $method_data = tutor_utils()->avalue_dot( 'withdraw_method_field.' . $method, $post );
172
  $available_withdraw_method = tutor_withdrawal_methods();
173
 
174
+ if ( tutor_utils()->count( $method_data ) ) {
175
+ $saved_data = array();
176
+ $saved_data['withdraw_method_key'] = $method;
177
+ $saved_data['withdraw_method_name'] = tutor_utils()->avalue_dot( $method . '.method_name', $available_withdraw_method );
178
 
179
+ foreach ( $method_data as $input_name => $value ) {
180
+ $saved_data[ $input_name ]['value'] = esc_sql( sanitize_text_field( $value ) );
181
+ $saved_data[ $input_name ]['label'] = tutor_utils()->avalue_dot( $method . ".form_fields.{$input_name}.label", $available_withdraw_method );
182
  }
183
 
184
+ update_user_meta( $user_id, '_tutor_withdraw_method_data', $saved_data );
185
  }
186
 
187
+ $msg = apply_filters( 'tutor_withdraw_method_set_success_msg', __( 'Withdrawal account information saved successfully!', 'tutor' ) );
188
+ wp_send_json_success( array( 'msg' => $msg ) );
189
  }
190
 
191
+ public function tutor_make_an_withdraw() {
192
  global $wpdb;
193
 
194
+ // Checking nonce
195
  tutor_utils()->checking_nonce();
196
 
197
+ do_action( 'tutor_withdraw_before' );
 
198
 
199
  $user_id = get_current_user_id();
200
+ $post = tutor_sanitize_data($_POST);
 
 
201
 
202
+ $withdraw_amount = sanitize_text_field( tutor_utils()->avalue_dot( 'tutor_withdraw_amount', $post ) );
 
203
 
204
+ $earning_sum = tutor_utils()->get_earning_sum();
205
+ $min_withdraw = tutor_utils()->get_option( 'min_withdraw_amount' );
 
206
 
207
+ $saved_withdraw_account = tutor_utils()->get_user_withdraw_method();
208
+ $formatted_balance = tutor_utils()->tutor_price( $earning_sum->balance );
209
+ $formatted_min_withdraw_amount = tutor_utils()->tutor_price( $min_withdraw );
210
 
211
+ if ( ! tutor_utils()->count( $saved_withdraw_account ) ) {
212
+ $no_withdraw_method = apply_filters( 'tutor_no_withdraw_method_msg', __( 'Please save withdraw method ', 'tutor' ) );
213
+ wp_send_json_error( array( 'msg' => $no_withdraw_method ) );
214
  }
215
 
216
+ if ( ( ! is_numeric( $withdraw_amount ) && ! is_float( $withdraw_amount ) ) || $withdraw_amount < $min_withdraw ) {
217
+ $required_min_withdraw = apply_filters( 'tutor_required_min_amount_msg', sprintf( __( 'Minimum withdrawal amount is %1$s %2$s %3$s ', 'tutor' ), '<strong>', $formatted_min_withdraw_amount, '</strong>' ) );
218
+ wp_send_json_error( array( 'msg' => $required_min_withdraw ) );
219
  }
220
 
221
+ if ( $earning_sum->balance < $withdraw_amount ) {
222
+ $insufficient_balence = apply_filters( 'tutor_withdraw_insufficient_balance_msg', __( 'Insufficient balance.', 'tutor' ) );
223
 
224
+ wp_send_json_error( array( 'msg' => $insufficient_balence ) );
225
  }
226
 
227
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
228
+
229
+ $withdraw_data = apply_filters(
230
+ 'tutor_pre_withdraw_data',
231
+ array(
232
+ 'user_id' => $user_id,
233
+ 'amount' => $withdraw_amount,
234
+ 'method_data' => maybe_serialize( $saved_withdraw_account ),
235
+ 'status' => 'pending',
236
+ 'created_at' => $date,
237
+ )
238
+ );
239
 
240
+ do_action( 'tutor_insert_withdraw_before', $withdraw_data );
 
 
 
 
 
 
 
 
 
 
241
 
242
+ $wpdb->insert( $wpdb->prefix . 'tutor_withdraws', $withdraw_data );
243
  $withdraw_id = $wpdb->insert_id;
244
 
245
+ do_action( 'tutor_insert_withdraw_after', $withdraw_id, $withdraw_data );
 
246
 
247
  /**
248
  * Getting earning and balance data again
249
  */
250
+ $earning = tutor_utils()->get_earning_sum();
251
+ $new_available_balance = tutor_utils()->tutor_price( $earning->balance );
252
 
253
+ do_action( 'tutor_withdraw_after' );
254
 
255
+ $withdraw_successfull_msg = apply_filters( 'tutor_withdraw_successful_msg', __( 'Withdrawal Request Sent!', 'tutor' ) );
256
+ wp_send_json_success(
257
+ array(
258
+ 'msg' => $withdraw_successfull_msg,
259
+ 'available_balance' => $new_available_balance,
260
+ )
261
+ );
262
  }
263
 
264
 
classes/Withdraw_Requests_List.php CHANGED
@@ -1,121 +1,127 @@
1
  <?php
2
  namespace TUTOR;
3
 
4
- if ( ! defined( 'ABSPATH' ) )
5
  exit;
 
6
 
7
- if (! class_exists('Tutor_List_Table')){
8
- include_once tutor()->path.'classes/Tutor_List_Table.php';
9
  }
10
 
11
  class Withdraw_Requests_List extends \Tutor_List_Table {
12
 
13
  const WITHDRAW_REQUEST_LIST_PAGE = 'tutor_withdraw_requests';
14
 
15
- function __construct(){
16
  global $status, $page;
17
 
18
- //Set parent defaults
19
- parent::__construct( array(
20
- 'singular' => 'withdraw', //singular name of the listed records
21
- 'plural' => 'withdraw', //plural name of the listed records
22
- 'ajax' => false //does this table support ajax?
23
- ) );
 
 
24
 
25
  $this->process_bulk_action();
26
  }
27
 
28
- function column_default($item, $column_name){
29
- switch($column_name){
30
  case 'testing_col':
31
  return $item->$column_name;
32
  default:
33
- return print_r($item,true); //Show the whole array for troubleshooting purposes
34
  }
35
  }
36
 
37
- function column_cb($item){
38
  return sprintf(
39
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
40
- /*$1%s*/ $this->_args['singular'], //Let's simply repurpose the table's singular label ("student")
41
- /*$2%s*/ $item->withdraw_id //The value of the checkbox should be the record's id
42
  );
43
  }
44
 
45
- function column_requested_user($item){
46
- echo "<p>{$item->user_name}</p><p>{$item->user_email}</p>";
47
 
48
  $actions = array();
49
- switch ($item->status){
50
  case 'pending':
51
- $actions['approved'] = sprintf('<a href="?page=%s&action=%s&withdraw_id=%s">'.__('Approve', 'tutor').'</a>',self::WITHDRAW_REQUEST_LIST_PAGE,'approved',
52
- $item->withdraw_id);
53
- $actions['rejected'] = sprintf('<a href="?page=%s&action=%s&withdraw_id=%s">'.__('Rejected', 'tutor').'</a>',self::WITHDRAW_REQUEST_LIST_PAGE,'rejected',$item->withdraw_id);
 
 
 
 
54
  break;
55
  case 'approved':
56
- $actions['rejected'] = sprintf('<a href="?page=%s&action=%s&withdraw_id=%s">'.__('Rejected', 'tutor').'</a>',self::WITHDRAW_REQUEST_LIST_PAGE,'rejected',$item->withdraw_id);
57
  break;
58
  case 'rejected':
59
- $actions['approved'] = sprintf('<a href="?page=%s&action=%s&withdraw_id=%s">'.__('Approve', 'tutor').'</a>',self::WITHDRAW_REQUEST_LIST_PAGE,'approved',$item->withdraw_id);
60
  break;
61
  }
62
 
63
- $actions['delete'] = sprintf('<a href="?page=%s&action=%s&withdraw_id=%s" onclick="return confirm(\'' . __('Are you Sure? It can not be undone.', 'tutor') . '\')">' . __('Delete', 'tutor') . '</a>', self::WITHDRAW_REQUEST_LIST_PAGE, 'delete', $item->withdraw_id);
64
 
65
- return "<div class='withdraw-list-row-actions'>". $this->row_actions($actions)."</div>";
66
  }
67
- function column_withdraw_method($item){
68
- if ($item->method_data){
69
- $data = maybe_unserialize($item->method_data);
70
 
71
- $method_name = tutor_utils()->avalue_dot('withdraw_method_name', $data);
72
 
73
- if ($method_name){
74
- echo "<p><strong>{$method_name}</strong></p>";
75
  }
76
 
77
- unset($data['withdraw_method_key'], $data['withdraw_method_name']);
78
 
79
- if (tutor_utils()->count($data)){
80
- foreach ($data as $method_field){
81
- $label = tutor_utils()->avalue_dot('label', $method_field);
82
- $value = tutor_utils()->avalue_dot('value', $method_field);
83
- echo "<p class='withdraw-method-data-row'> <span class='withdraw-method-label'>{$label}</span> : <span class='withdraw-method-value'>{$value}</span> </p>";
84
  }
85
  }
86
-
87
  }
88
  return '';
89
  }
90
 
91
- function column_requested_at($item){
92
- echo "<p>".date_i18n(get_option('date_format').' '.get_option('time_format'), strtotime($item->created_at))."</p>";
93
  }
94
 
95
- function column_amount($item){
96
  $available_status = array(
97
- 'pending' => __( 'pending', 'tutor' ),
98
- 'approved' => __( 'approved', 'tutor' ),
99
- 'rejected' => __( 'rejected', 'tutor' ),
100
  );
101
- echo "<p>".tutor_utils()->tutor_price($item->amount)."</p>";
102
- echo "<p><span class='withdraw-status withdraw-status-{$item->status}'>".__( isset( $available_status[$item->status] ) ? $available_status[$item->status] : $item->status, 'tutor' )."</span></p>";
103
  }
104
 
105
- function get_columns(){
106
  $columns = array(
107
- 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
108
- 'requested_user' => __('Requested By', 'tutor'),
109
- 'amount' => __('Amount', 'tutor'),
110
- 'withdraw_method' => __('Withdrawal Method', 'tutor'),
111
- 'requested_at' => __('Requested Time', 'tutor'),
112
  );
113
  return $columns;
114
  }
115
 
116
  function get_bulk_actions() {
117
  $actions = array(
118
- //'delete' => 'Delete'
119
  );
120
  return $actions;
121
  }
@@ -123,45 +129,51 @@ class Withdraw_Requests_List extends \Tutor_List_Table {
123
  function process_bulk_action() {
124
  global $wpdb;
125
 
126
- $withdraw_page_url = admin_url('admin.php?page=' . self::WITHDRAW_REQUEST_LIST_PAGE);
127
- $date = date("Y-m-d H:i:s", tutor_time());
128
- $redirect = false;
129
 
130
- //Detect when a bulk action is being triggered...
131
- if( 'delete'===$this->current_action() ) {
132
- $should_withdraw_delete = apply_filters('tutor_should_withdraw_delete', true);
133
 
134
- if ($should_withdraw_delete){
135
- $withdraw_id = (int) sanitize_text_field($_GET['withdraw_id']);
136
 
137
- do_action('tutor_before_delete_withdraw', $withdraw_id);
138
 
139
- $wpdb->delete($wpdb->prefix."tutor_withdraws",array('withdraw_id' =>$withdraw_id));
140
 
141
- do_action('tutor_after_delete_withdraw', $withdraw_id);
142
 
143
  $redirect = true;
144
- }else{
145
- wp_die('Items deleted (or they would be if we had items to delete)!');
146
  }
147
  }
148
 
149
-
150
  /**
151
  * Reject Withdraw
152
  */
153
- if( 'approved' === $this->current_action() ) {
154
- $withdraw_id = (int) sanitize_text_field($_GET['withdraw_id']);
155
- $withdraw = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_withdraws WHERE withdraw_id = %d ", $withdraw_id));
156
- if ( ! $withdraw || $withdraw->status === 'approved'){
157
  return;
158
  }
159
 
160
- do_action('tutor_before_approved_withdraw', $withdraw_id);
161
 
162
- $wpdb->update($wpdb->prefix."tutor_withdraws", array('status' => 'approved', 'updated_at' => $date ), array('withdraw_id' =>$withdraw_id));
 
 
 
 
 
 
 
163
 
164
- do_action('tutor_after_approved_withdraw', $withdraw_id);
165
 
166
  $redirect = true;
167
  }
@@ -169,25 +181,32 @@ class Withdraw_Requests_List extends \Tutor_List_Table {
169
  /**
170
  * Rejected
171
  */
172
- if( 'rejected' === $this->current_action() ) {
173
- $withdraw_id = (int) sanitize_text_field($_GET['withdraw_id']);
174
- $withdraw = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}tutor_withdraws WHERE withdraw_id = %d ", $withdraw_id));
175
- if ( ! $withdraw || $withdraw->status === 'rejected'){
176
  return;
177
  }
178
 
179
- do_action('tutor_before_rejected_withdraw', $withdraw_id);
180
 
181
- $wpdb->update($wpdb->prefix."tutor_withdraws", array('status' => 'rejected', 'updated_at' => $date ), array('withdraw_id' =>$withdraw_id));
 
 
 
 
 
 
 
182
 
183
- do_action('tutor_after_rejected_withdraw', $withdraw_id);
184
 
185
  $redirect = true;
186
  }
187
 
188
-
189
- if ($redirect){
190
- die("<script>location.href='{$withdraw_page_url}';</script>");
191
  }
192
  }
193
 
@@ -195,25 +214,27 @@ class Withdraw_Requests_List extends \Tutor_List_Table {
195
  $per_page = 20;
196
 
197
  $search_term = '';
198
- if (isset($_REQUEST['s'])){
199
- $search_term = sanitize_text_field($_REQUEST['s']);
200
  }
201
 
202
  $columns = $this->get_columns();
203
- $hidden = array();
204
-
205
- $this->_column_headers = array($columns, $hidden);
206
- $current_page = $this->get_pagenum();
207
-
208
- $start = ($current_page-1)*$per_page;
209
- $withdraw_requests = tutor_utils()->get_withdrawals_history(null, compact('start', 'per_page', 'search_term') );
210
- $this->items = $withdraw_requests->results;
211
- $count_result = $withdraw_requests->count;
212
-
213
- $this->set_pagination_args( array(
214
- 'total_items' => $count_result,
215
- 'per_page' => $per_page,
216
- 'total_pages' => ceil($count_result/$per_page)
217
- ) );
 
 
218
  }
219
  }
1
  <?php
2
  namespace TUTOR;
3
 
4
+ if ( ! defined( 'ABSPATH' ) ) {
5
  exit;
6
+ }
7
 
8
+ if ( ! class_exists( 'Tutor_List_Table' ) ) {
9
+ include_once tutor()->path . 'classes/Tutor_List_Table.php';
10
  }
11
 
12
  class Withdraw_Requests_List extends \Tutor_List_Table {
13
 
14
  const WITHDRAW_REQUEST_LIST_PAGE = 'tutor_withdraw_requests';
15
 
16
+ function __construct() {
17
  global $status, $page;
18
 
19
+ // Set parent defaults
20
+ parent::__construct(
21
+ array(
22
+ 'singular' => 'withdraw', // singular name of the listed records
23
+ 'plural' => 'withdraw', // plural name of the listed records
24
+ 'ajax' => false, // does this table support ajax?
25
+ )
26
+ );
27
 
28
  $this->process_bulk_action();
29
  }
30
 
31
+ function column_default( $item, $column_name ) {
32
+ switch ( $column_name ) {
33
  case 'testing_col':
34
  return $item->$column_name;
35
  default:
36
+ return print_r( $item, true ); // Show the whole array for troubleshooting purposes
37
  }
38
  }
39
 
40
+ function column_cb( $item ) {
41
  return sprintf(
42
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
43
+ /*$1%s*/ $this->_args['singular'], // Let's simply repurpose the table's singular label ("student")
44
+ /*$2%s*/ $item->withdraw_id // The value of the checkbox should be the record's id
45
  );
46
  }
47
 
48
+ function column_requested_user( $item ) {
49
+ echo '<p>' . $item->user_name . '</p><p>' . $item->user_email . '</p>';
50
 
51
  $actions = array();
52
+ switch ( $item->status ) {
53
  case 'pending':
54
+ $actions['approved'] = sprintf(
55
+ '<a href="?page=%s&action=%s&withdraw_id=%s">' . __( 'Approve', 'tutor' ) . '</a>',
56
+ self::WITHDRAW_REQUEST_LIST_PAGE,
57
+ 'approved',
58
+ $item->withdraw_id
59
+ );
60
+ $actions['rejected'] = sprintf( '<a href="?page=%s&action=%s&withdraw_id=%s">' . __( 'Rejected', 'tutor' ) . '</a>', self::WITHDRAW_REQUEST_LIST_PAGE, 'rejected', $item->withdraw_id );
61
  break;
62
  case 'approved':
63
+ $actions['rejected'] = sprintf( '<a href="?page=%s&action=%s&withdraw_id=%s">' . __( 'Rejected', 'tutor' ) . '</a>', self::WITHDRAW_REQUEST_LIST_PAGE, 'rejected', $item->withdraw_id );
64
  break;
65
  case 'rejected':
66
+ $actions['approved'] = sprintf( '<a href="?page=%s&action=%s&withdraw_id=%s">' . __( 'Approve', 'tutor' ) . '</a>', self::WITHDRAW_REQUEST_LIST_PAGE, 'approved', $item->withdraw_id );
67
  break;
68
  }
69
 
70
+ $actions['delete'] = sprintf( '<a href="?page=%s&action=%s&withdraw_id=%s" onclick="return confirm(\'' . __( 'Are you Sure? It can not be undone.', 'tutor' ) . '\')">' . __( 'Delete', 'tutor' ) . '</a>', self::WITHDRAW_REQUEST_LIST_PAGE, 'delete', $item->withdraw_id );
71
 
72
+ return '<div class="withdraw-list-row-actions">' . $this->row_actions( $actions ) . '</div>';
73
  }
74
+ function column_withdraw_method( $item ) {
75
+ if ( $item->method_data ) {
76
+ $data = maybe_unserialize( $item->method_data );
77
 
78
+ $method_name = tutor_utils()->avalue_dot( 'withdraw_method_name', $data );
79
 
80
+ if ( $method_name ) {
81
+ echo '<p><strong>' . $method_name . '</strong></p>';
82
  }
83
 
84
+ unset( $data['withdraw_method_key'], $data['withdraw_method_name'] );
85
 
86
+ if ( tutor_utils()->count( $data ) ) {
87
+ foreach ( $data as $method_field ) {
88
+ $label = tutor_utils()->avalue_dot( 'label', $method_field );
89
+ $value = tutor_utils()->avalue_dot( 'value', $method_field );
90
+ echo '<p class="withdraw-method-data-row"> <span class="withdraw-method-label">' . $label . '</span> : <span class="withdraw-method-value">' . $value . '</span> </p>';
91
  }
92
  }
 
93
  }
94
  return '';
95
  }
96
 
97
+ function column_requested_at( $item ) {
98
+ echo '<p>' . date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item->created_at ) ) . '</p>';
99
  }
100
 
101
+ function column_amount( $item ) {
102
  $available_status = array(
103
+ 'pending' => __( 'pending', 'tutor' ),
104
+ 'approved' => __( 'approved', 'tutor' ),
105
+ 'rejected' => __( 'rejected', 'tutor' ),
106
  );
107
+ echo '<p>' . tutor_utils()->tutor_price( $item->amount ) . '</p>';
108
+ echo '<p="withdraw-status withdraw-status-' . $item->status . '">' . __( isset( $available_status[ $item->status ] ) ? $available_status[ $item->status ] : $item->status, 'tutor' ) . '</span></p>';
109
  }
110
 
111
+ function get_columns() {
112
  $columns = array(
113
+ 'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
114
+ 'requested_user' => __( 'Requested By', 'tutor' ),
115
+ 'amount' => __( 'Amount', 'tutor' ),
116
+ 'withdraw_method' => __( 'Withdrawal Method', 'tutor' ),
117
+ 'requested_at' => __( 'Requested Time', 'tutor' ),
118
  );
119
  return $columns;
120
  }
121
 
122
  function get_bulk_actions() {
123
  $actions = array(
124
+ // 'delete' => 'Delete'
125
  );
126
  return $actions;
127
  }
129
  function process_bulk_action() {
130
  global $wpdb;
131
 
132
+ $withdraw_page_url = admin_url( 'admin.php?page=' . self::WITHDRAW_REQUEST_LIST_PAGE );
133
+ $date = date( 'Y-m-d H:i:s', tutor_time() );
134
+ $redirect = false;
135
 
136
+ // Detect when a bulk action is being triggered...
137
+ if ( 'delete' === $this->current_action() ) {
138
+ $should_withdraw_delete = apply_filters( 'tutor_should_withdraw_delete', true );
139
 
140
+ if ( $should_withdraw_delete ) {
141
+ $withdraw_id = (int) sanitize_text_field( $_GET['withdraw_id'] );
142
 
143
+ do_action( 'tutor_before_delete_withdraw', $withdraw_id );
144
 
145
+ $wpdb->delete( $wpdb->prefix . 'tutor_withdraws', array( 'withdraw_id' => $withdraw_id ) );
146
 
147
+ do_action( 'tutor_after_delete_withdraw', $withdraw_id );
148
 
149
  $redirect = true;
150
+ } else {
151
+ wp_die( 'Items deleted (or they would be if we had items to delete)!' );
152
  }
153
  }
154
 
 
155
  /**
156
  * Reject Withdraw
157
  */
158
+ if ( 'approved' === $this->current_action() ) {
159
+ $withdraw_id = (int) sanitize_text_field( $_GET['withdraw_id'] );
160
+ $withdraw = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_withdraws WHERE withdraw_id = %d ", $withdraw_id ) );
161
+ if ( ! $withdraw || $withdraw->status === 'approved' ) {
162
  return;
163
  }
164
 
165
+ do_action( 'tutor_before_approved_withdraw', $withdraw_id );
166
 
167
+ $wpdb->update(
168
+ $wpdb->prefix . 'tutor_withdraws',
169
+ array(
170
+ 'status' => 'approved',
171
+ 'updated_at' => $date,
172
+ ),
173
+ array( 'withdraw_id' => $withdraw_id )
174
+ );
175
 
176
+ do_action( 'tutor_after_approved_withdraw', $withdraw_id );
177
 
178
  $redirect = true;
179
  }
181
  /**
182
  * Rejected
183
  */
184
+ if ( 'rejected' === $this->current_action() ) {
185
+ $withdraw_id = (int) sanitize_text_field( $_GET['withdraw_id'] );
186
+ $withdraw = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}tutor_withdraws WHERE withdraw_id = %d ", $withdraw_id ) );
187
+ if ( ! $withdraw || $withdraw->status === 'rejected' ) {
188
  return;
189
  }
190
 
191
+ do_action( 'tutor_before_rejected_withdraw', $withdraw_id );
192
 
193
+ $wpdb->update(
194
+ $wpdb->prefix . 'tutor_withdraws',
195
+ array(
196
+ 'status' => 'rejected',
197
+ 'updated_at' => $date,
198
+ ),
199
+ array( 'withdraw_id' => $withdraw_id )
200
+ );
201
 
202
+ do_action( 'tutor_after_rejected_withdraw', $withdraw_id );
203
 
204
  $redirect = true;
205
  }
206
 
207
+ if($this->current_action()) {
208
+ wp_redirect( $withdraw_page_url );
209
+ exit;
210
  }
211
  }
212
 
214
  $per_page = 20;
215
 
216
  $search_term = '';
217
+ if ( isset( $_REQUEST['s'] ) ) {
218
+ $search_term = sanitize_text_field( $_REQUEST['s'] );
219
  }
220
 
221
  $columns = $this->get_columns();
222
+ $hidden = array();
223
+
224
+ $this->_column_headers = array( $columns, $hidden );
225
+ $current_page = $this->get_pagenum();
226
+
227
+ $start = ( $current_page - 1 ) * $per_page;
228
+ $withdraw_requests = tutor_utils()->get_withdrawals_history( null, compact( 'start', 'per_page', 'search_term' ) );
229
+ $this->items = $withdraw_requests->results;
230
+ $count_result = $withdraw_requests->count;
231
+
232
+ $this->set_pagination_args(
233
+ array(
234
+ 'total_items' => $count_result,
235
+ 'per_page' => $per_page,
236
+ 'total_pages' => ceil( $count_result / $per_page ),
237
+ )
238
+ );
239
  }
240
  }
classes/WooCommerce.php CHANGED
@@ -9,81 +9,85 @@
9
 
10
  namespace TUTOR;
11
 
12
- if (!defined('ABSPATH'))
13
  exit;
 
14
 
15
  class WooCommerce extends Tutor_Base {
16
 
17
  public function __construct() {
18
  parent::__construct();
19
 
20
- add_action('tutor_options_before_woocommerce', array($this, 'notice_before_option'));
21
 
22
- //Add option settings
23
- add_filter('tutor_monetization_options', array($this, 'tutor_monetization_options'));
24
- add_filter('tutor/options/attr', array($this, 'add_options'));
25
 
26
- $monetize_by = tutils()->get_option('monetize_by');
27
- if ($monetize_by !== 'wc') {
28
  return;
29
  }
30
 
31
  /**
32
  * Is Course Purchasable
33
  */
34
- add_filter('is_course_purchasable', array($this, 'is_course_purchasable'), 10, 2);
35
- add_filter('get_tutor_course_price', array($this, 'get_tutor_course_price'), 10, 2);
36
- add_filter('tutor_course_sell_by', array($this, 'tutor_course_sell_by'));
37
 
38
- add_filter('product_type_options', array($this, 'add_tutor_type_in_wc_product'));
39
 
40
- add_action('add_meta_boxes', array($this, 'register_meta_box'));
41
- add_action('save_post_' . $this->course_post_type, array($this, 'save_course_meta'));
42
- add_action('save_post_product', array($this, 'save_wc_product_meta'));
43
 
44
- add_action('tutor_course/single/before/enroll', 'wc_print_notices');
45
 
46
  /**
47
  * After place new order
48
  */
49
- add_action('woocommerce_new_order', array($this, 'course_placing_order_from_admin'), 10, 3);
50
- add_action('woocommerce_new_order_item', array($this, 'course_placing_order_from_customer'), 10, 3);
51
 
52
  /**
53
  * Order Status Hook
54
  *
55
  * Remove course from active courses if an order is cancelled or refunded
56
  */
57
- add_action('woocommerce_order_status_changed', array($this, 'enrolled_courses_status_change'), 10, 3);
58
 
59
  /**
60
  * Add Earning Data
61
  */
62
- add_action('woocommerce_new_order_item', array($this, 'add_earning_data'), 10, 3);
63
- add_action('woocommerce_order_status_changed', array($this, 'add_earning_data_status_change'), 10, 3);
64
 
65
  /**
66
  * WC Print Notices After Enroll
 
67
  * @since v.1.3.5
68
  */
69
- if (tutils()->has_wc()) {
70
- add_action('tutor_course/single/before/inner-wrap', 'wc_print_notices', 10);
71
- add_action('tutor_course/single/enrolled/before/inner-wrap', 'wc_print_notices', 10);
72
  }
73
 
74
  /**
75
  * Manage WooCommerce plugin dependency
 
76
  * @since v.1.7.8
77
  */
78
- $woocommerce_path = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'woocommerce' . DIRECTORY_SEPARATOR . 'woocommerce.php';
79
- register_deactivation_hook( $woocommerce_path, array($this, 'disable_tutor_monetization') );
80
  /**
81
- * Redirect student on enrolled courses after course
82
  * enrollment complete
 
83
  * @since 1.9.0
84
- */
85
- add_action( 'woocommerce_thankyou', array($this, 'redirect_to_enrolled_courses') );
86
-
87
  /**
88
  * Change woo commerce cart product link if it is tutor product
89
  */
@@ -92,7 +96,7 @@ class WooCommerce extends Tutor_Base {
92
 
93
  public function notice_before_option() {
94
  $has_wc = tutor_utils()->has_wc();
95
- if ($has_wc) {
96
  return;
97
  }
98
 
@@ -100,42 +104,47 @@ class WooCommerce extends Tutor_Base {
100
  ?>
101
  <div class="tutor-notice-warning">
102
  <p>
103
- <?php _e(' Seems like you don’t have WooCommerce plugin installed on your site. In order to use this functionality, you need to have the
104
- WooCommerce plugin installed. Get back on this page after installing the plugin and enable the following feature to start selling
105
- courses with Tutor.', 'tutor'); ?>
 
 
 
 
 
106
  </p>
107
- <p><?php _e('This notice will disappear after activating <strong>WooCommerce</strong>', 'tutor'); ?></p>
108
  </div>
109
  <?php
110
  echo ob_get_clean();
111
  }
112
 
113
- public function is_course_purchasable($bool, $course_id) {
114
- if (!tutor_utils()->has_wc()) {
115
  return false;
116
  }
117
 
118
- $course_id = tutor_utils()->get_post_id($course_id);
119
- $has_product_id = get_post_meta($course_id, '_tutor_course_product_id', true);
120
- if ($has_product_id) {
121
  return true;
122
  }
123
  return false;
124
  }
125
 
126
- public function get_tutor_course_price($price, $course_id) {
127
  $price = null;
128
 
129
- if (tutor_utils()->is_course_purchasable($course_id)) {
130
- if (tutor_utils()->has_wc()) {
131
- $product_id = tutor_utils()->get_course_product_id($course_id);
132
- $product = wc_get_product($product_id);
133
 
134
- if ($product) {
135
  ob_start();
136
  ?>
137
  <div class="price">
138
- <?php echo $product->get_price_html(); ?>
139
  </div>
140
  <?php
141
  return ob_get_clean();
@@ -150,12 +159,12 @@ class WooCommerce extends Tutor_Base {
150
  return 'woocommerce';
151
  }
152
 
153
- public function add_tutor_type_in_wc_product($types) {
154
- $types['tutor_product'] = array(
155
  'id' => '_tutor_product',
156
  'wrapper_class' => 'show_if_simple',
157
- 'label' => __('For Tutor', 'tutor'),
158
- 'description' => __('This checkmark ensure that you will sell a specif course via this product.', 'tutor'),
159
  'default' => 'no',
160
  );
161
 
@@ -163,11 +172,11 @@ class WooCommerce extends Tutor_Base {
163
  }
164
 
165
  public function register_meta_box() {
166
- add_meta_box('tutor-attach-product', __('Add Product', 'tutor'), array($this, 'course_add_product_metabox'), $this->course_post_type, 'advanced', 'high');
167
  }
168
 
169
  public function course_add_product_metabox() {
170
- include tutor()->path . 'views/metabox/course-add-product-metabox.php';
171
  }
172
 
173
  /**
@@ -175,25 +184,25 @@ class WooCommerce extends Tutor_Base {
175
  *
176
  * Save course meta for attaching product
177
  */
178
- public function save_course_meta($post_ID) {
179
- $product_id = (int)sanitize_text_field( tutor_utils()->avalue_dot('_tutor_course_product_id', $_POST, 0) ) ;
180
-
181
- if ($product_id === -1) {
182
- delete_post_meta($post_ID, '_tutor_course_product_id');
183
- } else if ($product_id) {
184
- update_post_meta($post_ID, '_tutor_course_product_id', $product_id);
185
- //Mark product for woocommerce
186
- update_post_meta($product_id, '_virtual', 'yes');
187
- update_post_meta($product_id, '_tutor_product', 'yes');
188
  }
189
  }
190
 
191
- public function save_wc_product_meta($post_ID) {
192
- $is_tutor_product = sanitize_text_field( tutor_utils()->avalue_dot('_tutor_product', $_POST) );
193
- if ($is_tutor_product === 'on') {
194
- update_post_meta($post_ID, '_tutor_product', 'yes');
195
  } else {
196
- delete_post_meta($post_ID, '_tutor_product');
197
  }
198
  }
199
 
@@ -201,27 +210,27 @@ class WooCommerce extends Tutor_Base {
201
  *
202
  * Take enrolled course action based on order status change
203
  */
204
- public function enrolled_courses_status_change($order_id, $status_from, $status_to) {
205
- if (!tutor_utils()->is_tutor_order($order_id)) {
206
  return;
207
  }
208
  global $wpdb;
209
 
210
- $enrolled_ids_with_course = $this->get_course_enrolled_ids_by_order_id($order_id);
211
 
212
- if ($enrolled_ids_with_course) {
213
- $enrolled_ids = wp_list_pluck($enrolled_ids_with_course, 'enrolled_id');
214
 
215
- if (is_array($enrolled_ids) && count($enrolled_ids)) {
216
- foreach ($enrolled_ids as $enrolled_id) {
217
 
218
- tutils()->course_enrol_status_change($enrolled_id, $status_to);
219
 
220
  // Invoke enrolled hook
221
- if($status_to == 'completed'){
222
- $user_id = get_post_field('post_author', $enrolled_id);
223
- $course_id = get_post_field('post_parent', $enrolled_id);
224
- do_action('tutor_after_enrolled', $course_id, $user_id, $enrolled_id);
225
  }
226
  }
227
  }
@@ -233,18 +242,22 @@ class WooCommerce extends Tutor_Base {
233
  *
234
  * @return array|bool
235
  */
236
- public function get_course_enrolled_ids_by_order_id($order_id) {
237
  global $wpdb;
238
- //Getting all of courses ids within this order
239
 
240
- $courses_ids = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE '_tutor_order_for_course_id_%' ", $order_id));
241
 
242
- if (is_array($courses_ids) && count($courses_ids)) {
243
  $course_enrolled_by_order = array();
244
- foreach ($courses_ids as $courses_id) {
245
- $course_id = str_replace('_tutor_order_for_course_id_', '', $courses_id->meta_key);
246
- //array(order_id => array('course_id' => $course_id, 'enrolled_id' => enrolled_id, 'order_id' => $courses_id->post_id))
247
- $course_enrolled_by_order[] = array('course_id' => $course_id, 'enrolled_id' => $courses_id->meta_value, 'order_id' => $courses_id->post_id);
 
 
 
 
248
  }
249
  return $course_enrolled_by_order;
250
  }
@@ -256,11 +269,11 @@ class WooCommerce extends Tutor_Base {
256
  *
257
  * TODO: right now it's unused
258
  */
259
- public function remove_active_course($order_id) {
260
  global $wpdb;
261
- //Getting all of courses ids within this order
262
 
263
- $courses_ids = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d meta_key LIKE '_tutor_order_for_course_id_%' ", $order_id));
264
  }
265
 
266
 
@@ -271,27 +284,28 @@ class WooCommerce extends Tutor_Base {
271
  *
272
  * Add option for WooCommerce settings
273
  */
274
- public function add_options($attr) {
275
 
276
  $attr['woocommerce'] = array(
277
- 'label' => __('WooCommerce', 'tutor'),
278
 
279
- 'sections' => array(
280
  'general' => array(
281
- 'label' => __('General', 'tutor'),
282
- 'desc' => __('WooCommerce Settings', 'tutor'),
283
  'fields' => array(
284
- /*'enable_course_sell_by_woocommerce' => array(
 
285
  'type' => 'checkbox',
286
  'label' => __('Enable / Disable', 'tutor'),
287
  'label_title' => __('Enable WooComerce to sell course', 'tutor'),
288
  'desc' => __('By integrating WooCommerce, you can sell your course', 'tutor'),
289
  ),*/
290
  'enable_guest_course_cart' => array(
291
- 'type' => 'checkbox',
292
- 'label' => __('Enable / Disable', 'tutor'),
293
- 'label_title' => __('Enable add to cart feature for guest users', 'tutor'),
294
- 'desc' => __('Enabling this will let an unregistered user purchase any course from the Course Details page. Head over to Documentation to know how to configure this setting.', 'tutor'),
295
  ),
296
  ),
297
  ),
@@ -310,10 +324,10 @@ class WooCommerce extends Tutor_Base {
310
  *
311
  * @since v.1.3.5
312
  */
313
- public function tutor_monetization_options($arr) {
314
  $has_wc = tutils()->has_wc();
315
- if ($has_wc) {
316
- $arr['wc'] = __('WooCommerce', 'tutor');
317
  }
318
  return $arr;
319
  }
@@ -327,59 +341,62 @@ class WooCommerce extends Tutor_Base {
327
  *
328
  * @since v.1.1.2
329
  */
330
- public function add_earning_data($item_id, $item, $order_id) {
331
  global $wpdb;
332
- $item = new \WC_Order_Item_Product($item);
333
 
334
- $product_id = $item->get_product_id();
335
- $if_has_course = tutor_utils()->product_belongs_with_course($product_id);
336
 
337
- if ($if_has_course) {
338
 
339
- $enable_tutor_earning = tutor_utils()->get_option('enable_tutor_earning');
340
- if (!$enable_tutor_earning) {
341
  return;
342
  }
343
 
344
- $course_id = $if_has_course->post_id;
345
- $user_id = $wpdb->get_var($wpdb->prepare("SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $course_id));
346
- $order_status = $wpdb->get_var($wpdb->prepare("SELECT post_status from {$wpdb->posts} where ID = %d ", $order_id));
347
 
348
  /**
349
  * Return here if already added this product from this order
 
350
  * @since v1.9.7
351
  */
352
- $exist_count = (int)$wpdb->get_var($wpdb->prepare(
353
- "SELECT COUNT(earning_id)
354
- FROM {$wpdb->prefix}tutor_earnings
355
- WHERE course_id=%d
356
- AND order_id=%d
 
357
  AND user_id=%d",
358
- $course_id,
359
- $order_id,
360
- $user_id
361
- ));
 
362
 
363
- if($exist_count>0) {
364
  return;
365
  }
366
 
367
  $total_price = $item->get_total();
368
 
369
- $fees_deduct_data = array();
370
- $tutor_earning_fees = tutor_utils()->get_option('tutor_earning_fees');
371
- $enable_fees_deducting = tutor_utils()->avalue_dot('enable_fees_deducting', $tutor_earning_fees);
372
 
373
  $course_price_grand_total = $total_price;
374
 
375
- if ($enable_fees_deducting) {
376
- $fees_name = tutor_utils()->avalue_dot('fees_name', $tutor_earning_fees);
377
- $fees_amount = (int) tutor_utils()->avalue_dot('fees_amount', $tutor_earning_fees);
378
- $fees_type = tutor_utils()->avalue_dot('fees_type', $tutor_earning_fees);
379
 
380
- if ($fees_amount > 0) {
381
- if ($fees_type === 'percent') {
382
- $fees_amount = ($total_price * $fees_amount) / 100;
383
  }
384
 
385
  /*
@@ -391,23 +408,23 @@ class WooCommerce extends Tutor_Base {
391
  }
392
 
393
  $fees_deduct_data = array(
394
- 'deduct_fees_amount' => $fees_amount,
395
- 'deduct_fees_name' => $fees_name,
396
- 'deduct_fees_type' => $fees_type,
397
  );
398
  }
399
 
400
- $instructor_rate = tutor_utils()->get_option('earning_instructor_commission');
401
- $admin_rate = tutor_utils()->get_option('earning_admin_commission');
402
 
403
  $instructor_amount = 0;
404
- if ($instructor_rate > 0) {
405
- $instructor_amount = ($course_price_grand_total * $instructor_rate) / 100;
406
  }
407
 
408
  $admin_amount = 0;
409
- if ($admin_rate > 0) {
410
- $admin_amount = ($course_price_grand_total * $admin_rate) / 100;
411
  }
412
 
413
  $commission_type = 'percent';
@@ -415,39 +432,39 @@ class WooCommerce extends Tutor_Base {
415
  // (Use Pro Filter - Start)
416
  // The response must be same array structure.
417
  // Do not change used variable names here, or change in both of here and pro plugin
418
- $pro_arg = [
419
- 'user_id' => $user_id,
420
- 'instructor_rate' => $instructor_rate,
421
- 'admin_rate' => $admin_rate,
422
- 'instructor_amount' => $instructor_amount,
423
- 'admin_amount' => $admin_amount,
424
- 'course_price_grand_total' => $course_price_grand_total,
425
- 'commission_type' => $commission_type
426
- ];
427
- $pro_calculation = apply_filters('tutor_pro_earning_calculator', $pro_arg);
428
- extract($pro_calculation);
429
- // (Use Pro Filter - End)
430
 
431
  $earning_data = array(
432
- 'user_id' => $user_id,
433
- 'course_id' => $course_id,
434
- 'order_id' => $order_id,
435
- 'order_status' => $order_status,
436
- 'course_price_total' => $total_price,
437
- 'course_price_grand_total' => $course_price_grand_total,
438
-
439
- 'instructor_amount' => $instructor_amount,
440
- 'instructor_rate' => $instructor_rate,
441
- 'admin_amount' => $admin_amount,
442
- 'admin_rate' => $admin_rate,
443
-
444
- 'commission_type' => $commission_type,
445
- 'process_by' => 'woocommerce',
446
- 'created_at' => date('Y-m-d H:i:s', tutor_time()),
447
  );
448
- $earning_data = apply_filters('tutor_new_earning_data', array_merge($earning_data, $fees_deduct_data));
449
 
450
- $wpdb->insert($wpdb->prefix . 'tutor_earnings', $earning_data);
451
  }
452
  }
453
 
@@ -460,37 +477,37 @@ class WooCommerce extends Tutor_Base {
460
  *
461
  * @since v.1.1.2
462
  */
463
- public function add_earning_data_status_change($order_id, $status_from, $status_to) {
464
- if (!tutor_utils()->is_tutor_order($order_id)) {
465
  return;
466
  }
467
  global $wpdb;
468
 
469
- $is_earning_data = (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(earning_id) FROM {$wpdb->prefix}tutor_earnings WHERE order_id = %d ", $order_id));
470
- if ($is_earning_data) {
471
- $wpdb->update($wpdb->prefix . 'tutor_earnings', array('order_status' => $status_to), array('order_id' => $order_id));
472
  }
473
  }
474
 
475
  /**
476
  * Course placing order from admin
477
- *
478
  * @param $order_id
479
  * @since v.1.6.7
480
  */
481
- public function course_placing_order_from_admin($order_id) {
482
- if (!is_admin()) {
483
  return;
484
  }
485
-
486
  $order = wc_get_order( $order_id );
487
- foreach ($order->get_items() as $item) {
488
- $product_id = $item->get_product_id();
489
- $if_has_course = tutor_utils()->product_belongs_with_course($product_id);
490
- if ($if_has_course) {
491
- $course_id = $if_has_course->post_id;
492
  $customer_id = $order->get_customer_id();
493
- tutor_utils()->do_enroll($course_id, $order_id, $customer_id);
494
  }
495
  }
496
  }
@@ -501,92 +518,97 @@ class WooCommerce extends Tutor_Base {
501
  * @param $order_id
502
  * @since v.1.6.7
503
  */
504
- public function course_placing_order_from_customer($item_id, $item, $order_id) {
505
- if (is_admin()) {
506
  return;
507
  }
508
 
509
- $item = new \WC_Order_Item_Product($item);
510
- $product_id = $item->get_product_id();
511
- $if_has_course = tutor_utils()->product_belongs_with_course($product_id);
512
 
513
- if ($if_has_course){
514
  $course_id = $if_has_course->post_id;
515
- tutor_utils()->do_enroll($course_id, $order_id);
516
  }
517
  }
518
 
519
  /**
520
  * Disable course monetization on woocommerce deactivation
 
521
  * @since v.1.7.8
522
  */
523
  public function disable_tutor_monetization() {
524
- tutils()->update_option('monetize_by', 'free');
525
- update_option('tutor_show_woocommerce_notice', true);
526
  }
527
 
528
  /**
529
- * Redirect student on enrolled courses after course
530
  * enrollment complete if course is purchasable
 
531
  * @param $order_id | int
532
  * @since 1.9.0
533
- */
534
  public function redirect_to_enrolled_courses( $order_id ) {
535
- if(!tutils()->get_option( 'wc_automatic_order_complete_redirect_to_courses' )) {
536
- // Since 1.9.1
537
- return;
538
- }
539
 
540
- //get woo order details
541
- $order = wc_get_order( $order_id );
542
- $tutor_product = false;
543
- $url = tutor_utils()->tutor_dashboard_url().'enrolled-courses/';
544
- foreach ($order->get_items() as $item) {
545
- $product_id = $item->get_product_id();
546
- //check if product associated with tutor course
547
- $if_has_course = tutor_utils()->product_belongs_with_course($product_id);
548
- if( $if_has_course ) {
549
- $tutor_product = true;
550
- }
551
  }
552
- //if tutor product & order status completed
553
- if ( $order->has_status( 'completed' ) && $tutor_product ) {
554
- wp_safe_redirect( $url );
555
- exit;
556
- }
 
557
  }
558
 
559
  /**
560
  * Change product url on cart page if product is tutor course
561
- *
562
  * @since 1.9.8
563
  */
564
  function tutor_update_product_url( $permalink, $cart_item ) {
565
 
566
- $woo_product_id = $cart_item['product_id'];
567
- $product_meta = get_post_meta( $woo_product_id );
568
 
569
- if( isset( $product_meta['_tutor_product'] ) && $product_meta['_tutor_product'][0] ) {
570
 
571
- global $wpdb;
572
- $table = $wpdb->base_prefix . 'postmeta';
573
- $post_id = $wpdb->get_var($wpdb->prepare("SELECT post_id FROM {$table} WHERE meta_key = '_tutor_course_product_id' AND meta_value = %d ", $woo_product_id));
574
 
575
- if( $post_id ) {
576
- $data = get_post_permalink( $post_id );
577
- return $data;
578
  }
579
  }
580
  }
581
  }
582
 
583
 
584
- add_action('admin_notices', function() {
 
 
585
 
586
- $show = get_option( 'tutor_show_woocommerce_notice' ) && tutils()->get_option('monetize_by', 'free')=='free';
587
 
588
- if($show) {
589
- $message = __('Since WooCommerce is disabled, your monetized courses have been set to free. Please make sure to enable Tutor LMS monetization if you decide to re-enable WooCommerce.', 'tutor');
590
- echo '<div class="notice notice-error"><p>' . $message . '</p></div>';
 
591
  }
592
- });
9
 
10
  namespace TUTOR;
11
 
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
  exit;
14
+ }
15
 
16
  class WooCommerce extends Tutor_Base {
17
 
18
  public function __construct() {
19
  parent::__construct();
20
 
21
+ add_action( 'tutor_options_before_woocommerce', array( $this, 'notice_before_option' ) );
22
 
23
+ // Add option settings
24
+ add_filter( 'tutor_monetization_options', array( $this, 'tutor_monetization_options' ) );
25
+ add_filter( 'tutor/options/attr', array( $this, 'add_options' ) );
26
 
27
+ $monetize_by = tutils()->get_option( 'monetize_by' );
28
+ if ( $monetize_by !== 'wc' ) {
29
  return;
30
  }
31
 
32
  /**
33
  * Is Course Purchasable
34
  */
35
+ add_filter( 'is_course_purchasable', array( $this, 'is_course_purchasable' ), 10, 2 );
36
+ add_filter( 'get_tutor_course_price', array( $this, 'get_tutor_course_price' ), 10, 2 );
37
+ add_filter( 'tutor_course_sell_by', array( $this, 'tutor_course_sell_by' ) );
38
 
39
+ add_filter( 'product_type_options', array( $this, 'add_tutor_type_in_wc_product' ) );
40
 
41
+ add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ) );
42
+ add_action( 'save_post_' . $this->course_post_type, array( $this, 'save_course_meta' ) );
43
+ add_action( 'save_post_product', array( $this, 'save_wc_product_meta' ) );
44
 
45
+ add_action( 'tutor_course/single/before/enroll', 'wc_print_notices' );
46
 
47
  /**
48
  * After place new order
49
  */
50
+ add_action( 'woocommerce_new_order', array( $this, 'course_placing_order_from_admin' ), 10, 3 );
51
+ add_action( 'woocommerce_new_order_item', array( $this, 'course_placing_order_from_customer' ), 10, 3 );
52
 
53
  /**
54
  * Order Status Hook
55
  *
56
  * Remove course from active courses if an order is cancelled or refunded
57
  */
58
+ add_action( 'woocommerce_order_status_changed', array( $this, 'enrolled_courses_status_change' ), 10, 3 );
59
 
60
  /**
61
  * Add Earning Data
62
  */
63
+ add_action( 'woocommerce_new_order_item', array( $this, 'add_earning_data' ), 10, 3 );
64
+ add_action( 'woocommerce_order_status_changed', array( $this, 'add_earning_data_status_change' ), 10, 3 );
65
 
66
  /**
67
  * WC Print Notices After Enroll
68
+ *
69
  * @since v.1.3.5
70
  */
71
+ if ( tutils()->has_wc() ) {
72
+ add_action( 'tutor_course/single/before/inner-wrap', 'wc_print_notices', 10 );
73
+ add_action( 'tutor_course/single/enrolled/before/inner-wrap', 'wc_print_notices', 10 );
74
  }
75
 
76
  /**
77
  * Manage WooCommerce plugin dependency
78
+ *
79
  * @since v.1.7.8
80
  */
81
+ $woocommerce_path = dirname( dirname( __DIR__ ) ) . DIRECTORY_SEPARATOR . 'woocommerce' . DIRECTORY_SEPARATOR . 'woocommerce.php';
82
+ register_deactivation_hook( $woocommerce_path, array( $this, 'disable_tutor_monetization' ) );
83
  /**
84
+ * Redirect student on enrolled courses after course
85
  * enrollment complete
86
+ *
87
  * @since 1.9.0
88
+ */
89
+ add_action( 'woocommerce_thankyou', array( $this, 'redirect_to_enrolled_courses' ) );
90
+
91
  /**
92
  * Change woo commerce cart product link if it is tutor product
93
  */
96
 
97
  public function notice_before_option() {
98
  $has_wc = tutor_utils()->has_wc();
99
+ if ( $has_wc ) {
100
  return;
101
  }
102
 
104
  ?>
105
  <div class="tutor-notice-warning">
106
  <p>
107
+ <?php
108
+ _e(
109
+ ' Seems like you don’t have WooCommerce plugin installed on your site. In order to use this functionality, you need to have the
110
+ WooCommerce plugin installed. Get back on this page after installing the plugin and enable the following feature to start selling
111
+ courses with Tutor.',
112
+ 'tutor'
113
+ );
114
+ ?>
115
  </p>
116
+ <p><?php _e( 'This notice will disappear after activating <strong>WooCommerce</strong>', 'tutor' ); ?></p>
117
  </div>
118
  <?php
119
  echo ob_get_clean();
120
  }
121
 
122
+ public function is_course_purchasable( $bool, $course_id ) {
123
+ if ( ! tutor_utils()->has_wc() ) {
124
  return false;
125
  }
126
 
127
+ $course_id = tutor_utils()->get_post_id( $course_id );
128
+ $has_product_id = get_post_meta( $course_id, '_tutor_course_product_id', true );
129
+ if ( $has_product_id ) {
130
  return true;
131
  }
132
  return false;
133
  }
134
 
135
+ public function get_tutor_course_price( $price, $course_id ) {
136
  $price = null;
137
 
138
+ if ( tutor_utils()->is_course_purchasable( $course_id ) ) {
139
+ if ( tutor_utils()->has_wc() ) {
140
+ $product_id = tutor_utils()->get_course_product_id( $course_id );
141
+ $product = wc_get_product( $product_id );
142
 
143
+ if ( $product ) {
144
  ob_start();
145
  ?>
146
  <div class="price">
147
+ <?php echo $product->get_price_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
148
  </div>
149
  <?php
150
  return ob_get_clean();
159
  return 'woocommerce';
160
  }
161
 
162
+ public function add_tutor_type_in_wc_product( $types ) {
163
+ $types['tutor_product'] = array(
164
  'id' => '_tutor_product',
165
  'wrapper_class' => 'show_if_simple',
166
+ 'label' => __( 'For Tutor', 'tutor' ),
167
+ 'description' => __( 'This checkmark ensure that you will sell a specif course via this product.', 'tutor' ),
168
  'default' => 'no',
169
  );
170
 
172
  }
173
 
174
  public function register_meta_box() {
175
+ add_meta_box( 'tutor-attach-product', __( 'Add Product', 'tutor' ), array( $this, 'course_add_product_metabox' ), $this->course_post_type, 'advanced', 'high' );
176
  }
177
 
178
  public function course_add_product_metabox() {
179
+ include tutor()->path . 'views/metabox/course-add-product-metabox.php';
180
  }
181
 
182
  /**
184
  *
185
  * Save course meta for attaching product
186
  */
187
+ public function save_course_meta( $post_ID ) {
188
+ $product_id = (int) sanitize_text_field( tutor_utils()->avalue_dot( '_tutor_course_product_id', $_POST, 0 ) );
189
+
190
+ if ( $product_id === -1 ) {
191
+ delete_post_meta( $post_ID, '_tutor_course_product_id' );
192
+ } elseif ( $product_id ) {
193
+ update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
194
+ // Mark product for woocommerce
195
+ update_post_meta( $product_id, '_virtual', 'yes' );
196
+ update_post_meta( $product_id, '_tutor_product', 'yes' );
197
  }
198
  }
199
 
200
+ public function save_wc_product_meta( $post_ID ) {
201
+ $is_tutor_product = sanitize_text_field( tutor_utils()->avalue_dot( '_tutor_product', $_POST ) );
202
+ if ( $is_tutor_product === 'on' ) {
203
+ update_post_meta( $post_ID, '_tutor_product', 'yes' );
204
  } else {
205
+ delete_post_meta( $post_ID, '_tutor_product' );
206
  }
207
  }
208
 
210
  *
211
  * Take enrolled course action based on order status change
212
  */
213
+ public function enrolled_courses_status_change( $order_id, $status_from, $status_to ) {
214
+ if ( ! tutor_utils()->is_tutor_order( $order_id ) ) {
215
  return;
216
  }
217
  global $wpdb;
218
 
219
+ $enrolled_ids_with_course = $this->get_course_enrolled_ids_by_order_id( $order_id );
220
 
221
+ if ( $enrolled_ids_with_course ) {
222
+ $enrolled_ids = wp_list_pluck( $enrolled_ids_with_course, 'enrolled_id' );
223
 
224
+ if ( is_array( $enrolled_ids ) && count( $enrolled_ids ) ) {
225
+ foreach ( $enrolled_ids as $enrolled_id ) {
226
 
227
+ tutils()->course_enrol_status_change( $enrolled_id, $status_to );
228
 
229
  // Invoke enrolled hook
230
+ if ( $status_to == 'completed' ) {
231
+ $user_id = get_post_field( 'post_author', $enrolled_id );
232
+ $course_id = get_post_field( 'post_parent', $enrolled_id );
233
+ do_action( 'tutor_after_enrolled', $course_id, $user_id, $enrolled_id );
234
  }
235
  }
236
  }
242
  *
243
  * @return array|bool
244
  */
245
+ public function get_course_enrolled_ids_by_order_id( $order_id ) {
246
  global $wpdb;
247
+ // Getting all of courses ids within this order
248
 
249
+ $courses_ids = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE '_tutor_order_for_course_id_%' ", $order_id ) );
250
 
251
+ if ( is_array( $courses_ids ) && count( $courses_ids ) ) {
252
  $course_enrolled_by_order = array();
253
+ foreach ( $courses_ids as $courses_id ) {
254
+ $course_id = str_replace( '_tutor_order_for_course_id_', '', $courses_id->meta_key );
255
+ // array(order_id => array('course_id' => $course_id, 'enrolled_id' => enrolled_id, 'order_id' => $courses_id->post_id))
256
+ $course_enrolled_by_order[] = array(
257
+ 'course_id' => $course_id,
258
+ 'enrolled_id' => $courses_id->meta_value,
259
+ 'order_id' => $courses_id->post_id,
260
+ );
261
  }
262
  return $course_enrolled_by_order;
263
  }
269
  *
270
  * TODO: right now it's unused
271
  */
272
+ public function remove_active_course( $order_id ) {
273
  global $wpdb;
274
+ // Getting all of courses ids within this order
275
 
276
+ $courses_ids = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE post_id = %d meta_key LIKE '_tutor_order_for_course_id_%' ", $order_id ) );
277
  }
278
 
279
 
284
  *
285
  * Add option for WooCommerce settings
286
  */
287
+ public function add_options( $attr ) {
288
 
289
  $attr['woocommerce'] = array(
290
+ 'label' => __( 'WooCommerce', 'tutor' ),
291
 
292
+ 'sections' => array(
293
  'general' => array(
294
+ 'label' => __( 'General', 'tutor' ),
295
+ 'desc' => __( 'WooCommerce Settings', 'tutor' ),
296
  'fields' => array(
297
+ /*
298
+ 'enable_course_sell_by_woocommerce' => array(
299
  'type' => 'checkbox',
300
  'label' => __('Enable / Disable', 'tutor'),
301
  'label_title' => __('Enable WooComerce to sell course', 'tutor'),
302
  'desc' => __('By integrating WooCommerce, you can sell your course', 'tutor'),
303
  ),*/
304
  'enable_guest_course_cart' => array(
305
+ 'type' => 'checkbox',
306
+ 'label' => __( 'Enable / Disable', 'tutor' ),
307
+ 'label_title' => __( 'Enable add to cart feature for guest users', 'tutor' ),
308
+ 'desc' => __( 'Enabling this will let an unregistered user purchase any course from the Course Details page. Head over to Documentation to know how to configure this setting.', 'tutor' ),
309
  ),
310
  ),
311
  ),
324
  *
325
  * @since v.1.3.5
326
  */
327
+ public function tutor_monetization_options( $arr ) {
328
  $has_wc = tutils()->has_wc();
329
+ if ( $has_wc ) {
330
+ $arr['wc'] = __( 'WooCommerce', 'tutor' );
331
  }
332
  return $arr;
333
  }
341
  *
342
  * @since v.1.1.2
343
  */
344
+ public function add_earning_data( $item_id, $item, $order_id ) {
345
  global $wpdb;
346
+ $item = new \WC_Order_Item_Product( $item );
347
 
348
+ $product_id = $item->get_product_id();
349
+ $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
350
 
351
+ if ( $if_has_course ) {
352
 
353
+ $enable_tutor_earning = tutor_utils()->get_option( 'enable_tutor_earning' );
354
+ if ( ! $enable_tutor_earning ) {
355
  return;
356
  }
357
 
358
+ $course_id = $if_has_course->post_id;
359
+ $user_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $course_id ) );
360
+ $order_status = $wpdb->get_var( $wpdb->prepare( "SELECT post_status from {$wpdb->posts} where ID = %d ", $order_id ) );
361
 
362
  /**
363
  * Return here if already added this product from this order
364
+ *
365
  * @since v1.9.7
366
  */
367
+ $exist_count = (int) $wpdb->get_var(
368
+ $wpdb->prepare(
369
+ "SELECT COUNT(earning_id)
370
+ FROM {$wpdb->prefix}tutor_earnings
371
+ WHERE course_id=%d
372
+ AND order_id=%d
373
  AND user_id=%d",
374
+ $course_id,
375
+ $order_id,
376
+ $user_id
377
+ )
378
+ );
379
 
380
+ if ( $exist_count > 0 ) {
381
  return;
382
  }
383
 
384
  $total_price = $item->get_total();
385
 
386
+ $fees_deduct_data = array();
387
+ $tutor_earning_fees = tutor_utils()->get_option( 'tutor_earning_fees' );
388
+ $enable_fees_deducting = tutor_utils()->avalue_dot( 'enable_fees_deducting', $tutor_earning_fees );
389
 
390
  $course_price_grand_total = $total_price;
391
 
392
+ if ( $enable_fees_deducting ) {
393
+ $fees_name = tutor_utils()->avalue_dot( 'fees_name', $tutor_earning_fees );
394
+ $fees_amount = (int) tutor_utils()->avalue_dot( 'fees_amount', $tutor_earning_fees );
395
+ $fees_type = tutor_utils()->avalue_dot( 'fees_type', $tutor_earning_fees );
396
 
397
+ if ( $fees_amount > 0 ) {
398
+ if ( $fees_type === 'percent' ) {
399
+ $fees_amount = ( $total_price * $fees_amount ) / 100;
400
  }
401
 
402
  /*
408
  }
409
 
410
  $fees_deduct_data = array(
411
+ 'deduct_fees_amount' => $fees_amount,
412
+ 'deduct_fees_name' => $fees_name,
413
+ 'deduct_fees_type' => $fees_type,
414
  );
415
  }
416
 
417
+ $instructor_rate = tutor_utils()->get_option( 'earning_instructor_commission' );
418
+ $admin_rate = tutor_utils()->get_option( 'earning_admin_commission' );
419
 
420
  $instructor_amount = 0;
421
+ if ( $instructor_rate > 0 ) {
422
+ $instructor_amount = ( $course_price_grand_total * $instructor_rate ) / 100;
423
  }
424
 
425
  $admin_amount = 0;
426
+ if ( $admin_rate > 0 ) {
427
+ $admin_amount = ( $course_price_grand_total * $admin_rate ) / 100;
428
  }
429
 
430
  $commission_type = 'percent';
432
  // (Use Pro Filter - Start)
433
  // The response must be same array structure.
434
  // Do not change used variable names here, or change in both of here and pro plugin
435
+ $pro_arg = array(
436
+ 'user_id' => $user_id,
437
+ 'instructor_rate' => $instructor_rate,
438
+ 'admin_rate' => $admin_rate,
439
+ 'instructor_amount' => $instructor_amount,
440
+ 'admin_amount' => $admin_amount,
441
+ 'course_price_grand_total' => $course_price_grand_total,
442
+ 'commission_type' => $commission_type,
443
+ );
444
+ $pro_calculation = apply_filters( 'tutor_pro_earning_calculator', $pro_arg );
445
+ extract( $pro_calculation );
446
+ // (Use Pro Filter - End)
447
 
448
  $earning_data = array(
449
+ 'user_id' => $user_id,
450
+ 'course_id' => $course_id,
451
+ 'order_id' => $order_id,
452
+ 'order_status' => $order_status,
453
+ 'course_price_total' => $total_price,
454
+ 'course_price_grand_total' => $course_price_grand_total,
455
+
456
+ 'instructor_amount' => $instructor_amount,
457
+ 'instructor_rate' => $instructor_rate,
458
+ 'admin_amount' => $admin_amount,
459
+ 'admin_rate' => $admin_rate,
460
+
461
+ 'commission_type' => $commission_type,
462
+ 'process_by' => 'woocommerce',
463
+ 'created_at' => date( 'Y-m-d H:i:s', tutor_time() ),
464
  );
465
+ $earning_data = apply_filters( 'tutor_new_earning_data', array_merge( $earning_data, $fees_deduct_data ) );
466
 
467
+ $wpdb->insert( $wpdb->prefix . 'tutor_earnings', $earning_data );
468
  }
469
  }
470
 
477
  *
478
  * @since v.1.1.2
479
  */
480
+ public function add_earning_data_status_change( $order_id, $status_from, $status_to ) {
481
+ if ( ! tutor_utils()->is_tutor_order( $order_id ) ) {
482
  return;
483
  }
484
  global $wpdb;
485
 
486
+ $is_earning_data = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(earning_id) FROM {$wpdb->prefix}tutor_earnings WHERE order_id = %d ", $order_id ) );
487
+ if ( $is_earning_data ) {
488
+ $wpdb->update( $wpdb->prefix . 'tutor_earnings', array( 'order_status' => $status_to ), array( 'order_id' => $order_id ) );
489
  }
490
  }
491
 
492
  /**
493
  * Course placing order from admin
494
+ *
495
  * @param $order_id
496
  * @since v.1.6.7
497
  */
498
+ public function course_placing_order_from_admin( $order_id ) {
499
+ if ( ! is_admin() ) {
500
  return;
501
  }
502
+
503
  $order = wc_get_order( $order_id );
504
+ foreach ( $order->get_items() as $item ) {
505
+ $product_id = $item->get_product_id();
506
+ $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
507
+ if ( $if_has_course ) {
508
+ $course_id = $if_has_course->post_id;
509
  $customer_id = $order->get_customer_id();
510
+ tutor_utils()->do_enroll( $course_id, $order_id, $customer_id );
511
  }
512
  }
513
  }
518
  * @param $order_id
519
  * @since v.1.6.7
520
  */
521
+ public function course_placing_order_from_customer( $item_id, $item, $order_id ) {
522
+ if ( is_admin() ) {
523
  return;
524
  }
525
 
526
+ $item = new \WC_Order_Item_Product( $item );
527
+ $product_id = $item->get_product_id();
528
+ $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
529
 
530
+ if ( $if_has_course ) {
531
  $course_id = $if_has_course->post_id;
532
+ tutor_utils()->do_enroll( $course_id, $order_id );
533
  }
534
  }
535
 
536
  /**
537
  * Disable course monetization on woocommerce deactivation
538
+ *
539
  * @since v.1.7.8
540
  */
541
  public function disable_tutor_monetization() {
542
+ tutils()->update_option( 'monetize_by', 'free' );
543
+ update_option( 'tutor_show_woocommerce_notice', true );
544
  }
545
 
546
  /**
547
+ * Redirect student on enrolled courses after course
548
  * enrollment complete if course is purchasable
549
+ *
550
  * @param $order_id | int
551
  * @since 1.9.0
552
+ */
553
  public function redirect_to_enrolled_courses( $order_id ) {
554
+ if ( ! tutils()->get_option( 'wc_automatic_order_complete_redirect_to_courses' ) ) {
555
+ // Since 1.9.1
556
+ return;
557
+ }
558
 
559
+ // get woo order details
560
+ $order = wc_get_order( $order_id );
561
+ $tutor_product = false;
562
+ $url = tutor_utils()->tutor_dashboard_url() . 'enrolled-courses/';
563
+ foreach ( $order->get_items() as $item ) {
564
+ $product_id = $item->get_product_id();
565
+ // check if product associated with tutor course
566
+ $if_has_course = tutor_utils()->product_belongs_with_course( $product_id );
567
+ if ( $if_has_course ) {
568
+ $tutor_product = true;
 
569
  }
570
+ }
571
+ // if tutor product & order status completed
572
+ if ( $order->has_status( 'completed' ) && $tutor_product ) {
573
+ wp_safe_redirect( $url );
574
+ exit;
575
+ }
576
  }
577
 
578
  /**
579
  * Change product url on cart page if product is tutor course
580
+ *
581
  * @since 1.9.8
582
  */
583
  function tutor_update_product_url( $permalink, $cart_item ) {
584
 
585
+ $woo_product_id = $cart_item['product_id'];
586
+ $product_meta = get_post_meta( $woo_product_id );
587
 
588
+ if ( isset( $product_meta['_tutor_product'] ) && $product_meta['_tutor_product'][0] ) {
589
 
590
+ global $wpdb;
591
+ $table = $wpdb->base_prefix . 'postmeta';
592
+ $post_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$table} WHERE meta_key = '_tutor_course_product_id' AND meta_value = %d ", $woo_product_id ) );
593
 
594
+ if ( $post_id ) {
595
+ $data = get_post_permalink( $post_id );
596
+ return $data;
597
  }
598
  }
599
  }
600
  }
601
 
602
 
603
+ add_action(
604
+ 'admin_notices',
605
+ function() {
606
 
607
+ $show = get_option( 'tutor_show_woocommerce_notice' ) && tutils()->get_option( 'monetize_by', 'free' ) == 'free';
608
 
609
+ if ( $show ) {
610
+ $message = __( 'Since WooCommerce is disabled, your monetized courses have been set to free. Please make sure to enable Tutor LMS monetization if you decide to re-enable WooCommerce.', 'tutor' );
611
+ echo '<div class="notice notice-error"><p>' . $message . '</p></div>';
612
+ }
613
  }
614
+ );
includes/tinymce_translate.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  /**
3
  * Add translation support for external tinyMCE button
4
- *
5
  * Containing all translate able strings
6
- *
7
  * @since 1.9.7
8
  */
9
  if ( ! defined( 'ABSPATH' ) )
@@ -33,4 +33,5 @@ function tutor_tinymce_plugin_translation() {
33
  return $translated;
34
  }
35
 
36
- $strings = tutor_tinymce_plugin_translation();
 
1
  <?php
2
  /**
3
  * Add translation support for external tinyMCE button
4
+ *
5
  * Containing all translate able strings
6
+ *
7
  * @since 1.9.7
8
  */
9
  if ( ! defined( 'ABSPATH' ) )
33
  return $translated;
34
  }
35
 
36
+ $strings = tutor_tinymce_plugin_translation();
37
+
includes/tutor-general-functions.php CHANGED
@@ -1,12 +1,71 @@
1
  <?php
2
- if (!defined('ABSPATH'))
3
  exit;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  /**
6
  * Tutor general Functions
7
  */
8
 
9
- if (!function_exists('tutor_withdrawal_methods')) {
10
  function tutor_withdrawal_methods() {
11
  $withdraw = new \TUTOR\Withdraw();
12
 
@@ -22,7 +81,7 @@ if (!function_exists('tutor_withdrawal_methods')) {
22
  * @since v.1.5.7
23
  */
24
 
25
- if (!function_exists('get_tutor_all_withdrawal_methods')) {
26
  function get_tutor_all_withdrawal_methods() {
27
  $withdraw = new \TUTOR\Withdraw();
28
 
@@ -30,10 +89,10 @@ if (!function_exists('get_tutor_all_withdrawal_methods')) {
30
  }
31
  }
32
 
33
- if (!function_exists('tutor_placeholder_img_src')) {
34
  function tutor_placeholder_img_src() {
35
  $src = tutor()->url . 'assets/images/placeholder.jpg';
36
- return apply_filters('tutor_placeholder_img_src', $src);
37
  }
38
  }
39
 
@@ -45,38 +104,38 @@ if (!function_exists('tutor_placeholder_img_src')) {
45
  * @since v.1.3.4
46
  */
47
 
48
- if (!function_exists('tutor_course_categories_dropdown')) {
49
- function tutor_course_categories_dropdown($post_ID = 0, $args = array()) {
50
 
51
  $default = array(
52
  'classes' => '',
53
- 'name' => 'tax_input[course-category]',
54
  'multiple' => true,
55
  );
56
 
57
- $args = apply_filters('tutor_course_categories_dropdown_args', array_merge($default, $args));
58
 
59
  $multiple_select = '';
60
 
61
- if (tutor_utils()->array_get('multiple', $args)) {
62
- if (isset($args['name'])) {
63
  $args['name'] = $args['name'] . '[]';
64
  }
65
  $multiple_select = "multiple='multiple'";
66
  }
67
 
68
- extract($args);
69
 
70
  $classes = (array) $classes;
71
- $classes = implode(' ', $classes);
72
 
73
  $categories = tutor_utils()->get_course_categories();
74
 
75
- $output = '';
76
- $output .= "<select name='{$name}' {$multiple_select} class='{$classes}' data-placeholder='" . __('Search Course Category. ex. Design, Development, Business', 'tutor') . "'>";
77
- $output .= "<option value=''>" . __('Select a category', 'tutor') . "</option>";
78
- $output .= _generate_categories_dropdown_option($post_ID, $categories, $args);
79
- $output .= "</select>";
80
 
81
  return $output;
82
  }
@@ -90,38 +149,38 @@ if (!function_exists('tutor_course_categories_dropdown')) {
90
  * @since v.1.3.4
91
  */
92
 
93
- if (!function_exists('tutor_course_tags_dropdown')) {
94
- function tutor_course_tags_dropdown($post_ID = 0, $args = array()) {
95
 
96
  $default = array(
97
  'classes' => '',
98
- 'name' => 'tax_input[course-tag]',
99
  'multiple' => true,
100
  );
101
 
102
- $args = apply_filters('tutor_course_tags_dropdown_args', array_merge($default, $args));
103
 
104
  $multiple_select = '';
105
 
106
- if (tutor_utils()->array_get('multiple', $args)) {
107
- if (isset($args['name'])) {
108
  $args['name'] = $args['name'] . '[]';
109
  }
110
  $multiple_select = "multiple='multiple'";
111
  }
112
 
113
- extract($args);
114
 
115
  $classes = (array) $classes;
116
- $classes = implode(' ', $classes);
117
 
118
  $tags = tutor_utils()->get_course_tags();
119
 
120
- $output = '';
121
- $output .= "<select name='{$name}' {$multiple_select} class='{$classes}' data-placeholder='" . __('Search Course Tags. ex. Design, Development, Business', 'tutor') . "'>";
122
- $output .= "<option value=''>" . __('Select a tag', 'tutor') . "</option>";
123
- $output .= _generate_tags_dropdown_option($post_ID, $tags, $args);
124
- $output .= "</select>";
125
 
126
  return $output;
127
  }
@@ -138,32 +197,38 @@ if (!function_exists('tutor_course_tags_dropdown')) {
138
  * @since v.1.3.4
139
  */
140
 
141
- if (!function_exists('_generate_categories_dropdown_option')) {
142
- function _generate_categories_dropdown_option($post_ID = 0, $categories = array(), $args = array(), $depth = 0) {
143
  $output = '';
144
 
145
- if (!tutor_utils()->count($categories)) return $output;
 
 
146
 
147
- if (!is_numeric($post_ID) || $post_ID < 1) return $output;
 
 
148
 
149
- foreach ($categories as $category_id => $category) {
150
- if (!$category->parent) $depth = 0;
 
 
151
 
152
- $childrens = tutor_utils()->array_get('children', $category);
153
- $has_in_term = has_term($category->term_id, 'course-category', $post_ID);
154
 
155
  $depth_seperator = '';
156
- if ($depth) {
157
- for ($depth_i = 0; $depth_i < $depth; $depth_i++) {
158
  $depth_seperator .= '-';
159
  }
160
  }
161
 
162
- $output .= "<option value='{$category->term_id}' " . selected($has_in_term, true, false) . " > {$depth_seperator} {$category->name}</option> ";
163
 
164
- if (tutor_utils()->count($childrens)) {
165
  $depth++;
166
- $output .= _generate_categories_dropdown_option($post_ID, $childrens, $args, $depth);
167
  }
168
  }
169
 
@@ -181,19 +246,23 @@ if (!function_exists('_generate_categories_dropdown_option')) {
181
  * @since v.1.3.4
182
  */
183
 
184
- if (!function_exists('_generate_tags_dropdown_option')) {
185
- function _generate_tags_dropdown_option($post_ID = 0, $tags = array(), $args = array(), $depth = 0) {
186
  $output = '';
187
 
188
- if (!tutor_utils()->count($tags)) return $output;
 
 
189
 
190
- if (!is_numeric($post_ID) || $post_ID < 1) return $output;
 
 
191
 
192
- foreach ($tags as $tag) {
193
 
194
- $has_in_term = has_term($tag->term_id, 'course-tag', $post_ID);
195
 
196
- $output .= "<option value='{$tag->name}' " . selected($has_in_term, true, false) . ">{$tag->name}</option> ";
197
 
198
  }
199
 
@@ -207,26 +276,26 @@ if (!function_exists('_generate_tags_dropdown_option')) {
207
  * @return string
208
  *
209
  * Generate course categories checkbox
210
- * @since v.1.3.4
211
  */
212
 
213
- if (!function_exists('tutor_course_categories_checkbox')) {
214
- function tutor_course_categories_checkbox($post_ID = 0, $args = array()) {
215
  $default = array(
216
- 'name' => 'tax_input[course-category]',
217
  );
218
 
219
- $args = apply_filters('tutor_course_categories_checkbox_args', array_merge($default, $args));
220
 
221
- if (isset($args['name'])) {
222
  $args['name'] = $args['name'] . '[]';
223
  }
224
 
225
- extract($args);
226
 
227
  $categories = tutor_utils()->get_course_categories();
228
- $output = '';
229
- $output .= __tutor_generate_categories_checkbox($post_ID, $categories, $args);
230
 
231
  return $output;
232
  }
@@ -238,26 +307,26 @@ if (!function_exists('tutor_course_categories_checkbox')) {
238
  * @return string
239
  *
240
  * Generate course tags checkbox
241
- * @since v.1.3.4
242
  */
243
 
244
- if (!function_exists('tutor_course_tags_checkbox')) {
245
- function tutor_course_tags_checkbox($post_ID = 0, $args = array()) {
246
  $default = array(
247
- 'name' => 'tax_input[course-tag]',
248
  );
249
 
250
- $args = apply_filters('tutor_course_tags_checkbox_args', array_merge($default, $args));
251
 
252
- if (isset($args['name'])) {
253
  $args['name'] = $args['name'] . '[]';
254
  }
255
 
256
- extract($args);
257
 
258
- $tags = tutor_utils()->get_course_tags();
259
- $output = '';
260
- $output .= __tutor_generate_tags_checkbox($post_ID, $tags, $args);
261
 
262
  return $output;
263
  }
@@ -274,28 +343,28 @@ if (!function_exists('tutor_course_tags_checkbox')) {
274
  *
275
  * @since v.1.3.4
276
  */
277
- if ( ! function_exists('__tutor_generate_categories_checkbox')){
278
- function __tutor_generate_categories_checkbox($post_ID = 0, $categories=array(), $args = array()){
279
-
280
- $output = '';
281
- $input_name = tutor_utils()->array_get('name', $args);
282
 
283
- if (tutor_utils()->count($categories)) {
284
- $output .= "<ul class='tax-input-course-category'>";
285
- foreach ($categories as $category_id => $category) {
286
- $childrens = tutor_utils()->array_get('children', $category);
287
- $has_in_term = has_term($category->term_id, 'course-category', $post_ID);
288
 
289
- $output .= "<li class='tax-input-course-category-item tax-input-course-category-item-{$category->term_id} '><label class='course-category-checkbox'> <input type='checkbox' name='{$input_name}' value='{$category->term_id}' " . checked($has_in_term, true, false) . " /> <span>{$category->name}</span> </label>";
 
 
 
 
290
 
291
- if (tutor_utils()->count($childrens)) {
292
- $output .= __tutor_generate_categories_checkbox($post_ID, $childrens, $args);
 
 
293
  }
294
- $output .= " </li>";
295
  }
296
- $output .= "</ul>";
297
  }
298
-
299
  return $output;
300
 
301
  }
@@ -311,22 +380,22 @@ if ( ! function_exists('__tutor_generate_categories_checkbox')){
311
  *
312
  * @since v.1.3.4
313
  */
314
- if (!function_exists('__tutor_generate_tags_checkbox')) {
315
- function __tutor_generate_tags_checkbox($post_ID = 0, $tags = array(), $args = array()) {
316
 
317
- $output = '';
318
- $input_name = tutor_utils()->array_get('name', $args);
319
 
320
- if (tutor_utils()->count($tags)) {
321
- $output .= "<ul class='tax-input-course-tag'>";
322
- foreach ($tags as $tag) {
323
- $has_in_term = has_term($tag->term_id, 'course-tag', $post_ID);
324
 
325
- $output .= "<li class='tax-input-course-tag-item tax-input-course-tag-item-{$tag->term_id} '><label class='course-tag-checkbox'> <input type='checkbox' name='{$input_name}' value='{$tag->term_id}' " . checked($has_in_term, true, false) . " /> <span>{$tag->name}</span> </label>";
326
 
327
- $output .= " </li>";
328
  }
329
- $output .= "</ul>";
330
  }
331
 
332
  return $output;
@@ -344,23 +413,23 @@ if (!function_exists('__tutor_generate_tags_checkbox')) {
344
  * @since v.1.3.4
345
  */
346
 
347
- if (!function_exists('course_builder_section_wrap')) {
348
- function course_builder_section_wrap($content = '', $title = '', $echo = true) {
349
  ob_start();
350
- ?>
351
  <div class="tutor-course-builder-section">
352
  <div class="tutor-course-builder-section-title">
353
  <h3><i class="tutor-icon-down"></i> <span><?php echo $title; ?></span></h3>
354
  </div>
355
  <div class="tutor-course-builder-section-content">
356
- <?php echo $content; ?>
357
  </div>
358
  </div>
359
  <?php
360
  $html = ob_get_clean();
361
 
362
- if ($echo) {
363
- echo $html;
364
  } else {
365
  return $html;
366
  }
@@ -368,48 +437,48 @@ if (!function_exists('course_builder_section_wrap')) {
368
  }
369
 
370
 
371
- if (!function_exists('get_tutor_header')) {
372
- function get_tutor_header($fullScreen = false) {
373
- $enable_spotlight_mode = tutor_utils()->get_option('enable_spotlight_mode');
374
 
375
- if ($enable_spotlight_mode || $fullScreen) {
376
- ?>
377
  <!doctype html>
378
  <html <?php language_attributes(); ?>>
379
 
380
  <head>
381
- <meta charset="<?php bloginfo('charset'); ?>" />
382
  <meta name="viewport" content="width=device-width, initial-scale=1" />
383
  <link rel="profile" href="https://gmpg.org/xfn/11" />
384
- <?php wp_head(); ?>
385
  </head>
386
 
387
  <body <?php body_class(); ?>>
388
  <div id="tutor-page-wrap" class="tutor-site-wrap site">
389
- <?php
390
- } else {
391
- get_header();
392
- }
393
  }
394
  }
 
395
 
396
- if (!function_exists('get_tutor_footer')) {
397
- function get_tutor_footer($fullScreen = false) {
398
- $enable_spotlight_mode = tutor_utils()->get_option('enable_spotlight_mode');
399
- if ($enable_spotlight_mode || $fullScreen) {
400
- ?>
401
  </div>
402
- <?php wp_footer(); ?>
403
 
404
  </body>
405
 
406
  </html>
407
- <?php
408
- } else {
409
- get_footer();
410
- }
411
  }
412
  }
 
413
 
414
  /**
415
  * @param null $key
@@ -421,11 +490,11 @@ if (!function_exists('get_tutor_header')) {
421
  *
422
  * @since v.1.3.6
423
  */
424
- if (!function_exists('get_tutor_option')) {
425
- function get_tutor_option($key = null, $default = false) {
426
- return tutils()->get_option($key, $default);
427
- }
428
  }
 
429
 
430
  /**
431
  * @param null $key
@@ -435,11 +504,11 @@ if (!function_exists('get_tutor_header')) {
435
  *
436
  * @since v.1.3.6
437
  */
438
- if (!function_exists('update_tutor_option')) {
439
- function update_tutor_option($key = null, $value = false) {
440
- tutils()->update_option($key, $value);
441
- }
442
  }
 
443
  /**
444
  * @param int $course_id
445
  * @param null $key
@@ -451,11 +520,11 @@ if (!function_exists('get_tutor_header')) {
451
  *
452
  * @since v.1.4.1
453
  */
454
- if (!function_exists('get_tutor_course_settings')) {
455
- function get_tutor_course_settings($course_id = 0, $key = null, $default = false) {
456
- return tutils()->get_course_settings($course_id, $key, $default);
457
- }
458
  }
 
459
 
460
  /**
461
  * @param int $lesson_id
@@ -467,11 +536,11 @@ if (!function_exists('get_tutor_header')) {
467
  * Get lesson content drip settings
468
  */
469
 
470
- if (!function_exists('get_item_content_drip_settings')) {
471
- function get_item_content_drip_settings($lesson_id = 0, $key = null, $default = false) {
472
- return tutils()->get_item_content_drip_settings($lesson_id, $key, $default);
473
- }
474
  }
 
475
 
476
  /**
477
  * @param null $msg
@@ -484,38 +553,39 @@ if (!function_exists('get_tutor_header')) {
484
  *
485
  * @since v.1.4.1
486
  */
487
- if (!function_exists('tutor_alert')) {
488
- function tutor_alert($msg = null, $type = 'warning', $echo = true) {
489
- if (!$msg) {
490
-
491
- if ($type === 'any') {
492
- if (!$msg) {
493
- $type = 'warning';
494
- $msg = tutor_flash_get($type);
495
- }
496
- if (!$msg) {
497
- $type = 'danger';
498
- $msg = tutor_flash_get($type);
499
- }
500
- if (!$msg) {
501
- $type = 'success';
502
- $msg = tutor_flash_get($type);
503
- }
504
- } else {
505
- $msg = tutor_flash_get($type);
506
  }
 
 
 
 
 
 
 
 
 
 
507
  }
508
- if (!$msg) {
509
- return $msg;
510
- }
 
511
 
512
- $html = "<div class='tutor-alert tutor-alert-{$type}'>{$msg}</div>";
513
- if ($echo) {
514
- echo $html;
515
- }
516
- return $html;
517
  }
 
518
  }
 
519
 
520
 
521
  /**
@@ -526,11 +596,11 @@ if (!function_exists('get_tutor_header')) {
526
  * @since v.1.4.2
527
  */
528
 
529
- if (!function_exists('tutor_nonce_field')) {
530
- function tutor_nonce_field($echo = true) {
531
- wp_nonce_field(tutor()->nonce_action, tutor()->nonce, $echo);
532
- }
533
  }
 
534
 
535
  /**
536
  * @param null $key
@@ -539,18 +609,18 @@ if (!function_exists('get_tutor_header')) {
539
  * Set Flash Message
540
  */
541
 
542
- if (!function_exists('tutor_flash_set')) {
543
- function tutor_flash_set($key = null, $message = '') {
544
- if (!$key) {
545
- return;
546
- }
547
- // ensure session is started
548
- if (session_status() !== PHP_SESSION_ACTIVE) {
549
- session_start();
550
- }
551
- $_SESSION[$key] = $message;
552
  }
 
553
  }
 
554
 
555
  /**
556
  * @param null $key
@@ -562,42 +632,42 @@ if (!function_exists('get_tutor_header')) {
562
  * Get flash message
563
  */
564
 
565
- if (!function_exists('tutor_flash_get')) {
566
- function tutor_flash_get($key = null) {
567
- if ($key) {
568
- // ensure session is started
569
- if (session_status() !== PHP_SESSION_ACTIVE) {
570
- @session_start();
571
- }
572
- if (empty($_SESSION)) {
573
- return null;
574
- }
575
- $message = tutils()->array_get($key, $_SESSION);
576
- if ($message) {
577
- unset($_SESSION[$key]);
578
- }
579
- return $message;
580
  }
581
- return $key;
 
 
 
 
582
  }
 
583
  }
 
584
 
585
- if (!function_exists('tutor_redirect_back')) {
586
- /**
587
- * @param null $url
588
- *
589
- * Redirect to back or a specific URL and terminate
590
- *
591
- * @since v.1.4.3
592
- */
593
- function tutor_redirect_back($url = null) {
594
- if (!$url) {
595
- $url = tutils()->referer();
596
- }
597
- wp_safe_redirect($url);
598
- exit();
599
  }
 
 
600
  }
 
601
 
602
  /**
603
  * @param string $action
@@ -608,35 +678,35 @@ if (!function_exists('get_tutor_header')) {
608
  * @since v.1.4.3
609
  */
610
 
611
- if (!function_exists('tutor_action_field')) {
612
- function tutor_action_field($action = '', $echo = true) {
613
- $output = '';
614
- if ($action) {
615
- $output = "<input type='hidden' name='tutor_action' value='{$action}'>";
616
- }
617
 
618
- if ($echo) {
619
- echo $output;
620
- } else {
621
- return $output;
622
- }
623
  }
624
  }
 
625
 
626
  /**
627
  * @return int|string
628
  *
629
- * Return current Time from wordpress time
630
  *
631
  * @since v.1.4.3
632
  */
633
 
634
- if (!function_exists('tutor_time')) {
635
- function tutor_time() {
636
- //return current_time( 'timestamp' );
637
- return time() + (get_option('gmt_offset') * HOUR_IN_SECONDS);
638
- }
639
  }
 
640
 
641
  /**
642
  * Toggle maintenance mode for the site.
@@ -649,23 +719,23 @@ if (!function_exists('get_tutor_header')) {
649
  *
650
  * @param bool $enable True to enable maintenance mode, false to disable.
651
  */
652
- if (!function_exists('tutor_maintenance_mode')) {
653
- function tutor_maintenance_mode($enable = false) {
654
- $file = ABSPATH . '.tutor_maintenance';
655
- if ($enable) {
656
- // Create maintenance file to signal that we are upgrading
657
- $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
658
-
659
- if (!file_exists($file)) {
660
- file_put_contents($file, $maintenance_string);
661
- }
662
- } else {
663
- if (file_exists($file)) {
664
- unlink($file);
665
- }
666
  }
667
  }
668
  }
 
669
 
670
  /**
671
  * @return bool
@@ -675,41 +745,41 @@ if (!function_exists('get_tutor_header')) {
675
  * @since v.1.6.0
676
  */
677
 
678
- if (!function_exists('is_single_course')) {
679
- function is_single_course() {
680
- global $wp_query;
681
- $course_post_type = tutor()->course_post_type;
682
 
683
- if (is_single() && !empty($wp_query->query['post_type']) && $wp_query->query['post_type'] === $course_post_type) {
684
- return true;
685
- }
686
- return false;
687
  }
 
688
  }
 
689
 
690
  /**
691
- * Require wp_date form return js date format
692
- *
693
  * this is helpfull for date picker
694
- *
695
  * @return string
696
- *
697
  * @since 1.9.7
698
  */
699
- if ( !function_exists( 'tutor_js_date_format_against_wp' ) ) {
700
- function tutor_js_date_format_against_wp() {
701
- $wp_date_format = get_option( 'date_format' );
702
- $default_format = 'yy-mm-dd';
703
-
704
- $formats = array(
705
- 'Y-m-d' => 'yy-mm-dd',
706
- 'm/d/Y' => 'mm-dd-yy',
707
- 'd/m/Y' => 'dd-mm-yy',
708
- 'F j, Y' => 'MM dd, yy'
709
- );
710
- return isset( $formats[$wp_date_format] ) ? $formats[$wp_date_format] : $default_format;
711
- }
712
  }
 
713
 
714
  /**
715
  * Convert date to desire format
@@ -720,10 +790,10 @@ if (!function_exists('get_tutor_header')) {
720
  *
721
  * @return string ( date )
722
  */
723
- if ( !function_exists( 'tutor_get_formated_date' ) ) {
724
- function tutor_get_formated_date( string $require_format, string $user_date) {
725
- return date($require_format, strtotime($user_date));
726
- }
727
  }
 
 
728
 
729
-
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
  exit;
4
+ }
5
+
6
+ /**
7
+ * Tutor input sanitization
8
+ */
9
+
10
+ if ( ! function_exists( 'tutor_sanitize_data' ) ) {
11
+ /**
12
+ * Escaping for Sanitize data.
13
+ *
14
+ * @since 1.9.13
15
+ *
16
+ * @param string $input.
17
+ * @param string $type.
18
+ * @return string
19
+ */
20
+ function tutor_sanitize_data( $input = null, $type = null ) {
21
+ $array = array();
22
+ $object = new stdClass();
23
+
24
+ if ( is_string( $input ) ) {
25
+
26
+ if ( 'textarea' == $type ) {
27
+ $input = sanitize_textarea_field( $input );
28
+ } elseif ( 'kses' == $type ) {
29
+ $input = wp_kses_post( $input );
30
+ } else {
31
+ $input = sanitize_text_field( $input );
32
+ }
33
+
34
+ return $input;
35
+
36
+ } elseif ( is_object( $input ) && count( get_object_vars( $input ) ) ) {
37
+
38
+ foreach ( $input as $key => $value ) {
39
+ if ( is_object( $value ) ) {
40
+ $object->$key = tutor_sanitize_data( $value );
41
+ } else {
42
+ $key = sanitize_text_field( $key );
43
+ $value = sanitize_text_field( $value );
44
+ $object->$key = $value;
45
+ }
46
+ }
47
+ return $object;
48
+ } elseif ( is_array( $input ) && count( $input ) ) {
49
+ foreach ( $input as $key => $value ) {
50
+ if ( is_array( $value ) ) {
51
+ $array[ $key ] = tutor_sanitize_data( $value );
52
+ } else {
53
+ $key = sanitize_text_field( $key );
54
+ $value = sanitize_text_field( $value );
55
+ $array[ $key ] = $value;
56
+ }
57
+ }
58
+
59
+ return $array;
60
+ }
61
+ }
62
+ }
63
 
64
  /**
65
  * Tutor general Functions
66
  */
67
 
68
+ if ( ! function_exists( 'tutor_withdrawal_methods' ) ) {
69
  function tutor_withdrawal_methods() {
70
  $withdraw = new \TUTOR\Withdraw();
71
 
81
  * @since v.1.5.7
82
  */
83
 
84
+ if ( ! function_exists( 'get_tutor_all_withdrawal_methods' ) ) {
85
  function get_tutor_all_withdrawal_methods() {
86
  $withdraw = new \TUTOR\Withdraw();
87
 
89
  }
90
  }
91
 
92
+ if ( ! function_exists( 'tutor_placeholder_img_src' ) ) {
93
  function tutor_placeholder_img_src() {
94
  $src = tutor()->url . 'assets/images/placeholder.jpg';
95
+ return apply_filters( 'tutor_placeholder_img_src', $src );
96
  }
97
  }
98
 
104
  * @since v.1.3.4
105
  */
106
 
107
+ if ( ! function_exists( 'tutor_course_categories_dropdown' ) ) {
108
+ function tutor_course_categories_dropdown( $post_ID = 0, $args = array() ) {
109
 
110
  $default = array(
111
  'classes' => '',
112
+ 'name' => 'tax_input[course-category]',
113
  'multiple' => true,
114
  );
115
 
116
+ $args = apply_filters( 'tutor_course_categories_dropdown_args', array_merge( $default, $args ) );
117
 
118
  $multiple_select = '';
119
 
120
+ if ( tutor_utils()->array_get( 'multiple', $args ) ) {
121
+ if ( isset( $args['name'] ) ) {
122
  $args['name'] = $args['name'] . '[]';
123
  }
124
  $multiple_select = "multiple='multiple'";
125
  }
126
 
127
+ extract( $args );
128
 
129
  $classes = (array) $classes;
130
+ $classes = implode( ' ', $classes );
131
 
132
  $categories = tutor_utils()->get_course_categories();
133
 
134
+ $output = '';
135
+ $output .= '<select name="' . $name . '" ' . $multiple_select . ' class="' . $classes . '" data-placeholder="' . __( 'Search Course Category. ex. Design, Development, Business', 'tutor' ) . '">';
136
+ $output .= '<option value="">' . __( 'Select a category', 'tutor' ) . '</option>';
137
+ $output .= _generate_categories_dropdown_option( $post_ID, $categories, $args );
138
+ $output .= '</select>';
139
 
140
  return $output;
141
  }
149
  * @since v.1.3.4
150
  */
151
 
152
+ if ( ! function_exists( 'tutor_course_tags_dropdown' ) ) {
153
+ function tutor_course_tags_dropdown( $post_ID = 0, $args = array() ) {
154
 
155
  $default = array(
156
  'classes' => '',
157
+ 'name' => 'tax_input[course-tag]',
158
  'multiple' => true,
159
  );
160
 
161
+ $args = apply_filters( 'tutor_course_tags_dropdown_args', array_merge( $default, $args ) );
162
 
163
  $multiple_select = '';
164
 
165
+ if ( tutor_utils()->array_get( 'multiple', $args ) ) {
166
+ if ( isset( $args['name'] ) ) {
167
  $args['name'] = $args['name'] . '[]';
168
  }
169
  $multiple_select = "multiple='multiple'";
170
  }
171
 
172
+ extract( $args );
173
 
174
  $classes = (array) $classes;
175
+ $classes = implode( ' ', $classes );
176
 
177
  $tags = tutor_utils()->get_course_tags();
178
 
179
+ $output = '';
180
+ $output .= '<select name=' . $name . ' ' . $multiple_select . ' class="' . $classes . '" data-placeholder="' . __( 'Search Course Tags. ex. Design, Development, Business', 'tutor' ) . '">';
181
+ $output .= '<option value="">' . __( 'Select a tag', 'tutor' ) . '</option>';
182
+ $output .= _generate_tags_dropdown_option( $post_ID, $tags, $args );
183
+ $output .= '</select>';
184
 
185
  return $output;
186
  }
197
  * @since v.1.3.4
198
  */
199
 
200
+ if ( ! function_exists( '_generate_categories_dropdown_option' ) ) {
201
+ function _generate_categories_dropdown_option( $post_ID = 0, $categories = array(), $args = array(), $depth = 0 ) {
202
  $output = '';
203
 
204
+ if ( ! tutor_utils()->count( $categories ) ) {
205
+ return $output;
206
+ }
207
 
208
+ if ( ! is_numeric( $post_ID ) || $post_ID < 1 ) {
209
+ return $output;
210
+ }
211
 
212
+ foreach ( $categories as $category_id => $category ) {
213
+ if ( ! $category->parent ) {
214
+ $depth = 0;
215
+ }
216
 
217
+ $childrens = tutor_utils()->array_get( 'children', $category );
218
+ $has_in_term = has_term( $category->term_id, 'course-category', $post_ID );
219
 
220
  $depth_seperator = '';
221
+ if ( $depth ) {
222
+ for ( $depth_i = 0; $depth_i < $depth; $depth_i++ ) {
223
  $depth_seperator .= '-';
224
  }
225
  }
226
 
227
+ $output .= '<option value="' . $category->term_id . '" ' . selected( $has_in_term, true, false ) . '> ' . $depth_seperator . ' ' . $category->name . '</option>';
228
 
229
+ if ( tutor_utils()->count( $childrens ) ) {
230
  $depth++;
231
+ $output .= _generate_categories_dropdown_option( $post_ID, $childrens, $args, $depth );
232
  }
233
  }
234
 
246
  * @since v.1.3.4
247
  */
248
 
249
+ if ( ! function_exists( '_generate_tags_dropdown_option' ) ) {
250
+ function _generate_tags_dropdown_option( $post_ID = 0, $tags = array(), $args = array(), $depth = 0 ) {
251
  $output = '';
252
 
253
+ if ( ! tutor_utils()->count( $tags ) ) {
254
+ return $output;
255
+ }
256
 
257
+ if ( ! is_numeric( $post_ID ) || $post_ID < 1 ) {
258
+ return $output;
259
+ }
260
 
261
+ foreach ( $tags as $tag ) {
262
 
263
+ $has_in_term = has_term( $tag->term_id, 'course-tag', $post_ID );
264
 
265
+ $output .= '<option value="' . $tag->name . '" ' . selected( $has_in_term, true, false ) . '>' . $tag->name . '</option>';
266
 
267
  }
268
 
276
  * @return string
277
  *
278
  * Generate course categories checkbox
279
+ * @since v.1.3.4
280
  */
281
 
282
+ if ( ! function_exists( 'tutor_course_categories_checkbox' ) ) {
283
+ function tutor_course_categories_checkbox( $post_ID = 0, $args = array() ) {
284
  $default = array(
285
+ 'name' => 'tax_input[course-category]',
286
  );
287
 
288
+ $args = apply_filters( 'tutor_course_categories_checkbox_args', array_merge( $default, $args ) );
289
 
290
+ if ( isset( $args['name'] ) ) {
291
  $args['name'] = $args['name'] . '[]';
292
  }
293
 
294
+ extract( $args );
295
 
296
  $categories = tutor_utils()->get_course_categories();
297
+ $output = '';
298
+ $output .= __tutor_generate_categories_checkbox( $post_ID, $categories, $args );
299
 
300
  return $output;
301
  }
307
  * @return string
308
  *
309
  * Generate course tags checkbox
310
+ * @since v.1.3.4
311
  */
312
 
313
+ if ( ! function_exists( 'tutor_course_tags_checkbox' ) ) {
314
+ function tutor_course_tags_checkbox( $post_ID = 0, $args = array() ) {
315
  $default = array(
316
+ 'name' => 'tax_input[course-tag]',
317
  );
318
 
319
+ $args = apply_filters( 'tutor_course_tags_checkbox_args', array_merge( $default, $args ) );
320
 
321
+ if ( isset( $args['name'] ) ) {
322
  $args['name'] = $args['name'] . '[]';
323
  }
324
 
325
+ extract( $args );
326
 
327
+ $tags = tutor_utils()->get_course_tags();
328
+ $output = '';
329
+ $output .= __tutor_generate_tags_checkbox( $post_ID, $tags, $args );
330
 
331
  return $output;
332
  }
343
  *
344
  * @since v.1.3.4
345
  */
346
+ if ( ! function_exists( '__tutor_generate_categories_checkbox' ) ) {
347
+ function __tutor_generate_categories_checkbox( $post_ID = 0, $categories = array(), $args = array() ) {
 
 
 
348
 
349
+ $output = '';
350
+ $input_name = tutor_utils()->array_get( 'name', $args );
 
 
 
351
 
352
+ if ( tutor_utils()->count( $categories ) ) {
353
+ $output .= '<ul class="tax-input-course-category">';
354
+ foreach ( $categories as $category_id => $category ) {
355
+ $childrens = tutor_utils()->array_get( 'children', $category );
356
+ $has_in_term = has_term( $category->term_id, 'course-category', $post_ID );
357
 
358
+ $output .= '<li class="tax-input-course-category-item tax-input-course-category-item-' . $category->term_id . '"><label class="course-category-checkbox"> <input type="checkbox" name="' . $input_name . '" value="' . $category->term_id . '" ' . checked( $has_in_term, true, false ) . '/> <span>' . $category->name . '</span> </label>';
359
+
360
+ if ( tutor_utils()->count( $childrens ) ) {
361
+ $output .= __tutor_generate_categories_checkbox( $post_ID, $childrens, $args );
362
  }
363
+ $output .= ' </li>';
364
  }
365
+ $output .= '</ul>';
366
  }
367
+
368
  return $output;
369
 
370
  }
380
  *
381
  * @since v.1.3.4
382
  */
383
+ if ( ! function_exists( '__tutor_generate_tags_checkbox' ) ) {
384
+ function __tutor_generate_tags_checkbox( $post_ID = 0, $tags = array(), $args = array() ) {
385
 
386
+ $output = '';
387
+ $input_name = tutor_utils()->array_get( 'name', $args );
388
 
389
+ if ( tutor_utils()->count( $tags ) ) {
390
+ $output .= '<ul class="tax-input-course-tag">';
391
+ foreach ( $tags as $tag ) {
392
+ $has_in_term = has_term( $tag->term_id, 'course-tag', $post_ID );
393
 
394
+ $output .= '<li class="tax-input-course-tag-item tax-input-course-tag-item-' . $tag->term_id . '"><label class="course-tag-checkbox"> <input type="checkbox" name="' . $input_name . '" value="' . $tag->term_id . '" ' . checked( $has_in_term, true, false ) . ' /> <span>' . $tag->name . '</span> </label>';
395
 
396
+ $output .= ' </li>';
397
  }
398
+ $output .= '</ul>';
399
  }
400
 
401
  return $output;
413
  * @since v.1.3.4
414
  */
415
 
416
+ if ( ! function_exists( 'course_builder_section_wrap' ) ) {
417
+ function course_builder_section_wrap( $content = '', $title = '', $echo = true ) {
418
  ob_start();
419
+ ?>
420
  <div class="tutor-course-builder-section">
421
  <div class="tutor-course-builder-section-title">
422
  <h3><i class="tutor-icon-down"></i> <span><?php echo $title; ?></span></h3>
423
  </div>
424
  <div class="tutor-course-builder-section-content">
425
+ <?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
426
  </div>
427
  </div>
428
  <?php
429
  $html = ob_get_clean();
430
 
431
+ if ( $echo ) {
432
+ echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
433
  } else {
434
  return $html;
435
  }
437
  }
438
 
439
 
440
+ if ( ! function_exists( 'get_tutor_header' ) ) {
441
+ function get_tutor_header( $fullScreen = false ) {
442
+ $enable_spotlight_mode = tutor_utils()->get_option( 'enable_spotlight_mode' );
443
 
444
+ if ( $enable_spotlight_mode || $fullScreen ) {
445
+ ?>
446
  <!doctype html>
447
  <html <?php language_attributes(); ?>>
448
 
449
  <head>
450
+ <meta charset="<?php bloginfo( 'charset' ); ?>" />
451
  <meta name="viewport" content="width=device-width, initial-scale=1" />
452
  <link rel="profile" href="https://gmpg.org/xfn/11" />
453
+ <?php wp_head(); ?>
454
  </head>
455
 
456
  <body <?php body_class(); ?>>
457
  <div id="tutor-page-wrap" class="tutor-site-wrap site">
458
+ <?php
459
+ } else {
460
+ get_header();
 
461
  }
462
  }
463
+ }
464
 
465
+ if ( ! function_exists( 'get_tutor_footer' ) ) {
466
+ function get_tutor_footer( $fullScreen = false ) {
467
+ $enable_spotlight_mode = tutor_utils()->get_option( 'enable_spotlight_mode' );
468
+ if ( $enable_spotlight_mode || $fullScreen ) {
469
+ ?>
470
  </div>
471
+ <?php wp_footer(); ?>
472
 
473
  </body>
474
 
475
  </html>
476
+ <?php
477
+ } else {
478
+ get_footer();
 
479
  }
480
  }
481
+ }
482
 
483
  /**
484
  * @param null $key
490
  *
491
  * @since v.1.3.6
492
  */
493
+ if ( ! function_exists( 'get_tutor_option' ) ) {
494
+ function get_tutor_option( $key = null, $default = false ) {
495
+ return tutils()->get_option( $key, $default );
 
496
  }
497
+ }
498
 
499
  /**
500
  * @param null $key
504
  *
505
  * @since v.1.3.6
506
  */
507
+ if ( ! function_exists( 'update_tutor_option' ) ) {
508
+ function update_tutor_option( $key = null, $value = false ) {
509
+ tutils()->update_option( $key, $value );
 
510
  }
511
+ }
512
  /**
513
  * @param int $course_id
514
  * @param null $key
520
  *
521
  * @since v.1.4.1
522
  */
523
+ if ( ! function_exists( 'get_tutor_course_settings' ) ) {
524
+ function get_tutor_course_settings( $course_id = 0, $key = null, $default = false ) {
525
+ return tutils()->get_course_settings( $course_id, $key, $default );
 
526
  }
527
+ }
528
 
529
  /**
530
  * @param int $lesson_id
536
  * Get lesson content drip settings
537
  */
538
 
539
+ if ( ! function_exists( 'get_item_content_drip_settings' ) ) {
540
+ function get_item_content_drip_settings( $lesson_id = 0, $key = null, $default = false ) {
541
+ return tutils()->get_item_content_drip_settings( $lesson_id, $key, $default );
 
542
  }
543
+ }
544
 
545
  /**
546
  * @param null $msg
553
  *
554
  * @since v.1.4.1
555
  */
556
+ if ( ! function_exists( 'tutor_alert' ) ) {
557
+ function tutor_alert( $msg = null, $type = 'warning', $echo = true ) {
558
+ if ( ! $msg ) {
559
+
560
+ if ( $type === 'any' ) {
561
+ if ( ! $msg ) {
562
+ $type = 'warning';
563
+ $msg = tutor_flash_get( $type );
 
 
 
 
 
 
 
 
 
 
 
564
  }
565
+ if ( ! $msg ) {
566
+ $type = 'danger';
567
+ $msg = tutor_flash_get( $type );
568
+ }
569
+ if ( ! $msg ) {
570
+ $type = 'success';
571
+ $msg = tutor_flash_get( $type );
572
+ }
573
+ } else {
574
+ $msg = tutor_flash_get( $type );
575
  }
576
+ }
577
+ if ( ! $msg ) {
578
+ return $msg;
579
+ }
580
 
581
+ $html = '<div class="tutor-alert tutor-alert-' . $type . '">' . $msg . '</div>';
582
+
583
+ if ( $echo ) {
584
+ echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
 
585
  }
586
+ return $html;
587
  }
588
+ }
589
 
590
 
591
  /**
596
  * @since v.1.4.2
597
  */
598
 
599
+ if ( ! function_exists( 'tutor_nonce_field' ) ) {
600
+ function tutor_nonce_field( $echo = true ) {
601
+ wp_nonce_field( tutor()->nonce_action, tutor()->nonce, $echo );
 
602
  }
603
+ }
604
 
605
  /**
606
  * @param null $key
609
  * Set Flash Message
610
  */
611
 
612
+ if ( ! function_exists( 'tutor_flash_set' ) ) {
613
+ function tutor_flash_set( $key = null, $message = '' ) {
614
+ if ( ! $key ) {
615
+ return;
616
+ }
617
+ // ensure session is started
618
+ if ( session_status() !== PHP_SESSION_ACTIVE ) {
619
+ session_start();
 
 
620
  }
621
+ $_SESSION[ $key ] = $message;
622
  }
623
+ }
624
 
625
  /**
626
  * @param null $key
632
  * Get flash message
633
  */
634
 
635
+ if ( ! function_exists( 'tutor_flash_get' ) ) {
636
+ function tutor_flash_get( $key = null ) {
637
+ if ( $key ) {
638
+ // ensure session is started
639
+ if ( session_status() !== PHP_SESSION_ACTIVE ) {
640
+ @session_start();
641
+ }
642
+ if ( empty( $_SESSION ) ) {
643
+ return null;
 
 
 
 
 
 
644
  }
645
+ $message = tutils()->array_get( $key, $_SESSION );
646
+ if ( $message ) {
647
+ unset( $_SESSION[ $key ] );
648
+ }
649
+ return $message;
650
  }
651
+ return $key;
652
  }
653
+ }
654
 
655
+ if ( ! function_exists( 'tutor_redirect_back' ) ) {
656
+ /**
657
+ * @param null $url
658
+ *
659
+ * Redirect to back or a specific URL and terminate
660
+ *
661
+ * @since v.1.4.3
662
+ */
663
+ function tutor_redirect_back( $url = null ) {
664
+ if ( ! $url ) {
665
+ $url = tutils()->referer();
 
 
 
666
  }
667
+ wp_safe_redirect( $url );
668
+ exit();
669
  }
670
+ }
671
 
672
  /**
673
  * @param string $action
678
  * @since v.1.4.3
679
  */
680
 
681
+ if ( ! function_exists( 'tutor_action_field' ) ) {
682
+ function tutor_action_field( $action = '', $echo = true ) {
683
+ $output = '';
684
+ if ( $action ) {
685
+ $output = '<input type="hidden" name="tutor_action" value="' . $action . '">';
686
+ }
687
 
688
+ if ( $echo ) {
689
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
690
+ } else {
691
+ return $output;
 
692
  }
693
  }
694
+ }
695
 
696
  /**
697
  * @return int|string
698
  *
699
+ * Return current Time from WordPress time
700
  *
701
  * @since v.1.4.3
702
  */
703
 
704
+ if ( ! function_exists( 'tutor_time' ) ) {
705
+ function tutor_time() {
706
+ // return current_time( 'timestamp' );
707
+ return time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
 
708
  }
709
+ }
710
 
711
  /**
712
  * Toggle maintenance mode for the site.
719
  *
720
  * @param bool $enable True to enable maintenance mode, false to disable.
721
  */
722
+ if ( ! function_exists( 'tutor_maintenance_mode' ) ) {
723
+ function tutor_maintenance_mode( $enable = false ) {
724
+ $file = ABSPATH . '.tutor_maintenance';
725
+ if ( $enable ) {
726
+ // Create maintenance file to signal that we are upgrading
727
+ $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
728
+
729
+ if ( ! file_exists( $file ) ) {
730
+ file_put_contents( $file, $maintenance_string );
731
+ }
732
+ } else {
733
+ if ( file_exists( $file ) ) {
734
+ unlink( $file );
 
735
  }
736
  }
737
  }
738
+ }
739
 
740
  /**
741
  * @return bool
745
  * @since v.1.6.0
746
  */
747
 
748
+ if ( ! function_exists( 'is_single_course' ) ) {
749
+ function is_single_course() {
750
+ global $wp_query;
751
+ $course_post_type = tutor()->course_post_type;
752
 
753
+ if ( is_single() && ! empty( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] === $course_post_type ) {
754
+ return true;
 
 
755
  }
756
+ return false;
757
  }
758
+ }
759
 
760
  /**
761
+ * Require wp_date form return js date format
762
+ *
763
  * this is helpfull for date picker
764
+ *
765
  * @return string
766
+ *
767
  * @since 1.9.7
768
  */
769
+ if ( ! function_exists( 'tutor_js_date_format_against_wp' ) ) {
770
+ function tutor_js_date_format_against_wp() {
771
+ $wp_date_format = get_option( 'date_format' );
772
+ $default_format = 'yy-mm-dd';
773
+
774
+ $formats = array(
775
+ 'Y-m-d' => 'yy-mm-dd',
776
+ 'm/d/Y' => 'mm-dd-yy',
777
+ 'd/m/Y' => 'dd-mm-yy',
778
+ 'F j, Y' => 'MM dd, yy',
779
+ );
780
+ return isset( $formats[ $wp_date_format ] ) ? $formats[ $wp_date_format ] : $default_format;
 
781
  }
782
+ }
783
 
784
  /**
785
  * Convert date to desire format
790
  *
791
  * @return string ( date )
792
  */
793
+ if ( ! function_exists( 'tutor_get_formated_date' ) ) {
794
+ function tutor_get_formated_date( string $require_format, string $user_date ) {
795
+ return date( $require_format, strtotime( $user_date ) );
 
796
  }
797
+ }
798
+
799
 
 
includes/tutor-template-functions.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
- if ( ! defined( 'ABSPATH' ) )
4
- exit;
 
5
 
6
  /**
7
  * @param null $template
@@ -16,39 +17,39 @@ if ( ! defined( 'ABSPATH' ) )
16
  * @updated v.1.4.3
17
  */
18
 
19
- if ( ! function_exists('tutor_get_template')) {
20
- function tutor_get_template( $template = null, $tutor_pro = false ) {
21
- if ( ! $template ) {
22
- return false;
23
- }
24
- $template = str_replace( '.', DIRECTORY_SEPARATOR, $template );
25
-
26
- /**
27
- * Get template first from child-theme if exists
28
- * If child theme not exists, then get template from parent theme
29
- */
30
- $template_location = trailingslashit( get_stylesheet_directory() ) . "tutor/{$template}.php";
31
- if ( ! file_exists($template_location)){
32
- $template_location = trailingslashit( get_template_directory() ) . "tutor/{$template}.php";
33
- }
34
- $file_in_theme = $template_location;
35
- if ( ! file_exists( $template_location ) ) {
36
- $template_location = trailingslashit( tutor()->path ) . "templates/{$template}.php";
37
-
38
- if ( $tutor_pro && function_exists('tutor_pro')){
39
- $pro_template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
40
- if (file_exists($pro_template_location)){
41
- $template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
42
- }
43
- }
44
-
45
- if ( ! file_exists($template_location)){
46
- echo '<div class="tutor-notice-warning"> '.__(sprintf('The file you are trying to load does not exist in your theme or Tutor LMS plugin location. If you are extending the Tutor LMS plugin, please create a php file here: %s ', "<code>{$file_in_theme}</code>"), 'tutor').' </div>';
47
- }
48
- }
49
-
50
- return apply_filters('tutor_get_template_path', $template_location, $template);
51
- }
52
  }
53
 
54
  /**
@@ -61,30 +62,30 @@ if ( ! function_exists('tutor_get_template')) {
61
  *
62
  * @since v.1.4.2
63
  */
64
- if ( ! function_exists('tutor_get_template_path')) {
65
- function tutor_get_template_path( $template = null, $tutor_pro = false ) {
66
- if ( ! $template ) {
67
- return false;
68
- }
69
- $template = str_replace( '.', DIRECTORY_SEPARATOR, $template );
70
-
71
- /**
72
- * Get template first from child-theme if exists
73
- * If child theme not exists, then get template from parent theme
74
- */
75
- $template_location = trailingslashit( get_stylesheet_directory() ) . "tutor/{$template}.php";
76
- if ( ! file_exists( $template_location ) ) {
77
- $template_location = trailingslashit( get_template_directory() ) . "tutor/{$template}.php";
78
- }
79
- if ( ! file_exists( $template_location ) ) {
80
- $template_location = trailingslashit( tutor()->path ) . "templates/{$template}.php";
81
- }
82
- if ( ! file_exists($template_location) && $tutor_pro && function_exists('tutor_pro')){
83
- $template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
84
- }
85
-
86
- return apply_filters( 'tutor_get_template_path', $template_location, $template );
87
- }
88
  }
89
 
90
  /**
@@ -99,21 +100,21 @@ if ( ! function_exists('tutor_get_template_path')) {
99
  * @updated v.1.1.2
100
  */
101
 
102
- if ( ! function_exists('tutor_load_template')) {
103
- function tutor_load_template( $template = null, $variables = array(), $tutor_pro = false ) {
104
- $variables = (array) $variables;
105
- $variables = apply_filters('get_tutor_load_template_variables', $variables);
106
- extract($variables);
107
 
108
- $isLoad = apply_filters('should_tutor_load_template', true, $template, $variables);
109
- if ( ! $isLoad){
110
- return;
111
- }
112
 
113
- do_action('tutor_load_template_before', $template, $variables);
114
- include tutor_get_template( $template, $tutor_pro );
115
- do_action('tutor_load_template_after', $template, $variables);
116
- }
117
  }
118
 
119
  /**
@@ -124,30 +125,30 @@ if ( ! function_exists('tutor_load_template')) {
124
  * @since v.1.4.3
125
  */
126
 
127
- if ( ! function_exists('tutor_load_template_part')) {
128
- function tutor_load_template_part( $template = null, $variables = array(), $tutor_pro = false ) {
129
- $variables = (array) $variables;
130
- $variables = apply_filters( 'get_tutor_load_template_variables', $variables );
131
- extract( $variables );
132
 
133
- /**
134
- * Get template first from child-theme if exists
135
- * If child theme not exists, then get template from parent theme
136
- */
137
- $template_location = trailingslashit( get_stylesheet_directory() ) . "tutor/template.php";
138
- if ( ! file_exists( $template_location ) ) {
139
- $template_location = trailingslashit( get_template_directory() ) . "tutor/template.php";
140
- }
141
 
142
- if ( ! file_exists( $template_location ) ) {
143
- $template_location = trailingslashit( tutor()->path ) . "templates/template.php";
144
- if ( ! file_exists( $template_location ) && $tutor_pro && function_exists( 'tutor_pro' ) ) {
145
- $template_location = trailingslashit( tutor_pro()->path ) . "templates/template.php";
146
- }
147
- }
148
 
149
- include apply_filters( 'tutor_get_template_part_path', $template_location, $template );
150
- }
151
  }
152
 
153
  /**
@@ -159,213 +160,225 @@ if ( ! function_exists('tutor_load_template_part')) {
159
  * @since v.1.4.3
160
  */
161
 
162
- if ( ! function_exists('tutor_get_template_html')) {
163
- function tutor_get_template_html( $template_name, $variables = array(), $tutor_pro = false ) {
164
- ob_start();
165
- tutor_load_template( $template_name, $variables, $tutor_pro );
166
 
167
- return ob_get_clean();
168
- }
169
  }
170
 
171
- if ( ! function_exists('tutor_course_loop_start')){
172
- function tutor_course_loop_start($echo = true ){
173
- ob_start();
174
- tutor_load_template('loop.loop-start');
175
- $output = apply_filters('tutor_course_loop_start', ob_get_clean());
176
 
177
- if ( $echo ) {
178
- echo $output;
179
- }
180
- return $output;
181
- }
182
  }
183
 
184
- if ( ! function_exists('tutor_course_loop_end')) {
185
- function tutor_course_loop_end( $echo = true ) {
186
- ob_start();
187
- tutor_load_template( 'loop.loop-end' );
188
 
189
- $output = apply_filters( 'tutor_course_loop_end', ob_get_clean() );
190
- if ( $echo ) {
191
- echo $output;
192
- }
193
 
194
- return $output;
195
- }
196
  }
197
 
198
- if ( ! function_exists('tutor_course_archive_pagination')) {
199
- function tutor_course_archive_pagination( $echo = true ) {
200
- ob_start();
201
- tutor_load_template( 'loop.tutor-pagination' );
202
 
203
- $output = apply_filters( 'tutor_course_archive_pagination', ob_get_clean() );
204
- if ( $echo ) {
205
- echo $output;
206
- }
207
 
208
- return $output;
209
- }
210
  }
211
 
212
- function tutor_course_loop_before_content(){
213
- ob_start();
214
- tutor_load_template( 'loop.loop-before-content' );
215
 
216
- $output = apply_filters( 'tutor_course_loop_before_content', ob_get_clean() );
217
- echo $output;
218
  }
219
 
220
- function tutor_course_loop_after_content(){
221
- ob_start();
222
- tutor_load_template( 'loop.loop-after-content' );
223
 
224
- $output = apply_filters( 'tutor_course_loop_after_content', ob_get_clean() );
225
- echo $output;
226
  }
227
 
228
- if ( ! function_exists('tutor_course_loop_title')) {
229
- function tutor_course_loop_title() {
230
- ob_start();
231
- tutor_load_template( 'loop.title' );
232
- $output = apply_filters( 'tutor_course_loop_title', ob_get_clean() );
233
 
234
- echo $output;
235
- }
236
  }
237
 
238
 
239
- if ( ! function_exists('tutor_course_loop_header')) {
240
- function tutor_course_loop_header() {
241
- ob_start();
242
- tutor_load_template( 'loop.header' );
243
- $output = apply_filters( 'tutor_course_loop_header', ob_get_clean() );
244
 
245
- echo $output;
246
- }
247
  }
248
 
249
- if ( ! function_exists('tutor_course_loop_footer')) {
250
- function tutor_course_loop_footer() {
251
- ob_start();
252
- tutor_load_template( 'loop.footer' );
253
- $output = apply_filters( 'tutor_course_loop_footer', ob_get_clean() );
254
 
255
- echo $output;
256
- }
257
  }
258
 
259
- //tutor_course_loop_footer
260
 
261
 
262
- if ( ! function_exists('tutor_course_loop_start_content_wrap')) {
263
- function tutor_course_loop_start_content_wrap() {
264
- ob_start();
265
- tutor_load_template( 'loop.start_content_wrap' );
266
- $output = apply_filters( 'tutor_course_loop_start_content_wrap', ob_get_clean() );
267
 
268
- echo $output;
269
- }
270
  }
271
 
272
- if ( ! function_exists('tutor_course_loop_end_content_wrap')) {
273
- function tutor_course_loop_end_content_wrap() {
274
- ob_start();
275
- tutor_load_template( 'loop.end_content_wrap' );
276
- $output = apply_filters( 'tutor_course_loop_end_content_wrap', ob_get_clean() );
277
 
278
- echo $output;
279
- }
280
  }
281
 
282
- if ( ! function_exists('tutor_course_loop_thumbnail')) {
283
- function tutor_course_loop_thumbnail($echo = true) {
284
- ob_start();
285
- tutor_load_template( 'loop.thumbnail' );
286
- $output = apply_filters( 'tutor_course_loop_thumbnail', ob_get_clean() );
287
 
288
- if ($echo){
289
- echo $output;
290
- }else{
291
- return $output;
292
- }
293
- }
294
  }
295
 
296
- if( ! function_exists('tutor_course_loop_wrap_classes')) {
297
- function tutor_course_loop_wrap_classes( $echo = true ) {
298
- $courseID = get_the_ID();
299
- $classes = apply_filters( 'tutor_course_loop_wrap_classes', array(
300
- 'tutor-course',
301
- 'tutor-course-loop',
302
- 'tutor-course-loop-' . $courseID,
303
- ) );
 
 
 
304
 
305
- $class = implode( ' ', $classes );
306
- if ( $echo ) {
307
- echo $class;
308
- }
309
 
310
- return $class;
311
- }
312
  }
313
 
314
- if( ! function_exists('tutor_course_loop_col_classes')) {
315
- function tutor_course_loop_col_classes( $echo = true ) {
316
- $course_filter = (bool) tutor_utils()->get_option('course_archive_filter', false);
317
- $shortcode_arg = isset($GLOBALS['tutor_shortcode_arg']) ? $GLOBALS['tutor_shortcode_arg']['column_per_row'] : null;
318
- $course_cols = $shortcode_arg===null ? tutor_utils()->get_option('courses_col_per_row', 3) : $shortcode_arg;
319
- $classes = apply_filters( 'tutor_course_loop_col_classes', array(
320
- 'tutor-course-col-' . $course_cols,
321
- ) );
 
 
 
322
 
323
- $class = implode( ' ', $classes );
324
- if ( $echo ) {
325
- echo $class;
326
- }
327
 
328
- return $class;
329
- }
330
  }
331
 
332
 
333
- if ( ! function_exists('tutor_container_classes')) {
334
- function tutor_container_classes( $echo = true ) {
335
-
336
- $classes = apply_filters( 'tutor_container_classes', array(
337
- 'tutor-wrap tutor-courses-wrap',
338
- 'tutor-container'
339
- ) );
340
 
341
- $class = implode( ' ', $classes );
 
 
 
 
 
 
342
 
343
- if ( $echo ) {
344
- echo $class;
345
- }
346
 
347
- return $class;
348
- }
349
- }
350
- if ( ! function_exists('tutor_post_class')) {
351
- function tutor_post_class($default = '') {
352
- $classes = apply_filters( 'tutor_post_class', array(
353
- 'tutor-wrap',
354
- $default
355
- ) );
356
 
357
- post_class( $classes );
358
- }
359
  }
 
 
 
 
 
 
 
 
 
360
 
361
- if ( ! function_exists('tutor_course_archive_filter_bar')) {
362
- function tutor_course_archive_filter_bar() {
363
- ob_start();
364
- tutor_load_template( 'global.course-archive-filter-bar' );
365
- $output = apply_filters( 'tutor_course_archive_filter_bar', ob_get_clean() );
366
-
367
- echo $output;
368
- }
 
 
 
 
369
  }
370
 
371
  /**
@@ -378,78 +391,81 @@ if ( ! function_exists('tutor_course_archive_filter_bar')) {
378
  *
379
  * @since v.1.3.1
380
  */
381
- if( ! function_exists('tutor_widget_course_loop_classes')) {
382
- function tutor_widget_course_loop_classes( $echo = true ) {
383
 
384
- $classes = apply_filters( 'tutor_widget_course_loop_classes', array(
385
- 'tutor-widget-course-loop',
386
- 'tutor-widget-course',
387
- 'tutor-widget-course-'.get_the_ID(),
388
- ) );
 
 
 
389
 
390
- $class = implode( ' ', $classes );
391
- if ( $echo ) {
392
- echo $class;
393
- }
394
 
395
- return $class;
396
- }
397
  }
398
 
399
  /**
400
  * Get the post thumbnail
401
  */
402
- if ( ! function_exists('get_tutor_course_thumbnail')) {
403
- function get_tutor_course_thumbnail($size = 'post-thumbnail', $url = false) {
404
- $post_id = get_the_ID();
405
- $post_thumbnail_id = (int) get_post_thumbnail_id( $post_id );
406
-
407
- if ( $post_thumbnail_id ) {
408
- //$size = apply_filters( 'post_thumbnail_size', $size, $post_id );
409
- $size = apply_filters( 'tutor_course_thumbnail_size', $size, $post_id );
410
- if ($url){
411
- return wp_get_attachment_image_url($post_thumbnail_id, $size);
412
- }
413
-
414
- $html = wp_get_attachment_image( $post_thumbnail_id, $size, false );
415
- } else {
416
- $placeHolderUrl = tutor()->url . 'assets/images/placeholder.jpg';
417
- if ($url){
418
- return $placeHolderUrl;
419
- }
420
- $html = sprintf('<img alt="%s" src="' . $placeHolderUrl . '" />', __('Placeholder', 'tutor'));
421
- }
422
-
423
- echo $html;
424
- }
425
  }
426
  /**
427
  * Get the course/post thumbnail src
428
  */
429
- if ( ! function_exists('get_tutor_course_thumbnail_src')) {
430
- function get_tutor_course_thumbnail_src($size = 'post-thumbnail') {
431
- $post_id = get_the_ID();
432
- $post_thumbnail_id = (int) get_post_thumbnail_id( $post_id );
433
 
434
- if ( $post_thumbnail_id ) {
435
- $size = apply_filters( 'tutor_course_thumbnail_size', $size, $post_id );
436
- $src = wp_get_attachment_image_url( $post_thumbnail_id, $size, false );
437
- } else {
438
- $src = tutor()->url . 'assets/images/placeholder.jpg';
439
- }
440
 
441
- return $src;
442
- }
443
  }
444
 
445
- if ( ! function_exists('tutor_course_loop_meta')) {
446
- function tutor_course_loop_meta() {
447
- ob_start();
448
- tutor_load_template( 'loop.meta' );
449
- $output = apply_filters( 'tutor_course_loop_meta', ob_get_clean() );
450
 
451
- echo $output;
452
- }
453
  }
454
 
455
  /**
@@ -458,41 +474,39 @@ if ( ! function_exists('tutor_course_loop_meta')) {
458
  * @since: v.1.0.0
459
  */
460
 
461
- if ( ! function_exists('tutor_course_loop_author')) {
462
- function tutor_course_loop_author() {
463
- ob_start();
464
- tutor_load_template( 'loop.course-author' );
465
- $output = apply_filters( 'tutor_course_loop_author', ob_get_clean() );
466
 
467
- echo $output;
468
- }
469
  }
470
 
471
  /**
472
  * Get formatted price with cart form
473
  */
474
 
475
- if ( ! function_exists('tutor_course_loop_price')) {
476
- function tutor_course_loop_price() {
477
- ob_start();
478
-
479
- if(tutils()->is_course_added_to_cart(get_the_ID())){
480
- tutor_load_template( 'loop.course-in-cart' );
481
- }
482
- else if(tutils()->is_enrolled(get_the_ID())){
483
- tutor_load_template( 'loop.course-continue' );
484
- }
485
- else{
486
- $tutor_course_sell_by = apply_filters('tutor_course_sell_by', null);
487
- if ($tutor_course_sell_by){
488
- tutor_load_template( 'loop.course-price-'.$tutor_course_sell_by );
489
- }else{
490
- tutor_load_template( 'loop.course-price' );
491
- }
492
- }
493
-
494
- echo apply_filters( 'tutor_course_loop_price', ob_get_clean() );
495
- }
496
  }
497
 
498
  /**
@@ -502,20 +516,20 @@ if ( ! function_exists('tutor_course_loop_price')) {
502
  * @updated v.1.4.5
503
  */
504
 
505
- if ( ! function_exists('tutor_course_loop_rating')) {
506
- function tutor_course_loop_rating() {
507
 
508
- $disable = get_tutor_option('disable_course_review');
509
- if ($disable){
510
- return;
511
- }
512
 
513
- ob_start();
514
- tutor_load_template( 'loop.rating' );
515
- $output = apply_filters( 'tutor_course_loop_rating', ob_get_clean() );
516
 
517
- echo $output;
518
- }
519
  }
520
 
521
  /**
@@ -526,32 +540,32 @@ if ( ! function_exists('tutor_course_loop_rating')) {
526
  * Get add to cart form
527
  */
528
 
529
- if ( ! function_exists('tutor_course_loop_add_to_cart')) {
530
- function tutor_course_loop_add_to_cart($echo = true) {
531
- ob_start();
532
- $tutor_course_sell_by = apply_filters('tutor_course_sell_by', null);
533
 
534
- if ($tutor_course_sell_by){
535
- tutor_load_template( 'loop.add-to-cart-'.$tutor_course_sell_by );
536
- }
537
 
538
- $output = apply_filters( 'tutor_course_loop_add_to_cart_link', ob_get_clean() );
539
 
540
- if ($echo){
541
- echo $output;
542
- }
543
- return $output;
544
- }
545
  }
546
 
547
- if ( ! function_exists('tutor_course_price')) {
548
- function tutor_course_price() {
549
- ob_start();
550
- tutor_load_template( 'single.course.wc-price-html' );
551
- $output = apply_filters( 'tutor_course_price', ob_get_clean() );
552
 
553
- echo $output;
554
- }
555
  }
556
 
557
  /**
@@ -561,13 +575,13 @@ if ( ! function_exists('tutor_course_price')) {
561
  *
562
  * @since: v.1.0.0
563
  */
564
- if ( ! function_exists('tutor_the_excerpt')) {
565
- function tutor_the_excerpt( $post_id = 0 ) {
566
- if ( ! $post_id ) {
567
- $post_id = get_the_ID();
568
- }
569
- echo tutor_get_the_excerpt( $post_id );
570
- }
571
  }
572
  /**
573
  * @param int $post_id
@@ -578,15 +592,15 @@ if ( ! function_exists('tutor_the_excerpt')) {
578
  *
579
  * @since: v.1.0.0
580
  */
581
- if ( ! function_exists('tutor_get_the_excerpt')) {
582
- function tutor_get_the_excerpt( $post_id = 0 ) {
583
- if ( ! $post_id ) {
584
- $post_id = get_the_ID();
585
- }
586
 
587
- $get_post = get_post($post_id);
588
- return apply_filters( 'tutor_get_the_excerpt', $get_post->post_excerpt );
589
- }
590
  }
591
 
592
  /**
@@ -597,16 +611,16 @@ if ( ! function_exists('tutor_get_the_excerpt')) {
597
  * @since: v.1.0.0
598
  */
599
 
600
- if ( ! function_exists('get_tutor_course_author')) {
601
- function get_tutor_course_author() {
602
- global $post;
603
- return apply_filters( 'get_tutor_course_author', get_the_author_meta( 'display_name', $post->post_author ) );
604
- }
605
  }
606
 
607
- function get_tutor_course_author_id(){
608
- global $post;
609
- return (int) $post->post_author;
610
  }
611
 
612
  /**
@@ -618,22 +632,22 @@ function get_tutor_course_author_id(){
618
  * @since: v.1.0.0
619
  */
620
 
621
- if ( ! function_exists('tutor_course_benefits')) {
622
- function tutor_course_benefits( $course_id = 0 ) {
623
- if ( ! $course_id ) {
624
- $course_id = get_the_ID();
625
- }
626
- $benefits = get_post_meta( $course_id, '_tutor_course_benefits', true );
627
 
628
- $benefits_array = array();
629
- if ($benefits){
630
- $benefits_array = explode("\n", $benefits);
631
- }
632
 
633
- $array = array_filter(array_map('trim', $benefits_array));
634
 
635
- return apply_filters( 'tutor_course/single/benefits', $array, $course_id );
636
- }
637
  }
638
 
639
  /**
@@ -646,17 +660,17 @@ if ( ! function_exists('tutor_course_benefits')) {
646
  * @since: v.1.0.0
647
  */
648
 
649
- if ( ! function_exists('tutor_course_benefits_html')) {
650
- function tutor_course_benefits_html($echo = true) {
651
- ob_start();
652
- tutor_load_template( 'single.course.course-benefits' );
653
- $output = apply_filters( 'tutor_course/single/benefits_html', ob_get_clean() );
654
 
655
- if ($echo){
656
- echo $output;
657
- }
658
- return $output;
659
- }
660
  }
661
 
662
  /**
@@ -668,19 +682,19 @@ if ( ! function_exists('tutor_course_benefits_html')) {
668
  *
669
  * @since: v.1.0.0
670
  */
671
- if ( ! function_exists('tutor_course_topics')) {
672
- function tutor_course_topics( $echo = true ) {
673
- ob_start();
674
- tutor_load_template( 'single.course.course-topics' );
675
- $output = apply_filters( 'tutor_course/single/topics', ob_get_clean() );
676
- wp_reset_postdata();
677
 
678
- if ( $echo ) {
679
- echo $output;
680
- }
681
 
682
- return $output;
683
- }
684
  }
685
 
686
  /**
@@ -692,21 +706,21 @@ if ( ! function_exists('tutor_course_topics')) {
692
  *
693
  * @since: v.1.0.0
694
  */
695
- if ( ! function_exists('tutor_course_requirements')) {
696
- function tutor_course_requirements( $course_id = 0 ) {
697
- if ( ! $course_id ) {
698
- $course_id = get_the_ID();
699
- }
700
- $requirements = get_post_meta( $course_id, '_tutor_course_requirements', true );
701
 
702
- $requirements_array = array();
703
- if ($requirements){
704
- $requirements_array = explode("\n", $requirements);
705
- }
706
 
707
- $array = array_filter(array_map('trim', $requirements_array));
708
- return apply_filters( 'tutor_course/single/requirements', $array, $course_id );
709
- }
710
  }
711
 
712
  /**
@@ -718,17 +732,17 @@ if ( ! function_exists('tutor_course_requirements')) {
718
  *
719
  * @since: v.1.0.0
720
  */
721
- if ( ! function_exists('tutor_course_requirements_html')) {
722
- function tutor_course_requirements_html($echo = true) {
723
- ob_start();
724
- tutor_load_template( 'single.course.course-requirements' );
725
- $output = apply_filters( 'tutor_course/single/requirements_html', ob_get_clean() );
726
 
727
- if ($echo){
728
- echo $output;
729
- }
730
- return $output;
731
- }
732
  }
733
 
734
 
@@ -741,21 +755,21 @@ if ( ! function_exists('tutor_course_requirements_html')) {
741
  *
742
  * @since: v.1.0.0
743
  */
744
- if ( ! function_exists('tutor_course_target_audience')) {
745
- function tutor_course_target_audience( $course_id = 0 ) {
746
- if ( ! $course_id ) {
747
- $course_id = get_the_ID();
748
- }
749
- $target_audience = get_post_meta( $course_id, '_tutor_course_target_audience', true );
750
 
751
- $target_audience_array = array();
752
- if ($target_audience){
753
- $target_audience_array = explode("\n", $target_audience);
754
- }
755
 
756
- $array = array_filter(array_map('trim', $target_audience_array));
757
- return apply_filters( 'tutor_course/single/target_audience', $array, $course_id );
758
- }
759
  }
760
 
761
  /**
@@ -767,105 +781,105 @@ if ( ! function_exists('tutor_course_target_audience')) {
767
  *
768
  * @since: v.1.0.0
769
  */
770
- if ( ! function_exists('tutor_course_target_audience_html')) {
771
- function tutor_course_target_audience_html($echo = true) {
772
- ob_start();
773
- tutor_load_template( 'single.course.course-target-audience' );
774
- $output = apply_filters( 'tutor_course/single/audience_html', ob_get_clean() );
775
 
776
- if ($echo){
777
- echo $output;
778
- }
779
- return $output;
780
- }
781
  }
782
 
783
 
784
- if ( ! function_exists('tutor_course_material_includes')) {
785
- function tutor_course_material_includes( $course_id = 0 ) {
786
- if ( ! $course_id ) {
787
- $course_id = get_the_ID();
788
- }
789
- $target_audience = get_post_meta( $course_id, '_tutor_course_material_includes', true );
790
 
791
- $target_audience_array = array();
792
- if ($target_audience){
793
- $target_audience_array = explode("\n", $target_audience);
794
- }
795
 
796
- $array = array_filter(array_map('trim', $target_audience_array));
797
- return apply_filters( 'tutor_course/single/material_includes', $array, $course_id );
798
- }
799
  }
800
 
801
- if ( ! function_exists('tutor_course_material_includes_html')) {
802
- function tutor_course_material_includes_html($echo = true) {
803
- ob_start();
804
- tutor_load_template( 'single.course.material-includes' );
805
- $output = apply_filters( 'tutor_course/single/material_includes', ob_get_clean() );
806
 
807
- if ($echo){
808
- echo $output;
809
- }
810
- return $output;
811
- }
812
  }
813
 
814
- //tutor_course_material_includes_html
815
 
816
 
817
- if ( ! function_exists('tutor_course_instructors_html')) {
818
- function tutor_course_instructors_html($echo = true) {
819
- $display_course_instructors = tutor_utils()->get_option('display_course_instructors');
820
- if ( ! $display_course_instructors){
821
- return null;
822
- }
823
 
824
- ob_start();
825
- tutor_load_template( 'single.course.instructors' );
826
- $output = apply_filters( 'tutor_course/single/instructors_html', ob_get_clean() );
827
 
828
- if ($echo){
829
- echo $output;
830
- }
831
- return $output;
832
- }
833
  }
834
 
835
- if ( ! function_exists('tutor_course_target_reviews_html')) {
836
- function tutor_course_target_reviews_html($echo = true) {
837
- ob_start();
838
- tutor_load_template( 'single.course.reviews' );
839
- $output = apply_filters( 'tutor_course/single/reviews_html', ob_get_clean() );
840
 
841
- if ($echo){
842
- echo $output;
843
- }
844
- return $output;
845
- }
846
  }
847
 
848
- if ( ! function_exists('tutor_course_target_review_form_html')) {
849
- function tutor_course_target_review_form_html($echo = true) {
850
- $isDisableReview = (bool) tutils()->get_option('disable_course_review');
851
- if ($isDisableReview){
852
- $output = apply_filters('tutor_review_disabled_text', '');
853
 
854
- if ($echo){
855
- echo $output;
856
- }
857
- return $output;
858
- }
859
 
860
- ob_start();
861
- tutor_load_template( 'single.course.review-form' );
862
- $output = apply_filters( 'tutor_course/single/reviews_form', ob_get_clean() );
863
 
864
- if ($echo){
865
- echo $output;
866
- }
867
- return $output;
868
- }
869
  }
870
 
871
  /**
@@ -877,18 +891,18 @@ if ( ! function_exists('tutor_course_target_review_form_html')) {
877
  *
878
  * @since: v.1.0.0
879
  */
880
- if ( ! function_exists('tutor_course_content')) {
881
- function tutor_course_content( $echo = true ) {
882
- ob_start();
883
- tutor_load_template( 'single.course.course-content' );
884
- $output = apply_filters( 'tutor_course/single/content', ob_get_clean() );
885
 
886
- if ( $echo ) {
887
- echo $output;
888
- }
889
 
890
- return $output;
891
- }
892
  }
893
 
894
  /**
@@ -896,29 +910,36 @@ if ( ! function_exists('tutor_course_content')) {
896
  *
897
  * @since: v.1.0.0
898
  */
899
- if ( ! function_exists('tutor_course_lead_info')) {
900
- function tutor_course_lead_info( $echo = true ) {
901
- ob_start();
902
-
903
- $course_id = get_the_ID();
904
- $course_post_type = tutor()->course_post_type;
905
- $queryCourse = new WP_Query(array('p' => $course_id, 'post_type' => $course_post_type));
906
-
907
- if ($queryCourse->have_posts()){
908
- while ($queryCourse->have_posts()){
909
- $queryCourse->the_post();
910
- tutor_load_template( 'single.course.lead-info' );
911
- }
912
- wp_reset_postdata();
913
- }
914
-
915
- $output = apply_filters( 'tutor_course/single/lead_info', ob_get_clean() );
916
-
917
- if ( $echo ) {
918
- echo $output;
919
- }
920
- return $output;
921
- }
 
 
 
 
 
 
 
922
  }
923
 
924
  /**
@@ -927,59 +948,69 @@ if ( ! function_exists('tutor_course_lead_info')) {
927
  * @return mixed|void
928
  */
929
 
930
- if ( ! function_exists('tutor_course_enrolled_lead_info')) {
931
- function tutor_course_enrolled_lead_info( $echo = true ) {
932
- ob_start();
933
-
934
- $course_id = get_the_ID();
935
- $course_post_type = tutor()->course_post_type;
936
- $queryCourse = new WP_Query( array( 'p' => $course_id, 'post_type' => $course_post_type ) );
937
-
938
- if ( $queryCourse->have_posts() ) {
939
- while ( $queryCourse->have_posts() ) {
940
- $queryCourse->the_post();
941
- tutor_load_template( 'single.course.enrolled.lead-info' );
942
- }
943
- wp_reset_postdata();
944
- }
945
-
946
- $output = apply_filters( 'tutor_course/single/enrolled/lead_info', ob_get_clean() );
947
-
948
- if ( $echo ) {
949
- echo $output;
950
- }
951
-
952
- return $output;
953
- }
954
- }
955
-
956
- if ( ! function_exists('tutor_lesson_lead_info')) {
957
- function tutor_lesson_lead_info( $lesson_id = 0, $echo = true ) {
958
- if ( ! $lesson_id ) {
959
- $lesson_id = get_the_ID();
960
- }
961
-
962
- ob_start();
963
- $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
964
- $course_post_type = tutor()->course_post_type;
965
- $queryCourse = new WP_Query( array( 'p' => $course_id, 'post_type' => $course_post_type ) );
966
-
967
- if ( $queryCourse->have_posts() ) {
968
- while ( $queryCourse->have_posts() ) {
969
- $queryCourse->the_post();
970
- tutor_load_template( 'single.course.enrolled.lead-info' );
971
- }
972
- wp_reset_postdata();
973
- }
974
- $output = apply_filters( 'tutor_course/single/enrolled/lead_info', ob_get_clean() );
975
-
976
- if ( $echo ) {
977
- echo $output;
978
- }
979
-
980
- return $output;
981
-
982
- }
 
 
 
 
 
 
 
 
 
 
983
  }
984
  /**
985
  * @param bool $echo
@@ -991,33 +1022,33 @@ if ( ! function_exists('tutor_lesson_lead_info')) {
991
  * @since: v.1.0.0
992
  */
993
 
994
- if ( ! function_exists('tutor_course_enroll_box')) {
995
- function tutor_course_enroll_box( $echo = true ) {
996
- $isLoggedIn = is_user_logged_in();
997
- $enrolled = tutor_utils()->is_enrolled();
998
 
999
- $is_administrator = current_user_can('administrator');
1000
- $is_instructor = tutor_utils()->is_instructor_of_this_course();
1001
- $course_content_access = (bool) get_tutor_option('course_content_access_for_ia');
1002
- ob_start();
1003
 
1004
- if ( $enrolled ) {
1005
- tutor_load_template( 'single.course.course-enrolled-box' );
1006
- $output = apply_filters( 'tutor_course/single/enrolled', ob_get_clean() );
1007
- } else if ( $course_content_access && ($is_administrator || $is_instructor) ) {
1008
- tutor_load_template( 'single.course.continue-lesson' );
1009
- $output = apply_filters( 'tutor_course/single/continue_lesson', ob_get_clean() );
1010
- } else {
1011
- tutor_load_template( 'single.course.course-enroll-box' );
1012
- $output = apply_filters( 'tutor_course/single/enroll', ob_get_clean() );
1013
- }
1014
 
1015
- if ( $echo ) {
1016
- echo $output;
1017
- }
1018
 
1019
- return $output;
1020
- }
1021
  }
1022
 
1023
  /**
@@ -1028,90 +1059,95 @@ if ( ! function_exists('tutor_course_enroll_box')) {
1028
  * Get Only add to cart form
1029
  */
1030
 
1031
- function tutor_single_course_add_to_cart($echo = true){
1032
- ob_start();
 
 
 
1033
 
1034
- $isLoggedIn = is_user_logged_in();
1035
- $output = '';
1036
 
1037
- $template = tutor_utils()->is_course_fully_booked(null) ? 'closed-enrollment' : 'add-to-cart';
1038
-
1039
- tutor_load_template( 'single.course.'.$template );
1040
- $output .= apply_filters( 'tutor_course/single/'.$template, ob_get_clean() );
1041
 
1042
- if (!$isLoggedIn) {
1043
- ob_start();
1044
- tutor_load_template( 'single.course.login' );
1045
- $login_form = apply_filters( 'tutor_course/global/login', ob_get_clean() );
1046
 
1047
- $output .= "<div class='tutor-cart-box-login-form' style='display: none;'><span class='login-overlay-close'></span><div class='tutor-cart-box-login-form-inner'><button class='tutor-popup-form-close tutor-icon-line-cross'></button>{$login_form}</div></div>";
1048
- }
1049
 
1050
- if ( $echo ) {
1051
- echo $output;
1052
- }
1053
 
1054
- return $output;
1055
  }
1056
 
1057
- if ( ! function_exists('tutor_course_enrolled_nav')) {
1058
- function tutor_course_enrolled_nav($echo = true) {
1059
- $course_post_type = tutor()->course_post_type;
1060
- $lesson_post_type = tutor()->lesson_post_type;
1061
 
1062
- ob_start();
1063
- global $post;
1064
 
1065
- if ( ! empty($post->post_type) && $post->post_type === $course_post_type){
1066
- tutor_load_template( 'single.course.enrolled.nav' );
1067
- }elseif(! empty($post->post_type) && $post->post_type === $lesson_post_type){
1068
- $lesson_id = get_the_ID();
1069
- $course_id = tutor_utils()->get_course_id_by('lesson', $lesson_id);
1070
 
1071
- $course_post_type = tutor()->course_post_type;
1072
- $queryCourse = new WP_Query(array('p' => $course_id, 'post_type' => $course_post_type));
 
 
 
 
 
1073
 
1074
- if ($queryCourse->have_posts()){
1075
- while ($queryCourse->have_posts()){
1076
- $queryCourse->the_post();
1077
- tutor_load_template( 'single.course.enrolled.nav' );
1078
- }
1079
- wp_reset_postdata();
1080
- }
1081
- }
1082
- $output = apply_filters( 'tutor_course/single/enrolled/nav', ob_get_clean() );
1083
 
1084
- if ( $echo ) {
1085
- echo $output;
1086
- }
1087
- return $output;
1088
- }
1089
  }
1090
 
1091
- if ( ! function_exists('tutor_course_video')){
1092
- function tutor_course_video($echo = true){
1093
- ob_start();
1094
- tutor_load_template( 'single.video.video' );
1095
- $output = apply_filters( 'tutor_course/single/video', ob_get_clean() );
1096
 
1097
- if ( $echo ) {
1098
- echo $output;
1099
- }
1100
- return $output;
1101
- }
1102
  }
1103
 
1104
- if ( ! function_exists('tutor_lesson_video')){
1105
- function tutor_lesson_video($echo = true){
1106
- ob_start();
1107
- tutor_load_template( 'single.video.video' );
1108
- $output = apply_filters( 'tutor_lesson/single/video', ob_get_clean() );
1109
 
1110
- if ( $echo ) {
1111
- echo $output;
1112
- }
1113
- return $output;
1114
- }
1115
  }
1116
 
1117
  /**
@@ -1124,17 +1160,17 @@ if ( ! function_exists('tutor_lesson_video')){
1124
  *
1125
  * @since v.1.0.0
1126
  */
1127
- if ( ! function_exists('get_tutor_posts_attachments')){
1128
- function get_tutor_posts_attachments($echo = true){
1129
- ob_start();
1130
- tutor_load_template( 'global.attachments' );
1131
- $output = apply_filters( 'tutor_lesson/single/attachments', ob_get_clean() );
1132
 
1133
- if ( $echo ) {
1134
- echo $output;
1135
- }
1136
- return $output;
1137
- }
1138
  }
1139
 
1140
  /**
@@ -1146,18 +1182,18 @@ if ( ! function_exists('get_tutor_posts_attachments')){
1146
  *
1147
  * @since v.1.0.0
1148
  */
1149
- if ( ! function_exists('tutor_lessons_sidebar')) {
1150
- function tutor_lessons_sidebar( $echo = true ) {
1151
- ob_start();
1152
- tutor_load_template( 'single.lesson.lesson_sidebar' );
1153
- $output = apply_filters( 'tutor_lesson/single/lesson_sidebar', ob_get_clean() );
1154
 
1155
- if ( $echo ) {
1156
- echo $output;
1157
- }
1158
 
1159
- return $output;
1160
- }
1161
  }
1162
 
1163
  /**
@@ -1168,46 +1204,46 @@ if ( ! function_exists('tutor_lessons_sidebar')) {
1168
  * Render Lesson Main Content
1169
  * @since v.1.0.0
1170
  */
1171
- if ( ! function_exists('tutor_lesson_content')) {
1172
- function tutor_lesson_content( $echo = true ) {
1173
- ob_start();
1174
- tutor_load_template( 'single.lesson.content' );
1175
- $output = apply_filters( 'tutor_lesson/single/content', ob_get_clean() );
1176
 
1177
- if ( $echo ) {
1178
- echo $output;
1179
- }
1180
 
1181
- return $output;
1182
- }
1183
  }
1184
 
1185
- if ( ! function_exists('tutor_lesson_mark_complete_html')) {
1186
- function tutor_lesson_mark_complete_html( $echo = true ) {
1187
- ob_start();
1188
- tutor_load_template( 'single.lesson.complete_form' );
1189
- $output = apply_filters( 'tutor_lesson/single/complete_form', ob_get_clean() );
1190
 
1191
- if ( $echo ) {
1192
- echo $output;
1193
- }
1194
 
1195
- return $output;
1196
- }
1197
  }
1198
 
1199
- if ( ! function_exists('tutor_course_mark_complete_html')) {
1200
- function tutor_course_mark_complete_html( $echo = true ) {
1201
- ob_start();
1202
- tutor_load_template( 'single.course.complete_form' );
1203
- $output = apply_filters( 'tutor_course/single/complete_form', ob_get_clean() );
1204
 
1205
- if ( $echo ) {
1206
- echo $output;
1207
- }
1208
 
1209
- return $output;
1210
- }
1211
  }
1212
 
1213
 
@@ -1221,65 +1257,65 @@ if ( ! function_exists('tutor_course_mark_complete_html')) {
1221
  * @since v.1.0.0
1222
  */
1223
 
1224
- if ( ! function_exists('tutor_course_completing_progress_bar')) {
1225
- function tutor_course_completing_progress_bar( $echo = true ) {
1226
- ob_start();
1227
- tutor_load_template( 'single.course.enrolled.completing-progress' );
1228
- $output = apply_filters( 'tutor_course/single/completing-progress-bar', ob_get_clean() );
1229
 
1230
- if ( $echo ) {
1231
- echo $output;
1232
- }
1233
 
1234
- return $output;
1235
- }
1236
  }
1237
 
1238
- function tutor_course_question_and_answer($echo = true){
1239
- ob_start();
1240
- tutor_load_template( 'single.course.enrolled.question_and_answer' );
1241
- $output = apply_filters( 'tutor_course/single/question_and_answer', ob_get_clean() );
1242
 
1243
- if ( $echo ) {
1244
- echo $output;
1245
- }
1246
 
1247
- return $output;
1248
  }
1249
 
1250
 
1251
- function tutor_course_announcements($echo = true){
1252
- ob_start();
1253
- tutor_load_template( 'single.course.enrolled.announcements' );
1254
- $output = apply_filters( 'tutor_course/single/announcements', ob_get_clean() );
1255
 
1256
- if ( $echo ) {
1257
- echo $output;
1258
- }
1259
 
1260
- return $output;
1261
  }
1262
 
1263
- function tutor_single_quiz_top($echo = true){
1264
- ob_start();
1265
- tutor_load_template( 'single.quiz.top' );
1266
- $output = apply_filters( 'tutor_single_quiz/top', ob_get_clean() );
1267
 
1268
- if ( $echo ) {
1269
- echo $output;
1270
- }
1271
- return $output;
1272
  }
1273
 
1274
- function tutor_single_quiz_body($echo = true){
1275
- ob_start();
1276
- tutor_load_template( 'single.quiz.body' );
1277
- $output = apply_filters( 'tutor_single_quiz/body', ob_get_clean() );
1278
 
1279
- if ( $echo ) {
1280
- echo $output;
1281
- }
1282
- return $output;
1283
  }
1284
 
1285
  /**
@@ -1289,99 +1325,99 @@ function tutor_single_quiz_body($echo = true){
1289
  *
1290
  * Get the quiz description
1291
  */
1292
- function tutor_single_quiz_content($echo = true){
1293
- ob_start();
1294
- tutor_load_template( 'single.quiz.content' );
1295
- $output = apply_filters( 'tutor_single_quiz/content', ob_get_clean() );
1296
 
1297
- if ( $echo ) {
1298
- echo $output;
1299
- }
1300
- return $output;
1301
  }
1302
 
1303
 
1304
- function tutor_single_quiz_no_course_belongs($echo = true){
1305
- ob_start();
1306
- tutor_load_template( 'single.quiz.no_course_belongs' );
1307
- $output = apply_filters( 'tutor_single_quiz/no_course_belongs', ob_get_clean() );
1308
 
1309
- if ( $echo ) {
1310
- echo $output;
1311
- }
1312
- return $output;
1313
  }
1314
 
1315
- function single_quiz_contents($echo = true){
1316
 
1317
- ob_start();
1318
- tutor_load_template( 'single.quiz.single_quiz_contents' );
1319
- $output = apply_filters( 'tutor_single_quiz/single_quiz_contents', ob_get_clean() );
1320
 
1321
- if ( $echo ) {
1322
- echo $output;
1323
- }
1324
- return $output;
1325
  }
1326
 
1327
- function get_tutor_course_level($course_id = 0){
1328
- if ( ! $course_id){
1329
- $course_id = get_the_ID();
1330
- }
1331
- if ( ! $course_id){
1332
- return '';
1333
- }
1334
 
1335
- $course_level = get_post_meta($course_id, '_tutor_course_level', true);
1336
 
1337
- if ($course_level){
1338
- return tutor_utils()->course_levels($course_level);
1339
- }
1340
- return false;
1341
  }
1342
 
1343
- if ( ! function_exists('get_tutor_course_duration_context')) {
1344
- function get_tutor_course_duration_context( $course_id = 0 ) {
1345
- if ( ! $course_id ) {
1346
- $course_id = get_the_ID();
1347
- }
1348
- if ( ! $course_id ) {
1349
- return '';
1350
- }
1351
- $duration = get_post_meta( $course_id, '_course_duration', true );
1352
- $durationHours = tutor_utils()->avalue_dot( 'hours', $duration );
1353
- $durationMinutes = tutor_utils()->avalue_dot( 'minutes', $duration );
1354
- $durationSeconds = tutor_utils()->avalue_dot( 'seconds', $duration );
1355
 
1356
- if ( $duration ) {
1357
- $output = '';
1358
- if ( $durationHours > 0 ) {
1359
- $output .= $durationHours . "h ";
1360
- }
1361
 
1362
- if ( $durationMinutes > 0 ) {
1363
- $output .= $durationMinutes . "m ";
1364
- }
1365
 
1366
- if ( $durationSeconds > 0 ) {
1367
- $output .= $durationSeconds ."s ";
1368
- }
1369
 
1370
- return $output;
1371
- }
1372
 
1373
- return false;
1374
- }
1375
  }
1376
- if ( ! function_exists('get_tutor_course_categories')){
1377
- function get_tutor_course_categories($course_id = 0){
1378
- if ( ! $course_id ) {
1379
- $course_id = get_the_ID();
1380
- }
1381
- $terms = get_the_terms( $course_id, 'course-category' );
1382
 
1383
- return $terms;
1384
- }
1385
  }
1386
 
1387
  /**
@@ -1392,15 +1428,15 @@ if ( ! function_exists('get_tutor_course_categories')){
1392
  * Get course tags
1393
  */
1394
 
1395
- if ( ! function_exists('get_tutor_course_tags')){
1396
- function get_tutor_course_tags($course_id = 0){
1397
- if ( ! $course_id ) {
1398
- $course_id = get_the_ID();
1399
- }
1400
- $terms = get_the_terms( $course_id, 'course-tag' );
1401
 
1402
- return $terms;
1403
- }
1404
  }
1405
 
1406
  /**
@@ -1411,18 +1447,18 @@ if ( ! function_exists('get_tutor_course_tags')){
1411
  * Template for course tags html
1412
  */
1413
 
1414
- if ( ! function_exists('tutor_course_tags_html')) {
1415
- function tutor_course_tags_html( $echo = true ) {
1416
- ob_start();
1417
- tutor_load_template( 'single.course.tags' );
1418
- $output = apply_filters( 'tutor_course/single/tags_html', ob_get_clean() );
1419
 
1420
- if ( $echo ) {
1421
- echo $output;
1422
- }
1423
 
1424
- return $output;
1425
- }
1426
  }
1427
 
1428
  /**
@@ -1433,18 +1469,18 @@ if ( ! function_exists('tutor_course_tags_html')) {
1433
  * Get Q&A in lesson sidebar
1434
  */
1435
 
1436
- if ( ! function_exists('tutor_lesson_sidebar_question_and_answer')) {
1437
- function tutor_lesson_sidebar_question_and_answer( $echo = true ) {
1438
- ob_start();
1439
- tutor_load_template( 'single.lesson.sidebar_question_and_answer' );
1440
- $output = apply_filters( 'tutor_lesson/single/sidebar_question_and_answer', ob_get_clean() );
1441
 
1442
- if ( $echo ) {
1443
- echo $output;
1444
- }
1445
 
1446
- return $output;
1447
- }
1448
  }
1449
 
1450
  /**
@@ -1455,25 +1491,25 @@ if ( ! function_exists('tutor_lesson_sidebar_question_and_answer')) {
1455
  * Get Social Share button to share on social media
1456
  */
1457
 
1458
- if ( ! function_exists('tutor_social_share')) {
1459
- function tutor_social_share( $echo = true ) {
1460
 
1461
- $output = '';
1462
- $tutor_social_share_icons = tutor_utils()->tutor_social_share_icons();
1463
 
1464
- if (tutor_utils()->count($tutor_social_share_icons)) {
1465
- ob_start();
1466
- tutor_load_template( 'single.course.social_share', array( 'tutor_social_share_icons' => $tutor_social_share_icons ) );
1467
- $output = apply_filters( 'tutor_course/single/social_share', ob_get_clean() );
1468
- }
1469
 
1470
- if ( $echo && $output!='' ) {
1471
- echo '<span>' . __('Share:', 'tutor') . '</span>';
1472
- echo $output;
1473
- }
1474
 
1475
- return $output;
1476
- }
1477
  }
1478
 
1479
  /**
@@ -1486,18 +1522,18 @@ if ( ! function_exists('tutor_social_share')) {
1486
  * @since v.1.3.3
1487
  */
1488
 
1489
- if ( ! function_exists('tutor_assignment_content')) {
1490
- function tutor_assignment_content( $echo = true ) {
1491
- ob_start();
1492
- tutor_load_template( 'single.assignment.content' );
1493
- $output = apply_filters( 'tutor_assignment/single/content', ob_get_clean() );
1494
 
1495
- if ( $echo ) {
1496
- echo $output;
1497
- }
1498
 
1499
- return $output;
1500
- }
1501
  }
1502
 
1503
  /**
@@ -1510,26 +1546,26 @@ if ( ! function_exists('tutor_assignment_content')) {
1510
  * @since v.1.4.0
1511
  */
1512
 
1513
- if ( ! function_exists('get_tnotice')) {
1514
- function get_tnotice( $msg = '', $title = 'Success', $type = 'success' ) {
1515
 
1516
- $output = '<div class="tnotice tnotice--' . $type . '">
1517
  <div class="tnotice__icon">&iexcl;</div>
1518
  <div class="tnotice__content">';
1519
 
1520
- if ($title){
1521
- $output .='<p class="tnotice__type">' . $title . '</p>';
1522
- }
1523
- $output .='<p class="tnotice__message">' . $msg . '</p>
1524
  </div>
1525
  </div>';
1526
 
1527
- return $output;
1528
- }
1529
  }
1530
 
1531
  /**
1532
- * @param int $course_content_id
1533
  * @param bool $echo
1534
  *
1535
  * @return mixed|void
@@ -1539,41 +1575,42 @@ if ( ! function_exists('get_tnotice')) {
1539
  * @since v.1.4.7
1540
  */
1541
 
1542
- function tutor_next_previous_pagination($course_content_id = 0, $echo = true){
1543
- $content_id = tutils()->get_post_id($course_content_id);
1544
- $contents = tutils()->get_course_prev_next_contents_by_id($content_id);
1545
- $previous_id = $contents->previous_id;
1546
- $next_id = $contents->next_id;
1547
 
1548
- ob_start();
1549
- do_action('tutor_lesson_next_previous_pagination_before');
1550
- tutor_load_template( 'single.next-previous-pagination', compact('previous_id', 'next_id') );
1551
- do_action('tutor_lesson_next_previous_pagination_after');
1552
- $output = apply_filters( 'tutor/single/next_previous_pagination', ob_get_clean() );
1553
 
1554
- if ( $echo ) {
1555
- echo $output;
1556
- }
1557
 
1558
- return $output;
1559
  }
1560
 
1561
 
1562
  /**
1563
  * Required login form in archive page
 
1564
  * @param bool $echo
1565
  * @since v 1.5.5
1566
  *
1567
  * @todo, it will be remove from 2.0.0
1568
  */
1569
- function tutor_archive_course_add_to_cart($echo = true){
1570
- _deprecated_function( __FUNCTION__, '1.5.8' );
1571
 
1572
- $output = '';
1573
- if ( $echo ) {
1574
- echo $output;
1575
- }
1576
- return $output;
1577
  }
1578
 
1579
  /**
@@ -1585,36 +1622,36 @@ function tutor_archive_course_add_to_cart($echo = true){
1585
  * @since v.1.5.8
1586
  */
1587
 
1588
- if ( ! function_exists('tutor_login_form_popup')) {
1589
- function tutor_login_form_popup($echo = true){
1590
- $output = '';
1591
- ob_start();
1592
- tutor_load_template('single.course.login');
1593
- $login_form = apply_filters('tutor_course/global/login', ob_get_clean());
1594
- $output .= "<div class='tutor-cart-box-login-form' style='display: none;'><span class='login-overlay-close'></span><div class='tutor-cart-box-login-form-inner'><button class='tutor-popup-form-close tutor-icon-line-cross'></button>{$login_form}</div></div>";
1595
 
1596
- $output = apply_filters('tutor_login_form_popup_html', $output);
1597
 
1598
- if ($echo) {
1599
- echo $output;
1600
- }
1601
- return $output;
1602
- }
1603
  }
1604
 
1605
  /**
1606
  * Load custom template from any given file
1607
- *
1608
  * Pass parameter as wish
1609
- *
1610
  * @since 1.9.8
1611
  */
1612
- if ( ! function_exists('tutor_load_template_from_custom_path')) {
1613
- function tutor_load_template_from_custom_path( $template = null, $data=array() ) {
1614
- do_action('tutor_load_template_from_custom_path_before', $template, $data);
1615
- if ( file_exists($template) ) {
1616
- include_once $template;
1617
- }
1618
- do_action('tutor_load_template_from_custom_path_after', $template, $data);
1619
- }
1620
- }
1
  <?php
2
 
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
 
7
  /**
8
  * @param null $template
17
  * @updated v.1.4.3
18
  */
19
 
20
+ if ( ! function_exists( 'tutor_get_template' ) ) {
21
+ function tutor_get_template( $template = null, $tutor_pro = false ) {
22
+ if ( ! $template ) {
23
+ return false;
24
+ }
25
+ $template = str_replace( '.', DIRECTORY_SEPARATOR, $template );
26
+
27
+ /**
28
+ * Get template first from child-theme if exists
29
+ * If child theme not exists, then get template from parent theme
30
+ */
31
+ $template_location = trailingslashit( get_stylesheet_directory() ) . "tutor/{$template}.php";
32
+ if ( ! file_exists( $template_location ) ) {
33
+ $template_location = trailingslashit( get_template_directory() ) . "tutor/{$template}.php";
34
+ }
35
+ $file_in_theme = $template_location;
36
+ if ( ! file_exists( $template_location ) ) {
37
+ $template_location = trailingslashit( tutor()->path ) . "templates/{$template}.php";
38
+
39
+ if ( $tutor_pro && function_exists( 'tutor_pro' ) ) {
40
+ $pro_template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
41
+ if ( file_exists( $pro_template_location ) ) {
42
+ $template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
43
+ }
44
+ }
45
+
46
+ if ( ! file_exists( $template_location ) ) {
47
+ echo '<div class="tutor-notice-warning"> ' . __( sprintf( 'The file you are trying to load does not exist in your theme or Tutor LMS plugin location. If you are extending the Tutor LMS plugin, please create a php file here: %s ', '<code>' . $file_in_theme . '</code>' ), 'tutor' ) . ' </div>';
48
+ }
49
+ }
50
+
51
+ return apply_filters( 'tutor_get_template_path', $template_location, $template );
52
+ }
53
  }
54
 
55
  /**
62
  *
63
  * @since v.1.4.2
64
  */
65
+ if ( ! function_exists( 'tutor_get_template_path' ) ) {
66
+ function tutor_get_template_path( $template = null, $tutor_pro = false ) {
67
+ if ( ! $template ) {
68
+ return false;
69
+ }
70
+ $template = str_replace( '.', DIRECTORY_SEPARATOR, $template );
71
+
72
+ /**
73
+ * Get template first from child-theme if exists
74
+ * If child theme not exists, then get template from parent theme
75
+ */
76
+ $template_location = trailingslashit( get_stylesheet_directory() ) . "tutor/{$template}.php";
77
+ if ( ! file_exists( $template_location ) ) {
78
+ $template_location = trailingslashit( get_template_directory() ) . "tutor/{$template}.php";
79
+ }
80
+ if ( ! file_exists( $template_location ) ) {
81
+ $template_location = trailingslashit( tutor()->path ) . "templates/{$template}.php";
82
+ }
83
+ if ( ! file_exists( $template_location ) && $tutor_pro && function_exists( 'tutor_pro' ) ) {
84
+ $template_location = trailingslashit( tutor_pro()->path ) . "templates/{$template}.php";
85
+ }
86
+
87
+ return apply_filters( 'tutor_get_template_path', $template_location, $template );
88
+ }
89
  }
90
 
91
  /**
100
  * @updated v.1.1.2
101
  */
102
 
103
+ if ( ! function_exists( 'tutor_load_template' ) ) {
104
+ function tutor_load_template( $template = null, $variables = array(), $tutor_pro = false ) {
105
+ $variables = (array) $variables;
106
+ $variables = apply_filters( 'get_tutor_load_template_variables', $variables );
107
+ extract( $variables );
108
 
109
+ $isLoad = apply_filters( 'should_tutor_load_template', true, $template, $variables );
110
+ if ( ! $isLoad ) {
111
+ return;
112
+ }
113
 
114
+ do_action( 'tutor_load_template_before', $template, $variables );
115
+ include tutor_get_template( $template, $tutor_pro );
116
+ do_action( 'tutor_load_template_after', $template, $variables );
117
+ }
118
  }
119
 
120
  /**
125
  * @since v.1.4.3
126
  */
127
 
128
+ if ( ! function_exists( 'tutor_load_template_part' ) ) {
129
+ function tutor_load_template_part( $template = null, $variables = array(), $tutor_pro = false ) {
130
+ $variables = (array) $variables;
131
+ $variables = apply_filters( 'get_tutor_load_template_variables', $variables );
132
+ extract( $variables );
133
 
134
+ /**
135
+ * Get template first from child-theme if exists
136
+ * If child theme not exists, then get template from parent theme
137
+ */
138
+ $template_location = trailingslashit( get_stylesheet_directory() ) . 'tutor/template.php';
139
+ if ( ! file_exists( $template_location ) ) {
140
+ $template_location = trailingslashit( get_template_directory() ) . 'tutor/template.php';
141
+ }
142
 
143
+ if ( ! file_exists( $template_location ) ) {
144
+ $template_location = trailingslashit( tutor()->path ) . 'templates/template.php';
145
+ if ( ! file_exists( $template_location ) && $tutor_pro && function_exists( 'tutor_pro' ) ) {
146
+ $template_location = trailingslashit( tutor_pro()->path ) . 'templates/template.php';
147
+ }
148
+ }
149
 
150
+ include apply_filters( 'tutor_get_template_part_path', $template_location, $template );
151
+ }
152
  }
153
 
154
  /**
160
  * @since v.1.4.3
161
  */
162
 
163
+ if ( ! function_exists( 'tutor_get_template_html' ) ) {
164
+ function tutor_get_template_html( $template_name, $variables = array(), $tutor_pro = false ) {
165
+ ob_start();
166
+ tutor_load_template( $template_name, $variables, $tutor_pro );
167
 
168
+ return ob_get_clean();
169
+ }
170
  }
171
 
172
+ if ( ! function_exists( 'tutor_course_loop_start' ) ) {
173
+ function tutor_course_loop_start( $echo = true ) {
174
+ ob_start();
175
+ tutor_load_template( 'loop.loop-start' );
176
+ $output = apply_filters( 'tutor_course_loop_start', ob_get_clean() );
177
 
178
+ if ( $echo ) {
179
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
180
+ }
181
+ return $output;
182
+ }
183
  }
184
 
185
+ if ( ! function_exists( 'tutor_course_loop_end' ) ) {
186
+ function tutor_course_loop_end( $echo = true ) {
187
+ ob_start();
188
+ tutor_load_template( 'loop.loop-end' );
189
 
190
+ $output = apply_filters( 'tutor_course_loop_end', ob_get_clean() );
191
+ if ( $echo ) {
192
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
193
+ }
194
 
195
+ return $output;
196
+ }
197
  }
198
 
199
+ if ( ! function_exists( 'tutor_course_archive_pagination' ) ) {
200
+ function tutor_course_archive_pagination( $echo = true ) {
201
+ ob_start();
202
+ tutor_load_template( 'loop.tutor-pagination' );
203
 
204
+ $output = apply_filters( 'tutor_course_archive_pagination', ob_get_clean() );
205
+ if ( $echo ) {
206
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
207
+ }
208
 
209
+ return $output;
210
+ }
211
  }
212
 
213
+ function tutor_course_loop_before_content() {
214
+ ob_start();
215
+ tutor_load_template( 'loop.loop-before-content' );
216
 
217
+ $output = apply_filters( 'tutor_course_loop_before_content', ob_get_clean() );
218
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
219
  }
220
 
221
+ function tutor_course_loop_after_content() {
222
+ ob_start();
223
+ tutor_load_template( 'loop.loop-after-content' );
224
 
225
+ $output = apply_filters( 'tutor_course_loop_after_content', ob_get_clean() );
226
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
227
  }
228
 
229
+ if ( ! function_exists( 'tutor_course_loop_title' ) ) {
230
+ function tutor_course_loop_title() {
231
+ ob_start();
232
+ tutor_load_template( 'loop.title' );
233
+ $output = apply_filters( 'tutor_course_loop_title', ob_get_clean() );
234
 
235
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
236
+ }
237
  }
238
 
239
 
240
+ if ( ! function_exists( 'tutor_course_loop_header' ) ) {
241
+ function tutor_course_loop_header() {
242
+ ob_start();
243
+ tutor_load_template( 'loop.header' );
244
+ $output = apply_filters( 'tutor_course_loop_header', ob_get_clean() );
245
 
246
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
247
+ }
248
  }
249
 
250
+ if ( ! function_exists( 'tutor_course_loop_footer' ) ) {
251
+ function tutor_course_loop_footer() {
252
+ ob_start();
253
+ tutor_load_template( 'loop.footer' );
254
+ $output = apply_filters( 'tutor_course_loop_footer', ob_get_clean() );
255
 
256
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
257
+ }
258
  }
259
 
260
+ // tutor_course_loop_footer
261
 
262
 
263
+ if ( ! function_exists( 'tutor_course_loop_start_content_wrap' ) ) {
264
+ function tutor_course_loop_start_content_wrap() {
265
+ ob_start();
266
+ tutor_load_template( 'loop.start_content_wrap' );
267
+ $output = apply_filters( 'tutor_course_loop_start_content_wrap', ob_get_clean() );
268
 
269
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
270
+ }
271
  }
272
 
273
+ if ( ! function_exists( 'tutor_course_loop_end_content_wrap' ) ) {
274
+ function tutor_course_loop_end_content_wrap() {
275
+ ob_start();
276
+ tutor_load_template( 'loop.end_content_wrap' );
277
+ $output = apply_filters( 'tutor_course_loop_end_content_wrap', ob_get_clean() );
278
 
279
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
280
+ }
281
  }
282
 
283
+ if ( ! function_exists( 'tutor_course_loop_thumbnail' ) ) {
284
+ function tutor_course_loop_thumbnail( $echo = true ) {
285
+ ob_start();
286
+ tutor_load_template( 'loop.thumbnail' );
287
+ $output = apply_filters( 'tutor_course_loop_thumbnail', ob_get_clean() );
288
 
289
+ if ( $echo ) {
290
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
291
+ } else {
292
+ return $output;
293
+ }
294
+ }
295
  }
296
 
297
+ if ( ! function_exists( 'tutor_course_loop_wrap_classes' ) ) {
298
+ function tutor_course_loop_wrap_classes( $echo = true ) {
299
+ $courseID = get_the_ID();
300
+ $classes = apply_filters(
301
+ 'tutor_course_loop_wrap_classes',
302
+ array(
303
+ 'tutor-course',
304
+ 'tutor-course-loop',
305
+ 'tutor-course-loop-' . $courseID,
306
+ )
307
+ );
308
 
309
+ $class = implode( ' ', $classes );
310
+ if ( $echo ) {
311
+ echo esc_attr( $class );
312
+ }
313
 
314
+ return esc_attr( $class );
315
+ }
316
  }
317
 
318
+ if ( ! function_exists( 'tutor_course_loop_col_classes' ) ) {
319
+ function tutor_course_loop_col_classes( $echo = true ) {
320
+ $course_filter = (bool) tutor_utils()->get_option( 'course_archive_filter', false );
321
+ $shortcode_arg = isset( $GLOBALS['tutor_shortcode_arg'] ) ? $GLOBALS['tutor_shortcode_arg']['column_per_row'] : null;
322
+ $course_cols = $shortcode_arg === null ? tutor_utils()->get_option( 'courses_col_per_row', 3 ) : $shortcode_arg;
323
+ $classes = apply_filters(
324
+ 'tutor_course_loop_col_classes',
325
+ array(
326
+ 'tutor-course-col-' . $course_cols,
327
+ )
328
+ );
329
 
330
+ $class = implode( ' ', $classes );
331
+ if ( $echo ) {
332
+ echo esc_attr( $class );
333
+ }
334
 
335
+ return esc_attr( $class );
336
+ }
337
  }
338
 
339
 
340
+ if ( ! function_exists( 'tutor_container_classes' ) ) {
341
+ function tutor_container_classes( $echo = true ) {
 
 
 
 
 
342
 
343
+ $classes = apply_filters(
344
+ 'tutor_container_classes',
345
+ array(
346
+ 'tutor-wrap tutor-courses-wrap',
347
+ 'tutor-container',
348
+ )
349
+ );
350
 
351
+ $class = implode( ' ', $classes );
 
 
352
 
353
+ if ( $echo ) {
354
+ echo esc_attr( $class );
355
+ }
 
 
 
 
 
 
356
 
357
+ return esc_attr( $class );
358
+ }
359
  }
360
+ if ( ! function_exists( 'tutor_post_class' ) ) {
361
+ function tutor_post_class( $default = '' ) {
362
+ $classes = apply_filters(
363
+ 'tutor_post_class',
364
+ array(
365
+ 'tutor-wrap',
366
+ $default,
367
+ )
368
+ );
369
 
370
+ post_class( $classes );
371
+ }
372
+ }
373
+
374
+ if ( ! function_exists( 'tutor_course_archive_filter_bar' ) ) {
375
+ function tutor_course_archive_filter_bar() {
376
+ ob_start();
377
+ tutor_load_template( 'global.course-archive-filter-bar' );
378
+ $output = apply_filters( 'tutor_course_archive_filter_bar', ob_get_clean() );
379
+
380
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
381
+ }
382
  }
383
 
384
  /**
391
  *
392
  * @since v.1.3.1
393
  */
394
+ if ( ! function_exists( 'tutor_widget_course_loop_classes' ) ) {
395
+ function tutor_widget_course_loop_classes( $echo = true ) {
396
 
397
+ $classes = apply_filters(
398
+ 'tutor_widget_course_loop_classes',
399
+ array(
400
+ 'tutor-widget-course-loop',
401
+ 'tutor-widget-course',
402
+ 'tutor-widget-course-' . get_the_ID(),
403
+ )
404
+ );
405
 
406
+ $class = implode( ' ', $classes );
407
+ if ( $echo ) {
408
+ echo esc_attr( $class );
409
+ }
410
 
411
+ return esc_attr( $class );
412
+ }
413
  }
414
 
415
  /**
416
  * Get the post thumbnail
417
  */
418
+ if ( ! function_exists( 'get_tutor_course_thumbnail' ) ) {
419
+ function get_tutor_course_thumbnail( $size = 'post-thumbnail', $url = false ) {
420
+ $post_id = get_the_ID();
421
+ $post_thumbnail_id = (int) get_post_thumbnail_id( $post_id );
422
+
423
+ if ( $post_thumbnail_id ) {
424
+ // $size = apply_filters( 'post_thumbnail_size', $size, $post_id );
425
+ $size = apply_filters( 'tutor_course_thumbnail_size', $size, $post_id );
426
+ if ( $url ) {
427
+ return wp_get_attachment_image_url( $post_thumbnail_id, $size );
428
+ }
429
+
430
+ $html = wp_get_attachment_image( $post_thumbnail_id, $size, false );
431
+ } else {
432
+ $placeHolderUrl = tutor()->url . 'assets/images/placeholder.jpg';
433
+ if ( $url ) {
434
+ return $placeHolderUrl;
435
+ }
436
+ $html = sprintf( '<img alt="%s" src="' . $placeHolderUrl . '" />', __( 'Placeholder', 'tutor' ) );
437
+ }
438
+
439
+ echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
440
+ }
441
  }
442
  /**
443
  * Get the course/post thumbnail src
444
  */
445
+ if ( ! function_exists( 'get_tutor_course_thumbnail_src' ) ) {
446
+ function get_tutor_course_thumbnail_src( $size = 'post-thumbnail' ) {
447
+ $post_id = get_the_ID();
448
+ $post_thumbnail_id = (int) get_post_thumbnail_id( $post_id );
449
 
450
+ if ( $post_thumbnail_id ) {
451
+ $size = apply_filters( 'tutor_course_thumbnail_size', $size, $post_id );
452
+ $src = wp_get_attachment_image_url( $post_thumbnail_id, $size, false );
453
+ } else {
454
+ $src = tutor()->url . 'assets/images/placeholder.jpg';
455
+ }
456
 
457
+ return $src;
458
+ }
459
  }
460
 
461
+ if ( ! function_exists( 'tutor_course_loop_meta' ) ) {
462
+ function tutor_course_loop_meta() {
463
+ ob_start();
464
+ tutor_load_template( 'loop.meta' );
465
+ $output = apply_filters( 'tutor_course_loop_meta', ob_get_clean() );
466
 
467
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
468
+ }
469
  }
470
 
471
  /**
474
  * @since: v.1.0.0
475
  */
476
 
477
+ if ( ! function_exists( 'tutor_course_loop_author' ) ) {
478
+ function tutor_course_loop_author() {
479
+ ob_start();
480
+ tutor_load_template( 'loop.course-author' );
481
+ $output = apply_filters( 'tutor_course_loop_author', ob_get_clean() );
482
 
483
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
484
+ }
485
  }
486
 
487
  /**
488
  * Get formatted price with cart form
489
  */
490
 
491
+ if ( ! function_exists( 'tutor_course_loop_price' ) ) {
492
+ function tutor_course_loop_price() {
493
+ ob_start();
494
+
495
+ if ( tutils()->is_course_added_to_cart( get_the_ID() ) ) {
496
+ tutor_load_template( 'loop.course-in-cart' );
497
+ } elseif ( tutils()->is_enrolled( get_the_ID() ) ) {
498
+ tutor_load_template( 'loop.course-continue' );
499
+ } else {
500
+ $tutor_course_sell_by = apply_filters( 'tutor_course_sell_by', null );
501
+ if ( $tutor_course_sell_by ) {
502
+ tutor_load_template( 'loop.course-price-' . $tutor_course_sell_by );
503
+ } else {
504
+ tutor_load_template( 'loop.course-price' );
505
+ }
506
+ }
507
+
508
+ echo apply_filters( 'tutor_course_loop_price', ob_get_clean() );
509
+ }
 
 
510
  }
511
 
512
  /**
516
  * @updated v.1.4.5
517
  */
518
 
519
+ if ( ! function_exists( 'tutor_course_loop_rating' ) ) {
520
+ function tutor_course_loop_rating() {
521
 
522
+ $disable = get_tutor_option( 'disable_course_review' );
523
+ if ( $disable ) {
524
+ return;
525
+ }
526
 
527
+ ob_start();
528
+ tutor_load_template( 'loop.rating' );
529
+ $output = apply_filters( 'tutor_course_loop_rating', ob_get_clean() );
530
 
531
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
532
+ }
533
  }
534
 
535
  /**
540
  * Get add to cart form
541
  */
542
 
543
+ if ( ! function_exists( 'tutor_course_loop_add_to_cart' ) ) {
544
+ function tutor_course_loop_add_to_cart( $echo = true ) {
545
+ ob_start();
546
+ $tutor_course_sell_by = apply_filters( 'tutor_course_sell_by', null );
547
 
548
+ if ( $tutor_course_sell_by ) {
549
+ tutor_load_template( 'loop.add-to-cart-' . $tutor_course_sell_by );
550
+ }
551
 
552
+ $output = apply_filters( 'tutor_course_loop_add_to_cart_link', ob_get_clean() );
553
 
554
+ if ( $echo ) {
555
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
556
+ }
557
+ return $output;
558
+ }
559
  }
560
 
561
+ if ( ! function_exists( 'tutor_course_price' ) ) {
562
+ function tutor_course_price() {
563
+ ob_start();
564
+ tutor_load_template( 'single.course.wc-price-html' );
565
+ $output = apply_filters( 'tutor_course_price', ob_get_clean() );
566
 
567
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
568
+ }
569
  }
570
 
571
  /**
575
  *
576
  * @since: v.1.0.0
577
  */
578
+ if ( ! function_exists( 'tutor_the_excerpt' ) ) {
579
+ function tutor_the_excerpt( $post_id = 0 ) {
580
+ if ( ! $post_id ) {
581
+ $post_id = get_the_ID();
582
+ }
583
+ echo tutor_get_the_excerpt( $post_id );
584
+ }
585
  }
586
  /**
587
  * @param int $post_id
592
  *
593
  * @since: v.1.0.0
594
  */
595
+ if ( ! function_exists( 'tutor_get_the_excerpt' ) ) {
596
+ function tutor_get_the_excerpt( $post_id = 0 ) {
597
+ if ( ! $post_id ) {
598
+ $post_id = get_the_ID();
599
+ }
600
 
601
+ $get_post = get_post( $post_id );
602
+ return apply_filters( 'tutor_get_the_excerpt', $get_post->post_excerpt );
603
+ }
604
  }
605
 
606
  /**
611
  * @since: v.1.0.0
612
  */
613
 
614
+ if ( ! function_exists( 'get_tutor_course_author' ) ) {
615
+ function get_tutor_course_author() {
616
+ global $post;
617
+ return apply_filters( 'get_tutor_course_author', get_the_author_meta( 'display_name', $post->post_author ) );
618
+ }
619
  }
620
 
621
+ function get_tutor_course_author_id() {
622
+ global $post;
623
+ return (int) $post->post_author;
624
  }
625
 
626
  /**
632
  * @since: v.1.0.0
633
  */
634
 
635
+ if ( ! function_exists( 'tutor_course_benefits' ) ) {
636
+ function tutor_course_benefits( $course_id = 0 ) {
637
+ if ( ! $course_id ) {
638
+ $course_id = get_the_ID();
639
+ }
640
+ $benefits = get_post_meta( $course_id, '_tutor_course_benefits', true );
641
 
642
+ $benefits_array = array();
643
+ if ( $benefits ) {
644
+ $benefits_array = explode( "\n", $benefits );
645
+ }
646
 
647
+ $array = array_filter( array_map( 'trim', $benefits_array ) );
648
 
649
+ return apply_filters( 'tutor_course/single/benefits', $array, $course_id );
650
+ }
651
  }
652
 
653
  /**
660
  * @since: v.1.0.0
661
  */
662
 
663
+ if ( ! function_exists( 'tutor_course_benefits_html' ) ) {
664
+ function tutor_course_benefits_html( $echo = true ) {
665
+ ob_start();
666
+ tutor_load_template( 'single.course.course-benefits' );
667
+ $output = apply_filters( 'tutor_course/single/benefits_html', ob_get_clean() );
668
 
669
+ if ( $echo ) {
670
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
671
+ }
672
+ return $output;
673
+ }
674
  }
675
 
676
  /**
682
  *
683
  * @since: v.1.0.0
684
  */
685
+ if ( ! function_exists( 'tutor_course_topics' ) ) {
686
+ function tutor_course_topics( $echo = true ) {
687
+ ob_start();
688
+ tutor_load_template( 'single.course.course-topics' );
689
+ $output = apply_filters( 'tutor_course/single/topics', ob_get_clean() );
690
+ wp_reset_postdata();
691
 
692
+ if ( $echo ) {
693
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
694
+ }
695
 
696
+ return $output;
697
+ }
698
  }
699
 
700
  /**
706
  *
707
  * @since: v.1.0.0
708
  */
709
+ if ( ! function_exists( 'tutor_course_requirements' ) ) {
710
+ function tutor_course_requirements( $course_id = 0 ) {
711
+ if ( ! $course_id ) {
712
+ $course_id = get_the_ID();
713
+ }
714
+ $requirements = get_post_meta( $course_id, '_tutor_course_requirements', true );
715
 
716
+ $requirements_array = array();
717
+ if ( $requirements ) {
718
+ $requirements_array = explode( "\n", $requirements );
719
+ }
720
 
721
+ $array = array_filter( array_map( 'trim', $requirements_array ) );
722
+ return apply_filters( 'tutor_course/single/requirements', $array, $course_id );
723
+ }
724
  }
725
 
726
  /**
732
  *
733
  * @since: v.1.0.0
734
  */
735
+ if ( ! function_exists( 'tutor_course_requirements_html' ) ) {
736
+ function tutor_course_requirements_html( $echo = true ) {
737
+ ob_start();
738
+ tutor_load_template( 'single.course.course-requirements' );
739
+ $output = apply_filters( 'tutor_course/single/requirements_html', ob_get_clean() );
740
 
741
+ if ( $echo ) {
742
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
743
+ }
744
+ return $output;
745
+ }
746
  }
747
 
748
 
755
  *
756
  * @since: v.1.0.0
757
  */
758
+ if ( ! function_exists( 'tutor_course_target_audience' ) ) {
759
+ function tutor_course_target_audience( $course_id = 0 ) {
760
+ if ( ! $course_id ) {
761
+ $course_id = get_the_ID();
762
+ }
763
+ $target_audience = get_post_meta( $course_id, '_tutor_course_target_audience', true );
764
 
765
+ $target_audience_array = array();
766
+ if ( $target_audience ) {
767
+ $target_audience_array = explode( "\n", $target_audience );
768
+ }
769
 
770
+ $array = array_filter( array_map( 'trim', $target_audience_array ) );
771
+ return apply_filters( 'tutor_course/single/target_audience', $array, $course_id );
772
+ }
773
  }
774
 
775
  /**
781
  *
782
  * @since: v.1.0.0
783
  */
784
+ if ( ! function_exists( 'tutor_course_target_audience_html' ) ) {
785
+ function tutor_course_target_audience_html( $echo = true ) {
786
+ ob_start();
787
+ tutor_load_template( 'single.course.course-target-audience' );
788
+ $output = apply_filters( 'tutor_course/single/audience_html', ob_get_clean() );
789
 
790
+ if ( $echo ) {
791
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
792
+ }
793
+ return $output;
794
+ }
795
  }
796
 
797
 
798
+ if ( ! function_exists( 'tutor_course_material_includes' ) ) {
799
+ function tutor_course_material_includes( $course_id = 0 ) {
800
+ if ( ! $course_id ) {
801
+ $course_id = get_the_ID();
802
+ }
803
+ $target_audience = get_post_meta( $course_id, '_tutor_course_material_includes', true );
804
 
805
+ $target_audience_array = array();
806
+ if ( $target_audience ) {
807
+ $target_audience_array = explode( "\n", $target_audience );
808
+ }
809
 
810
+ $array = array_filter( array_map( 'trim', $target_audience_array ) );
811
+ return apply_filters( 'tutor_course/single/material_includes', $array, $course_id );
812
+ }
813
  }
814
 
815
+ if ( ! function_exists( 'tutor_course_material_includes_html' ) ) {
816
+ function tutor_course_material_includes_html( $echo = true ) {
817
+ ob_start();
818
+ tutor_load_template( 'single.course.material-includes' );
819
+ $output = apply_filters( 'tutor_course/single/material_includes', ob_get_clean() );
820
 
821
+ if ( $echo ) {
822
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
823
+ }
824
+ return $output;
825
+ }
826
  }
827
 
828
+ // tutor_course_material_includes_html
829
 
830
 
831
+ if ( ! function_exists( 'tutor_course_instructors_html' ) ) {
832
+ function tutor_course_instructors_html( $echo = true ) {
833
+ $display_course_instructors = tutor_utils()->get_option( 'display_course_instructors' );
834
+ if ( ! $display_course_instructors ) {
835
+ return null;
836
+ }
837
 
838
+ ob_start();
839
+ tutor_load_template( 'single.course.instructors' );
840
+ $output = apply_filters( 'tutor_course/single/instructors_html', ob_get_clean() );
841
 
842
+ if ( $echo ) {
843
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
844
+ }
845
+ return $output;
846
+ }
847
  }
848
 
849
+ if ( ! function_exists( 'tutor_course_target_reviews_html' ) ) {
850
+ function tutor_course_target_reviews_html( $echo = true ) {
851
+ ob_start();
852
+ tutor_load_template( 'single.course.reviews' );
853
+ $output = apply_filters( 'tutor_course/single/reviews_html', ob_get_clean() );
854
 
855
+ if ( $echo ) {
856
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
857
+ }
858
+ return $output;
859
+ }
860
  }
861
 
862
+ if ( ! function_exists( 'tutor_course_target_review_form_html' ) ) {
863
+ function tutor_course_target_review_form_html( $echo = true ) {
864
+ $isDisableReview = (bool) tutils()->get_option( 'disable_course_review' );
865
+ if ( $isDisableReview ) {
866
+ $output = apply_filters( 'tutor_review_disabled_text', '' );
867
 
868
+ if ( $echo ) {
869
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
870
+ }
871
+ return $output;
872
+ }
873
 
874
+ ob_start();
875
+ tutor_load_template( 'single.course.review-form' );
876
+ $output = apply_filters( 'tutor_course/single/reviews_form', ob_get_clean() );
877
 
878
+ if ( $echo ) {
879
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
880
+ }
881
+ return $output;
882
+ }
883
  }
884
 
885
  /**
891
  *
892
  * @since: v.1.0.0
893
  */
894
+ if ( ! function_exists( 'tutor_course_content' ) ) {
895
+ function tutor_course_content( $echo = true ) {
896
+ ob_start();
897
+ tutor_load_template( 'single.course.course-content' );
898
+ $output = apply_filters( 'tutor_course/single/content', ob_get_clean() );
899
 
900
+ if ( $echo ) {
901
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
902
+ }
903
 
904
+ return $output;
905
+ }
906
  }
907
 
908
  /**
910
  *
911
  * @since: v.1.0.0
912
  */
913
+ if ( ! function_exists( 'tutor_course_lead_info' ) ) {
914
+ function tutor_course_lead_info( $echo = true ) {
915
+ ob_start();
916
+
917
+ // exit('failed');
918
+
919
+ $course_id = get_the_ID();
920
+ $course_post_type = tutor()->course_post_type;
921
+ $queryCourse = new WP_Query(
922
+ array(
923
+ 'p' => $course_id,
924
+ 'post_type' => $course_post_type,
925
+ )
926
+ );
927
+
928
+ if ( $queryCourse->have_posts() ) {
929
+ while ( $queryCourse->have_posts() ) {
930
+ $queryCourse->the_post();
931
+ tutor_load_template( 'single.course.lead-info' );
932
+ }
933
+ wp_reset_postdata();
934
+ }
935
+
936
+ $output = apply_filters( 'tutor_course/single/lead_info', ob_get_clean() );
937
+
938
+ if ( $echo ) {
939
+ echo $output;
940
+ }
941
+ return $output;
942
+ }
943
  }
944
 
945
  /**
948
  * @return mixed|void
949
  */
950
 
951
+ if ( ! function_exists( 'tutor_course_enrolled_lead_info' ) ) {
952
+ function tutor_course_enrolled_lead_info( $echo = true ) {
953
+ ob_start();
954
+
955
+ $course_id = get_the_ID();
956
+ $course_post_type = tutor()->course_post_type;
957
+ $queryCourse = new WP_Query(
958
+ array(
959
+ 'p' => $course_id,
960
+ 'post_type' => $course_post_type,
961
+ )
962
+ );
963
+
964
+ if ( $queryCourse->have_posts() ) {
965
+ while ( $queryCourse->have_posts() ) {
966
+ $queryCourse->the_post();
967
+ tutor_load_template( 'single.course.enrolled.lead-info' );
968
+ }
969
+ wp_reset_postdata();
970
+ }
971
+
972
+ $output = apply_filters( 'tutor_course/single/enrolled/lead_info', ob_get_clean() );
973
+
974
+ if ( $echo ) {
975
+ echo $output;
976
+ }
977
+
978
+ return $output;
979
+ }
980
+ }
981
+
982
+ if ( ! function_exists( 'tutor_lesson_lead_info' ) ) {
983
+ function tutor_lesson_lead_info( $lesson_id = 0, $echo = true ) {
984
+ if ( ! $lesson_id ) {
985
+ $lesson_id = get_the_ID();
986
+ }
987
+
988
+ ob_start();
989
+ $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
990
+ $course_post_type = tutor()->course_post_type;
991
+ $queryCourse = new WP_Query(
992
+ array(
993
+ 'p' => $course_id,
994
+ 'post_type' => $course_post_type,
995
+ )
996
+ );
997
+
998
+ if ( $queryCourse->have_posts() ) {
999
+ while ( $queryCourse->have_posts() ) {
1000
+ $queryCourse->the_post();
1001
+ tutor_load_template( 'single.course.enrolled.lead-info' );
1002
+ }
1003
+ wp_reset_postdata();
1004
+ }
1005
+ $output = apply_filters( 'tutor_course/single/enrolled/lead_info', ob_get_clean() );
1006
+
1007
+ if ( $echo ) {
1008
+ echo $output;
1009
+ }
1010
+
1011
+ return $output;
1012
+
1013
+ }
1014
  }
1015
  /**
1016
  * @param bool $echo
1022
  * @since: v.1.0.0
1023
  */
1024
 
1025
+ if ( ! function_exists( 'tutor_course_enroll_box' ) ) {
1026
+ function tutor_course_enroll_box( $echo = true ) {
1027
+ $isLoggedIn = is_user_logged_in();
1028
+ $enrolled = tutor_utils()->is_enrolled();
1029
 
1030
+ $is_administrator = current_user_can( 'administrator' );
1031
+ $is_instructor = tutor_utils()->is_instructor_of_this_course();
1032
+ $course_content_access = (bool) get_tutor_option( 'course_content_access_for_ia' );
1033
+ ob_start();
1034
 
1035
+ if ( $enrolled ) {
1036
+ tutor_load_template( 'single.course.course-enrolled-box' );
1037
+ $output = apply_filters( 'tutor_course/single/enrolled', ob_get_clean() );
1038
+ } elseif ( $course_content_access && ( $is_administrator || $is_instructor ) ) {
1039
+ tutor_load_template( 'single.course.continue-lesson' );
1040
+ $output = apply_filters( 'tutor_course/single/continue_lesson', ob_get_clean() );
1041
+ } else {
1042
+ tutor_load_template( 'single.course.course-enroll-box' );
1043
+ $output = apply_filters( 'tutor_course/single/enroll', ob_get_clean() );
1044
+ }
1045
 
1046
+ if ( $echo ) {
1047
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1048
+ }
1049
 
1050
+ return $output;
1051
+ }
1052
  }
1053
 
1054
  /**
1059
  * Get Only add to cart form
1060
  */
1061
 
1062
+ function tutor_single_course_add_to_cart( $echo = true ) {
1063
+ ob_start();
1064
+
1065
+ $isLoggedIn = is_user_logged_in();
1066
+ $output = '';
1067
 
1068
+ $template = tutor_utils()->is_course_fully_booked( null ) ? 'closed-enrollment' : 'add-to-cart';
 
1069
 
1070
+ tutor_load_template( 'single.course.' . $template );
1071
+ $output .= apply_filters( 'tutor_course/single/' . $template, ob_get_clean() );
 
 
1072
 
1073
+ if ( ! $isLoggedIn ) {
1074
+ ob_start();
1075
+ tutor_load_template( 'single.course.login' );
1076
+ $login_form = apply_filters( 'tutor_course/global/login', ob_get_clean() );
1077
 
1078
+ $output .= '<div class="tutor-cart-box-login-form" style="display: none;"><span class="login-overlay-close"></span><div class="tutor-cart-box-login-form-inner"><button class="tutor-popup-form-close tutor-icon-line-cross"></button>' . $login_form . '</div></div>';
1079
+ }
1080
 
1081
+ if ( $echo ) {
1082
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1083
+ }
1084
 
1085
+ return $output;
1086
  }
1087
 
1088
+ if ( ! function_exists( 'tutor_course_enrolled_nav' ) ) {
1089
+ function tutor_course_enrolled_nav( $echo = true ) {
1090
+ $course_post_type = tutor()->course_post_type;
1091
+ $lesson_post_type = tutor()->lesson_post_type;
1092
 
1093
+ ob_start();
1094
+ global $post;
1095
 
1096
+ if ( ! empty( $post->post_type ) && $post->post_type === $course_post_type ) {
1097
+ tutor_load_template( 'single.course.enrolled.nav' );
1098
+ } elseif ( ! empty( $post->post_type ) && $post->post_type === $lesson_post_type ) {
1099
+ $lesson_id = get_the_ID();
1100
+ $course_id = tutor_utils()->get_course_id_by( 'lesson', $lesson_id );
1101
 
1102
+ $course_post_type = tutor()->course_post_type;
1103
+ $queryCourse = new WP_Query(
1104
+ array(
1105
+ 'p' => $course_id,
1106
+ 'post_type' => $course_post_type,
1107
+ )
1108
+ );
1109
 
1110
+ if ( $queryCourse->have_posts() ) {
1111
+ while ( $queryCourse->have_posts() ) {
1112
+ $queryCourse->the_post();
1113
+ tutor_load_template( 'single.course.enrolled.nav' );
1114
+ }
1115
+ wp_reset_postdata();
1116
+ }
1117
+ }
1118
+ $output = apply_filters( 'tutor_course/single/enrolled/nav', ob_get_clean() );
1119
 
1120
+ if ( $echo ) {
1121
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1122
+ }
1123
+ return $output;
1124
+ }
1125
  }
1126
 
1127
+ if ( ! function_exists( 'tutor_course_video' ) ) {
1128
+ function tutor_course_video( $echo = true ) {
1129
+ ob_start();
1130
+ tutor_load_template( 'single.video.video' );
1131
+ $output = apply_filters( 'tutor_course/single/video', ob_get_clean() );
1132
 
1133
+ if ( $echo ) {
1134
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1135
+ }
1136
+ return $output;
1137
+ }
1138
  }
1139
 
1140
+ if ( ! function_exists( 'tutor_lesson_video' ) ) {
1141
+ function tutor_lesson_video( $echo = true ) {
1142
+ ob_start();
1143
+ tutor_load_template( 'single.video.video' );
1144
+ $output = apply_filters( 'tutor_lesson/single/video', ob_get_clean() );
1145
 
1146
+ if ( $echo ) {
1147
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1148
+ }
1149
+ return $output;
1150
+ }
1151
  }
1152
 
1153
  /**
1160
  *
1161
  * @since v.1.0.0
1162
  */
1163
+ if ( ! function_exists( 'get_tutor_posts_attachments' ) ) {
1164
+ function get_tutor_posts_attachments( $echo = true ) {
1165
+ ob_start();
1166
+ tutor_load_template( 'global.attachments' );
1167
+ $output = apply_filters( 'tutor_lesson/single/attachments', ob_get_clean() );
1168
 
1169
+ if ( $echo ) {
1170
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1171
+ }
1172
+ return $output;
1173
+ }
1174
  }
1175
 
1176
  /**
1182
  *
1183
  * @since v.1.0.0
1184
  */
1185
+ if ( ! function_exists( 'tutor_lessons_sidebar' ) ) {
1186
+ function tutor_lessons_sidebar( $echo = true ) {
1187
+ ob_start();
1188
+ tutor_load_template( 'single.lesson.lesson_sidebar' );
1189
+ $output = apply_filters( 'tutor_lesson/single/lesson_sidebar', ob_get_clean() );
1190
 
1191
+ if ( $echo ) {
1192
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1193
+ }
1194
 
1195
+ return $output;
1196
+ }
1197
  }
1198
 
1199
  /**
1204
  * Render Lesson Main Content
1205
  * @since v.1.0.0
1206
  */
1207
+ if ( ! function_exists( 'tutor_lesson_content' ) ) {
1208
+ function tutor_lesson_content( $echo = true ) {
1209
+ ob_start();
1210
+ tutor_load_template( 'single.lesson.content' );
1211
+ $output = apply_filters( 'tutor_lesson/single/content', ob_get_clean() );
1212
 
1213
+ if ( $echo ) {
1214
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1215
+ }
1216
 
1217
+ return $output;
1218
+ }
1219
  }
1220
 
1221
+ if ( ! function_exists( 'tutor_lesson_mark_complete_html' ) ) {
1222
+ function tutor_lesson_mark_complete_html( $echo = true ) {
1223
+ ob_start();
1224
+ tutor_load_template( 'single.lesson.complete_form' );
1225
+ $output = apply_filters( 'tutor_lesson/single/complete_form', ob_get_clean() );
1226
 
1227
+ if ( $echo ) {
1228
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1229
+ }
1230
 
1231
+ return $output;
1232
+ }
1233
  }
1234
 
1235
+ if ( ! function_exists( 'tutor_course_mark_complete_html' ) ) {
1236
+ function tutor_course_mark_complete_html( $echo = true ) {
1237
+ ob_start();
1238
+ tutor_load_template( 'single.course.complete_form' );
1239
+ $output = apply_filters( 'tutor_course/single/complete_form', ob_get_clean() );
1240
 
1241
+ if ( $echo ) {
1242
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1243
+ }
1244
 
1245
+ return $output;
1246
+ }
1247
  }
1248
 
1249
 
1257
  * @since v.1.0.0
1258
  */
1259
 
1260
+ if ( ! function_exists( 'tutor_course_completing_progress_bar' ) ) {
1261
+ function tutor_course_completing_progress_bar( $echo = true ) {
1262
+ ob_start();
1263
+ tutor_load_template( 'single.course.enrolled.completing-progress' );
1264
+ $output = apply_filters( 'tutor_course/single/completing-progress-bar', ob_get_clean() );
1265
 
1266
+ if ( $echo ) {
1267
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1268
+ }
1269
 
1270
+ return $output;
1271
+ }
1272
  }
1273
 
1274
+ function tutor_course_question_and_answer( $echo = true ) {
1275
+ ob_start();
1276
+ tutor_load_template( 'single.course.enrolled.question_and_answer' );
1277
+ $output = apply_filters( 'tutor_course/single/question_and_answer', ob_get_clean() );
1278
 
1279
+ if ( $echo ) {
1280
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1281
+ }
1282
 
1283
+ return $output;
1284
  }
1285
 
1286
 
1287
+ function tutor_course_announcements( $echo = true ) {
1288
+ ob_start();
1289
+ tutor_load_template( 'single.course.enrolled.announcements' );
1290
+ $output = apply_filters( 'tutor_course/single/announcements', ob_get_clean() );
1291
 
1292
+ if ( $echo ) {
1293
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1294
+ }
1295
 
1296
+ return $output;
1297
  }
1298
 
1299
+ function tutor_single_quiz_top( $echo = true ) {
1300
+ ob_start();
1301
+ tutor_load_template( 'single.quiz.top' );
1302
+ $output = apply_filters( 'tutor_single_quiz/top', ob_get_clean() );
1303
 
1304
+ if ( $echo ) {
1305
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1306
+ }
1307
+ return $output;
1308
  }
1309
 
1310
+ function tutor_single_quiz_body( $echo = true ) {
1311
+ ob_start();
1312
+ tutor_load_template( 'single.quiz.body' );
1313
+ $output = apply_filters( 'tutor_single_quiz/body', ob_get_clean() );
1314
 
1315
+ if ( $echo ) {
1316
+ echo $output;
1317
+ }
1318
+ return $output;
1319
  }
1320
 
1321
  /**
1325
  *
1326
  * Get the quiz description
1327
  */
1328
+ function tutor_single_quiz_content( $echo = true ) {
1329
+ ob_start();
1330
+ tutor_load_template( 'single.quiz.content' );
1331
+ $output = apply_filters( 'tutor_single_quiz/content', ob_get_clean() );
1332
 
1333
+ if ( $echo ) {
1334
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1335
+ }
1336
+ return $output;
1337
  }
1338
 
1339
 
1340
+ function tutor_single_quiz_no_course_belongs( $echo = true ) {
1341
+ ob_start();
1342
+ tutor_load_template( 'single.quiz.no_course_belongs' );
1343
+ $output = apply_filters( 'tutor_single_quiz/no_course_belongs', ob_get_clean() );
1344
 
1345
+ if ( $echo ) {
1346
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1347
+ }
1348
+ return $output;
1349
  }
1350
 
1351
+ function single_quiz_contents( $echo = true ) {
1352
 
1353
+ ob_start();
1354
+ tutor_load_template( 'single.quiz.single_quiz_contents' );
1355
+ $output = apply_filters( 'tutor_single_quiz/single_quiz_contents', ob_get_clean() );
1356
 
1357
+ if ( $echo ) {
1358
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1359
+ }
1360
+ return $output;
1361
  }
1362
 
1363
+ function get_tutor_course_level( $course_id = 0 ) {
1364
+ if ( ! $course_id ) {
1365
+ $course_id = get_the_ID();
1366
+ }
1367
+ if ( ! $course_id ) {
1368
+ return '';
1369
+ }
1370
 
1371
+ $course_level = get_post_meta( $course_id, '_tutor_course_level', true );
1372
 
1373
+ if ( $course_level ) {
1374
+ return tutor_utils()->course_levels( $course_level );
1375
+ }
1376
+ return false;
1377
  }
1378
 
1379
+ if ( ! function_exists( 'get_tutor_course_duration_context' ) ) {
1380
+ function get_tutor_course_duration_context( $course_id = 0 ) {
1381
+ if ( ! $course_id ) {
1382
+ $course_id = get_the_ID();
1383
+ }
1384
+ if ( ! $course_id ) {
1385
+ return '';
1386
+ }
1387
+ $duration = get_post_meta( $course_id, '_course_duration', true );
1388
+ $durationHours = tutor_utils()->avalue_dot( 'hours', $duration );
1389
+ $durationMinutes = tutor_utils()->avalue_dot( 'minutes', $duration );
1390
+ $durationSeconds = tutor_utils()->avalue_dot( 'seconds', $duration );
1391
 
1392
+ if ( $duration ) {
1393
+ $output = '';
1394
+ if ( $durationHours > 0 ) {
1395
+ $output .= $durationHours . 'h ';
1396
+ }
1397
 
1398
+ if ( $durationMinutes > 0 ) {
1399
+ $output .= $durationMinutes . 'm ';
1400
+ }
1401
 
1402
+ if ( $durationSeconds > 0 ) {
1403
+ $output .= $durationSeconds . 's ';
1404
+ }
1405
 
1406
+ return $output;
1407
+ }
1408
 
1409
+ return false;
1410
+ }
1411
  }
1412
+ if ( ! function_exists( 'get_tutor_course_categories' ) ) {
1413
+ function get_tutor_course_categories( $course_id = 0 ) {
1414
+ if ( ! $course_id ) {
1415
+ $course_id = get_the_ID();
1416
+ }
1417
+ $terms = get_the_terms( $course_id, 'course-category' );
1418
 
1419
+ return $terms;
1420
+ }
1421
  }
1422
 
1423
  /**
1428
  * Get course tags
1429
  */
1430
 
1431
+ if ( ! function_exists( 'get_tutor_course_tags' ) ) {
1432
+ function get_tutor_course_tags( $course_id = 0 ) {
1433
+ if ( ! $course_id ) {
1434
+ $course_id = get_the_ID();
1435
+ }
1436
+ $terms = get_the_terms( $course_id, 'course-tag' );
1437
 
1438
+ return $terms;
1439
+ }
1440
  }
1441
 
1442
  /**
1447
  * Template for course tags html
1448
  */
1449
 
1450
+ if ( ! function_exists( 'tutor_course_tags_html' ) ) {
1451
+ function tutor_course_tags_html( $echo = true ) {
1452
+ ob_start();
1453
+ tutor_load_template( 'single.course.tags' );
1454
+ $output = apply_filters( 'tutor_course/single/tags_html', ob_get_clean() );
1455
 
1456
+ if ( $echo ) {
1457
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1458
+ }
1459
 
1460
+ return $output;
1461
+ }
1462
  }
1463
 
1464
  /**
1469
  * Get Q&A in lesson sidebar
1470
  */
1471
 
1472
+ if ( ! function_exists( 'tutor_lesson_sidebar_question_and_answer' ) ) {
1473
+ function tutor_lesson_sidebar_question_and_answer( $echo = true ) {
1474
+ ob_start();
1475
+ tutor_load_template( 'single.lesson.sidebar_question_and_answer' );
1476
+ $output = apply_filters( 'tutor_lesson/single/sidebar_question_and_answer', ob_get_clean() );
1477
 
1478
+ if ( $echo ) {
1479
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1480
+ }
1481
 
1482
+ return $output;
1483
+ }
1484
  }
1485
 
1486
  /**
1491
  * Get Social Share button to share on social media
1492
  */
1493
 
1494
+ if ( ! function_exists( 'tutor_social_share' ) ) {
1495
+ function tutor_social_share( $echo = true ) {
1496
 
1497
+ $output = '';
1498
+ $tutor_social_share_icons = tutor_utils()->tutor_social_share_icons();
1499
 
1500
+ if ( tutor_utils()->count( $tutor_social_share_icons ) ) {
1501
+ ob_start();
1502
+ tutor_load_template( 'single.course.social_share', array( 'tutor_social_share_icons' => $tutor_social_share_icons ) );
1503
+ $output = apply_filters( 'tutor_course/single/social_share', ob_get_clean() );
1504
+ }
1505
 
1506
+ if ( $echo && $output != '' ) {
1507
+ echo '<span>' . __( 'Share:', 'tutor' ) . '</span>';
1508
+ echo $output;
1509
+ }
1510
 
1511
+ return $output;
1512
+ }
1513
  }
1514
 
1515
  /**
1522
  * @since v.1.3.3
1523
  */
1524
 
1525
+ if ( ! function_exists( 'tutor_assignment_content' ) ) {
1526
+ function tutor_assignment_content( $echo = true ) {
1527
+ ob_start();
1528
+ tutor_load_template( 'single.assignment.content' );
1529
+ $output = apply_filters( 'tutor_assignment/single/content', ob_get_clean() );
1530
 
1531
+ if ( $echo ) {
1532
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1533
+ }
1534
 
1535
+ return $output;
1536
+ }
1537
  }
1538
 
1539
  /**
1546
  * @since v.1.4.0
1547
  */
1548
 
1549
+ if ( ! function_exists( 'get_tnotice' ) ) {
1550
+ function get_tnotice( $msg = '', $title = 'Success', $type = 'success' ) {
1551
 
1552
+ $output = '<div class="tnotice tnotice--' . $type . '">
1553
  <div class="tnotice__icon">&iexcl;</div>
1554
  <div class="tnotice__content">';
1555
 
1556
+ if ( $title ) {
1557
+ $output .= '<p class="tnotice__type">' . $title . '</p>';
1558
+ }
1559
+ $output .= '<p class="tnotice__message">' . $msg . '</p>
1560
  </div>
1561
  </div>';
1562
 
1563
+ return $output;
1564
+ }
1565
  }
1566
 
1567
  /**
1568
+ * @param int $course_content_id
1569
  * @param bool $echo
1570
  *
1571
  * @return mixed|void
1575
  * @since v.1.4.7
1576
  */
1577
 
1578
+ function tutor_next_previous_pagination( $course_content_id = 0, $echo = true ) {
1579
+ $content_id = tutils()->get_post_id( $course_content_id );
1580
+ $contents = tutils()->get_course_prev_next_contents_by_id( $content_id );
1581
+ $previous_id = $contents->previous_id;
1582
+ $next_id = $contents->next_id;
1583
 
1584
+ ob_start();
1585
+ do_action( 'tutor_lesson_next_previous_pagination_before' );
1586
+ tutor_load_template( 'single.next-previous-pagination', compact( 'previous_id', 'next_id' ) );
1587
+ do_action( 'tutor_lesson_next_previous_pagination_after' );
1588
+ $output = apply_filters( 'tutor/single/next_previous_pagination', ob_get_clean() );
1589
 
1590
+ if ( $echo ) {
1591
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1592
+ }
1593
 
1594
+ return $output;
1595
  }
1596
 
1597
 
1598
  /**
1599
  * Required login form in archive page
1600
+ *
1601
  * @param bool $echo
1602
  * @since v 1.5.5
1603
  *
1604
  * @todo, it will be remove from 2.0.0
1605
  */
1606
+ function tutor_archive_course_add_to_cart( $echo = true ) {
1607
+ _deprecated_function( __FUNCTION__, '1.5.8' );
1608
 
1609
+ $output = '';
1610
+ if ( $echo ) {
1611
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1612
+ }
1613
+ return $output;
1614
  }
1615
 
1616
  /**
1622
  * @since v.1.5.8
1623
  */
1624
 
1625
+ if ( ! function_exists( 'tutor_login_form_popup' ) ) {
1626
+ function tutor_login_form_popup( $echo = true ) {
1627
+ $output = '';
1628
+ ob_start();
1629
+ tutor_load_template( 'single.course.login' );
1630
+ $login_form = apply_filters( 'tutor_course/global/login', ob_get_clean() );
1631
+ $output .= '<div class="tutor-cart-box-login-form" style="display: none;"><span class="login-overlay-close"></span><div class="tutor-cart-box-login-form-inner"><button class="tutor-popup-form-close tutor-icon-line-cross"></button>' . $login_form . '</div></div>';
1632
 
1633
+ $output = apply_filters( 'tutor_login_form_popup_html', $output );
1634
 
1635
+ if ( $echo ) {
1636
+ echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1637
+ }
1638
+ return $output;
1639
+ }
1640
  }
1641
 
1642
  /**
1643
  * Load custom template from any given file
1644
+ *
1645
  * Pass parameter as wish
1646
+ *
1647
  * @since 1.9.8
1648
  */
1649
+ if ( ! function_exists( 'tutor_load_template_from_custom_path' ) ) {
1650
+ function tutor_load_template_from_custom_path( $template = null, $data = array() ) {
1651
+ do_action( 'tutor_load_template_from_custom_path_before', $template, $data );
1652
+ if ( file_exists( $template ) ) {
1653
+ include_once $template;
1654
+ }
1655
+ do_action( 'tutor_load_template_from_custom_path_after', $template, $data );
1656
+ }
1657
+ }
languages/tutor.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2021 Tutor LMS
2
  # This file is distributed under the same license as the Tutor LMS package.
3
  msgid ""
4
  msgstr ""
@@ -17,95 +17,95 @@ msgstr ""
17
  msgid "Tutor Instructor"
18
  msgstr ""
19
 
20
- #: classes/Addons.php:26
21
  msgid "BuddyPress"
22
  msgstr ""
23
 
24
- #: classes/Addons.php:30
25
  msgid "Gradebook"
26
  msgstr ""
27
 
28
- #: classes/Addons.php:34
29
  msgid "Content Drip"
30
  msgstr ""
31
 
32
- #: classes/Addons.php:38
33
  msgid "Enrollments"
34
  msgstr ""
35
 
36
- #: classes/Addons.php:42
37
  msgid "WooCommerce Subscriptions"
38
  msgstr ""
39
 
40
- #: classes/Addons.php:46
41
  msgid "Paid Memberships Pro"
42
  msgstr ""
43
 
44
- #: classes/Addons.php:50
45
  msgid "Restrict Content Pro"
46
  msgstr ""
47
 
48
- #: classes/Addons.php:54
49
  msgid "Tutor Assignments"
50
  msgstr ""
51
 
52
- #: classes/Addons.php:58
53
  msgid "Tutor Certificate"
54
  msgstr ""
55
 
56
- #: classes/Addons.php:62
57
  msgid "Tutor Course Attachments"
58
  msgstr ""
59
 
60
- #: classes/Addons.php:66
61
  msgid "Tutor Course Preview"
62
  msgstr ""
63
 
64
- #: classes/Addons.php:70
65
  msgid "Tutor E-Mail"
66
  msgstr ""
67
 
68
- #: classes/Addons.php:74
69
  msgid "Tutor Multi Instructors"
70
  msgstr ""
71
 
72
- #: classes/Addons.php:78
73
  msgid "Tutor Prerequisites"
74
  msgstr ""
75
 
76
- #: classes/Addons.php:82
77
  msgid "Tutor Report"
78
  msgstr ""
79
 
80
- #: classes/Addons.php:86
81
  msgid "Quiz Export/Import"
82
  msgstr ""
83
 
84
- #: classes/Addons.php:87
85
  msgid "Save time by exporting/importing quiz data with easy options."
86
  msgstr ""
87
 
88
- #: classes/Addons.php:90
89
  msgid "Tutor Zoom Integration"
90
  msgstr ""
91
 
92
- #: classes/Addons.php:91
93
  msgid "Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page."
94
  msgstr ""
95
 
96
- #: classes/Addons.php:94
97
  msgid "Google Classroom Integration"
98
  msgstr ""
99
 
100
- #: classes/Addons.php:95
101
  msgid "Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course."
102
  msgstr ""
103
 
104
- #: classes/Addons.php:102
105
  msgid "WPML Multilingual CMS"
106
  msgstr ""
107
 
108
- #: classes/Addons.php:103
109
  msgid "Create multilingual courses, lessons, dashboard and more for a global audience."
110
  msgstr ""
111
 
@@ -117,7 +117,7 @@ msgstr ""
117
  msgid "Tutor LMS"
118
  msgstr ""
119
 
120
- #: classes/Admin.php:56, classes/Admin.php:56, templates/single/course/lead-info.php:91, templates/single/course/enrolled/lead-info.php:92
121
  msgid "Categories"
122
  msgstr ""
123
 
@@ -125,15 +125,15 @@ msgstr ""
125
  msgid "Tags"
126
  msgstr ""
127
 
128
- #: classes/Admin.php:60, classes/Admin.php:60, classes/Course.php:484, classes/Options.php:593, classes/Quiz_Attempts_List.php:113, templates/student-public-profile.php:103, views/pages/students.php:8
129
  msgid "Students"
130
  msgstr ""
131
 
132
- #: classes/Admin.php:63, classes/Admin.php:63, classes/Course.php:182, classes/Course.php:261, classes/Options.php:554, views/pages/instructors.php:29
133
  msgid "Instructors"
134
  msgstr ""
135
 
136
- #: classes/Admin.php:66, classes/Admin.php:66, classes/Utils.php:1295, classes/Utils.php:2480, templates/dashboard/announcements.php:123, views/pages/announcements.php:104, views/pages/announcements.php:114
137
  msgid "Announcements"
138
  msgstr ""
139
 
@@ -145,7 +145,7 @@ msgstr ""
145
  msgid "Q & A "
146
  msgstr ""
147
 
148
- #: classes/Admin.php:70, classes/Admin.php:70, classes/Utils.php:2482, templates/dashboard/quiz-attempts.php:19, views/pages/quiz_attempts.php:29
149
  msgid "Quiz Attempts"
150
  msgstr ""
151
 
@@ -157,7 +157,7 @@ msgstr ""
157
  msgid "Add-ons"
158
  msgstr ""
159
 
160
- #: classes/Admin.php:80, classes/Admin.php:80, classes/Admin.php:453, classes/Utils.php:2495, templates/dashboard/settings.php:8, views/modal/add_quiz.php:24, views/modal/edit_quiz.php:35, templates/dashboard/notifications/profile-completion.php:14, templates/dashboard/settings/education.php:7, templates/dashboard/settings/skill.php:8
161
  msgid "Settings"
162
  msgstr ""
163
 
@@ -177,11 +177,11 @@ msgstr ""
177
  msgid "Tutor Pages"
178
  msgstr ""
179
 
180
- #: classes/Admin.php:139, classes/Instructors_List.php:121, templates/dashboard/dashboard.php:90, templates/dashboard/purchase_history.php:23, templates/dashboard/withdraw.php:186, views/pages/view_attempt.php:59, views/pages/tools/tutor_pages.php:13
181
  msgid "Status"
182
  msgstr ""
183
 
184
- #: classes/Admin.php:245, templates/permission-denied.php:39, templates/dashboard/create-course.php:24, templates/single/lesson/required-enroll.php:5
185
  msgid "Permission Denied"
186
  msgstr ""
187
 
@@ -201,187 +201,187 @@ msgstr ""
201
  msgid "If you like %1$s please leave us a %2$s rating. A huge thanks in advance!"
202
  msgstr ""
203
 
204
- #: classes/Ajax.php:62, classes/Ajax.php:115, classes/Ajax.php:179, classes/Ajax.php:237, classes/Ajax.php:290, classes/Ajax.php:332, classes/Ajax.php:353, classes/Ajax.php:456, classes/Ajax.php:527, classes/Course.php:424, classes/Course.php:459, classes/Course.php:696, classes/Course.php:747, classes/Course.php:784, classes/Course.php:797, classes/Instructor.php:250, classes/Lesson.php:121, classes/Lesson.php:161, classes/Lesson.php:218, classes/Quiz.php:147, classes/Quiz.php:549, classes/Quiz.php:645, classes/Quiz.php:691, classes/Quiz.php:735, classes/Quiz.php:775, classes/Quiz.php:798, classes/Quiz.php:894, classes/Quiz.php:917, classes/Quiz.php:938, classes/Quiz.php:1049, classes/Quiz.php:1094, classes/Quiz.php:1175, classes/Quiz.php:1235, classes/Quiz.php:1260, classes/Q_and_A.php:71
205
  msgid "Access Denied"
206
  msgstr ""
207
 
208
- #: classes/Ajax.php:165
209
  msgid "Rating placed success"
210
  msgstr ""
211
 
212
- #: classes/Ajax.php:184
213
  msgid "Empty question title or body"
214
  msgstr ""
215
 
216
- #: classes/Ajax.php:216
217
  msgid "Question has been added successfully"
218
  msgstr ""
219
 
220
- #: classes/Ajax.php:226
221
  msgid "Please write answer"
222
  msgstr ""
223
 
224
- #: classes/Ajax.php:259
225
  msgid "Answer has been added successfully"
226
  msgstr ""
227
 
228
- #: classes/Ajax.php:280
229
  msgid "Course added to wish list"
230
  msgstr ""
231
 
232
- #: classes/Ajax.php:277
233
  msgid "Course removed from wish list"
234
  msgstr ""
235
 
236
- #: classes/Ajax.php:396, classes/Ajax.php:400
237
  msgid "ERROR:"
238
  msgstr ""
239
 
240
- #: classes/Ajax.php:400
241
  msgid "Username is required."
242
  msgstr ""
243
 
244
- #: classes/Ajax.php:442
245
  msgid "Announcement created successfully"
246
  msgstr ""
247
 
248
- #: classes/Ajax.php:443
249
  msgid "Announcement updated successfully"
250
  msgstr ""
251
 
252
- #: classes/Ajax.php:444
253
  msgid "Announcement creation failed"
254
  msgstr ""
255
 
256
- #: classes/Ajax.php:445
257
  msgid "Announcement update failed"
258
  msgstr ""
259
 
260
- #: classes/Ajax.php:474
261
  msgid "Course name required"
262
  msgstr ""
263
 
264
- #: classes/Ajax.php:479
265
  msgid "Announcement title required"
266
  msgstr ""
267
 
268
- #: classes/Ajax.php:483
269
  msgid "Announcement summary required"
270
  msgstr ""
271
 
272
- #: classes/Ajax.php:540
273
  msgid "Announcement delete failed"
274
  msgstr ""
275
 
276
- #: classes/Ajax.php:534
277
  msgid "Announcement deleted successfully"
278
  msgstr ""
279
 
280
- #: classes/Course.php:156
281
  msgid "Fully booked"
282
  msgstr ""
283
 
284
- #: classes/Course.php:178, classes/Course.php:260
285
  msgid "Course Builder"
286
  msgstr ""
287
 
288
- #: classes/Course.php:179, classes/Course.php:262
289
  msgid "Additional Data"
290
  msgstr ""
291
 
292
- #: classes/Course.php:180, classes/Course.php:259
293
  msgid "Video"
294
  msgstr ""
295
 
296
- #: classes/Course.php:189, classes/Course.php:1328, views/options/options_generator.php:2
297
  msgid "Tutor Settings"
298
  msgstr ""
299
 
300
- #: classes/Course.php:469
301
  msgid "Topic has been updated"
302
  msgstr ""
303
 
304
- #: classes/Course.php:483, classes/Options.php:447, classes/Post_types.php:172, templates/single/course/course-topics.php:38
305
  msgid "Lessons"
306
  msgstr ""
307
 
308
- #: classes/Course.php:485, templates/course-filter/filters.php:74, templates/dashboard/earning/statement.php:30
309
  msgid "Price"
310
  msgstr ""
311
 
312
- #: classes/Course.php:515
313
  msgid "free"
314
  msgstr ""
315
 
316
- #: classes/Course.php:565
317
  msgid "Please Sign In first"
318
  msgstr ""
319
 
320
- #: classes/Course.php:613, classes/Lesson.php:310
321
  msgid "Please Sign-In"
322
  msgstr ""
323
 
324
- #: classes/Course.php:729
325
- msgid "<p>No instructor available or you have already added maximum instructors</p>"
326
  msgstr ""
327
 
328
- #: classes/Course.php:734
329
- msgid "To add unlimited multiple instructors in your course, get %sTutor LMS Pro%s"
330
  msgstr ""
331
 
332
- #: classes/Course.php:1163
333
  msgid "complete all lessons to mark this course as complete"
334
  msgstr ""
335
 
336
- #: classes/Course.php:1200
337
  msgid "You have to pass %s quizzes to complete this course."
338
  msgstr ""
339
 
340
- #: classes/Course.php:1307
341
  msgid "Make This Course Public"
342
  msgstr ""
343
 
344
- #: classes/Course.php:1309
345
  msgid "No enrollment required."
346
  msgstr ""
347
 
348
- #: classes/Course.php:1317
349
  msgid "Disable Q&A"
350
  msgstr ""
351
 
352
- #: classes/Course.php:1374
353
  msgid "Invalid Course ID or Access Denied."
354
  msgstr ""
355
 
356
- #: classes/Course_Settings_Tabs.php:31, classes/Options.php:223, classes/Tutor_Setup.php:400, views/metabox/course/settings-tabs.php:13
357
  msgid "Course Settings"
358
  msgstr ""
359
 
360
- #: classes/Course_Settings_Tabs.php:37, classes/Options.php:120, classes/Options.php:123, classes/Options.php:222, classes/Tutor_Setup.php:561, classes/WooCommerce.php:281
361
  msgid "General"
362
  msgstr ""
363
 
364
- #: classes/Course_Settings_Tabs.php:38, classes/Options.php:124, classes/Tutor_Setup.php:361
365
  msgid "General Settings"
366
  msgstr ""
367
 
368
- #: classes/Course_Settings_Tabs.php:44
369
  msgid "Maximum Students"
370
  msgstr ""
371
 
372
- #: classes/Course_Settings_Tabs.php:45, classes/Options.php:136, classes/Options.php:143, classes/Options.php:163, classes/Options.php:170, classes/Options.php:177, classes/Options.php:184, classes/Options.php:197, classes/Options.php:228, classes/Options.php:246, classes/Options.php:263, classes/Options.php:296, classes/Options.php:314, classes/Options.php:320, classes/Options.php:456, classes/Options.php:563, classes/Options.php:577, classes/Options.php:584, classes/Options.php:609, classes/Options.php:616, classes/Options.php:634, classes/Options.php:658, classes/User.php:177
373
  msgid "Enable"
374
  msgstr ""
375
 
376
- #: classes/Course_Settings_Tabs.php:47
377
  msgid "Number of students that can enrol in this course. Set 0 for no limits."
378
  msgstr ""
379
 
380
- #: classes/Course_Widget.php:22
381
  msgid "Tutor Course"
382
  msgstr ""
383
 
384
- #: classes/Course_Widget.php:23
385
  msgid "Display courses wherever widget support is available."
386
  msgstr ""
387
 
@@ -389,51 +389,51 @@ msgstr ""
389
  msgid "New title"
390
  msgstr ""
391
 
392
- #: classes/Course_Widget.php:114
393
- msgid "Title:"
394
  msgstr ""
395
 
396
- #: classes/Course_Widget.php:119
397
- msgid "ID:"
398
  msgstr ""
399
 
400
- #: classes/Course_Widget.php:121
401
  msgid "Place single course id or comma (,) separated course ids"
402
  msgstr ""
403
 
404
- #: classes/Course_Widget.php:125
405
  msgid "Exclude IDS:"
406
  msgstr ""
407
 
408
- #: classes/Course_Widget.php:128
409
  msgid "Place comma (,) separated courses ids which you like to exclude from the query"
410
  msgstr ""
411
 
412
- #: classes/Course_Widget.php:133
413
- msgid "Category:"
414
  msgstr ""
415
 
416
- #: classes/Course_Widget.php:136
417
  msgid "Place comma (,) separated category ids"
418
  msgstr ""
419
 
420
- #: classes/Course_Widget.php:141
421
  msgid "OrderBy"
422
  msgstr ""
423
 
424
- #: classes/Course_Widget.php:154
425
- msgid "order"
426
  msgstr ""
427
 
428
- #: classes/Course_Widget.php:163
429
  msgid "Count:"
430
  msgstr ""
431
 
432
- #: classes/Course_Widget.php:166
433
  msgid "Total results you like to show"
434
  msgstr ""
435
 
436
- #: classes/Dashboard.php:48
437
  msgid "Auto Draft"
438
  msgstr ""
439
 
@@ -449,7 +449,7 @@ msgstr ""
449
  msgid "Check and place necessary information here."
450
  msgstr ""
451
 
452
- #: classes/Email.php:32, classes/Instructors_List.php:116, classes/Students_List.php:66
453
  msgid "Name"
454
  msgstr ""
455
 
@@ -505,15 +505,15 @@ msgstr ""
505
  msgid "This key is invalid or has already been used. Please reset your password again if needed."
506
  msgstr ""
507
 
508
- #: classes/FormHandler.php:119
509
  msgid "Please enter your password."
510
  msgstr ""
511
 
512
- #: classes/FormHandler.php:124
513
  msgid "Passwords do not match."
514
  msgstr ""
515
 
516
- #: classes/FormHandler.php:162
517
  msgid "Password Reset Request for %s"
518
  msgstr ""
519
 
@@ -565,856 +565,852 @@ msgstr ""
565
  msgid "Instructor has been added successfully"
566
  msgstr ""
567
 
568
- #: classes/Instructors_List.php:68, classes/Withdraw_Requests_List.php:51, classes/Withdraw_Requests_List.php:59
569
  msgid "Approve"
570
  msgstr ""
571
 
572
- #: classes/Instructors_List.php:71
573
  msgid "Sure to Block?"
574
  msgstr ""
575
 
576
- #: classes/Instructors_List.php:71
577
  msgid "Block"
578
  msgstr ""
579
 
580
- #: classes/Instructors_List.php:74
581
  msgid "Sure to Un Block?"
582
  msgstr ""
583
 
584
- #: classes/Instructors_List.php:74
585
  msgid "Unblock"
586
  msgstr ""
587
 
588
- #: classes/Instructors_List.php:84
589
  msgid "Reject"
590
  msgstr ""
591
 
592
- #: classes/Instructors_List.php:84
593
  msgid "Remove as Instructor"
594
  msgstr ""
595
 
596
- #: classes/Instructors_List.php:85
597
  msgid "Sure to Reject?"
598
  msgstr ""
599
 
600
- #: classes/Instructors_List.php:85
601
  msgid "Sure to Remove as Instructor?"
602
  msgstr ""
603
 
604
- #: classes/Instructors_List.php:117, classes/Students_List.php:67, templates/dashboard/registration.php:83, templates/dashboard/registration.php:86, views/pages/add_new_instructor.php:69, views/pages/add_new_instructor.php:75, templates/dashboard/instructor/registration.php:86, templates/dashboard/instructor/registration.php:89
605
  msgid "E-Mail"
606
  msgstr ""
607
 
608
- #: classes/Instructors_List.php:118
609
  msgid "Total Course"
610
  msgstr ""
611
 
612
- #: classes/Instructors_List.php:119
613
  msgid "Instructor Commission"
614
  msgstr ""
615
 
616
- #: classes/Instructors_List.php:120, classes/Tutor_List_Table.php:409, classes/Tutor_List_Table.php:1287, templates/dashboard/announcements.php:112, templates/dashboard/announcements.php:122, templates/dashboard/purchase_history.php:24, views/pages/announcements.php:94, views/pages/announcements.php:113, templates/dashboard/assignments/submitted.php:71
617
  msgid "Date"
618
  msgstr ""
619
 
620
- #: classes/Lesson.php:53, views/metabox/lesson-metabox.php:3, views/pages/announcements.php:194, views/pages/announcements.php:276, templates/dashboard/announcements/create.php:19, templates/dashboard/announcements/update.php:20
621
  msgid "Select Course"
622
  msgstr ""
623
 
624
- #: classes/Lesson.php:54
625
  msgid "Lesson Video"
626
  msgstr ""
627
 
628
- #: classes/Lesson.php:55, templates/global/attachments.php:25, templates/single/assignment/content.php:144
629
  msgid "Attachments"
630
  msgstr ""
631
 
632
- #: classes/Lesson.php:131
633
  msgid "Draft Lesson"
634
  msgstr ""
635
 
636
- #: classes/Lesson.php:187
637
  msgid "Couldn't create lesson."
638
  msgstr ""
639
 
640
- #: classes/Lesson.php:271, classes/Options.php:219, classes/Question_Answers_List.php:75, classes/Quiz_Attempts_List.php:115, classes/Tutor_Setup.php:562, templates/student-public-profile.php:98, templates/dashboard/question-answer.php:27, templates/shortcode/tutor-instructor.php:27, views/pages/view_attempt.php:73, templates/dashboard/announcements/details.php:19, templates/dashboard/assignments/review.php:44, templates/dashboard/assignments/submitted.php:30, templates/dashboard/earning/statement.php:13, templates/single/quiz/top.php:27
641
  msgid "Course"
642
  msgstr ""
643
 
644
- #: classes/Options.php:86
645
  msgid "Option Updated"
646
  msgstr ""
647
 
648
- #: classes/Options.php:93
649
  msgid "/course/sample-course/<code>lessons</code>/sample-lesson/"
650
  msgstr ""
651
 
652
- #: classes/Options.php:96
653
  msgctxt "tutor student profile"
654
  msgid "profile"
655
  msgstr ""
656
 
657
- #: classes/Options.php:99, classes/Tutor_Setup.php:327
658
  msgid "Unlimited"
659
  msgstr ""
660
 
661
- #: classes/Options.php:103, views/metabox/video-metabox.php:19
662
  msgid "HTML 5 (mp4)"
663
  msgstr ""
664
 
665
- #: classes/Options.php:104, views/metabox/video-metabox.php:20
666
  msgid "External URL"
667
  msgstr ""
668
 
669
- #: classes/Options.php:105, views/metabox/video-metabox.php:21
670
  msgid "Youtube"
671
  msgstr ""
672
 
673
- #: classes/Options.php:106, views/metabox/video-metabox.php:22
674
  msgid "Vimeo"
675
  msgstr ""
676
 
677
- #: classes/Options.php:107, views/metabox/video-metabox.php:23
678
  msgid "Embedded"
679
  msgstr ""
680
 
681
- #: classes/Options.php:111
682
  msgid "Keyword Search"
683
  msgstr ""
684
 
685
- #: classes/Options.php:112, templates/course-filter/filters.php:33
686
- msgid "Category"
687
- msgstr ""
688
-
689
- #: classes/Options.php:113, templates/course-filter/filters.php:42
690
  msgid "Tag"
691
  msgstr ""
692
 
693
- #: classes/Options.php:114, views/metabox/course-level-metabox.php:10
694
  msgid "Difficulty Level"
695
  msgstr ""
696
 
697
- #: classes/Options.php:115
698
  msgid "Price Type"
699
  msgstr ""
700
 
701
- #: classes/Options.php:128, classes/Utils.php:6791
702
  msgid "Dashboard Page"
703
  msgstr ""
704
 
705
- #: classes/Options.php:131
706
  msgid "This page will be used for student and instructor dashboard"
707
  msgstr ""
708
 
709
- #: classes/Options.php:135, classes/Tutor_Setup.php:371
710
  msgid "Public Profile"
711
  msgstr ""
712
 
713
- #: classes/Options.php:138
714
  msgid "Enable this to make a profile publicly visible"
715
  msgstr ""
716
 
717
- #: classes/Options.php:142
718
  msgid "Profile Completion"
719
  msgstr ""
720
 
721
- #: classes/Options.php:145
722
  msgid "Enabling this feature will show a notification bar to students and instructors to complete their profile information"
723
  msgstr ""
724
 
725
- #: classes/Options.php:149
726
  msgid "Tutor Native Login"
727
  msgstr ""
728
 
729
- #: classes/Options.php:150, classes/Options.php:327, classes/Options.php:334, classes/Options.php:341, classes/Options.php:348, classes/Options.php:355, classes/Options.php:362, classes/Options.php:369, classes/Options.php:376, classes/Options.php:383, classes/Options.php:390, classes/Options.php:397, classes/Options.php:404, classes/Options.php:411, classes/Options.php:418, classes/Options.php:425, classes/Options.php:532
730
  msgid "Disable"
731
  msgstr ""
732
 
733
- #: classes/Options.php:152
734
  msgid "Disable to use the default WordPress login page"
735
  msgstr ""
736
 
737
- #: classes/Options.php:156
738
  msgid "Course Visibility"
739
  msgstr ""
740
 
741
- #: classes/Options.php:157
742
  msgid "Logged in only"
743
  msgstr ""
744
 
745
- #: classes/Options.php:158
746
  msgid "Students must be logged in to view course"
747
  msgstr ""
748
 
749
- #: classes/Options.php:162
750
  msgid "Erase upon uninstallation"
751
  msgstr ""
752
 
753
- #: classes/Options.php:164
754
  msgid "Delete all data during uninstallation"
755
  msgstr ""
756
 
757
- #: classes/Options.php:169
758
  msgid "Spotlight mode"
759
  msgstr ""
760
 
761
- #: classes/Options.php:172
762
  msgid "This will hide the header and the footer and enable spotlight (full screen) mode when students view lessons."
763
  msgstr ""
764
 
765
- #: classes/Options.php:176, classes/Tutor_Setup.php:381
766
  msgid "YouTube Player"
767
  msgstr ""
768
 
769
- #: classes/Options.php:179, classes/Options.php:186
770
  msgid "Disable this option to use Tutor LMS video player."
771
  msgstr ""
772
 
773
- #: classes/Options.php:183, classes/Tutor_Setup.php:386
774
  msgid "Vimeo Player"
775
  msgstr ""
776
 
777
- #: classes/Options.php:190
778
  msgid "Pagination"
779
  msgstr ""
780
 
781
- #: classes/Options.php:192
782
  msgid "Number of items you would like displayed \"per page\" in the pagination"
783
  msgstr ""
784
 
785
- #: classes/Options.php:196
786
  msgid "Maintenance Mode"
787
  msgstr ""
788
 
789
- #: classes/Options.php:199
790
  msgid "Enabling the maintenance mode allows you to display a custom message on the frontend. During this time, visitors can not access the site content. But the wp-admin dashboard will remain accessible."
791
  msgstr ""
792
 
793
- #: classes/Options.php:203
794
  msgid "Frontend Admin Bar"
795
  msgstr ""
796
 
797
- #: classes/Options.php:204
798
  msgid "Hide"
799
  msgstr ""
800
 
801
- #: classes/Options.php:206
802
  msgid "Hide admin bar option allow you to hide WordPress admin bar entirely from the frontend. It will still show to administrator roles user"
803
  msgstr ""
804
 
805
- #: classes/Options.php:210
806
  msgid "Error message for wrong login credentials"
807
  msgstr ""
808
 
809
- #: classes/Options.php:212
810
  msgid "Login error message displayed when the user puts wrong login credentials."
811
  msgstr ""
812
 
813
- #: classes/Options.php:227
814
  msgid "Gutenberg Editor"
815
  msgstr ""
816
 
817
- #: classes/Options.php:229
818
  msgid "Use Gutenberg editor on course description area."
819
  msgstr ""
820
 
821
- #: classes/Options.php:233, classes/Options.php:239, classes/Options.php:308, classes/Options.php:461, classes/WooCommerce.php:292
822
  msgid "Enable / Disable"
823
  msgstr ""
824
 
825
- #: classes/Options.php:234
826
  msgid "Hide course products from shop page"
827
  msgstr ""
828
 
829
- #: classes/Options.php:235
830
  msgid "Enabling this feature will remove course products from the shop page."
831
  msgstr ""
832
 
833
- #: classes/Options.php:240
834
  msgid "Course Content Access"
835
  msgstr ""
836
 
837
- #: classes/Options.php:241
838
  msgid "Allow instructors and admins to view the course content without enrolling"
839
  msgstr ""
840
 
841
- #: classes/Options.php:245
842
  msgid "Auto redirect to courses"
843
  msgstr ""
844
 
845
- #: classes/Options.php:247
846
  msgid "When a user's WooCommerce order is auto-completed, they will be redirected to enrolled courses"
847
  msgstr ""
848
 
849
- #: classes/Options.php:251
850
  msgid "Course Completion Process"
851
  msgstr ""
852
 
853
- #: classes/Options.php:255
854
  msgid "Flexible"
855
  msgstr ""
856
 
857
- #: classes/Options.php:256
858
  msgid "Strict Mode"
859
  msgstr ""
860
 
861
- #: classes/Options.php:258
862
  msgid "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."
863
  msgstr ""
864
 
865
- #: classes/Options.php:262
866
  msgid "Course Retake"
867
  msgstr ""
868
 
869
- #: classes/Options.php:264
870
  msgid "Enabling this feature will allow students to reset course progress and start over."
871
  msgstr ""
872
 
873
- #: classes/Options.php:269
874
  msgid "Archive"
875
  msgstr ""
876
 
877
- #: classes/Options.php:270
878
  msgid "Course Archive Settings"
879
  msgstr ""
880
 
881
- #: classes/Options.php:274
882
  msgid "Course Archive Page"
883
  msgstr ""
884
 
885
- #: classes/Options.php:277
886
  msgid "This page will be used to list all the published courses."
887
  msgstr ""
888
 
889
- #: classes/Options.php:281
890
  msgid "Column Per Row"
891
  msgstr ""
892
 
893
- #: classes/Options.php:284
894
  msgid "Define how many column you want to use to display courses."
895
  msgstr ""
896
 
897
- #: classes/Options.php:288, classes/Tutor_Setup.php:419
898
  msgid "Courses Per Page"
899
  msgstr ""
900
 
901
- #: classes/Options.php:291
902
  msgid "Define how many courses you want to show per page"
903
  msgstr ""
904
 
905
- #: classes/Options.php:295
906
  msgid "Course Filter"
907
  msgstr ""
908
 
909
- #: classes/Options.php:297
910
  msgid "Show sorting and filtering options on course archive page"
911
  msgstr ""
912
 
913
- #: classes/Options.php:301
914
  msgid "Preferred Course Filters"
915
  msgstr ""
916
 
917
- #: classes/Options.php:303
918
  msgid "Choose preferred filter options you'd like to show in course archive page."
919
  msgstr ""
920
 
921
- #: classes/Options.php:309
922
  msgid "Course Display Settings"
923
  msgstr ""
924
 
925
- #: classes/Options.php:313
926
  msgid "Display Instructor Info"
927
  msgstr ""
928
 
929
- #: classes/Options.php:315
930
  msgid "Show instructor bio on each page"
931
  msgstr ""
932
 
933
- #: classes/Options.php:319
934
  msgid "Question and Answer"
935
  msgstr ""
936
 
937
- #: classes/Options.php:322
938
  msgid "Enabling this feature will add a Q&amp;A section on every course."
939
  msgstr ""
940
 
941
- #: classes/Options.php:326
942
  msgid "Course Author"
943
  msgstr ""
944
 
945
- #: classes/Options.php:329
946
  msgid "Disabling this feature will be removed course author name from the course page."
947
  msgstr ""
948
 
949
- #: classes/Options.php:333
950
  msgid "Course Level"
951
  msgstr ""
952
 
953
- #: classes/Options.php:336
954
  msgid "Disabling this feature will be removed course level from the course page."
955
  msgstr ""
956
 
957
- #: classes/Options.php:340
958
  msgid "Course Share"
959
  msgstr ""
960
 
961
- #: classes/Options.php:343
962
  msgid "Disabling this feature will be removed course share option from the course page."
963
  msgstr ""
964
 
965
- #: classes/Options.php:347
966
  msgid "Course Duration"
967
  msgstr ""
968
 
969
- #: classes/Options.php:350
970
  msgid "Disabling this feature will be removed course duration from the course page."
971
  msgstr ""
972
 
973
- #: classes/Options.php:354
974
  msgid "Course Total Enrolled"
975
  msgstr ""
976
 
977
- #: classes/Options.php:357
978
  msgid "Disabling this feature will be removed course total enrolled from the course page."
979
  msgstr ""
980
 
981
- #: classes/Options.php:361
982
  msgid "Course Update Date"
983
  msgstr ""
984
 
985
- #: classes/Options.php:364
986
  msgid "Disabling this feature will be removed course update date from the course page."
987
  msgstr ""
988
 
989
- #: classes/Options.php:368
990
  msgid "Course Progress Bar"
991
  msgstr ""
992
 
993
- #: classes/Options.php:371
994
  msgid "Disabling this feature will be removed completing progress bar from the course page."
995
  msgstr ""
996
 
997
- #: classes/Options.php:375
998
  msgid "Course Material"
999
  msgstr ""
1000
 
1001
- #: classes/Options.php:378
1002
  msgid "Disabling this feature will be removed course material from the course page."
1003
  msgstr ""
1004
 
1005
- #: classes/Options.php:382
1006
  msgid "Course About"
1007
  msgstr ""
1008
 
1009
- #: classes/Options.php:385
1010
  msgid "Disabling this feature will be removed course about from the course page."
1011
  msgstr ""
1012
 
1013
- #: classes/Options.php:389
1014
  msgid "Course Description"
1015
  msgstr ""
1016
 
1017
- #: classes/Options.php:392
1018
  msgid "Disabling this feature will be removed course description from the course page."
1019
  msgstr ""
1020
 
1021
- #: classes/Options.php:396
1022
  msgid "Course Benefits"
1023
  msgstr ""
1024
 
1025
- #: classes/Options.php:399
1026
  msgid "Disabling this feature will be removed course benefits from the course page."
1027
  msgstr ""
1028
 
1029
- #: classes/Options.php:403
1030
  msgid "Course Requirements"
1031
  msgstr ""
1032
 
1033
- #: classes/Options.php:406
1034
  msgid "Disabling this feature will be removed course requirements from the course page."
1035
  msgstr ""
1036
 
1037
- #: classes/Options.php:410
1038
  msgid "Course Target Audience"
1039
  msgstr ""
1040
 
1041
- #: classes/Options.php:413
1042
  msgid "Disabling this feature will be removed course target audience from the course page."
1043
  msgstr ""
1044
 
1045
- #: classes/Options.php:417
1046
  msgid "Course Announcements"
1047
  msgstr ""
1048
 
1049
- #: classes/Options.php:420
1050
  msgid "Disabling this feature will be removed course announcements from the course page."
1051
  msgstr ""
1052
 
1053
- #: classes/Options.php:424
1054
  msgid "Course Review"
1055
  msgstr ""
1056
 
1057
- #: classes/Options.php:427
1058
  msgid "Disabling this feature will be removed course review system from the course page."
1059
  msgstr ""
1060
 
1061
- #: classes/Options.php:431
1062
  msgid "Preferred Video Source"
1063
  msgstr ""
1064
 
1065
- #: classes/Options.php:433
1066
  msgid "Choose video sources you'd like to support. Unchecking all will not disable video feature."
1067
  msgstr ""
1068
 
1069
- #: classes/Options.php:437
1070
  msgid "Default Video Source"
1071
  msgstr ""
1072
 
1073
- #: classes/Options.php:440
1074
  msgid "Choose video source to be selected by default."
1075
  msgstr ""
1076
 
1077
- #: classes/Options.php:450
1078
  msgid "Lesson Settings"
1079
  msgstr ""
1080
 
1081
- #: classes/Options.php:451
1082
  msgid "Lesson settings will be here"
1083
  msgstr ""
1084
 
1085
- #: classes/Options.php:455, views/modal/edit-lesson.php:12
1086
  msgid "Classic Editor"
1087
  msgstr ""
1088
 
1089
- #: classes/Options.php:457
1090
  msgid "Enable classic editor to get full support of any editor/page builder."
1091
  msgstr ""
1092
 
1093
- #: classes/Options.php:462
1094
  msgid "Automatically load next course content."
1095
  msgstr ""
1096
 
1097
- #: classes/Options.php:463
1098
  msgid "Enabling this feature will be load next course content automatically after finishing current video."
1099
  msgstr ""
1100
 
1101
- #: classes/Options.php:467
1102
  msgid "Lesson Permalink Base"
1103
  msgstr ""
1104
 
1105
- #: classes/Options.php:473
1106
  msgid "Youtube API Key"
1107
  msgstr ""
1108
 
1109
- #: classes/Options.php:482, classes/Options.php:485, classes/Quiz_Attempts_List.php:114, classes/Tutor_Setup.php:563, views/metabox/course-contents.php:169, views/metabox/course-topics.php:62, views/pages/view_attempt.php:39, templates/single/quiz/top.php:24
1110
  msgid "Quiz"
1111
  msgstr ""
1112
 
1113
- #: classes/Options.php:486
1114
  msgid "The values you set here define the default values that are used in the settings form when you create a new quiz."
1115
  msgstr ""
1116
 
1117
- #: classes/Options.php:490, classes/Tutor_Setup.php:432, views/modal/edit_quiz.php:144
1118
  msgid "Time Limit"
1119
  msgstr ""
1120
 
1121
- #: classes/Options.php:491
1122
  msgid "0 means unlimited time."
1123
  msgstr ""
1124
 
1125
- #: classes/Options.php:502, views/modal/edit_quiz.php:156
1126
  msgid "Weeks"
1127
  msgstr ""
1128
 
1129
- #: classes/Options.php:503, views/modal/edit_quiz.php:155
1130
  msgid "Days"
1131
  msgstr ""
1132
 
1133
- #: classes/Options.php:504, views/modal/edit_quiz.php:154
1134
  msgid "Hours"
1135
  msgstr ""
1136
 
1137
- #: classes/Options.php:505, views/modal/edit_quiz.php:153
1138
  msgid "Minutes"
1139
  msgstr ""
1140
 
1141
- #: classes/Options.php:506, views/modal/edit_quiz.php:152
1142
  msgid "Seconds"
1143
  msgstr ""
1144
 
1145
- #: classes/Options.php:513
1146
  msgid "When time expires"
1147
  msgstr ""
1148
 
1149
- #: classes/Options.php:517, classes/Tutor_Setup.php:439
1150
  msgid "The current quiz answers are submitted automatically."
1151
  msgstr ""
1152
 
1153
- #: classes/Options.php:518, classes/Tutor_Setup.php:440
1154
  msgid "The current quiz answers are submitted by students."
1155
  msgstr ""
1156
 
1157
- #: classes/Options.php:519, classes/Tutor_Setup.php:441
1158
  msgid "Attempts must be submitted before time expires, otherwise they will not be counted"
1159
  msgstr ""
1160
 
1161
- #: classes/Options.php:521
1162
  msgid "Choose which action to follow when the quiz time expires."
1163
  msgstr ""
1164
 
1165
- #: classes/Options.php:525
1166
  msgid "Attempts allowed"
1167
  msgstr ""
1168
 
1169
- #: classes/Options.php:527
1170
  msgid "The highest number of attempts students are allowed to take for a quiz. 0 means unlimited attempts."
1171
  msgstr ""
1172
 
1173
- #: classes/Options.php:531
1174
  msgid "Show Previous button"
1175
  msgstr ""
1176
 
1177
- #: classes/Options.php:534
1178
  msgid "Choose whether to show or hide previous button for single question."
1179
  msgstr ""
1180
 
1181
- #: classes/Options.php:538
1182
  msgid "Final grade calculation"
1183
  msgstr ""
1184
 
1185
- #: classes/Options.php:542, classes/Tutor_Setup.php:455
1186
  msgid "Highest Grade"
1187
  msgstr ""
1188
 
1189
- #: classes/Options.php:543, classes/Tutor_Setup.php:460
1190
  msgid "Average Grade"
1191
  msgstr ""
1192
 
1193
- #: classes/Options.php:544, classes/Tutor_Setup.php:465
1194
  msgid "First Attempt"
1195
  msgstr ""
1196
 
1197
- #: classes/Options.php:545, classes/Tutor_Setup.php:470
1198
  msgid "Last Attempt"
1199
  msgstr ""
1200
 
1201
- #: classes/Options.php:547
1202
  msgid "When multiple attempts are allowed, which method should be used to calculate a student's final grade for the quiz."
1203
  msgstr ""
1204
 
1205
- #: classes/Options.php:557
1206
  msgid "Instructor Profile Settings"
1207
  msgstr ""
1208
 
1209
- #: classes/Options.php:558, classes/Options.php:597, classes/Options.php:629
1210
  msgid "Enable Disable Option to on/off notification on various event"
1211
  msgstr ""
1212
 
1213
- #: classes/Options.php:562
1214
  msgid "Course Marketplace"
1215
  msgstr ""
1216
 
1217
- #: classes/Options.php:565
1218
  msgid "Allow multiple instructors to upload their courses."
1219
  msgstr ""
1220
 
1221
- #: classes/Options.php:569, classes/Utils.php:6792
1222
  msgid "Instructor Registration Page"
1223
  msgstr ""
1224
 
1225
- #: classes/Options.php:572
1226
  msgid "This page will be used to sign up new instructors."
1227
  msgstr ""
1228
 
1229
- #: classes/Options.php:576
1230
  msgid "Allow publishing course"
1231
  msgstr ""
1232
 
1233
- #: classes/Options.php:579
1234
  msgid "Enable instructors to publish course directly. <strong>Do not select</strong> if admins want to review courses before publishing."
1235
  msgstr ""
1236
 
1237
- #: classes/Options.php:583
1238
  msgid "Become Instructor Button"
1239
  msgstr ""
1240
 
1241
- #: classes/Options.php:586
1242
  msgid "Uncheck this option to hide the button from student dashboard."
1243
  msgstr ""
1244
 
1245
- #: classes/Options.php:596
1246
  msgid "Student Profile settings"
1247
  msgstr ""
1248
 
1249
- #: classes/Options.php:601, classes/Utils.php:6793
1250
  msgid "Student Registration Page"
1251
  msgstr ""
1252
 
1253
- #: classes/Options.php:604
1254
  msgid "Choose the page for student registration page"
1255
  msgstr ""
1256
 
1257
- #: classes/Options.php:608
1258
  msgid "Show reviews on profile"
1259
  msgstr ""
1260
 
1261
- #: classes/Options.php:611
1262
  msgid "Enabling this will show the reviews written by each student on their profile"
1263
  msgstr ""
1264
 
1265
- #: classes/Options.php:615
1266
  msgid "Show completed courses"
1267
  msgstr ""
1268
 
1269
- #: classes/Options.php:618
1270
  msgid "Completed courses will be shown on student profiles. <br/> For example, you can see this link-"
1271
  msgstr ""
1272
 
1273
- #: classes/Options.php:625, classes/Options.php:633, classes/Tutor_Setup.php:491, templates/dashboard/earning.php:123, templates/dashboard/earning/chart-body.php:17, templates/dashboard/earning/statement.php:14, templates/dashboard/earning/statements.php:133
1274
  msgid "Earning"
1275
  msgstr ""
1276
 
1277
- #: classes/Options.php:628
1278
  msgid "Earning and commission allocation"
1279
  msgstr ""
1280
 
1281
- #: classes/Options.php:636
1282
  msgid "If disabled, the Admin will receive 100% of the earning"
1283
  msgstr ""
1284
 
1285
- #: classes/Options.php:640
1286
  msgid "Admin Commission Percentage"
1287
  msgstr ""
1288
 
1289
- #: classes/Options.php:642
1290
  msgid "Define the commission of the Admin from each sale.(after deducting fees)"
1291
  msgstr ""
1292
 
1293
- #: classes/Options.php:646
1294
  msgid "Instructor Commission Percentage"
1295
  msgstr ""
1296
 
1297
- #: classes/Options.php:648
1298
  msgid "Define the commission for instructors from each sale.(after deducting fees)"
1299
  msgstr ""
1300
 
1301
- #: classes/Options.php:652
1302
  msgid "Fee Deduction"
1303
  msgstr ""
1304
 
1305
- #: classes/Options.php:653
1306
  msgid "Fees are charged from the entire sales amount. The remaining amount will be divided among admin and instructors."
1307
  msgstr ""
1308
 
1309
- #: classes/Options.php:663
1310
  msgid "Fee Name"
1311
  msgstr ""
1312
 
1313
- #: classes/Options.php:668
1314
  msgid "Fee Amount"
1315
  msgstr ""
1316
 
1317
- #: classes/Options.php:676
1318
  msgid "Select Fees Type"
1319
  msgstr ""
1320
 
1321
- #: classes/Options.php:677
1322
  msgid "Percent"
1323
  msgstr ""
1324
 
1325
- #: classes/Options.php:678
1326
  msgid "Fixed"
1327
  msgstr ""
1328
 
1329
- #: classes/Options.php:686
1330
  msgid "Show Statement Per Page"
1331
  msgstr ""
1332
 
1333
- #: classes/Options.php:688
1334
  msgid "Define the number of statements to show."
1335
  msgstr ""
1336
 
1337
- #: classes/Options.php:695, templates/dashboard/withdraw.php:43
1338
  msgid "Withdrawal"
1339
  msgstr ""
1340
 
1341
- #: classes/Options.php:698
1342
  msgid "Withdrawal Settings"
1343
  msgstr ""
1344
 
1345
- #: classes/Options.php:702
1346
  msgid "Minimum Withdraw Amount"
1347
  msgstr ""
1348
 
1349
- #: classes/Options.php:704
1350
  msgid "Instructors should earn equal or above this amount to make a withdraw request."
1351
  msgstr ""
1352
 
1353
- #: classes/Options.php:710
1354
  msgid "Withdraw Methods"
1355
  msgstr ""
1356
 
1357
- #: classes/Options.php:711
1358
  msgid "Set withdraw settings"
1359
  msgstr ""
1360
 
1361
- #: classes/Options.php:717
1362
  msgid "Style"
1363
  msgstr ""
1364
 
1365
- #: classes/Options.php:720
1366
  msgid "Color Style"
1367
  msgstr ""
1368
 
1369
- #: classes/Options.php:724
1370
  msgid "Primary Color"
1371
  msgstr ""
1372
 
1373
- #: classes/Options.php:729
1374
  msgid "Primary Hover Color"
1375
  msgstr ""
1376
 
1377
- #: classes/Options.php:734
1378
  msgid "Text color"
1379
  msgstr ""
1380
 
1381
- #: classes/Options.php:739
1382
  msgid "Light color"
1383
  msgstr ""
1384
 
1385
- #: classes/Options.php:746
1386
  msgid "Button Primary Color"
1387
  msgstr ""
1388
 
1389
- #: classes/Options.php:752
1390
  msgid "Button Danger Color"
1391
  msgstr ""
1392
 
1393
- #: classes/Options.php:757
1394
  msgid "Button Success Color"
1395
  msgstr ""
1396
 
1397
- #: classes/Options.php:762
1398
  msgid "Button Warning Color"
1399
  msgstr ""
1400
 
1401
- #: classes/Options.php:772, classes/Options.php:775
1402
  msgid "Monetization"
1403
  msgstr ""
1404
 
1405
- #: classes/Options.php:776
1406
  msgid "You can monetize your LMS website by selling courses in a various way."
1407
  msgstr ""
1408
 
1409
- #: classes/Options.php:781
1410
  msgid "Monetize Option"
1411
  msgstr ""
1412
 
1413
- #: classes/Options.php:785
1414
  msgid "Disable Monetization"
1415
  msgstr ""
1416
 
1417
- #: classes/Options.php:787
1418
  msgid "Select a monetization option to generate revenue by selling courses. Supports: WooCommerce, Easy Digital Downloads, Paid Memberships Pro"
1419
  msgstr ""
1420
 
@@ -1455,11 +1451,11 @@ msgstr ""
1455
  msgid "Edit Course"
1456
  msgstr ""
1457
 
1458
- #: classes/Post_types.php:48, templates/dashboard/create-course.php:29, templates/single/lesson/required-enroll.php:10
1459
  msgid "View Course"
1460
  msgstr ""
1461
 
1462
- #: classes/Post_types.php:49, classes/Tutor_List_Table.php:1252, templates/student-public-profile.php:98, templates/student-public-profile.php:159, templates/dashboard/announcements.php:85, templates/dashboard/assignments.php:34, templates/dashboard/purchase_history.php:21, templates/shortcode/tutor-instructor.php:27, views/pages/announcements.php:59, templates/single/course/instructors.php:72
1463
  msgid "Courses"
1464
  msgstr ""
1465
 
@@ -1754,7 +1750,7 @@ msgstr ""
1754
  msgid "View Assignment"
1755
  msgstr ""
1756
 
1757
- #: classes/Post_types.php:287, views/metabox/course-topics.php:91
1758
  msgid "Assignments"
1759
  msgstr ""
1760
 
@@ -1824,91 +1820,91 @@ msgstr ""
1824
  msgid "Preview course"
1825
  msgstr ""
1826
 
1827
- #: classes/Question_Answers_List.php:44, classes/Question_Answers_List.php:76, classes/Quiz.php:1120, templates/dashboard/question-answer.php:28, views/modal/question_form.php:146, views/pages/answer.php:11, templates/dashboard/question-answer/answers.php:13
1828
  msgid "Answer"
1829
  msgstr ""
1830
 
1831
- #: classes/Question_Answers_List.php:73, classes/Quiz.php:807, templates/dashboard/question-answer.php:25, views/pages/view_attempt.php:192, templates/dashboard/my-quiz-attempts/attempts-details.php:210, templates/dashboard/quiz-attempts/quiz-reviews.php:227
1832
  msgid "Question"
1833
  msgstr ""
1834
 
1835
- #: classes/Question_Answers_List.php:74, templates/student-public-profile.php:103, templates/dashboard/question-answer.php:26, templates/dashboard/quiz-attempts.php:31, templates/dashboard/assignments/review.php:50, templates/dashboard/assignments/submitted.php:72
1836
  msgid "Student"
1837
  msgstr ""
1838
 
1839
- #: classes/Quiz.php:531
1840
  msgid "Quiz has been timeout already"
1841
  msgstr ""
1842
 
1843
- #: classes/Quiz.php:670, classes/Quiz.php:753, views/metabox/course-contents.php:110, views/metabox/course-contents.php:200
1844
  msgid "QUIZ"
1845
  msgstr ""
1846
 
1847
- #: classes/Quiz.php:877
1848
  msgid "Please make sure you have added more than one option and saved them"
1849
  msgstr ""
1850
 
1851
- #: classes/Quiz.php:873
1852
  msgid "Please select the correct answer"
1853
  msgstr ""
1854
 
1855
- #: classes/Quiz.php:986, views/modal/question_answer_form.php:21
1856
  msgid "True"
1857
  msgstr ""
1858
 
1859
- #: classes/Quiz.php:993, views/modal/question_answer_form.php:25
1860
  msgid "False"
1861
  msgstr ""
1862
 
1863
- #: classes/Quiz.php:1104
1864
  msgid "Answer options &amp; mark correct"
1865
  msgstr ""
1866
 
1867
- #: classes/Quiz.php:1107
1868
  msgid "Make sure you’re saving the answers in the right order. Students will have to match this order exactly."
1869
  msgstr ""
1870
 
1871
- #: classes/Quiz.php:1142, classes/Quiz.php:1136, views/modal/question_form.php:170, views/modal/question_form.php:163, views/pages/view_attempt.php:342, templates/dashboard/quiz-attempts/quiz-reviews.php:400
1872
  msgid "Mark as correct"
1873
  msgstr ""
1874
 
1875
- #: classes/Quiz.php:1292
1876
  msgid "Access Denied."
1877
  msgstr ""
1878
 
1879
- #: classes/Quiz_Attempts_List.php:38
1880
  msgid "Review"
1881
  msgstr ""
1882
 
1883
- #: classes/Quiz_Attempts_List.php:45
1884
  msgid " ago"
1885
  msgstr ""
1886
 
1887
- #: classes/Quiz_Attempts_List.php:92
1888
  msgid " out of "
1889
  msgstr ""
1890
 
1891
- #: classes/Quiz_Attempts_List.php:93
1892
  msgid " pass "
1893
  msgstr ""
1894
 
1895
- #: classes/Quiz_Attempts_List.php:98, templates/dashboard/my-quiz-attempts.php:88, templates/dashboard/quiz-attempts.php:95, views/pages/view_attempt.php:101, templates/dashboard/my-quiz-attempts/attempts-details.php:171, templates/dashboard/quiz-attempts/quiz-reviews.php:159, templates/single/quiz/previous-attempts.php:75
1896
  msgid "Fail"
1897
  msgstr ""
1898
 
1899
- #: classes/Quiz_Attempts_List.php:96, templates/dashboard/my-quiz-attempts.php:88, templates/dashboard/quiz-attempts.php:95, views/pages/view_attempt.php:99, templates/dashboard/my-quiz-attempts/attempts-details.php:169, templates/dashboard/quiz-attempts/quiz-reviews.php:157, templates/single/quiz/previous-attempts.php:75
1900
  msgid "Pass"
1901
  msgstr ""
1902
 
1903
- #: classes/Quiz_Attempts_List.php:86, templates/dashboard/my-quiz-attempts.php:86, templates/dashboard/quiz-attempts.php:93, views/pages/view_attempt.php:92, templates/single/quiz/previous-attempts.php:73
1904
  msgid "Under Review"
1905
  msgstr ""
1906
 
1907
- #: classes/Quiz_Attempts_List.php:116
1908
  msgid "Total Questions"
1909
  msgstr ""
1910
 
1911
- #: classes/Quiz_Attempts_List.php:117
1912
  msgid "Earned Points"
1913
  msgstr ""
1914
 
@@ -1968,7 +1964,7 @@ msgstr ""
1968
  msgid "Setup Wizard"
1969
  msgstr ""
1970
 
1971
- #: classes/Tutor.php:519, classes/Utils.php:2467, templates/dashboard/dashboard.php:9
1972
  msgid "Dashboard"
1973
  msgstr ""
1974
 
@@ -2000,27 +1996,27 @@ msgstr ""
2000
  msgid "Easy Digital Downloads"
2001
  msgstr ""
2002
 
2003
- #: classes/TutorEDD.php:106, classes/WooCommerce.php:166
2004
  msgid "Add Product"
2005
  msgstr ""
2006
 
2007
- #: classes/Tutor_List_Table.php:360, classes/Tutor_List_Table.php:1261, templates/dashboard/announcements.php:89, templates/dashboard/assignments.php:38, views/pages/announcements.php:68
2008
  msgid "All"
2009
  msgstr ""
2010
 
2011
- #: classes/Tutor_List_Table.php:384, classes/Tutor_List_Table.php:1277, templates/dashboard/announcements.php:104, templates/dashboard/assignments.php:52, views/pages/announcements.php:84
2012
  msgid "Sort By"
2013
  msgstr ""
2014
 
2015
- #: classes/Tutor_List_Table.php:507
2016
  msgid "Bulk Actions"
2017
  msgstr ""
2018
 
2019
- #: classes/Tutor_List_Table.php:1270, templates/dashboard/announcements.php:98, templates/dashboard/assignments.php:47, views/pages/announcements.php:77, templates/dashboard/announcements/update.php:30
2020
  msgid "No course found"
2021
  msgstr ""
2022
 
2023
- #: classes/Tutor_List_Table.php:1295, classes/Tutor_List_Table.php:1297, views/pages/announcements.php:51, views/pages/question_answer.php:23, views/pages/students.php:13, views/pages/withdraw_requests.php:13
2024
  msgid "Search"
2025
  msgstr ""
2026
 
@@ -2064,7 +2060,7 @@ msgstr ""
2064
  msgid "weeks"
2065
  msgstr ""
2066
 
2067
- #: classes/Tutor_Setup.php:275, classes/Tutor_Setup.php:564, classes/Utils.php:2477
2068
  msgid "Instructor"
2069
  msgstr ""
2070
 
@@ -2144,7 +2140,7 @@ msgstr ""
2144
  msgid "What message to display when the quiz time expires?"
2145
  msgstr ""
2146
 
2147
- #: classes/Tutor_Setup.php:447, views/modal/edit_quiz.php:211, templates/single/quiz/top.php:65
2148
  msgid "Attempts Allowed"
2149
  msgstr ""
2150
 
@@ -2248,7 +2244,7 @@ msgstr ""
2248
  msgid "Payment"
2249
  msgstr ""
2250
 
2251
- #: classes/Tutor_Setup.php:567, templates/single/quiz/body.php:432
2252
  msgid "Finish"
2253
  msgstr ""
2254
 
@@ -2280,7 +2276,7 @@ msgstr ""
2280
  msgid "Skip This Step"
2281
  msgstr ""
2282
 
2283
- #: classes/Tutor_Setup.php:623, classes/Tutor_Setup.php:730, templates/shortcode/tutor-instructor.php:48, views/modal/add_quiz.php:71, views/modal/add_quiz.php:88, views/modal/edit_quiz.php:130
2284
  msgid "Next"
2285
  msgstr ""
2286
 
@@ -2368,354 +2364,354 @@ msgstr ""
2368
  msgid "Tutor &rsaquo; Setup Wizard"
2369
  msgstr ""
2370
 
2371
- #: classes/User.php:179
2372
  msgid "Dismiss"
2373
  msgstr ""
2374
 
2375
- #: classes/Utils.php:922
2376
  msgid "Nonce not matched"
2377
  msgstr ""
2378
 
2379
- #: classes/Utils.php:1294
2380
  msgid "Q&A"
2381
  msgstr ""
2382
 
2383
- #: classes/Utils.php:2162, templates/student-public-profile.php:116
2384
  msgid "Course Enrolled"
2385
  msgstr ""
2386
 
2387
- #: classes/Utils.php:2468, templates/dashboard/my-profile.php:21
2388
  msgid "My Profile"
2389
  msgstr ""
2390
 
2391
- #: classes/Utils.php:2469, templates/dashboard/dashboard.php:36, templates/dashboard/enrolled-courses.php:9
2392
  msgid "Enrolled Courses"
2393
  msgstr ""
2394
 
2395
- #: classes/Utils.php:2470, templates/dashboard/wishlist.php:10
2396
  msgid "Wishlist"
2397
  msgstr ""
2398
 
2399
- #: classes/Utils.php:2471
2400
  msgid "Reviews"
2401
  msgstr ""
2402
 
2403
- #: classes/Utils.php:2472, templates/dashboard/my-quiz-attempts.php:26
2404
  msgid "My Quiz Attempts"
2405
  msgstr ""
2406
 
2407
- #: classes/Utils.php:2473, templates/dashboard/purchase_history.php:9
2408
  msgid "Purchase History"
2409
  msgstr ""
2410
 
2411
- #: classes/Utils.php:2478
2412
  msgid "Create Course"
2413
  msgstr ""
2414
 
2415
- #: classes/Utils.php:2479, templates/dashboard/my-courses.php:9
2416
  msgid "My Courses"
2417
  msgstr ""
2418
 
2419
- #: classes/Utils.php:2481
2420
  msgid "Withdrawals"
2421
  msgstr ""
2422
 
2423
- #: classes/Utils.php:2483, templates/dashboard/question-answer.php:10, views/pages/question_answer.php:18
2424
  msgid "Question & Answer"
2425
  msgstr ""
2426
 
2427
- #: classes/Utils.php:2496
2428
  msgid "Logout"
2429
  msgstr ""
2430
 
2431
- #: classes/Utils.php:2507
2432
  msgid "Retrieve Password"
2433
  msgstr ""
2434
 
2435
- #: classes/Utils.php:2611, templates/dashboard/dashboard.php:27
2436
  msgid "Pending"
2437
  msgstr ""
2438
 
2439
- #: classes/Utils.php:2612
2440
  msgid "Approved"
2441
  msgstr ""
2442
 
2443
- #: classes/Utils.php:2613
2444
  msgid "Blocked"
2445
  msgstr ""
2446
 
2447
- #: classes/Utils.php:4228
2448
  msgid "True/False"
2449
  msgstr ""
2450
 
2451
- #: classes/Utils.php:4229
2452
  msgid "Single Choice"
2453
  msgstr ""
2454
 
2455
- #: classes/Utils.php:4230
2456
  msgid "Multiple Choice"
2457
  msgstr ""
2458
 
2459
- #: classes/Utils.php:4231
2460
  msgid "Open Ended/Essay"
2461
  msgstr ""
2462
 
2463
- #: classes/Utils.php:4232
2464
  msgid "Fill In The Blanks"
2465
  msgstr ""
2466
 
2467
- #: classes/Utils.php:4233
2468
  msgid "Short Answer"
2469
  msgstr ""
2470
 
2471
- #: classes/Utils.php:4234
2472
  msgid "Matching"
2473
  msgstr ""
2474
 
2475
- #: classes/Utils.php:4235
2476
  msgid "Image Matching"
2477
  msgstr ""
2478
 
2479
- #: classes/Utils.php:4236
2480
  msgid "Image Answering"
2481
  msgstr ""
2482
 
2483
- #: classes/Utils.php:4237
2484
  msgid "Ordering"
2485
  msgstr ""
2486
 
2487
- #: classes/Utils.php:5064
2488
  msgid "All Levels"
2489
  msgstr ""
2490
 
2491
- #: classes/Utils.php:5065, templates/course-filter/filters.php:4
2492
  msgid "Beginner"
2493
  msgstr ""
2494
 
2495
- #: classes/Utils.php:5066, templates/course-filter/filters.php:5
2496
  msgid "Intermediate"
2497
  msgstr ""
2498
 
2499
- #: classes/Utils.php:5067, templates/course-filter/filters.php:6
2500
  msgid "Expert"
2501
  msgstr ""
2502
 
2503
- #: classes/Utils.php:5090
2504
  msgid "Courses Taken"
2505
  msgstr ""
2506
 
2507
- #: classes/Utils.php:5097
2508
  msgid "Enrolled Course"
2509
  msgstr ""
2510
 
2511
- #: classes/Utils.php:5101
2512
  msgid "Reviews Written"
2513
  msgstr ""
2514
 
2515
- #: classes/Utils.php:5387
2516
  msgid "Website URL"
2517
  msgstr ""
2518
 
2519
- #: classes/Utils.php:5392
2520
  msgid "Github URL"
2521
  msgstr ""
2522
 
2523
- #: classes/Utils.php:5397
2524
  msgid "Facebook URL"
2525
  msgstr ""
2526
 
2527
- #: classes/Utils.php:5402
2528
  msgid "Twitter URL"
2529
  msgstr ""
2530
 
2531
- #: classes/Utils.php:5407
2532
  msgid "Linkedin URL"
2533
  msgstr ""
2534
 
2535
- #: classes/Utils.php:6756
2536
  msgid "Not Taken"
2537
  msgstr ""
2538
 
2539
- #: classes/Utils.php:6754
2540
  msgid "In Progress"
2541
  msgstr ""
2542
 
2543
- #: classes/Utils.php:6750
2544
  msgid "Completed"
2545
  msgstr ""
2546
 
2547
- #: classes/Utils.php:6933, templates/dashboard/my-profile.php:34, templates/dashboard/registration.php:50, templates/dashboard/registration.php:53, views/pages/add_new_instructor.php:29, views/pages/add_new_instructor.php:35, templates/dashboard/instructor/registration.php:51, templates/dashboard/instructor/registration.php:54, templates/dashboard/settings/profile.php:95, templates/dashboard/settings/profile.php:97
2548
  msgid "First Name"
2549
  msgstr ""
2550
 
2551
- #: classes/Utils.php:6934, templates/dashboard/my-profile.php:42, templates/dashboard/registration.php:60, templates/dashboard/registration.php:63, views/pages/add_new_instructor.php:43, views/pages/add_new_instructor.php:49, templates/dashboard/instructor/registration.php:61, templates/dashboard/instructor/registration.php:64, templates/dashboard/settings/profile.php:104, templates/dashboard/settings/profile.php:106
2552
  msgid "Last Name"
2553
  msgstr ""
2554
 
2555
- #: classes/Utils.php:6935, views/metabox/user-profile-fields.php:37
2556
  msgid "Profile Photo"
2557
  msgstr ""
2558
 
2559
- #: classes/Utils.php:6936
2560
  msgid "Withdraw Method"
2561
  msgstr ""
2562
 
2563
- #: classes/Withdraw.php:37
2564
  msgid "Bank Transfer"
2565
  msgstr ""
2566
 
2567
- #: classes/Withdraw.php:39
2568
  msgid "Get your payment directly into your bank account"
2569
  msgstr ""
2570
 
2571
- #: classes/Withdraw.php:44
2572
  msgid "Instruction"
2573
  msgstr ""
2574
 
2575
- #: classes/Withdraw.php:45
2576
  msgid "Write instruction for the instructor to fill bank information"
2577
  msgstr ""
2578
 
2579
- #: classes/Withdraw.php:52
2580
  msgid "Account Name"
2581
  msgstr ""
2582
 
2583
- #: classes/Withdraw.php:57
2584
  msgid "Account Number"
2585
  msgstr ""
2586
 
2587
- #: classes/Withdraw.php:62
2588
  msgid "Bank Name"
2589
  msgstr ""
2590
 
2591
- #: classes/Withdraw.php:66
2592
  msgid "IBAN"
2593
  msgstr ""
2594
 
2595
- #: classes/Withdraw.php:70
2596
  msgid "BIC / SWIFT"
2597
  msgstr ""
2598
 
2599
- #: classes/Withdraw.php:77
2600
  msgid "E-Check"
2601
  msgstr ""
2602
 
2603
- #: classes/Withdraw.php:82
2604
  msgid "Your Physical Address"
2605
  msgstr ""
2606
 
2607
- #: classes/Withdraw.php:83
2608
  msgid "We will send you an E-Check to this address directly."
2609
  msgstr ""
2610
 
2611
- #: classes/Withdraw.php:89
2612
  msgid "PayPal"
2613
  msgstr ""
2614
 
2615
- #: classes/Withdraw.php:94
2616
  msgid "PayPal E-Mail Address"
2617
  msgstr ""
2618
 
2619
- #: classes/Withdraw.php:95
2620
  msgid "We will use this email address to send the money to your Paypal account"
2621
  msgstr ""
2622
 
2623
- #: classes/Withdraw.php:186
2624
  msgid "Withdrawal account information saved successfully!"
2625
  msgstr ""
2626
 
2627
- #: classes/Withdraw.php:213
2628
  msgid "Please save withdraw method "
2629
  msgstr ""
2630
 
2631
- #: classes/Withdraw.php:218
2632
- msgid "Minimum withdrawal amount is %s %s %s "
2633
  msgstr ""
2634
 
2635
- #: classes/Withdraw.php:223
2636
  msgid "Insufficient balance."
2637
  msgstr ""
2638
 
2639
- #: classes/Withdraw.php:256
2640
  msgid "Withdrawal Request Sent!"
2641
  msgstr ""
2642
 
2643
- #: classes/Withdraw_Requests_List.php:53, classes/Withdraw_Requests_List.php:56
2644
  msgid "Rejected"
2645
  msgstr ""
2646
 
2647
- #: classes/Withdraw_Requests_List.php:63
2648
  msgid "Are you Sure? It can not be undone."
2649
  msgstr ""
2650
 
2651
- #: classes/Withdraw_Requests_List.php:63, templates/dashboard/announcements.php:156, templates/dashboard/my-courses.php:78, templates/dashboard/question-answer.php:40, views/pages/announcements.php:142, templates/dashboard/announcements/details.php:32, templates/dashboard/settings/profile.php:67, views/options/field-types/media.php:29
2652
  msgid "Delete"
2653
  msgstr ""
2654
 
2655
- #: classes/Withdraw_Requests_List.php:97
2656
  msgid "pending"
2657
  msgstr ""
2658
 
2659
- #: classes/Withdraw_Requests_List.php:98
2660
  msgid "approved"
2661
  msgstr ""
2662
 
2663
- #: classes/Withdraw_Requests_List.php:99
2664
  msgid "rejected"
2665
  msgstr ""
2666
 
2667
- #: classes/Withdraw_Requests_List.php:108
2668
  msgid "Requested By"
2669
  msgstr ""
2670
 
2671
- #: classes/Withdraw_Requests_List.php:109, templates/dashboard/purchase_history.php:22, templates/dashboard/withdraw.php:139, templates/dashboard/withdraw.php:185
2672
  msgid "Amount"
2673
  msgstr ""
2674
 
2675
- #: classes/Withdraw_Requests_List.php:110, templates/dashboard/withdraw.php:183
2676
  msgid "Withdrawal Method"
2677
  msgstr ""
2678
 
2679
- #: classes/Withdraw_Requests_List.php:111
2680
  msgid "Requested Time"
2681
  msgstr ""
2682
 
2683
- #: classes/WooCommerce.php:103
2684
  msgid ""
2685
- " Seems like you don’t have WooCommerce plugin installed on your site. In order to use this functionality, you need to have the \n"
2686
- " WooCommerce plugin installed. Get back on this page after installing the plugin and enable the following feature to start selling \n"
2687
  " courses with Tutor."
2688
  msgstr ""
2689
 
2690
- #: classes/WooCommerce.php:107
2691
  msgid "This notice will disappear after activating <strong>WooCommerce</strong>"
2692
  msgstr ""
2693
 
2694
- #: classes/WooCommerce.php:157
2695
  msgid "For Tutor"
2696
  msgstr ""
2697
 
2698
- #: classes/WooCommerce.php:158
2699
  msgid "This checkmark ensure that you will sell a specif course via this product."
2700
  msgstr ""
2701
 
2702
- #: classes/WooCommerce.php:277, classes/WooCommerce.php:316
2703
  msgid "WooCommerce"
2704
  msgstr ""
2705
 
2706
- #: classes/WooCommerce.php:282
2707
  msgid "WooCommerce Settings"
2708
  msgstr ""
2709
 
2710
- #: classes/WooCommerce.php:293
2711
  msgid "Enable add to cart feature for guest users"
2712
  msgstr ""
2713
 
2714
- #: classes/WooCommerce.php:294
2715
  msgid "Enabling this will let an unregistered user purchase any course from the Course Details page. Head over to Documentation to know how to configure this setting."
2716
  msgstr ""
2717
 
2718
- #: classes/WooCommerce.php:589
2719
  msgid "Since WooCommerce is disabled, your monetized courses have been set to free. Please make sure to enable Tutor LMS monetization if you decide to re-enable WooCommerce."
2720
  msgstr ""
2721
 
@@ -2765,27 +2761,27 @@ msgstr ""
2765
  msgid "Count"
2766
  msgstr ""
2767
 
2768
- #: includes/tutor-general-functions.php:76
2769
  msgid "Search Course Category. ex. Design, Development, Business"
2770
  msgstr ""
2771
 
2772
- #: includes/tutor-general-functions.php:77
2773
  msgid "Select a category"
2774
  msgstr ""
2775
 
2776
- #: includes/tutor-general-functions.php:121
2777
  msgid "Search Course Tags. ex. Design, Development, Business"
2778
  msgstr ""
2779
 
2780
- #: includes/tutor-general-functions.php:122
2781
  msgid "Select a tag"
2782
  msgstr ""
2783
 
2784
- #: includes/tutor-template-functions.php:420
2785
  msgid "Placeholder"
2786
  msgstr ""
2787
 
2788
- #: includes/tutor-template-functions.php:1471
2789
  msgid "Share:"
2790
  msgstr ""
2791
 
@@ -2881,31 +2877,31 @@ msgstr ""
2881
  msgid "Topic not found for given ID"
2882
  msgstr ""
2883
 
2884
- #: templates/dashboard.php:64, templates/dashboard/index.php:66
2885
  msgid "%d Ratings"
2886
  msgstr ""
2887
 
2888
- #: templates/dashboard.php:86, templates/dashboard/index.php:89
2889
  msgid "Become an instructor"
2890
  msgstr ""
2891
 
2892
- #: templates/dashboard.php:105
2893
  msgid "Your Application is pending from"
2894
  msgstr ""
2895
 
2896
- #: templates/dashboard.php:96, templates/dashboard/index.php:82
2897
  msgid "Add A New Course"
2898
  msgstr ""
2899
 
2900
- #: templates/dashboard.php:127
2901
  msgid "Your application to become an instructor was rejected on"
2902
  msgstr ""
2903
 
2904
- #: templates/instructor-setting.php:8
2905
  msgid "Instructor List Layout"
2906
  msgstr ""
2907
 
2908
- #: templates/instructor-setting.php:28
2909
  msgid "Selected one will be used if layout is not defined as shortcode attribute."
2910
  msgstr ""
2911
 
@@ -2913,91 +2909,95 @@ msgstr ""
2913
  msgid "Please Sign-In to view this section"
2914
  msgstr ""
2915
 
2916
- #: templates/permission-denied.php:42
2917
  msgid "You don't have enough privilege to access this page"
2918
  msgstr ""
2919
 
2920
- #: templates/permission-denied.php:45
2921
  msgid "Please make sure you are logged in to correct account if the content needs authorization."
2922
  msgstr ""
2923
 
2924
- #: templates/public-profile-setting.php:8
2925
  msgid "Public Profile Layout"
2926
  msgstr ""
2927
 
2928
- #: templates/public-profile-setting.php:28
2929
  msgid "Selected one will be used as public profile layout."
2930
  msgstr ""
2931
 
2932
- #: templates/single-preview-lesson.php:69, templates/single/lesson/lesson_sidebar.php:41
2933
  msgid "Lesson List"
2934
  msgstr ""
2935
 
2936
- #: templates/single-preview-lesson.php:194, templates/single-quiz.php:35, templates/single/assignment/content.php:31, templates/single/lesson/content.php:34, templates/single/quiz/single_quiz_contents.php:14
2937
  msgid "Go to Course Home"
2938
  msgstr ""
2939
 
2940
- #: templates/student-public-profile.php:116
2941
  msgid "Courses Enrolled"
2942
  msgstr ""
2943
 
2944
- #: templates/student-public-profile.php:121
2945
  msgid "Courses Completed"
2946
  msgstr ""
2947
 
2948
- #: templates/student-public-profile.php:121
2949
  msgid "Course Completed"
2950
  msgstr ""
2951
 
2952
- #: templates/student-public-profile.php:153
2953
  msgid "Biography"
2954
  msgstr ""
2955
 
2956
- #: templates/course-filter/filters.php:9, templates/dashboard/create-course.php:196, templates/loop/course-continue.php:19, templates/loop/course-in-cart.php:20, templates/loop/course-price-edd.php:20, templates/loop/course-price-woocommerce.php:20, templates/loop/course-price-woocommerce.php:35, templates/loop/course-price.php:19, views/metabox/course-add-edd-product-metabox.php:59, views/metabox/course-add-product-metabox.php:66, templates/single/course/wc-price-html.php:23
2957
  msgid "Free"
2958
  msgstr ""
2959
 
2960
- #: templates/course-filter/filters.php:10, views/metabox/course-add-edd-product-metabox.php:55, views/metabox/course-add-product-metabox.php:62
2961
  msgid "Paid"
2962
  msgstr ""
2963
 
 
 
 
 
2964
  #: templates/course-filter/filters.php:54
2965
  msgid "Level"
2966
  msgstr ""
2967
 
2968
- #: templates/dashboard/announcements.php:59
2969
  msgid "Announcement"
2970
  msgstr ""
2971
 
2972
- #: templates/dashboard/announcements.php:66
2973
  msgid "Create Announcement"
2974
  msgstr ""
2975
 
2976
- #: templates/dashboard/announcements.php:69
2977
  msgid "Notify all students of your course"
2978
  msgstr ""
2979
 
2980
- #: templates/dashboard/announcements.php:75
2981
  msgid "Add New Announcement"
2982
  msgstr ""
2983
 
2984
- #: templates/dashboard/announcements.php:106, templates/dashboard/assignments.php:54
2985
  msgid "ASC"
2986
  msgstr ""
2987
 
2988
- #: templates/dashboard/announcements.php:107, templates/dashboard/assignments.php:55
2989
  msgid "DESC"
2990
  msgstr ""
2991
 
2992
- #: templates/dashboard/announcements.php:167, views/pages/announcements.php:152
2993
  msgid "Announcements not found"
2994
  msgstr ""
2995
 
2996
- #: templates/dashboard/announcements.php:144, templates/dashboard/assignments.php:99, templates/dashboard/quiz-attempts.php:99, templates/dashboard/assignments/submitted.php:91, templates/single/quiz/previous-attempts.php:79
2997
  msgid "Details"
2998
  msgstr ""
2999
 
3000
- #: templates/dashboard/announcements.php:152, templates/dashboard/my-courses.php:75, views/pages/announcements.php:139, templates/dashboard/announcements/details.php:33
3001
  msgid "Edit"
3002
  msgstr ""
3003
 
@@ -3005,131 +3005,127 @@ msgstr ""
3005
  msgid "Create Date"
3006
  msgstr ""
3007
 
3008
- #: templates/dashboard/assignments.php:122
3009
  msgid "No assignment available"
3010
  msgstr ""
3011
 
3012
- #: templates/dashboard/assignments.php:73, templates/dashboard/dashboard.php:88
3013
  msgid "Course Name"
3014
  msgstr ""
3015
 
3016
- #: templates/dashboard/assignments.php:74, templates/dashboard/assignments/submitted.php:46, templates/dashboard/assignments/submitted.php:73
3017
  msgid "Total Points"
3018
  msgstr ""
3019
 
3020
- #: templates/dashboard/assignments.php:75
3021
  msgid "Total Submits"
3022
  msgstr ""
3023
 
3024
- #: templates/dashboard/assignments.php:93, templates/dashboard/reviews.php:64, templates/dashboard/reviews/given-reviews.php:53
3025
- msgid "Course: "
3026
- msgstr ""
3027
-
3028
- #: templates/dashboard/create-course.php:25
3029
  msgid "You don't have the right to edit this course"
3030
  msgstr ""
3031
 
3032
- #: templates/dashboard/create-course.php:26
3033
  msgid "Please make sure you are logged in to correct account"
3034
  msgstr ""
3035
 
3036
- #: templates/dashboard/create-course.php:54, views/modal/edit_quiz.php:257, views/modal/edit_quiz.php:344
3037
  msgid "Save"
3038
  msgstr ""
3039
 
3040
- #: templates/dashboard/create-course.php:60
3041
  msgid "Preview"
3042
  msgstr ""
3043
 
3044
- #: templates/dashboard/create-course.php:68, templates/dashboard/create-course.php:252
3045
  msgid "Submit for Review"
3046
  msgstr ""
3047
 
3048
- #: templates/dashboard/create-course.php:64, templates/dashboard/create-course.php:250
3049
  msgid "Publish Course"
3050
  msgstr ""
3051
 
3052
- #: templates/dashboard/create-course.php:72
3053
  msgid "Exit"
3054
  msgstr ""
3055
 
3056
- #: templates/dashboard/create-course.php:111, templates/dashboard/my-quiz-attempts.php:33, templates/dashboard/quiz-attempts.php:30, templates/dashboard/earning/statements.php:132, templates/single/quiz/previous-attempts.php:16
3057
  msgid "Course Info"
3058
  msgstr ""
3059
 
3060
- #: templates/dashboard/create-course.php:118
3061
  msgid "Course Title"
3062
  msgstr ""
3063
 
3064
- #: templates/dashboard/create-course.php:120
3065
  msgid "ex. Learn photoshop CS6 from scratch"
3066
  msgstr ""
3067
 
3068
- #: templates/dashboard/create-course.php:127, views/modal/question_form.php:110, templates/single/assignment/content.php:134, templates/single/course/course-content.php:26
3069
  msgid "Description"
3070
  msgstr ""
3071
 
3072
- #: templates/dashboard/create-course.php:146
3073
  msgid "Choose a category"
3074
  msgstr ""
3075
 
3076
- #: templates/dashboard/create-course.php:160
3077
  msgid "Choose a tag"
3078
  msgstr ""
3079
 
3080
- #: templates/dashboard/create-course.php:180
3081
  msgid "Course Price"
3082
  msgstr ""
3083
 
3084
- #: templates/dashboard/create-course.php:189
3085
  msgid "Set course price"
3086
  msgstr ""
3087
 
3088
- #: templates/dashboard/create-course.php:207
3089
  msgid "Course Thumbnail"
3090
  msgstr ""
3091
 
3092
- #: templates/dashboard/create-course.php:230
3093
  msgid "Important Guideline: %1$s 700x430 pixels %2$s %3$s File Support: %1$s jpg, .jpeg,. gif, or .png %2$s no text on the image."
3094
  msgstr ""
3095
 
3096
- #: templates/dashboard/create-course.php:232, views/metabox/video-metabox.php:106, views/modal/question_answer_edit_form.php:214, views/modal/question_answer_edit_form.php:177, views/modal/question_answer_edit_form.php:124, views/modal/question_answer_edit_form.php:34, views/modal/question_answer_form.php:230, views/modal/question_answer_form.php:201, views/modal/question_answer_form.php:157, views/modal/question_answer_form.php:48
3097
  msgid "Upload Image"
3098
  msgstr ""
3099
 
3100
- #: templates/dashboard/create-course.php:248
3101
  msgid "Save course as draft"
3102
  msgstr ""
3103
 
3104
- #: templates/dashboard/create-course.php:262
3105
  msgid "Course Upload Tips"
3106
  msgstr ""
3107
 
3108
- #: templates/dashboard/create-course.php:264
3109
  msgid "Set the Course Price option or make it free."
3110
  msgstr ""
3111
 
3112
- #: templates/dashboard/create-course.php:265
3113
  msgid "Standard size for the course thumbnail is 700x430."
3114
  msgstr ""
3115
 
3116
- #: templates/dashboard/create-course.php:266
3117
  msgid "Video section controls the course overview video."
3118
  msgstr ""
3119
 
3120
- #: templates/dashboard/create-course.php:267
3121
  msgid "Course Builder is where you create & organize a course."
3122
  msgstr ""
3123
 
3124
- #: templates/dashboard/create-course.php:268
3125
  msgid "Add Topics in the Course Builder section to create lessons, quizzes, and assignments."
3126
  msgstr ""
3127
 
3128
- #: templates/dashboard/create-course.php:269
3129
  msgid "Prerequisites refers to the fundamental courses to complete before taking this particular course."
3130
  msgstr ""
3131
 
3132
- #: templates/dashboard/create-course.php:270
3133
  msgid "Information from the Additional Data section shows up on the course single page."
3134
  msgstr ""
3135
 
@@ -3153,19 +3149,19 @@ msgstr ""
3153
  msgid "Total Students"
3154
  msgstr ""
3155
 
3156
- #: templates/dashboard/dashboard.php:64
3157
  msgid "Total Courses"
3158
  msgstr ""
3159
 
3160
- #: templates/dashboard/dashboard.php:70
3161
  msgid "Total Earnings"
3162
  msgstr ""
3163
 
3164
- #: templates/dashboard/dashboard.php:84
3165
  msgid "Most Popular Courses"
3166
  msgstr ""
3167
 
3168
- #: templates/dashboard/dashboard.php:89
3169
  msgid "Enrolled"
3170
  msgstr ""
3171
 
@@ -3181,7 +3177,7 @@ msgstr ""
3181
  msgid "Reports"
3182
  msgstr ""
3183
 
3184
- #: templates/dashboard/earning.php:53, templates/dashboard/earning/report.php:36, templates/dashboard/earning/statements.php:32, templates/dashboard/earning/statements.php:116
3185
  msgid "Statements"
3186
  msgstr ""
3187
 
@@ -3197,11 +3193,11 @@ msgstr ""
3197
  msgid "My Earnings"
3198
  msgstr ""
3199
 
3200
- #: templates/dashboard/earning.php:72, templates/dashboard/earning/report-date_range.php:41, templates/dashboard/earning/report-last_month.php:40, templates/dashboard/earning/report-last_week.php:44, templates/dashboard/earning/report-last_year.php:40, templates/dashboard/earning/report-this_month.php:42, templates/dashboard/earning/report-this_week.php:42, templates/dashboard/earning/report-this_year.php:38
3201
  msgid "Based on course price"
3202
  msgstr ""
3203
 
3204
- #: templates/dashboard/earning.php:74, templates/dashboard/earning/report-date_range.php:43, templates/dashboard/earning/report-last_month.php:42, templates/dashboard/earning/report-last_week.php:46, templates/dashboard/earning/report-last_year.php:42, templates/dashboard/earning/report-this_month.php:44, templates/dashboard/earning/report-this_week.php:44, templates/dashboard/earning/report-this_year.php:40
3205
  msgid "All time sales"
3206
  msgstr ""
3207
 
@@ -3213,7 +3209,7 @@ msgstr ""
3213
  msgid "All time withdrawals"
3214
  msgstr ""
3215
 
3216
- #: templates/dashboard/earning.php:86, templates/dashboard/earning/report-date_range.php:49, templates/dashboard/earning/report-last_month.php:48, templates/dashboard/earning/report-last_week.php:52, templates/dashboard/earning/report-last_year.php:48, templates/dashboard/earning/report-this_month.php:50, templates/dashboard/earning/report-this_week.php:50, templates/dashboard/earning/report-this_year.php:46
3217
  msgid "Deducted Commissions"
3218
  msgstr ""
3219
 
@@ -3229,15 +3225,15 @@ msgstr ""
3229
  msgid "All Courses"
3230
  msgstr ""
3231
 
3232
- #: templates/dashboard/enrolled-courses.php:81
3233
  msgid "You haven't purchased any course"
3234
  msgstr ""
3235
 
3236
- #: templates/dashboard/enrolled-courses.php:59, templates/dashboard/enrolled-courses/active-courses.php:53, templates/dashboard/enrolled-courses/completed-courses.php:53
3237
  msgid "Total Lessons:"
3238
  msgstr ""
3239
 
3240
- #: templates/dashboard/enrolled-courses.php:65, templates/dashboard/enrolled-courses/active-courses.php:59, templates/dashboard/enrolled-courses/completed-courses.php:59
3241
  msgid "Completed Lessons:"
3242
  msgstr ""
3243
 
@@ -3245,11 +3241,11 @@ msgstr ""
3245
  msgid "You are already logged in"
3246
  msgstr ""
3247
 
3248
- #: templates/dashboard/my-courses.php:90
3249
  msgid "Not Found"
3250
  msgstr ""
3251
 
3252
- #: templates/dashboard/my-courses.php:91, templates/dashboard/reviews.php:85, templates/dashboard/assignments/review.php:19, templates/dashboard/reviews/given-reviews.php:37
3253
  msgid "Sorry, but you are looking for something that isn't here."
3254
  msgstr ""
3255
 
@@ -3269,19 +3265,19 @@ msgstr ""
3269
  msgid "View"
3270
  msgstr ""
3271
 
3272
- #: templates/dashboard/my-courses.php:103
3273
  msgid "Delete This Course?"
3274
  msgstr ""
3275
 
3276
- #: templates/dashboard/my-courses.php:104
3277
  msgid "You are going to delete this course, it can't be undone"
3278
  msgstr ""
3279
 
3280
- #: templates/dashboard/my-courses.php:109, templates/dashboard/question-answer.php:72, templates/dashboard/withdraw.php:155, views/modal/add_quiz.php:58, views/modal/add_quiz.php:74, views/modal/add_quiz.php:91, views/modal/edit_quiz.php:71, views/modal/edit_quiz.php:133, views/modal/question_form.php:221, views/modal/review.php:19, views/pages/announcements.php:246, views/pages/announcements.php:328, templates/dashboard/announcements/create.php:53, templates/dashboard/announcements/details.php:29, templates/dashboard/announcements/update.php:52, templates/single/lesson/sidebar_question_and_answer.php:115, templates/single/course/enrolled/question_and_answer.php:52, templates/single/course/enrolled/question_and_answer.php:136
3281
  msgid "Cancel"
3282
  msgstr ""
3283
 
3284
- #: templates/dashboard/my-courses.php:110
3285
  msgid "Yes, Delete Course"
3286
  msgstr ""
3287
 
@@ -3289,47 +3285,47 @@ msgstr ""
3289
  msgid "Registration Date"
3290
  msgstr ""
3291
 
3292
- #: templates/dashboard/my-profile.php:50
3293
  msgid "Username"
3294
  msgstr ""
3295
 
3296
- #: templates/dashboard/my-profile.php:58
3297
  msgid "Email"
3298
  msgstr ""
3299
 
3300
- #: templates/dashboard/my-profile.php:66, views/pages/add_new_instructor.php:82, views/pages/add_new_instructor.php:88, templates/dashboard/settings/profile.php:124, templates/dashboard/settings/profile.php:126
3301
  msgid "Phone Number"
3302
  msgstr ""
3303
 
3304
- #: templates/dashboard/my-profile.php:75, views/pages/add_new_instructor.php:121, templates/dashboard/settings/profile.php:135
3305
  msgid "Bio"
3306
  msgstr ""
3307
 
3308
- #: templates/dashboard/my-quiz-attempts.php:102
3309
  msgid "You have not attempted any quiz yet"
3310
  msgstr ""
3311
 
3312
- #: templates/dashboard/my-quiz-attempts.php:34, templates/dashboard/quiz-attempts.php:32, templates/single/quiz/previous-attempts.php:17
3313
  msgid "Correct Answer"
3314
  msgstr ""
3315
 
3316
- #: templates/dashboard/my-quiz-attempts.php:35, templates/dashboard/quiz-attempts.php:33, templates/single/quiz/previous-attempts.php:18
3317
  msgid "Incorrect Answer"
3318
  msgstr ""
3319
 
3320
- #: templates/dashboard/my-quiz-attempts.php:36, templates/dashboard/my-quiz-attempts/attempts-details.php:120, templates/dashboard/quiz-attempts/quiz-reviews.php:108, templates/single/quiz/previous-attempts.php:19
3321
  msgid "Earned Marks"
3322
  msgstr ""
3323
 
3324
- #: templates/dashboard/my-quiz-attempts.php:37, templates/dashboard/quiz-attempts.php:35, views/pages/view_attempt.php:87, templates/dashboard/assignments/submitted.php:74, templates/single/quiz/previous-attempts.php:20
3325
  msgid "Result"
3326
  msgstr ""
3327
 
3328
- #: templates/dashboard/my-quiz-attempts.php:54, templates/dashboard/quiz-attempts.php:53, templates/single/quiz/previous-attempts.php:41
3329
  msgid "Question: "
3330
  msgstr ""
3331
 
3332
- #: templates/dashboard/my-quiz-attempts.php:55, templates/dashboard/quiz-attempts.php:54, templates/single/quiz/previous-attempts.php:42
3333
  msgid "Total Marks: "
3334
  msgstr ""
3335
 
@@ -3337,27 +3333,23 @@ msgstr ""
3337
  msgid "No purchase history available"
3338
  msgstr ""
3339
 
3340
- #: templates/dashboard/purchase_history.php:20, views/pages/tools/tutor_pages.php:11
3341
- msgid "ID"
3342
- msgstr ""
3343
-
3344
- #: templates/dashboard/question-answer.php:83
3345
  msgid "No question is available"
3346
  msgstr ""
3347
 
3348
- #: templates/dashboard/question-answer.php:66
3349
  msgid "Delete This Question?"
3350
  msgstr ""
3351
 
3352
- #: templates/dashboard/question-answer.php:67
3353
  msgid "You are going to delete this question, it can't be undone"
3354
  msgstr ""
3355
 
3356
- #: templates/dashboard/question-answer.php:73
3357
  msgid "Yes, Delete Question"
3358
  msgstr ""
3359
 
3360
- #: templates/dashboard/quiz-attempts.php:117
3361
  msgid "No quiz attempt yet."
3362
  msgstr ""
3363
 
@@ -3365,23 +3357,23 @@ msgstr ""
3365
  msgid "Earned Mark"
3366
  msgstr ""
3367
 
3368
- #: templates/dashboard/registration.php:73, templates/dashboard/registration.php:76, views/pages/add_new_instructor.php:56, views/pages/add_new_instructor.php:62, templates/dashboard/instructor/registration.php:76, templates/dashboard/instructor/registration.php:79, templates/dashboard/settings/profile.php:115
3369
  msgid "User Name"
3370
  msgstr ""
3371
 
3372
- #: templates/dashboard/registration.php:96, templates/dashboard/registration.php:99, templates/global/login.php:47, templates/template-part/form-retrieve-password.php:25, views/pages/add_new_instructor.php:95, views/pages/add_new_instructor.php:101, templates/dashboard/instructor/registration.php:99, templates/dashboard/instructor/registration.php:102
3373
  msgid "Password"
3374
  msgstr ""
3375
 
3376
- #: templates/dashboard/registration.php:106, views/pages/add_new_instructor.php:108, templates/dashboard/instructor/registration.php:109
3377
  msgid "Password confirmation"
3378
  msgstr ""
3379
 
3380
- #: templates/dashboard/registration.php:109, views/pages/add_new_instructor.php:114, templates/dashboard/instructor/registration.php:112
3381
  msgid "Password Confirmation"
3382
  msgstr ""
3383
 
3384
- #: templates/dashboard/registration.php:132
3385
  msgid "Register"
3386
  msgstr ""
3387
 
@@ -3406,10 +3398,14 @@ msgid "Given"
3406
  msgstr ""
3407
 
3408
  #: templates/dashboard/reviews.php:51
3409
- msgid "Showing results %d to %d out of %d"
 
 
 
 
3410
  msgstr ""
3411
 
3412
- #: templates/dashboard/reviews.php:72, templates/profile/reviews_wrote.php:49, views/pages/answer.php:54, views/pages/answer.php:94, templates/dashboard/question-answer/answers.php:24, templates/dashboard/question-answer/answers.php:52, templates/dashboard/reviews/given-reviews.php:67, templates/single/course/reviews.php:93, templates/single/lesson/sidebar_question_and_answer.php:54, templates/single/lesson/sidebar_question_and_answer.php:83, templates/single/course/enrolled/question_and_answer.php:75, templates/single/course/enrolled/question_and_answer.php:104
3413
  msgid "%s ago"
3414
  msgstr ""
3415
 
@@ -3425,63 +3421,63 @@ msgstr ""
3425
  msgid "Withdrawal request is pending for approval, please hold tight."
3426
  msgstr ""
3427
 
3428
- #: templates/dashboard/withdraw.php:49, templates/dashboard/withdraw.php:114
3429
  msgid "Current Balance"
3430
  msgstr ""
3431
 
3432
- #: templates/dashboard/withdraw.php:55
3433
- msgid "You currently have %s %s %s and this is insufficient balance to withdraw"
3434
  msgstr ""
3435
 
3436
- #: templates/dashboard/withdraw.php:53
3437
- msgid "You currently have %s %s %s ready to withdraw"
3438
  msgstr ""
3439
 
3440
- #: templates/dashboard/withdraw.php:65, templates/dashboard/withdraw.php:108
3441
  msgid "Withdrawal Request"
3442
  msgstr ""
3443
 
3444
- #: templates/dashboard/withdraw.php:77
3445
  msgid "The preferred payment method is selected as %s. "
3446
  msgstr ""
3447
 
3448
- #: templates/dashboard/withdraw.php:78
3449
- msgid "You can change your %s withdrawal preference %s"
3450
  msgstr ""
3451
 
3452
- #: templates/dashboard/withdraw.php:96
3453
  msgid "Your withdrawal request has been successfully accepted"
3454
  msgstr ""
3455
 
3456
- #: templates/dashboard/withdraw.php:97
3457
  msgid "Please check your transaction notification on your connected withdrawal method"
3458
  msgstr ""
3459
 
3460
- #: templates/dashboard/withdraw.php:109
3461
  msgid "Please enter withdrawal amount and click the submit request button"
3462
  msgstr ""
3463
 
3464
- #: templates/dashboard/withdraw.php:118
3465
  msgid "Selected Payment Method"
3466
  msgstr ""
3467
 
3468
- #: templates/dashboard/withdraw.php:149
3469
  msgid "Minimum withdraw amount is"
3470
  msgstr ""
3471
 
3472
- #: templates/dashboard/withdraw.php:156
3473
  msgid "Submit Request"
3474
  msgstr ""
3475
 
3476
- #: templates/dashboard/withdraw.php:174
3477
  msgid "Withdrawal History"
3478
  msgstr ""
3479
 
3480
- #: templates/dashboard/withdraw.php:264
3481
  msgid "No withdrawal yet"
3482
  msgstr ""
3483
 
3484
- #: templates/dashboard/withdraw.php:184
3485
  msgid "Requested On"
3486
  msgstr ""
3487
 
@@ -3521,39 +3517,39 @@ msgstr ""
3521
  msgid "Release Date (newest first)"
3522
  msgstr ""
3523
 
3524
- #: templates/global/course-archive-filter-bar.php:27
3525
  msgid "Release Date (oldest first)"
3526
  msgstr ""
3527
 
3528
- #: templates/global/course-archive-filter-bar.php:28
3529
  msgid "Course Title (a-z)"
3530
  msgstr ""
3531
 
3532
- #: templates/global/course-archive-filter-bar.php:29
3533
  msgid "Course Title (z-a)"
3534
  msgstr ""
3535
 
3536
- #: templates/global/login.php:46
3537
  msgid "Username or Email Address"
3538
  msgstr ""
3539
 
3540
- #: templates/global/login.php:48
3541
  msgid "Remember Me"
3542
  msgstr ""
3543
 
3544
- #: templates/global/login.php:49
3545
  msgid "Log In"
3546
  msgstr ""
3547
 
3548
- #: templates/global/login.php:50
3549
  msgid "Create a new account"
3550
  msgstr ""
3551
 
3552
- #: templates/global/login.php:60
3553
  msgid "Forgot Password?"
3554
  msgstr ""
3555
 
3556
- #: templates/loop/course-continue.php:18, templates/single/course/course-enrolled-box.php:53
3557
  msgid "Continue Course"
3558
  msgstr ""
3559
 
@@ -3561,7 +3557,7 @@ msgstr ""
3561
  msgid "View Cart"
3562
  msgstr ""
3563
 
3564
- #: templates/loop/course-price-edd.php:19, templates/loop/course-price-woocommerce.php:19, templates/loop/course-price.php:18
3565
  msgid "Get Enrolled"
3566
  msgstr ""
3567
 
@@ -3569,11 +3565,11 @@ msgstr ""
3569
  msgid "Start Learning "
3570
  msgstr ""
3571
 
3572
- #: templates/loop/meta.php:39, templates/single/course/lead-info.php:62, templates/single/course/enrolled/lead-info.php:62
3573
  msgid "by"
3574
  msgstr ""
3575
 
3576
- #: templates/loop/meta.php:48
3577
  msgid "In"
3578
  msgstr ""
3579
 
@@ -3585,23 +3581,23 @@ msgstr ""
3585
  msgid "No course yet."
3586
  msgstr ""
3587
 
3588
- #: templates/profile/reviews_wrote.php:24
3589
  msgid "No review yet."
3590
  msgstr ""
3591
 
3592
- #: templates/profile/reviews_wrote.php:57
3593
  msgid "On"
3594
  msgstr ""
3595
 
3596
- #: templates/shortcode/instructor-filter.php:29, templates/shortcode/instructor-filter.php:59
3597
  msgid "Clear All"
3598
  msgstr ""
3599
 
3600
- #: templates/shortcode/instructor-filter.php:42, templates/shortcode/instructor-filter.php:49
3601
  msgid "Search any instructor..."
3602
  msgstr ""
3603
 
3604
- #: templates/shortcode/instructor-filter.php:67
3605
  msgid "Apply Filter"
3606
  msgstr ""
3607
 
@@ -3637,19 +3633,19 @@ msgstr ""
3637
  msgid "When selling the course"
3638
  msgstr ""
3639
 
3640
- #: views/metabox/course-add-edd-product-metabox.php:38
3641
  msgid "Sell your product, process by EDD"
3642
  msgstr ""
3643
 
3644
- #: views/metabox/course-add-edd-product-metabox.php:48, views/metabox/course-add-product-metabox.php:55
3645
  msgid "Course Type"
3646
  msgstr ""
3647
 
3648
- #: views/metabox/course-add-product-metabox.php:45
3649
  msgid "Edit attached Product"
3650
  msgstr ""
3651
 
3652
- #: views/metabox/course-add-product-metabox.php:46
3653
  msgid "Select a product if you want to sell your course. The sale will be handled by your preferred monetization option. (WooCommerce, EDD, Paid Memberships Pro)"
3654
  msgstr ""
3655
 
@@ -3657,15 +3653,15 @@ msgstr ""
3657
  msgid "Total Course Duration"
3658
  msgstr ""
3659
 
3660
- #: views/metabox/course-additional-data.php:26, views/metabox/video-metabox.php:147
3661
  msgid "HH"
3662
  msgstr ""
3663
 
3664
- #: views/metabox/course-additional-data.php:30, views/metabox/video-metabox.php:152
3665
  msgid "MM"
3666
  msgstr ""
3667
 
3668
- #: views/metabox/course-additional-data.php:35, views/metabox/video-metabox.php:157
3669
  msgid "SS"
3670
  msgstr ""
3671
 
@@ -3673,89 +3669,89 @@ msgstr ""
3673
  msgid "Benefits of the course"
3674
  msgstr ""
3675
 
3676
- #: views/metabox/course-additional-data.php:55
3677
  msgid ""
3678
  "List the knowledge and skills that students will learn after completing this course. (One per line)\n"
3679
  ""
3680
  msgstr ""
3681
 
3682
- #: views/metabox/course-additional-data.php:64
3683
  msgid "Requirements/Instructions"
3684
  msgstr ""
3685
 
3686
- #: views/metabox/course-additional-data.php:71
3687
  msgid "Additional requirements or special instructions for the students (One per line)"
3688
  msgstr ""
3689
 
3690
- #: views/metabox/course-additional-data.php:79
3691
  msgid "Targeted Audience"
3692
  msgstr ""
3693
 
3694
- #: views/metabox/course-additional-data.php:86
3695
  msgid "Specify the target audience that will benefit the most from the course. (One line per target audience.)"
3696
  msgstr ""
3697
 
3698
- #: views/metabox/course-additional-data.php:95
3699
  msgid "Materials Included"
3700
  msgstr ""
3701
 
3702
- #: views/metabox/course-additional-data.php:102
3703
  msgid "A list of assets you will be providing for the students in this course (One per line)"
3704
  msgstr ""
3705
 
3706
- #: views/metabox/course-contents.php:27
3707
  msgid "Add a topic to build your course"
3708
  msgstr ""
3709
 
3710
- #: views/metabox/course-contents.php:43
3711
  msgid "Delete Topic"
3712
  msgstr ""
3713
 
3714
- #: views/metabox/course-contents.php:56, views/metabox/course-topics.php:31
3715
  msgid "Topic Name"
3716
  msgstr ""
3717
 
3718
- #: views/metabox/course-contents.php:62
3719
  msgid "Topic title will be publicly show where required, you can call it as a section also in course"
3720
  msgstr ""
3721
 
3722
- #: views/metabox/course-contents.php:69, views/metabox/course-topics.php:43
3723
  msgid "Topic Summary"
3724
  msgstr ""
3725
 
3726
- #: views/metabox/course-contents.php:74, views/metabox/course-topics.php:48
3727
  msgid "The idea of a summary is a short text to prepare students for the activities within the topic or week. The text is shown on the course page under the topic name."
3728
  msgstr ""
3729
 
3730
- #: views/metabox/course-contents.php:78
3731
  msgid "Update Topic"
3732
  msgstr ""
3733
 
3734
- #: views/metabox/course-contents.php:165, views/metabox/course-topics.php:76
3735
  msgid "Lesson"
3736
  msgstr ""
3737
 
3738
- #: views/metabox/course-topics.php:11
3739
  msgid "Expand all"
3740
  msgstr ""
3741
 
3742
- #: views/metabox/course-topics.php:12
3743
  msgid "Collapse all"
3744
  msgstr ""
3745
 
3746
- #: views/metabox/course-topics.php:23
3747
  msgid "Add new topic"
3748
  msgstr ""
3749
 
3750
- #: views/metabox/course-topics.php:27, views/metabox/course-topics.php:53
3751
  msgid "Add Topic"
3752
  msgstr ""
3753
 
3754
- #: views/metabox/course-topics.php:36
3755
  msgid "Topic titles are displayed publicly wherever required. Each topic may contain one or more lessons, quiz and assignments."
3756
  msgstr ""
3757
 
3758
- #: views/metabox/course-topics.php:105
3759
  msgid "Zoom Meeting"
3760
  msgstr ""
3761
 
@@ -3767,15 +3763,15 @@ msgstr ""
3767
  msgid "Add More Instructors"
3768
  msgstr ""
3769
 
3770
- #: views/metabox/instructors-metabox.php:49
3771
  msgid "Add instructors"
3772
  msgstr ""
3773
 
3774
- #: views/metabox/instructors-metabox.php:58
3775
  msgid "Search instructors..."
3776
  msgstr ""
3777
 
3778
- #: views/metabox/instructors-metabox.php:63
3779
  msgid "Add Instructors"
3780
  msgstr ""
3781
 
@@ -3787,7 +3783,7 @@ msgstr ""
3787
  msgid "Select a course"
3788
  msgstr ""
3789
 
3790
- #: views/metabox/lesson-metabox.php:22
3791
  msgid "Choose the course for this lesson"
3792
  msgstr ""
3793
 
@@ -3811,92 +3807,92 @@ msgstr ""
3811
  msgid "Upload"
3812
  msgstr ""
3813
 
3814
- #: views/metabox/video-metabox.php:41
3815
  msgid "Video Source"
3816
  msgstr ""
3817
 
3818
- #: views/metabox/video-metabox.php:39
3819
  msgid "Course Intro Video"
3820
  msgstr ""
3821
 
3822
- #: views/metabox/video-metabox.php:50
3823
  msgid "Select Video Source"
3824
  msgstr ""
3825
 
3826
- #: views/metabox/video-metabox.php:61
3827
  msgid "Select your preferred video type."
3828
  msgstr ""
3829
 
3830
- #: views/metabox/video-metabox.php:74
3831
  msgid "Upload Video"
3832
  msgstr ""
3833
 
3834
- #: views/metabox/video-metabox.php:76
3835
  msgid "Media ID"
3836
  msgstr ""
3837
 
3838
- #: views/metabox/video-metabox.php:97
3839
  msgid "Video Poster"
3840
  msgstr ""
3841
 
3842
- #: views/metabox/video-metabox.php:98
3843
  msgid "Thumb Size: 700x430 pixels. File Support: jpg, jpeg, or png"
3844
  msgstr ""
3845
 
3846
- #: views/metabox/video-metabox.php:118
3847
  msgid "External Video URL"
3848
  msgstr ""
3849
 
3850
- #: views/metabox/video-metabox.php:122
3851
  msgid "YouTube Video URL"
3852
  msgstr ""
3853
 
3854
- #: views/metabox/video-metabox.php:125
3855
  msgid "Vimeo Video URL"
3856
  msgstr ""
3857
 
3858
- #: views/metabox/video-metabox.php:128
3859
  msgid "Place your embedded code here"
3860
  msgstr ""
3861
 
3862
- #: views/metabox/video-metabox.php:140
3863
  msgid "Video playback time"
3864
  msgstr ""
3865
 
3866
- #: views/modal/add_quiz.php:18, views/modal/edit_quiz.php:29
3867
  msgid "Quiz Info"
3868
  msgstr ""
3869
 
3870
- #: views/modal/add_quiz.php:21, views/modal/edit_quiz.php:32, templates/dashboard/my-quiz-attempts/attempts-details.php:115, templates/dashboard/quiz-attempts/quiz-reviews.php:103, templates/single/quiz/top.php:38
3871
  msgid "Questions"
3872
  msgstr ""
3873
 
3874
- #: views/modal/add_quiz.php:27, views/modal/edit_quiz.php:38
3875
  msgid "Advanced Options"
3876
  msgstr ""
3877
 
3878
- #: views/modal/add_quiz.php:40, views/modal/edit_quiz.php:49
3879
  msgid "Type your quiz title here"
3880
  msgstr ""
3881
 
3882
- #: views/modal/add_quiz.php:55, views/modal/edit_quiz.php:68
3883
  msgid "Save &amp; Next"
3884
  msgstr ""
3885
 
3886
- #: views/modal/add_quiz.php:69, views/modal/add_quiz.php:86, views/modal/edit_quiz.php:129, views/modal/edit_quiz.php:256, views/modal/edit_quiz.php:343, views/modal/question_form.php:11, templates/dashboard/assignments/review.php:34, templates/dashboard/assignments/submitted.php:21, templates/single/quiz/body.php:389
3887
  msgid "Back"
3888
  msgstr ""
3889
 
3890
- #: views/modal/add_quiz.php:108, views/modal/edit_quiz.php:357
3891
  msgid "Knowledge Base"
3892
  msgstr ""
3893
 
3894
- #: views/modal/add_quiz.php:110, views/modal/edit_quiz.php:359
3895
  msgid "Documentation"
3896
  msgstr ""
3897
 
3898
- #: views/modal/add_quiz.php:111, views/modal/edit_quiz.php:360
3899
- msgid "Need any Help? Please visit our %s and %s."
3900
  msgstr ""
3901
 
3902
  #: views/modal/edit-lesson.php:25
@@ -3923,279 +3919,279 @@ msgstr ""
3923
  msgid "Update Lesson"
3924
  msgstr ""
3925
 
3926
- #: views/modal/edit_quiz.php:121
3927
  msgid "Add Question"
3928
  msgstr ""
3929
 
3930
- #: views/modal/edit_quiz.php:164
3931
  msgid "Hide quiz time - display"
3932
  msgstr ""
3933
 
3934
- #: views/modal/edit_quiz.php:167
3935
  msgid "Time limit for this quiz. 0 means no time limit."
3936
  msgstr ""
3937
 
3938
- #: views/modal/edit_quiz.php:171
3939
  msgid "Quiz Feedback Mode"
3940
  msgstr ""
3941
 
3942
- #: views/modal/edit_quiz.php:173
3943
  msgid "Pick the quiz system\"s behaviour on choice based questions"
3944
  msgstr ""
3945
 
3946
- #: views/modal/edit_quiz.php:181
3947
  msgid "Default"
3948
  msgstr ""
3949
 
3950
- #: views/modal/edit_quiz.php:182
3951
  msgid "Answers shown after quiz is finished"
3952
  msgstr ""
3953
 
3954
- #: views/modal/edit_quiz.php:191
3955
  msgid "Retry Mode"
3956
  msgstr ""
3957
 
3958
- #: views/modal/edit_quiz.php:192
3959
  msgid "Unlimited attempts on each question."
3960
  msgstr ""
3961
 
3962
- #: views/modal/edit_quiz.php:201
3963
  msgid "Reveal Mode"
3964
  msgstr ""
3965
 
3966
- #: views/modal/edit_quiz.php:202
3967
  msgid "Show result after the attempt."
3968
  msgstr ""
3969
 
3970
- #: views/modal/edit_quiz.php:211, views/modal/question_form.php:110
3971
  msgid "Optional"
3972
  msgstr ""
3973
 
3974
- #: views/modal/edit_quiz.php:226
3975
  msgid "Restriction on the number of attempts a student is allowed to take for this quiz. 0 for no limit"
3976
  msgstr ""
3977
 
3978
- #: views/modal/edit_quiz.php:230
3979
  msgid "Passing Grade (%)"
3980
  msgstr ""
3981
 
3982
- #: views/modal/edit_quiz.php:236
3983
  msgid "Set the passing percentage for this quiz"
3984
  msgstr ""
3985
 
3986
- #: views/modal/edit_quiz.php:240
3987
  msgid "Max questions allowed to answer"
3988
  msgstr ""
3989
 
3990
- #: views/modal/edit_quiz.php:246
3991
  msgid "This amount of question will be available for students to answer, and question will comes randomly from all available questions belongs with a quiz, if this amount greater than available question, then all questions will be available for a student to answer."
3992
  msgstr ""
3993
 
3994
- #: views/modal/edit_quiz.php:257, views/modal/edit_quiz.php:344
3995
  msgid "Saved"
3996
  msgstr ""
3997
 
3998
- #: views/modal/edit_quiz.php:274
3999
  msgid "Quiz Auto Start"
4000
  msgstr ""
4001
 
4002
- #: views/modal/edit_quiz.php:277
4003
  msgid "If you enable this option, the quiz will start automatically after the page is loaded."
4004
  msgstr ""
4005
 
4006
- #: views/modal/edit_quiz.php:283
4007
  msgid "Question Layout"
4008
  msgstr ""
4009
 
4010
- #: views/modal/edit_quiz.php:286
4011
  msgid "Set question layout view"
4012
  msgstr ""
4013
 
4014
- #: views/modal/edit_quiz.php:287
4015
  msgid "Single Question"
4016
  msgstr ""
4017
 
4018
- #: views/modal/edit_quiz.php:288
4019
  msgid "Question Pagination"
4020
  msgstr ""
4021
 
4022
- #: views/modal/edit_quiz.php:289
4023
  msgid "Question below each other"
4024
  msgstr ""
4025
 
4026
- #: views/modal/edit_quiz.php:294
4027
  msgid "Questions Order"
4028
  msgstr ""
4029
 
4030
- #: views/modal/edit_quiz.php:297
4031
  msgid "Random"
4032
  msgstr ""
4033
 
4034
- #: views/modal/edit_quiz.php:298
4035
  msgid "Sorting"
4036
  msgstr ""
4037
 
4038
- #: views/modal/edit_quiz.php:300
4039
  msgid "Ascending"
4040
  msgstr ""
4041
 
4042
- #: views/modal/edit_quiz.php:301
4043
  msgid "Descending"
4044
  msgstr ""
4045
 
4046
- #: views/modal/edit_quiz.php:315
4047
  msgid "Hide question number"
4048
  msgstr ""
4049
 
4050
- #: views/modal/edit_quiz.php:318
4051
  msgid "Show/hide question number during attempt."
4052
  msgstr ""
4053
 
4054
- #: views/modal/edit_quiz.php:322
4055
  msgid "Short answer characters limit"
4056
  msgstr ""
4057
 
4058
- #: views/modal/edit_quiz.php:328
4059
  msgid "Student will place answer in short answer question type within this characters limit."
4060
  msgstr ""
4061
 
4062
- #: views/modal/edit_quiz.php:332
4063
  msgid "Open-Ended/Essay questions answer character limit"
4064
  msgstr ""
4065
 
4066
- #: views/modal/edit_quiz.php:338
4067
  msgid "Students will place the answer in the Open-Ended/Essay question type within this character limit."
4068
  msgstr ""
4069
 
4070
- #: views/modal/question_answer_edit_form.php:3, views/modal/question_answer_form.php:3
4071
  msgid "No option is necessary for this answer type"
4072
  msgstr ""
4073
 
4074
- #: views/modal/question_answer_edit_form.php:239, views/modal/question_answer_form.php:247
4075
  msgid "Answer input value"
4076
  msgstr ""
4077
 
4078
- #: views/modal/question_answer_edit_form.php:245, views/modal/question_answer_form.php:253
4079
  msgid "The answers that students enter should match with this text. Write in <strong>small caps</strong>"
4080
  msgstr ""
4081
 
4082
- #: views/modal/question_answer_edit_form.php:202, views/modal/question_answer_form.php:217
4083
  msgid "Image matched text"
4084
  msgstr ""
4085
 
4086
- #: views/modal/question_answer_edit_form.php:107, views/modal/question_answer_edit_form.php:25, views/modal/question_answer_form.php:138, views/modal/question_answer_form.php:115, views/modal/question_answer_form.php:36
4087
  msgid "Answer title"
4088
  msgstr ""
4089
 
4090
- #: views/modal/question_answer_edit_form.php:115, views/modal/question_answer_form.php:147, views/modal/question_answer_form.php:124
4091
  msgid "Matched Answer title"
4092
  msgstr ""
4093
 
4094
- #: views/modal/question_answer_edit_form.php:149, views/modal/question_answer_edit_form.php:58, views/modal/question_answer_form.php:173, views/modal/question_answer_form.php:65
4095
  msgid "Display format for options"
4096
  msgstr ""
4097
 
4098
- #: views/modal/question_answer_edit_form.php:154, views/modal/question_answer_edit_form.php:63, views/modal/question_answer_form.php:178, views/modal/question_answer_form.php:70
4099
  msgid "Only text"
4100
  msgstr ""
4101
 
4102
- #: views/modal/question_answer_edit_form.php:160, views/modal/question_answer_edit_form.php:69, views/modal/question_answer_form.php:184, views/modal/question_answer_form.php:76
4103
  msgid "Only Image"
4104
  msgstr ""
4105
 
4106
- #: views/modal/question_answer_edit_form.php:166, views/modal/question_answer_edit_form.php:74, views/modal/question_answer_form.php:190, views/modal/question_answer_form.php:82
4107
  msgid "Text &amp; Image both"
4108
  msgstr ""
4109
 
4110
- #: views/modal/question_answer_edit_form.php:83, views/modal/question_answer_form.php:91, templates/single/lesson/sidebar_question_and_answer.php:153, templates/single/course/enrolled/question_and_answer.php:36
4111
  msgid "Question Title"
4112
  msgstr ""
4113
 
4114
- #: views/modal/question_answer_edit_form.php:89
4115
  msgid "Please make sure that <b>{dash}</b> variable contains in your question title to show dash, You can use multiple variable"
4116
  msgstr ""
4117
 
4118
- #: views/modal/question_answer_edit_form.php:93, views/modal/question_answer_form.php:101
4119
  msgid "Correct Answer(s)"
4120
  msgstr ""
4121
 
4122
- #: views/modal/question_answer_edit_form.php:99
4123
  msgid "Separate multiple answer by pipe <b>( | )</b> , 1 answer per variable assigned in question"
4124
  msgstr ""
4125
 
4126
- #: views/modal/question_answer_edit_form.php:253
4127
  msgid "Update Answer"
4128
  msgstr ""
4129
 
4130
- #: views/modal/question_answer_form.php:97
4131
  msgid "Please make sure to use the <strong>{dash}</strong> variable in your question title to show the blanks in your question. You can use multiple <strong>{dash}</strong> variables in one question."
4132
  msgstr ""
4133
 
4134
- #: views/modal/question_answer_form.php:107
4135
  msgid "Separate multiple answers by a vertical bar <strong>|</strong>. 1 answer per <strong>{dash}</strong> variable is defined in the question. Example: Apple | Banana | Orange"
4136
  msgstr ""
4137
 
4138
- #: views/modal/question_answer_form.php:16
4139
  msgid "Select the correct option"
4140
  msgstr ""
4141
 
4142
- #: views/modal/question_answer_form.php:261
4143
  msgid "Save Answer"
4144
  msgstr ""
4145
 
4146
- #: views/modal/question_form.php:21
4147
  msgid "Write your question here"
4148
  msgstr ""
4149
 
4150
- #: views/modal/question_form.php:24
4151
  msgid "Type your question here"
4152
  msgstr ""
4153
 
4154
- #: views/modal/question_form.php:30
4155
  msgid "Question Type"
4156
  msgstr ""
4157
 
4158
- #: views/modal/question_form.php:35
4159
  msgid "True or False"
4160
  msgstr ""
4161
 
4162
- #: views/modal/question_form.php:54
4163
  msgid "Pro version required"
4164
  msgstr ""
4165
 
4166
- #: views/modal/question_form.php:75
4167
  msgid "Answer Required"
4168
  msgstr ""
4169
 
4170
- #: views/modal/question_form.php:82
4171
  msgid "Randomize"
4172
  msgstr ""
4173
 
4174
- #: views/modal/question_form.php:88
4175
  msgid "Point(s) for this answer"
4176
  msgstr ""
4177
 
4178
- #: views/modal/question_form.php:91
4179
  msgid "set the mark ex. 10"
4180
  msgstr ""
4181
 
4182
- #: views/modal/question_form.php:104
4183
  msgid "Display Points"
4184
  msgstr ""
4185
 
4186
- #: views/modal/question_form.php:123
4187
  msgid "Input options for the question and select the correct answer."
4188
  msgstr ""
4189
 
4190
- #: views/modal/question_form.php:126
4191
  msgid "Make sure you’re saving the answers in the right order. Students will have to match this order."
4192
  msgstr ""
4193
 
4194
- #: views/modal/question_form.php:199
4195
  msgid "Add An Option"
4196
  msgstr ""
4197
 
4198
- #: views/modal/question_form.php:218
4199
  msgid "Save &amp; Continue"
4200
  msgstr ""
4201
 
@@ -4219,7 +4215,7 @@ msgstr ""
4219
  msgid "Settings Saved"
4220
  msgstr ""
4221
 
4222
- #: views/options/options_generator.php:84
4223
  msgid "Save Settings"
4224
  msgstr ""
4225
 
@@ -4231,15 +4227,15 @@ msgstr ""
4231
  msgid "Themes"
4232
  msgstr ""
4233
 
4234
- #: views/pages/addons.php:94, views/pages/addons.php:90
4235
  msgid "No %s currently avaialable"
4236
  msgstr ""
4237
 
4238
- #: views/pages/addons.php:59
4239
  msgid "Buy Now"
4240
  msgstr ""
4241
 
4242
- #: views/pages/addons.php:79, views/pages/enable_disable_addons.php:110, views/pages/tutor-pro-addons.php:56
4243
  msgid "Version"
4244
  msgstr ""
4245
 
@@ -4247,43 +4243,43 @@ msgstr ""
4247
  msgid "Add new instructor"
4248
  msgstr ""
4249
 
4250
- #: views/pages/announcements.php:53
4251
  msgid "Search Announcements"
4252
  msgstr ""
4253
 
4254
- #: views/pages/announcements.php:106
4255
  msgid "Add new"
4256
  msgstr ""
4257
 
4258
- #: views/pages/announcements.php:181, templates/dashboard/announcements/create.php:6
4259
  msgid "Create New Announcement"
4260
  msgstr ""
4261
 
4262
- #: views/pages/announcements.php:216, views/pages/announcements.php:298, templates/dashboard/announcements/create.php:35, templates/dashboard/announcements/update.php:36
4263
  msgid "Announcement Title"
4264
  msgstr ""
4265
 
4266
- #: views/pages/announcements.php:220, views/pages/announcements.php:302, templates/dashboard/announcements/update.php:38
4267
  msgid "Announcement title"
4268
  msgstr ""
4269
 
4270
- #: views/pages/announcements.php:226, views/pages/announcements.php:308, templates/dashboard/announcements/create.php:41, templates/dashboard/announcements/update.php:42
4271
  msgid "Summary"
4272
  msgstr ""
4273
 
4274
- #: views/pages/announcements.php:230, views/pages/announcements.php:312, templates/dashboard/announcements/update.php:44
4275
  msgid "Summary..."
4276
  msgstr ""
4277
 
4278
- #: views/pages/announcements.php:243, templates/dashboard/announcements/create.php:52
4279
  msgid "Publish"
4280
  msgstr ""
4281
 
4282
- #: views/pages/announcements.php:261, templates/dashboard/announcements/update.php:6
4283
  msgid "Update Announcement"
4284
  msgstr ""
4285
 
4286
- #: views/pages/announcements.php:325, views/pages/view_attempt.php:365, templates/dashboard/announcements/update.php:51, templates/dashboard/quiz-attempts/quiz-reviews.php:420
4287
  msgid "Update"
4288
  msgstr ""
4289
 
@@ -4295,7 +4291,7 @@ msgstr ""
4295
  msgid "Place answer"
4296
  msgstr ""
4297
 
4298
- #: views/pages/answer.php:64
4299
  msgid "on"
4300
  msgstr ""
4301
 
@@ -4307,6 +4303,10 @@ msgstr ""
4307
  msgid "Required Plugin(s)"
4308
  msgstr ""
4309
 
 
 
 
 
4310
  #: views/pages/get-pro.php:2
4311
  msgid "Get pro plugin from themeum.com"
4312
  msgstr ""
@@ -4331,7 +4331,7 @@ msgstr ""
4331
  msgid "Completely Uninstall and erase all data"
4332
  msgstr ""
4333
 
4334
- #: views/pages/view_attempt.php:7, templates/dashboard/my-quiz-attempts/attempts-details.php:24, templates/dashboard/my-quiz-attempts/attempts-details.php:83, templates/dashboard/quiz-attempts/quiz-reviews.php:22
4335
  msgid "Attempt not found"
4336
  msgstr ""
4337
 
@@ -4355,63 +4355,63 @@ msgstr ""
4355
  msgid "Quiz Time"
4356
  msgstr ""
4357
 
4358
- #: views/pages/view_attempt.php:157, templates/dashboard/quiz-attempts/quiz-reviews.php:195
4359
  msgid "Reminder:"
4360
  msgstr ""
4361
 
4362
- #: views/pages/view_attempt.php:157, templates/dashboard/quiz-attempts/quiz-reviews.php:195
4363
  msgid "Please review answers for question no. %s"
4364
  msgstr ""
4365
 
4366
- #: views/pages/view_attempt.php:169, templates/dashboard/quiz-attempts/quiz-reviews.php:205
4367
  msgid "Manually reviewed at: "
4368
  msgstr ""
4369
 
4370
- #: views/pages/view_attempt.php:185, templates/dashboard/my-quiz-attempts/attempts-details.php:203, templates/dashboard/quiz-attempts/quiz-reviews.php:220
4371
  msgid "Quiz Overview"
4372
  msgstr ""
4373
 
4374
- #: views/pages/view_attempt.php:190, templates/dashboard/earning/statement.php:55, templates/dashboard/earning/statement.php:60, templates/dashboard/earning/statements.php:183, templates/dashboard/earning/statements.php:190, templates/dashboard/my-quiz-attempts/attempts-details.php:209, templates/dashboard/quiz-attempts/quiz-reviews.php:226
4375
  msgid "Type"
4376
  msgstr ""
4377
 
4378
- #: views/pages/view_attempt.php:191, templates/dashboard/my-quiz-attempts/attempts-details.php:208, templates/dashboard/quiz-attempts/quiz-reviews.php:225
4379
  msgid "No."
4380
  msgstr ""
4381
 
4382
- #: views/pages/view_attempt.php:193, templates/dashboard/my-quiz-attempts/attempts-details.php:211, templates/dashboard/quiz-attempts/quiz-reviews.php:228
4383
  msgid "Given Answers"
4384
  msgstr ""
4385
 
4386
- #: views/pages/view_attempt.php:194, templates/dashboard/my-quiz-attempts/attempts-details.php:213, templates/dashboard/quiz-attempts/quiz-reviews.php:230
4387
  msgid "Correct/Incorrect"
4388
  msgstr ""
4389
 
4390
- #: views/pages/view_attempt.php:195, templates/dashboard/quiz-attempts/quiz-reviews.php:231
4391
  msgid "Manual Review"
4392
  msgstr ""
4393
 
4394
- #: views/pages/view_attempt.php:331, views/pages/view_attempt.php:324, templates/dashboard/my-quiz-attempts/attempts-details.php:119, templates/dashboard/my-quiz-attempts/attempts-details.php:379, templates/dashboard/my-quiz-attempts/attempts-details.php:374, templates/dashboard/quiz-attempts/quiz-reviews.php:107, templates/dashboard/quiz-attempts/quiz-reviews.php:393, templates/dashboard/quiz-attempts/quiz-reviews.php:388
4395
  msgid "Incorrect"
4396
  msgstr ""
4397
 
4398
- #: views/pages/view_attempt.php:327, views/pages/view_attempt.php:311, templates/dashboard/my-quiz-attempts/attempts-details.php:118, templates/dashboard/my-quiz-attempts/attempts-details.php:370, templates/dashboard/quiz-attempts/quiz-reviews.php:106, templates/dashboard/quiz-attempts/quiz-reviews.php:384
4399
  msgid "Correct"
4400
  msgstr ""
4401
 
4402
- #: views/pages/view_attempt.php:320, templates/dashboard/my-quiz-attempts/attempts-details.php:376, templates/dashboard/quiz-attempts/quiz-reviews.php:390
4403
  msgid "Review Required"
4404
  msgstr ""
4405
 
4406
- #: views/pages/view_attempt.php:343, templates/dashboard/quiz-attempts/quiz-reviews.php:401
4407
  msgid "Mark as In correct"
4408
  msgstr ""
4409
 
4410
- #: views/pages/view_attempt.php:361, templates/dashboard/my-quiz-attempts/attempts-details.php:185, templates/dashboard/quiz-attempts/quiz-reviews.php:173, templates/dashboard/quiz-attempts/quiz-reviews.php:416
4411
  msgid "Instructor Feedback"
4412
  msgstr ""
4413
 
4414
- #: views/pages/view_attempt.php:365, templates/dashboard/quiz-attempts/quiz-reviews.php:420
4415
  msgid "Updated"
4416
  msgstr ""
4417
 
@@ -4488,7 +4488,7 @@ msgid "Oldest"
4488
  msgstr ""
4489
 
4490
  #: templates/dashboard/assignments/submitted.php:87
4491
- msgid "%s Pending %s"
4492
  msgstr ""
4493
 
4494
  #: templates/dashboard/assignments/submitted.php:88
@@ -4496,11 +4496,11 @@ msgid "Evaluate"
4496
  msgstr ""
4497
 
4498
  #: templates/dashboard/assignments/submitted.php:90
4499
- msgid "%s Pass %s"
4500
  msgstr ""
4501
 
4502
  #: templates/dashboard/assignments/submitted.php:90
4503
- msgid "%s Fail %s"
4504
  msgstr ""
4505
 
4506
  #: templates/dashboard/earning/earning-report-top-menu.php:12
@@ -4535,19 +4535,19 @@ msgstr ""
4535
  msgid "My Earning"
4536
  msgstr ""
4537
 
4538
- #: templates/dashboard/earning/report-date_range.php:56, templates/dashboard/earning/report-date_range.php:58, templates/dashboard/earning/report-last_month.php:55, templates/dashboard/earning/report-last_month.php:57, templates/dashboard/earning/report-last_week.php:59, templates/dashboard/earning/report-last_week.php:61, templates/dashboard/earning/report-last_year.php:55, templates/dashboard/earning/report-last_year.php:57, templates/dashboard/earning/report-this_month.php:57, templates/dashboard/earning/report-this_month.php:59, templates/dashboard/earning/report-this_week.php:57, templates/dashboard/earning/report-this_week.php:59, templates/dashboard/earning/report-this_year.php:53, templates/dashboard/earning/report-this_year.php:55
4539
  msgid "Deducted Fees"
4540
  msgstr ""
4541
 
4542
  #: templates/dashboard/earning/report-date_range.php:67, templates/dashboard/earning/report-last_week.php:74, templates/dashboard/earning/report-this_week.php:67
4543
- msgid "Showing Result from %s to %s"
4544
  msgstr ""
4545
 
4546
- #: templates/dashboard/earning/report-date_range.php:74, templates/dashboard/earning/report-last_month.php:72, templates/dashboard/earning/report-last_week.php:81, templates/dashboard/earning/report-last_year.php:76, templates/dashboard/earning/report-this_month.php:77, templates/dashboard/earning/report-this_week.php:74, templates/dashboard/earning/report-this_year.php:74
4547
  msgid "Sales statements for this period"
4548
  msgstr ""
4549
 
4550
- #: templates/dashboard/earning/report-last_month.php:65, templates/dashboard/earning/report-this_month.php:70
4551
  msgid "Earning Data for the month of %s"
4552
  msgstr ""
4553
 
@@ -4555,47 +4555,47 @@ msgstr ""
4555
  msgid "Earning Data for the year of %s"
4556
  msgstr ""
4557
 
4558
- #: templates/dashboard/earning/report.php:27
4559
  msgid "Earning Report"
4560
  msgstr ""
4561
 
4562
- #: templates/dashboard/earning/statement.php:70, templates/dashboard/earning/statements.php:200
4563
  msgid "There is not enough sales data to generate a statement"
4564
  msgstr ""
4565
 
4566
- #: templates/dashboard/earning/statement.php:15, templates/dashboard/earning/statements.php:135
4567
  msgid "Deduct"
4568
  msgstr ""
4569
 
4570
- #: templates/dashboard/earning/statement.php:38, templates/dashboard/earning/statements.php:146
4571
  msgid "Date:"
4572
  msgstr ""
4573
 
4574
- #: templates/dashboard/earning/statement.php:53, templates/dashboard/earning/statements.php:134
4575
  msgid "Commission"
4576
  msgstr ""
4577
 
4578
- #: templates/dashboard/earning/statement.php:54, templates/dashboard/earning/statements.php:182
4579
  msgid "Rate"
4580
  msgstr ""
4581
 
4582
- #: templates/dashboard/earning/statement.php:57
4583
  msgid "Deducted"
4584
  msgstr ""
4585
 
4586
- #: templates/dashboard/earning/statements.php:29
4587
  msgid "Report"
4588
  msgstr ""
4589
 
4590
- #: templates/dashboard/earning/statements.php:125
4591
- msgid "Showing results %d to %d of %d"
4592
  msgstr ""
4593
 
4594
- #: templates/dashboard/earning/statements.php:157
4595
  msgid "Price: "
4596
  msgstr ""
4597
 
4598
- #: templates/dashboard/earning/statements.php:169
4599
  msgid "Purchaser"
4600
  msgstr ""
4601
 
@@ -4663,43 +4663,43 @@ msgstr ""
4663
  msgid "Register as instructor"
4664
  msgstr ""
4665
 
4666
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:92
4667
  msgid "You have no access."
4668
  msgstr ""
4669
 
4670
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:102, templates/dashboard/quiz-attempts/quiz-reviews.php:89
4671
  msgid "Back to Attempt List"
4672
  msgstr ""
4673
 
4674
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:107, templates/dashboard/quiz-attempts/quiz-reviews.php:95
4675
  msgid "Quiz:"
4676
  msgstr ""
4677
 
4678
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:108, templates/dashboard/quiz-attempts/quiz-reviews.php:96
4679
  msgid "Course:"
4680
  msgstr ""
4681
 
4682
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:113, templates/dashboard/quiz-attempts/quiz-reviews.php:101
4683
  msgid "#"
4684
  msgstr ""
4685
 
4686
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:114, templates/dashboard/quiz-attempts/quiz-reviews.php:102
4687
  msgid "Attempts Date"
4688
  msgstr ""
4689
 
4690
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:116, templates/dashboard/quiz-attempts/quiz-reviews.php:104
4691
  msgid "Total Marks"
4692
  msgstr ""
4693
 
4694
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:117, templates/dashboard/quiz-attempts/quiz-reviews.php:105
4695
  msgid "Pass Marks"
4696
  msgstr ""
4697
 
4698
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:121, templates/dashboard/quiz-attempts/quiz-reviews.php:109
4699
  msgid "Results"
4700
  msgstr ""
4701
 
4702
- #: templates/dashboard/my-quiz-attempts/attempts-details.php:212, templates/dashboard/quiz-attempts/quiz-reviews.php:229
4703
  msgid "Correct Answers"
4704
  msgstr ""
4705
 
@@ -4715,11 +4715,11 @@ msgstr ""
4715
  msgid "Set Your"
4716
  msgstr ""
4717
 
4718
- #: templates/dashboard/notifications/profile-completion.php:23
4719
  msgid "% Complete"
4720
  msgstr ""
4721
 
4722
- #: templates/dashboard/notifications/profile-completion.php:23
4723
  msgid "You are almost done!"
4724
  msgstr ""
4725
 
@@ -4735,11 +4735,11 @@ msgstr ""
4735
  msgid "Update Review"
4736
  msgstr ""
4737
 
4738
- #: templates/dashboard/reviews/given-reviews.php:59
4739
  msgid "Edit Feedback"
4740
  msgstr ""
4741
 
4742
- #: templates/dashboard/reviews/given-reviews.php:85
4743
  msgid "Edit Review"
4744
  msgstr ""
4745
 
@@ -4747,7 +4747,7 @@ msgstr ""
4747
  msgid "Reset Password"
4748
  msgstr ""
4749
 
4750
- #: templates/dashboard/settings/nav-bar.php:31
4751
  msgid "Withdraw"
4752
  msgstr ""
4753
 
@@ -4759,43 +4759,43 @@ msgstr ""
4759
  msgid "Upload Cover Photo"
4760
  msgstr ""
4761
 
4762
- #: templates/dashboard/settings/profile.php:49
4763
  msgid "Profile Photo Size"
4764
  msgstr ""
4765
 
4766
- #: templates/dashboard/settings/profile.php:49
4767
  msgid "200x200"
4768
  msgstr ""
4769
 
4770
- #: templates/dashboard/settings/profile.php:49, templates/dashboard/settings/profile.php:50
4771
  msgid "pixels"
4772
  msgstr ""
4773
 
4774
- #: templates/dashboard/settings/profile.php:50
4775
  msgid "Cover Photo Size"
4776
  msgstr ""
4777
 
4778
- #: templates/dashboard/settings/profile.php:50
4779
  msgid "700x430"
4780
  msgstr ""
4781
 
4782
- #: templates/dashboard/settings/profile.php:51
4783
  msgid "Saving..."
4784
  msgstr ""
4785
 
4786
- #: templates/dashboard/settings/profile.php:64
4787
  msgid "Upload Photo"
4788
  msgstr ""
4789
 
4790
- #: templates/dashboard/settings/profile.php:146
4791
  msgid "Display name publicly as"
4792
  msgstr ""
4793
 
4794
- #: templates/dashboard/settings/profile.php:182
4795
  msgid "The display name is shown in all public fields, such as the author name, instructor name, student name, and name that will be printed on the certificate."
4796
  msgstr ""
4797
 
4798
- #: templates/dashboard/settings/profile.php:212
4799
  msgid "Update Profile"
4800
  msgstr ""
4801
 
@@ -4815,91 +4815,91 @@ msgstr ""
4815
  msgid "Select a withdraw method"
4816
  msgstr ""
4817
 
4818
- #: templates/dashboard/settings/withdraw-settings.php:38
4819
  msgid "Min withdraw"
4820
  msgstr ""
4821
 
4822
- #: templates/dashboard/settings/withdraw-settings.php:103
4823
  msgid "Save Withdrawal Account"
4824
  msgstr ""
4825
 
4826
- #: templates/single/assignment/content.php:80
4827
  msgid "Time Duration : "
4828
  msgstr ""
4829
 
4830
- #: templates/single/assignment/content.php:81, templates/single/quiz/top.php:66, templates/single/quiz/top.php:81
4831
  msgid "No limit"
4832
  msgstr ""
4833
 
4834
- #: templates/single/assignment/content.php:92
4835
  msgid "Deadline : "
4836
  msgstr ""
4837
 
4838
- #: templates/single/assignment/content.php:93, templates/single/course/course-topics.php:135
4839
  msgid "Expired"
4840
  msgstr ""
4841
 
4842
- #: templates/single/assignment/content.php:105
4843
  msgid "Total Points : "
4844
  msgstr ""
4845
 
4846
- #: templates/single/assignment/content.php:109
4847
  msgid "Minimum Pass Points : "
4848
  msgstr ""
4849
 
4850
- #: templates/single/assignment/content.php:126
4851
  msgid "You have missed the submission deadline. Please contact the instructor for more information."
4852
  msgstr ""
4853
 
4854
- #: templates/single/assignment/content.php:299
4855
  msgid "Submit assignment"
4856
  msgstr ""
4857
 
4858
- #: templates/single/assignment/content.php:227
4859
- msgid "You received %s points out of %s"
4860
  msgstr ""
4861
 
4862
- #: templates/single/assignment/content.php:229
4863
  msgid "Your Grade is "
4864
  msgstr ""
4865
 
4866
- #: templates/single/assignment/content.php:239
4867
  msgid "Failed"
4868
  msgstr ""
4869
 
4870
- #: templates/single/assignment/content.php:233
4871
  msgid "Passed"
4872
  msgstr ""
4873
 
4874
- #: templates/single/assignment/content.php:252
4875
  msgid "Your Answers"
4876
  msgstr ""
4877
 
4878
- #: templates/single/assignment/content.php:263
4879
  msgid "Your uploaded file(s)"
4880
  msgstr ""
4881
 
4882
- #: templates/single/assignment/content.php:283
4883
  msgid "Instructor Note"
4884
  msgstr ""
4885
 
4886
- #: templates/single/assignment/content.php:167
4887
  msgid "Assignment answer form"
4888
  msgstr ""
4889
 
4890
- #: templates/single/assignment/content.php:177
4891
  msgid "Write your answer briefly"
4892
  msgstr ""
4893
 
4894
- #: templates/single/assignment/content.php:184
4895
  msgid "Attach assignment files"
4896
  msgstr ""
4897
 
4898
- #: templates/single/assignment/content.php:190
4899
  msgid "Upload file"
4900
  msgstr ""
4901
 
4902
- #: templates/single/assignment/content.php:201
4903
  msgid "Submit Assignment"
4904
  msgstr ""
4905
 
@@ -4907,15 +4907,15 @@ msgstr ""
4907
  msgid "Please make sure that your EDD product exists and valid for this course"
4908
  msgstr ""
4909
 
4910
- #: templates/single/course/add-to-cart-woocommerce.php:45
4911
  msgid "Please make sure that your product exists and valid for this course"
4912
  msgstr ""
4913
 
4914
- #: templates/single/course/add-to-cart.php:73
4915
  msgid "Enroll Now"
4916
  msgstr ""
4917
 
4918
- #: templates/single/course/add-to-cart.php:58
4919
  msgid "Start Learning"
4920
  msgstr ""
4921
 
@@ -4931,39 +4931,35 @@ msgstr ""
4931
  msgid "Complete Course"
4932
  msgstr ""
4933
 
4934
- #: templates/single/course/continue-lesson.php:41
4935
  msgid "Continue to lesson"
4936
  msgstr ""
4937
 
4938
- #: templates/single/course/course-benefits.php:31
4939
  msgid "What Will I Learn?"
4940
  msgstr ""
4941
 
4942
- #: templates/single/course/course-enrolled-box.php:51
4943
  msgid "Start Course"
4944
  msgstr ""
4945
 
4946
- #: templates/single/course/course-enrolled-box.php:49
4947
  msgid "Retake This Course"
4948
  msgstr ""
4949
 
4950
- #: templates/single/course/course-enrolled-box.php:76
4951
  msgid "You have been enrolled on %s."
4952
  msgstr ""
4953
 
4954
- #: templates/single/course/course-requirements.php:29
4955
- msgid "Requirements"
4956
- msgstr ""
4957
-
4958
  #: templates/single/course/course-target-audience.php:28
4959
  msgid "Target Audience"
4960
  msgstr ""
4961
 
4962
- #: templates/single/course/course-topics.php:30
4963
  msgid "Topics for this course"
4964
  msgstr ""
4965
 
4966
- #: templates/single/course/course-topics.php:137
4967
  msgid "Live"
4968
  msgstr ""
4969
 
@@ -4983,27 +4979,27 @@ msgstr ""
4983
  msgid "students"
4984
  msgstr ""
4985
 
4986
- #: templates/single/course/lead-info.php:70, templates/single/course/enrolled/lead-info.php:70
4987
  msgid "Course level:"
4988
  msgstr ""
4989
 
4990
- #: templates/single/course/lead-info.php:110, templates/single/course/enrolled/lead-info.php:111
4991
  msgid "Duration"
4992
  msgstr ""
4993
 
4994
- #: templates/single/course/lead-info.php:117, templates/single/course/enrolled/lead-info.php:118
4995
  msgid "Total Enrolled"
4996
  msgstr ""
4997
 
4998
- #: templates/single/course/lead-info.php:124, templates/single/course/enrolled/lead-info.php:125
4999
  msgid "Last Update"
5000
  msgstr ""
5001
 
5002
- #: templates/single/course/lead-info.php:140, templates/single/course/enrolled/lead-info.php:158
5003
  msgid "About Course"
5004
  msgstr ""
5005
 
5006
- #: templates/single/course/login.php:20
5007
  msgid "Login"
5008
  msgstr ""
5009
 
@@ -5039,7 +5035,7 @@ msgstr ""
5039
  msgid "Complete Lesson"
5040
  msgstr ""
5041
 
5042
- #: templates/single/lesson/lesson_sidebar.php:43
5043
  msgid "Browse Q&A"
5044
  msgstr ""
5045
 
@@ -5051,59 +5047,59 @@ msgstr ""
5051
  msgid "Course name : %s"
5052
  msgstr ""
5053
 
5054
- #: templates/single/lesson/sidebar_question_and_answer.php:132
5055
  msgid "No questions yet"
5056
  msgstr ""
5057
 
5058
- #: templates/single/lesson/sidebar_question_and_answer.php:133
5059
  msgid "Be the first to ask your question! You’ll be able to add details in the next step."
5060
  msgstr ""
5061
 
5062
- #: templates/single/lesson/sidebar_question_and_answer.php:102, templates/single/course/enrolled/question_and_answer.php:123
5063
  msgid "Add an answer"
5064
  msgstr ""
5065
 
5066
- #: templates/single/lesson/sidebar_question_and_answer.php:111, templates/single/course/enrolled/question_and_answer.php:132
5067
  msgid "Write your answer here..."
5068
  msgstr ""
5069
 
5070
- #: templates/single/lesson/sidebar_question_and_answer.php:117, templates/single/course/enrolled/question_and_answer.php:138
5071
  msgid "Add Answer"
5072
  msgstr ""
5073
 
5074
- #: templates/single/lesson/sidebar_question_and_answer.php:144, templates/single/course/enrolled/question_and_answer.php:25
5075
  msgid "Ask a new question"
5076
  msgstr ""
5077
 
5078
- #: templates/single/lesson/sidebar_question_and_answer.php:169
5079
  msgid "Submit My Question"
5080
  msgstr ""
5081
 
5082
- #: templates/single/quiz/body.php:452
5083
  msgid "Start Quiz"
5084
  msgstr ""
5085
 
5086
- #: templates/single/quiz/body.php:53
5087
  msgid "Time remaining : "
5088
  msgstr ""
5089
 
5090
- #: templates/single/quiz/body.php:94
5091
  msgid "Reattempt"
5092
  msgstr ""
5093
 
5094
- #: templates/single/quiz/body.php:146
5095
  msgid "Marks : "
5096
  msgstr ""
5097
 
5098
- #: templates/single/quiz/body.php:331, templates/single/quiz/body.php:340
5099
  msgid "characters remaining"
5100
  msgstr ""
5101
 
5102
- #: templates/single/quiz/body.php:395
5103
  msgid "Answer &amp; Next Question"
5104
  msgstr ""
5105
 
5106
- #: templates/single/quiz/body.php:395, templates/single/quiz/body.php:412
5107
  msgid "Submit Quiz"
5108
  msgstr ""
5109
 
@@ -5139,7 +5135,7 @@ msgstr ""
5139
  msgid "Passing Grade"
5140
  msgstr ""
5141
 
5142
- #: views/options/field-types/radio.php:5, views/options/field-types/select.php:4, views/metabox/course/field-types/select.php:4, views/options/field-types/groups/select.php:5, views/metabox/course/field-types/groups/select.php:5
5143
  msgid "Select Option"
5144
  msgstr ""
5145
 
@@ -5257,180 +5253,176 @@ msgstr ""
5257
  msgid "Server environment"
5258
  msgstr ""
5259
 
5260
- #: views/pages/tools/status.php:132
5261
  msgid "Server info"
5262
  msgstr ""
5263
 
5264
- #: views/pages/tools/status.php:133
5265
  msgid "Information about the web server that is currently hosting your site."
5266
  msgstr ""
5267
 
5268
- #: views/pages/tools/status.php:137
5269
  msgid "PHP version"
5270
  msgstr ""
5271
 
5272
- #: views/pages/tools/status.php:138
5273
  msgid "The version of PHP installed on your hosting server."
5274
  msgstr ""
5275
 
5276
- #: views/pages/tools/status.php:149
5277
  msgid "We recommend using PHP version 7.2 or above for greater performance and security."
5278
  msgstr ""
5279
 
5280
- #: views/pages/tools/status.php:147
5281
  msgid "Tutor will run under this version of PHP, however, it has reached end of life. We recommend using PHP version 7.2 or above for greater performance and security."
5282
  msgstr ""
5283
 
5284
- #: views/pages/tools/status.php:160
5285
  msgid "PHP post max size"
5286
  msgstr ""
5287
 
5288
- #: views/pages/tools/status.php:161
5289
  msgid "The largest filesize that can be contained in one post."
5290
  msgstr ""
5291
 
5292
- #: views/pages/tools/status.php:165
5293
  msgid "PHP time limit"
5294
  msgstr ""
5295
 
5296
- #: views/pages/tools/status.php:166
5297
  msgid "The amount of time (in seconds) that your site will spend on a single operation before timing out (to avoid server lockups)"
5298
  msgstr ""
5299
 
5300
- #: views/pages/tools/status.php:170
5301
  msgid "PHP max input vars"
5302
  msgstr ""
5303
 
5304
- #: views/pages/tools/status.php:171
5305
  msgid "The maximum number of variables your server can use for a single function to avoid overloads."
5306
  msgstr ""
5307
 
5308
- #: views/pages/tools/status.php:175
5309
  msgid "cURL version"
5310
  msgstr ""
5311
 
5312
- #: views/pages/tools/status.php:176
5313
  msgid "The version of cURL installed on your server."
5314
  msgstr ""
5315
 
5316
- #: views/pages/tools/status.php:180
5317
  msgid "SUHOSIN installed"
5318
  msgstr ""
5319
 
5320
- #: views/pages/tools/status.php:181
5321
  msgid "Suhosin is an advanced protection system for PHP installations. It was designed to protect your servers on the one hand against a number of well known problems in PHP applications and on the other hand against potential unknown vulnerabilities within these applications or the PHP core itself. If enabled on your server, Suhosin may need to be configured to increase its data submission limits."
5322
  msgstr ""
5323
 
5324
- #: views/pages/tools/status.php:191
5325
  msgid "MySQL version"
5326
  msgstr ""
5327
 
5328
- #: views/pages/tools/status.php:192
5329
  msgid "The version of MySQL installed on your hosting server."
5330
  msgstr ""
5331
 
5332
- #. translators: %1$s: MySQL version, %2$s: Recommended MySQL version.
5333
- #: views/pages/tools/status.php:197
5334
  msgid "%1$s - We recommend a minimum MySQL version of 5.6. See: %2$s"
5335
  msgstr ""
5336
 
5337
- #: views/pages/tools/status.php:197
5338
  msgid "WordPress requirements"
5339
  msgstr ""
5340
 
5341
- #: views/pages/tools/status.php:206
5342
  msgid "Max upload size"
5343
  msgstr ""
5344
 
5345
- #: views/pages/tools/status.php:207
5346
  msgid "The largest filesize that can be uploaded to your WordPress installation."
5347
  msgstr ""
5348
 
5349
- #: views/pages/tools/status.php:211
5350
  msgid "Default timezone is UTC"
5351
  msgstr ""
5352
 
5353
- #: views/pages/tools/status.php:212
5354
  msgid "The default timezone for your server."
5355
  msgstr ""
5356
 
5357
  #. translators: %s: default timezone..
5358
- #: views/pages/tools/status.php:217
5359
  msgid "Default timezone is %s - it should be UTC"
5360
  msgstr ""
5361
 
5362
- #: views/pages/tools/status.php:225
5363
  msgid "fsockopen/cURL"
5364
  msgstr ""
5365
 
5366
- #: views/pages/tools/status.php:226
5367
  msgid "Payment gateways can use cURL to communicate with remote servers to authorize payments, other plugins may also use it when communicating with remote services."
5368
  msgstr ""
5369
 
5370
- #: views/pages/tools/status.php:232
5371
  msgid "Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider."
5372
  msgstr ""
5373
 
5374
- #: views/pages/tools/status.php:238
5375
  msgid "DOMDocument"
5376
  msgstr ""
5377
 
5378
- #: views/pages/tools/status.php:239
5379
  msgid "HTML/Multipart emails use DOMDocument to generate inline CSS in templates."
5380
  msgstr ""
5381
 
5382
- #. translators: %s: classname and link.
5383
- #: views/pages/tools/status.php:246
5384
  msgid "Your server does not have the %s class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument."
5385
  msgstr ""
5386
 
5387
- #: views/pages/tools/status.php:252
5388
  msgid "GZip"
5389
  msgstr ""
5390
 
5391
- #: views/pages/tools/status.php:253
5392
  msgid "GZip (gzopen) is used to open the GEOIP database from MaxMind."
5393
  msgstr ""
5394
 
5395
- #. translators: %s: classname and link.
5396
- #: views/pages/tools/status.php:260
5397
  msgid "Your server does not support the %s function - this is required to use the GeoIP database from MaxMind."
5398
  msgstr ""
5399
 
5400
- #: views/pages/tools/status.php:266
5401
  msgid "Multibyte string"
5402
  msgstr ""
5403
 
5404
- #: views/pages/tools/status.php:267
5405
  msgid "Multibyte String (mbstring) is used to convert character encoding, like for emails or converting characters to lowercase."
5406
  msgstr ""
5407
 
5408
- #. translators: %s: classname and link.
5409
- #: views/pages/tools/status.php:274
5410
  msgid "Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it."
5411
  msgstr ""
5412
 
5413
- #: views/pages/tools/tutor_pages.php:12
5414
  msgid "Page Name"
5415
  msgstr ""
5416
 
5417
- #: views/pages/tools/tutor_pages.php:47
5418
  msgid " Page not set"
5419
  msgstr ""
5420
 
5421
- #: views/pages/tools/tutor_pages.php:53
5422
  msgid " Page deleted, please set new one"
5423
  msgstr ""
5424
 
5425
- #: views/pages/tools/tutor_pages.php:59
5426
  msgid "Page visibility is not public"
5427
  msgstr ""
5428
 
5429
- #: views/pages/tools/tutor_pages.php:83
5430
  msgid "Re-Generate Tutor Pages"
5431
  msgstr ""
5432
 
5433
- #: views/pages/tools/tutor_pages.php:88
5434
  msgid "Note: This tool will install all the missing Tutor pages. Pages already defined and set up will not be replaced."
5435
  msgstr ""
5436
 
@@ -5450,7 +5442,7 @@ msgstr ""
5450
  msgid " Complete"
5451
  msgstr ""
5452
 
5453
- #: templates/single/course/enrolled/nav.php:26
5454
  msgid "Course Page"
5455
  msgstr ""
5456
 
1
+ # Copyright (C) 2022 Tutor LMS
2
  # This file is distributed under the same license as the Tutor LMS package.
3
  msgid ""
4
  msgstr ""
17
  msgid "Tutor Instructor"
18
  msgstr ""
19
 
20
+ #: classes/Addons.php:27
21
  msgid "BuddyPress"
22
  msgstr ""
23
 
24
+ #: classes/Addons.php:31
25
  msgid "Gradebook"
26
  msgstr ""
27
 
28
+ #: classes/Addons.php:35
29
  msgid "Content Drip"
30
  msgstr ""
31
 
32
+ #: classes/Addons.php:39
33
  msgid "Enrollments"
34
  msgstr ""
35
 
36
+ #: classes/Addons.php:43
37
  msgid "WooCommerce Subscriptions"
38
  msgstr ""
39
 
40
+ #: classes/Addons.php:47
41
  msgid "Paid Memberships Pro"
42
  msgstr ""
43
 
44
+ #: classes/Addons.php:51
45
  msgid "Restrict Content Pro"
46
  msgstr ""
47
 
48
+ #: classes/Addons.php:55
49
  msgid "Tutor Assignments"
50
  msgstr ""
51
 
52
+ #: classes/Addons.php:59
53
  msgid "Tutor Certificate"
54
  msgstr ""
55
 
56
+ #: classes/Addons.php:63
57
  msgid "Tutor Course Attachments"
58
  msgstr ""
59
 
60
+ #: classes/Addons.php:67
61
  msgid "Tutor Course Preview"
62
  msgstr ""
63
 
64
+ #: classes/Addons.php:71
65
  msgid "Tutor E-Mail"
66
  msgstr ""
67
 
68
+ #: classes/Addons.php:75
69
  msgid "Tutor Multi Instructors"
70
  msgstr ""
71
 
72
+ #: classes/Addons.php:79
73
  msgid "Tutor Prerequisites"
74
  msgstr ""
75
 
76
+ #: classes/Addons.php:83
77
  msgid "Tutor Report"
78
  msgstr ""
79
 
80
+ #: classes/Addons.php:87
81
  msgid "Quiz Export/Import"
82
  msgstr ""
83
 
84
+ #: classes/Addons.php:88
85
  msgid "Save time by exporting/importing quiz data with easy options."
86
  msgstr ""
87
 
88
+ #: classes/Addons.php:91
89
  msgid "Tutor Zoom Integration"
90
  msgstr ""
91
 
92
+ #: classes/Addons.php:92
93
  msgid "Connect Tutor LMS with Zoom to host live online classes. Students can attend live classes right from the lesson page."
94
  msgstr ""
95
 
96
+ #: classes/Addons.php:95
97
  msgid "Google Classroom Integration"
98
  msgstr ""
99
 
100
+ #: classes/Addons.php:96
101
  msgid "Helps connect Google Classrooms with Tutor LMS courses, allowing you to use features like Classroom streams and files directly from the Tutor LMS course."
102
  msgstr ""
103
 
104
+ #: classes/Addons.php:103
105
  msgid "WPML Multilingual CMS"
106
  msgstr ""
107
 
108
+ #: classes/Addons.php:104
109
  msgid "Create multilingual courses, lessons, dashboard and more for a global audience."
110
  msgstr ""
111
 
117
  msgid "Tutor LMS"
118
  msgstr ""
119
 
120
+ #: classes/Admin.php:56, classes/Admin.php:56, templates/single/course/lead-info.php:92, templates/single/course/enrolled/lead-info.php:93
121
  msgid "Categories"
122
  msgstr ""
123
 
125
  msgid "Tags"
126
  msgstr ""
127
 
128
+ #: classes/Admin.php:60, classes/Admin.php:60, classes/Course.php:507, classes/Options.php:594, classes/Quiz_Attempts_List.php:117, templates/student-public-profile.php:103, views/pages/students.php:8
129
  msgid "Students"
130
  msgstr ""
131
 
132
+ #: classes/Admin.php:63, classes/Admin.php:63, classes/Course.php:195, classes/Course.php:276, classes/Options.php:555, views/pages/instructors.php:29
133
  msgid "Instructors"
134
  msgstr ""
135
 
136
+ #: classes/Admin.php:66, classes/Admin.php:66, classes/Utils.php:1333, classes/Utils.php:2582, templates/dashboard/announcements.php:124, views/pages/announcements.php:105, views/pages/announcements.php:115
137
  msgid "Announcements"
138
  msgstr ""
139
 
145
  msgid "Q & A "
146
  msgstr ""
147
 
148
+ #: classes/Admin.php:70, classes/Admin.php:70, classes/Utils.php:2590, templates/dashboard/quiz-attempts.php:19, views/pages/quiz_attempts.php:29
149
  msgid "Quiz Attempts"
150
  msgstr ""
151
 
157
  msgid "Add-ons"
158
  msgstr ""
159
 
160
+ #: classes/Admin.php:80, classes/Admin.php:80, classes/Admin.php:453, classes/Utils.php:2614, templates/dashboard/settings.php:8, views/modal/add_quiz.php:22, views/modal/edit_quiz.php:35, templates/dashboard/notifications/profile-completion.php:14, templates/dashboard/settings/education.php:7, templates/dashboard/settings/skill.php:8
161
  msgid "Settings"
162
  msgstr ""
163
 
177
  msgid "Tutor Pages"
178
  msgstr ""
179
 
180
+ #: classes/Admin.php:139, classes/Instructors_List.php:130, templates/dashboard/dashboard.php:92, templates/dashboard/purchase_history.php:23, templates/dashboard/withdraw.php:185, views/pages/view_attempt.php:59, views/pages/tools/tutor_pages.php:11
181
  msgid "Status"
182
  msgstr ""
183
 
184
+ #: classes/Admin.php:245, templates/permission-denied.php:40, templates/dashboard/create-course.php:25, templates/single/lesson/required-enroll.php:5
185
  msgid "Permission Denied"
186
  msgstr ""
187
 
201
  msgid "If you like %1$s please leave us a %2$s rating. A huge thanks in advance!"
202
  msgstr ""
203
 
204
+ #: classes/Ajax.php:66, classes/Ajax.php:119, classes/Ajax.php:206, classes/Ajax.php:270, classes/Ajax.php:349, classes/Ajax.php:392, classes/Ajax.php:413, classes/Ajax.php:526, classes/Ajax.php:598, classes/Course.php:447, classes/Course.php:482, classes/Course.php:725, classes/Course.php:778, classes/Course.php:815, classes/Course.php:835, classes/Instructor.php:250, classes/Lesson.php:124, classes/Lesson.php:164, classes/Lesson.php:220, classes/Quiz.php:148, classes/Quiz.php:560, classes/Quiz.php:652, classes/Quiz.php:707, classes/Quiz.php:750, classes/Quiz.php:792, classes/Quiz.php:815, classes/Quiz.php:910, classes/Quiz.php:933, classes/Quiz.php:954, classes/Quiz.php:1082, classes/Quiz.php:1127, classes/Quiz.php:1208, classes/Quiz.php:1268, classes/Quiz.php:1293, classes/Q_and_A.php:71
205
  msgid "Access Denied"
206
  msgstr ""
207
 
208
+ #: classes/Ajax.php:189
209
  msgid "Rating placed success"
210
  msgstr ""
211
 
212
+ #: classes/Ajax.php:211
213
  msgid "Empty question title or body"
214
  msgstr ""
215
 
216
+ #: classes/Ajax.php:249
217
  msgid "Question has been added successfully"
218
  msgstr ""
219
 
220
+ #: classes/Ajax.php:259
221
  msgid "Please write answer"
222
  msgstr ""
223
 
224
+ #: classes/Ajax.php:295
225
  msgid "Answer has been added successfully"
226
  msgstr ""
227
 
228
+ #: classes/Ajax.php:334
229
  msgid "Course added to wish list"
230
  msgstr ""
231
 
232
+ #: classes/Ajax.php:323
233
  msgid "Course removed from wish list"
234
  msgstr ""
235
 
236
+ #: classes/Ajax.php:464, classes/Ajax.php:468
237
  msgid "ERROR:"
238
  msgstr ""
239
 
240
+ #: classes/Ajax.php:468
241
  msgid "Username is required."
242
  msgstr ""
243
 
244
+ #: classes/Ajax.php:512
245
  msgid "Announcement created successfully"
246
  msgstr ""
247
 
248
+ #: classes/Ajax.php:513
249
  msgid "Announcement updated successfully"
250
  msgstr ""
251
 
252
+ #: classes/Ajax.php:514
253
  msgid "Announcement creation failed"
254
  msgstr ""
255
 
256
+ #: classes/Ajax.php:515
257
  msgid "Announcement update failed"
258
  msgstr ""
259
 
260
+ #: classes/Ajax.php:544
261
  msgid "Course name required"
262
  msgstr ""
263
 
264
+ #: classes/Ajax.php:549
265
  msgid "Announcement title required"
266
  msgstr ""
267
 
268
+ #: classes/Ajax.php:553
269
  msgid "Announcement summary required"
270
  msgstr ""
271
 
272
+ #: classes/Ajax.php:611
273
  msgid "Announcement delete failed"
274
  msgstr ""
275
 
276
+ #: classes/Ajax.php:605
277
  msgid "Announcement deleted successfully"
278
  msgstr ""
279
 
280
+ #: classes/Course.php:169
281
  msgid "Fully booked"
282
  msgstr ""
283
 
284
+ #: classes/Course.php:191, classes/Course.php:275
285
  msgid "Course Builder"
286
  msgstr ""
287
 
288
+ #: classes/Course.php:192, classes/Course.php:277
289
  msgid "Additional Data"
290
  msgstr ""
291
 
292
+ #: classes/Course.php:193, classes/Course.php:274
293
  msgid "Video"
294
  msgstr ""
295
 
296
+ #: classes/Course.php:203, classes/Course.php:1380, views/options/options_generator.php:2
297
  msgid "Tutor Settings"
298
  msgstr ""
299
 
300
+ #: classes/Course.php:492
301
  msgid "Topic has been updated"
302
  msgstr ""
303
 
304
+ #: classes/Course.php:506, classes/Options.php:448, classes/Post_types.php:172, templates/single/course/course-topics.php:39
305
  msgid "Lessons"
306
  msgstr ""
307
 
308
+ #: classes/Course.php:508, templates/course-filter/filters.php:74, templates/dashboard/earning/statement.php:29
309
  msgid "Price"
310
  msgstr ""
311
 
312
+ #: classes/Course.php:537
313
  msgid "free"
314
  msgstr ""
315
 
316
+ #: classes/Course.php:587
317
  msgid "Please Sign In first"
318
  msgstr ""
319
 
320
+ #: classes/Course.php:635, classes/Lesson.php:310
321
  msgid "Please Sign-In"
322
  msgstr ""
323
 
324
+ #: classes/Course.php:761
325
+ msgid "No instructor available or you have already added maximum instructors"
326
  msgstr ""
327
 
328
+ #: classes/Course.php:765
329
+ msgid "To add unlimited multiple instructors in your course, get %1$sTutor LMS Pro%2$s"
330
  msgstr ""
331
 
332
+ #: classes/Course.php:1210
333
  msgid "complete all lessons to mark this course as complete"
334
  msgstr ""
335
 
336
+ #: classes/Course.php:1247
337
  msgid "You have to pass %s quizzes to complete this course."
338
  msgstr ""
339
 
340
+ #: classes/Course.php:1359
341
  msgid "Make This Course Public"
342
  msgstr ""
343
 
344
+ #: classes/Course.php:1361
345
  msgid "No enrollment required."
346
  msgstr ""
347
 
348
+ #: classes/Course.php:1369
349
  msgid "Disable Q&A"
350
  msgstr ""
351
 
352
+ #: classes/Course.php:1429
353
  msgid "Invalid Course ID or Access Denied."
354
  msgstr ""
355
 
356
+ #: classes/Course_Settings_Tabs.php:32, classes/Options.php:224, classes/Tutor_Setup.php:400, views/metabox/course/settings-tabs.php:13
357
  msgid "Course Settings"
358
  msgstr ""
359
 
360
+ #: classes/Course_Settings_Tabs.php:38, classes/Options.php:121, classes/Options.php:124, classes/Options.php:223, classes/Tutor_Setup.php:561, classes/WooCommerce.php:294
361
  msgid "General"
362
  msgstr ""
363
 
364
+ #: classes/Course_Settings_Tabs.php:39, classes/Options.php:125, classes/Tutor_Setup.php:361
365
  msgid "General Settings"
366
  msgstr ""
367
 
368
+ #: classes/Course_Settings_Tabs.php:45
369
  msgid "Maximum Students"
370
  msgstr ""
371
 
372
+ #: classes/Course_Settings_Tabs.php:46, classes/Options.php:137, classes/Options.php:144, classes/Options.php:164, classes/Options.php:171, classes/Options.php:178, classes/Options.php:185, classes/Options.php:198, classes/Options.php:229, classes/Options.php:247, classes/Options.php:264, classes/Options.php:297, classes/Options.php:315, classes/Options.php:321, classes/Options.php:457, classes/Options.php:564, classes/Options.php:578, classes/Options.php:585, classes/Options.php:610, classes/Options.php:617, classes/Options.php:635, classes/Options.php:659, classes/User.php:193
373
  msgid "Enable"
374
  msgstr ""
375
 
376
+ #: classes/Course_Settings_Tabs.php:48
377
  msgid "Number of students that can enrol in this course. Set 0 for no limits."
378
  msgstr ""
379
 
380
+ #: classes/Course_Widget.php:23
381
  msgid "Tutor Course"
382
  msgstr ""
383
 
384
+ #: classes/Course_Widget.php:24
385
  msgid "Display courses wherever widget support is available."
386
  msgstr ""
387
 
389
  msgid "New title"
390
  msgstr ""
391
 
392
+ #: classes/Course_Widget.php:115
393
+ msgid "Title"
394
  msgstr ""
395
 
396
+ #: classes/Course_Widget.php:122, templates/dashboard/purchase_history.php:20, views/pages/tools/tutor_pages.php:9
397
+ msgid "ID"
398
  msgstr ""
399
 
400
+ #: classes/Course_Widget.php:126
401
  msgid "Place single course id or comma (,) separated course ids"
402
  msgstr ""
403
 
404
+ #: classes/Course_Widget.php:131
405
  msgid "Exclude IDS:"
406
  msgstr ""
407
 
408
+ #: classes/Course_Widget.php:134
409
  msgid "Place comma (,) separated courses ids which you like to exclude from the query"
410
  msgstr ""
411
 
412
+ #: classes/Course_Widget.php:140, classes/Options.php:113, templates/course-filter/filters.php:33
413
+ msgid "Category"
414
  msgstr ""
415
 
416
+ #: classes/Course_Widget.php:144
417
  msgid "Place comma (,) separated category ids"
418
  msgstr ""
419
 
420
+ #: classes/Course_Widget.php:150
421
  msgid "OrderBy"
422
  msgstr ""
423
 
424
+ #: classes/Course_Widget.php:165
425
+ msgid "Order"
426
  msgstr ""
427
 
428
+ #: classes/Course_Widget.php:175
429
  msgid "Count:"
430
  msgstr ""
431
 
432
+ #: classes/Course_Widget.php:178
433
  msgid "Total results you like to show"
434
  msgstr ""
435
 
436
+ #: classes/Dashboard.php:50
437
  msgid "Auto Draft"
438
  msgstr ""
439
 
449
  msgid "Check and place necessary information here."
450
  msgstr ""
451
 
452
+ #: classes/Email.php:32, classes/Instructors_List.php:125, classes/Students_List.php:66
453
  msgid "Name"
454
  msgstr ""
455
 
505
  msgid "This key is invalid or has already been used. Please reset your password again if needed."
506
  msgstr ""
507
 
508
+ #: classes/FormHandler.php:118
509
  msgid "Please enter your password."
510
  msgstr ""
511
 
512
+ #: classes/FormHandler.php:123
513
  msgid "Passwords do not match."
514
  msgstr ""
515
 
516
+ #: classes/FormHandler.php:165
517
  msgid "Password Reset Request for %s"
518
  msgstr ""
519
 
565
  msgid "Instructor has been added successfully"
566
  msgstr ""
567
 
568
+ #: classes/Instructors_List.php:76, classes/Withdraw_Requests_List.php:55, classes/Withdraw_Requests_List.php:66
569
  msgid "Approve"
570
  msgstr ""
571
 
572
+ #: classes/Instructors_List.php:79
573
  msgid "Sure to Block?"
574
  msgstr ""
575
 
576
+ #: classes/Instructors_List.php:79
577
  msgid "Block"
578
  msgstr ""
579
 
580
+ #: classes/Instructors_List.php:82
581
  msgid "Sure to Un Block?"
582
  msgstr ""
583
 
584
+ #: classes/Instructors_List.php:82
585
  msgid "Unblock"
586
  msgstr ""
587
 
588
+ #: classes/Instructors_List.php:92
589
  msgid "Reject"
590
  msgstr ""
591
 
592
+ #: classes/Instructors_List.php:92
593
  msgid "Remove as Instructor"
594
  msgstr ""
595
 
596
+ #: classes/Instructors_List.php:93
597
  msgid "Sure to Reject?"
598
  msgstr ""
599
 
600
+ #: classes/Instructors_List.php:93
601
  msgid "Sure to Remove as Instructor?"
602
  msgstr ""
603
 
604
+ #: classes/Instructors_List.php:126, classes/Students_List.php:67, templates/dashboard/registration.php:81, templates/dashboard/registration.php:83, views/pages/add_new_instructor.php:69, views/pages/add_new_instructor.php:75, templates/dashboard/instructor/registration.php:86, templates/dashboard/instructor/registration.php:89
605
  msgid "E-Mail"
606
  msgstr ""
607
 
608
+ #: classes/Instructors_List.php:127
609
  msgid "Total Course"
610
  msgstr ""
611
 
612
+ #: classes/Instructors_List.php:128
613
  msgid "Instructor Commission"
614
  msgstr ""
615
 
616
+ #: classes/Instructors_List.php:129, classes/Tutor_List_Table.php:438, classes/Tutor_List_Table.php:1368, templates/dashboard/announcements.php:113, templates/dashboard/announcements.php:123, templates/dashboard/purchase_history.php:24, views/pages/announcements.php:95, views/pages/announcements.php:114, templates/dashboard/assignments/submitted.php:71
617
  msgid "Date"
618
  msgstr ""
619
 
620
+ #: classes/Lesson.php:56, views/metabox/lesson-metabox.php:3, views/pages/announcements.php:197, views/pages/announcements.php:279, templates/dashboard/announcements/create.php:19, templates/dashboard/announcements/update.php:20
621
  msgid "Select Course"
622
  msgstr ""
623
 
624
+ #: classes/Lesson.php:57
625
  msgid "Lesson Video"
626
  msgstr ""
627
 
628
+ #: classes/Lesson.php:58, templates/global/attachments.php:25, templates/single/assignment/content.php:155
629
  msgid "Attachments"
630
  msgstr ""
631
 
632
+ #: classes/Lesson.php:134
633
  msgid "Draft Lesson"
634
  msgstr ""
635
 
636
+ #: classes/Lesson.php:189
637
  msgid "Couldn't create lesson."
638
  msgstr ""
639
 
640
+ #: classes/Lesson.php:273, classes/Options.php:220, classes/Question_Answers_List.php:78, classes/Quiz_Attempts_List.php:119, classes/Tutor_Setup.php:562, templates/student-public-profile.php:98, templates/dashboard/assignments.php:95, templates/dashboard/question-answer.php:27, templates/shortcode/tutor-instructor.php:27, views/pages/view_attempt.php:73, templates/dashboard/announcements/details.php:19, templates/dashboard/assignments/review.php:44, templates/dashboard/assignments/submitted.php:30, templates/dashboard/earning/statement.php:12, templates/single/quiz/top.php:27
641
  msgid "Course"
642
  msgstr ""
643
 
644
+ #: classes/Options.php:87
645
  msgid "Option Updated"
646
  msgstr ""
647
 
648
+ #: classes/Options.php:94
649
  msgid "/course/sample-course/<code>lessons</code>/sample-lesson/"
650
  msgstr ""
651
 
652
+ #: classes/Options.php:97
653
  msgctxt "tutor student profile"
654
  msgid "profile"
655
  msgstr ""
656
 
657
+ #: classes/Options.php:100, classes/Tutor_Setup.php:327
658
  msgid "Unlimited"
659
  msgstr ""
660
 
661
+ #: classes/Options.php:104, views/metabox/video-metabox.php:21
662
  msgid "HTML 5 (mp4)"
663
  msgstr ""
664
 
665
+ #: classes/Options.php:105, views/metabox/video-metabox.php:25
666
  msgid "External URL"
667
  msgstr ""
668
 
669
+ #: classes/Options.php:106, views/metabox/video-metabox.php:29
670
  msgid "Youtube"
671
  msgstr ""
672
 
673
+ #: classes/Options.php:107, views/metabox/video-metabox.php:33
674
  msgid "Vimeo"
675
  msgstr ""
676
 
677
+ #: classes/Options.php:108, views/metabox/video-metabox.php:37
678
  msgid "Embedded"
679
  msgstr ""
680
 
681
+ #: classes/Options.php:112
682
  msgid "Keyword Search"
683
  msgstr ""
684
 
685
+ #: classes/Options.php:114, templates/course-filter/filters.php:42
 
 
 
 
686
  msgid "Tag"
687
  msgstr ""
688
 
689
+ #: classes/Options.php:115, views/metabox/course-level-metabox.php:10
690
  msgid "Difficulty Level"
691
  msgstr ""
692
 
693
+ #: classes/Options.php:116
694
  msgid "Price Type"
695
  msgstr ""
696
 
697
+ #: classes/Options.php:129, classes/Utils.php:7185
698
  msgid "Dashboard Page"
699
  msgstr ""
700
 
701
+ #: classes/Options.php:132
702
  msgid "This page will be used for student and instructor dashboard"
703
  msgstr ""
704
 
705
+ #: classes/Options.php:136, classes/Tutor_Setup.php:371
706
  msgid "Public Profile"
707
  msgstr ""
708
 
709
+ #: classes/Options.php:139
710
  msgid "Enable this to make a profile publicly visible"
711
  msgstr ""
712
 
713
+ #: classes/Options.php:143
714
  msgid "Profile Completion"
715
  msgstr ""
716
 
717
+ #: classes/Options.php:146
718
  msgid "Enabling this feature will show a notification bar to students and instructors to complete their profile information"
719
  msgstr ""
720
 
721
+ #: classes/Options.php:150
722
  msgid "Tutor Native Login"
723
  msgstr ""
724
 
725
+ #: classes/Options.php:151, classes/Options.php:328, classes/Options.php:335, classes/Options.php:342, classes/Options.php:349, classes/Options.php:356, classes/Options.php:363, classes/Options.php:370, classes/Options.php:377, classes/Options.php:384, classes/Options.php:391, classes/Options.php:398, classes/Options.php:405, classes/Options.php:412, classes/Options.php:419, classes/Options.php:426, classes/Options.php:533
726
  msgid "Disable"
727
  msgstr ""
728
 
729
+ #: classes/Options.php:153
730
  msgid "Disable to use the default WordPress login page"
731
  msgstr ""
732
 
733
+ #: classes/Options.php:157
734
  msgid "Course Visibility"
735
  msgstr ""
736
 
737
+ #: classes/Options.php:158
738
  msgid "Logged in only"
739
  msgstr ""
740
 
741
+ #: classes/Options.php:159
742
  msgid "Students must be logged in to view course"
743
  msgstr ""
744
 
745
+ #: classes/Options.php:163
746
  msgid "Erase upon uninstallation"
747
  msgstr ""
748
 
749
+ #: classes/Options.php:165
750
  msgid "Delete all data during uninstallation"
751
  msgstr ""
752
 
753
+ #: classes/Options.php:170
754
  msgid "Spotlight mode"
755
  msgstr ""
756
 
757
+ #: classes/Options.php:173
758
  msgid "This will hide the header and the footer and enable spotlight (full screen) mode when students view lessons."
759
  msgstr ""
760
 
761
+ #: classes/Options.php:177, classes/Tutor_Setup.php:381
762
  msgid "YouTube Player"
763
  msgstr ""
764
 
765
+ #: classes/Options.php:180, classes/Options.php:187
766
  msgid "Disable this option to use Tutor LMS video player."
767
  msgstr ""
768
 
769
+ #: classes/Options.php:184, classes/Tutor_Setup.php:386
770
  msgid "Vimeo Player"
771
  msgstr ""
772
 
773
+ #: classes/Options.php:191
774
  msgid "Pagination"
775
  msgstr ""
776
 
777
+ #: classes/Options.php:193
778
  msgid "Number of items you would like displayed \"per page\" in the pagination"
779
  msgstr ""
780
 
781
+ #: classes/Options.php:197
782
  msgid "Maintenance Mode"
783
  msgstr ""
784
 
785
+ #: classes/Options.php:200
786
  msgid "Enabling the maintenance mode allows you to display a custom message on the frontend. During this time, visitors can not access the site content. But the wp-admin dashboard will remain accessible."
787
  msgstr ""
788
 
789
+ #: classes/Options.php:204
790
  msgid "Frontend Admin Bar"
791
  msgstr ""
792
 
793
+ #: classes/Options.php:205
794
  msgid "Hide"
795
  msgstr ""
796
 
797
+ #: classes/Options.php:207
798
  msgid "Hide admin bar option allow you to hide WordPress admin bar entirely from the frontend. It will still show to administrator roles user"
799
  msgstr ""
800
 
801
+ #: classes/Options.php:211
802
  msgid "Error message for wrong login credentials"
803
  msgstr ""
804
 
805
+ #: classes/Options.php:213
806
  msgid "Login error message displayed when the user puts wrong login credentials."
807
  msgstr ""
808
 
809
+ #: classes/Options.php:228
810
  msgid "Gutenberg Editor"
811
  msgstr ""
812
 
813
+ #: classes/Options.php:230
814
  msgid "Use Gutenberg editor on course description area."
815
  msgstr ""
816
 
817
+ #: classes/Options.php:234, classes/Options.php:240, classes/Options.php:309, classes/Options.php:462, classes/WooCommerce.php:306
818
  msgid "Enable / Disable"
819
  msgstr ""
820
 
821
+ #: classes/Options.php:235
822
  msgid "Hide course products from shop page"
823
  msgstr ""
824
 
825
+ #: classes/Options.php:236
826
  msgid "Enabling this feature will remove course products from the shop page."
827
  msgstr ""
828
 
829
+ #: classes/Options.php:241
830
  msgid "Course Content Access"
831
  msgstr ""
832
 
833
+ #: classes/Options.php:242
834
  msgid "Allow instructors and admins to view the course content without enrolling"
835
  msgstr ""
836
 
837
+ #: classes/Options.php:246
838
  msgid "Auto redirect to courses"
839
  msgstr ""
840
 
841
+ #: classes/Options.php:248
842
  msgid "When a user's WooCommerce order is auto-completed, they will be redirected to enrolled courses"
843
  msgstr ""
844
 
845
+ #: classes/Options.php:252
846
  msgid "Course Completion Process"
847
  msgstr ""
848
 
849
+ #: classes/Options.php:256
850
  msgid "Flexible"
851
  msgstr ""
852
 
853
+ #: classes/Options.php:257
854
  msgid "Strict Mode"
855
  msgstr ""
856
 
857
+ #: classes/Options.php:259
858
  msgid "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."
859
  msgstr ""
860
 
861
+ #: classes/Options.php:263
862
  msgid "Course Retake"
863
  msgstr ""
864
 
865
+ #: classes/Options.php:265
866
  msgid "Enabling this feature will allow students to reset course progress and start over."
867
  msgstr ""
868
 
869
+ #: classes/Options.php:270
870
  msgid "Archive"
871
  msgstr ""
872
 
873
+ #: classes/Options.php:271
874
  msgid "Course Archive Settings"
875
  msgstr ""
876
 
877
+ #: classes/Options.php:275
878
  msgid "Course Archive Page"
879
  msgstr ""
880
 
881
+ #: classes/Options.php:278
882
  msgid "This page will be used to list all the published courses."
883
  msgstr ""
884
 
885
+ #: classes/Options.php:282
886
  msgid "Column Per Row"
887
  msgstr ""
888
 
889
+ #: classes/Options.php:285
890
  msgid "Define how many column you want to use to display courses."
891
  msgstr ""
892
 
893
+ #: classes/Options.php:289, classes/Tutor_Setup.php:419
894
  msgid "Courses Per Page"
895
  msgstr ""
896
 
897
+ #: classes/Options.php:292
898
  msgid "Define how many courses you want to show per page"
899
  msgstr ""
900
 
901
+ #: classes/Options.php:296
902
  msgid "Course Filter"
903
  msgstr ""
904
 
905
+ #: classes/Options.php:298
906
  msgid "Show sorting and filtering options on course archive page"
907
  msgstr ""
908
 
909
+ #: classes/Options.php:302
910
  msgid "Preferred Course Filters"
911
  msgstr ""
912
 
913
+ #: classes/Options.php:304
914
  msgid "Choose preferred filter options you'd like to show in course archive page."
915
  msgstr ""
916
 
917
+ #: classes/Options.php:310
918
  msgid "Course Display Settings"
919
  msgstr ""
920
 
921
+ #: classes/Options.php:314
922
  msgid "Display Instructor Info"
923
  msgstr ""
924
 
925
+ #: classes/Options.php:316
926
  msgid "Show instructor bio on each page"
927
  msgstr ""
928
 
929
+ #: classes/Options.php:320
930
  msgid "Question and Answer"
931
  msgstr ""
932
 
933
+ #: classes/Options.php:323
934
  msgid "Enabling this feature will add a Q&amp;A section on every course."
935
  msgstr ""
936
 
937
+ #: classes/Options.php:327
938
  msgid "Course Author"
939
  msgstr ""
940
 
941
+ #: classes/Options.php:330
942
  msgid "Disabling this feature will be removed course author name from the course page."
943
  msgstr ""
944
 
945
+ #: classes/Options.php:334
946
  msgid "Course Level"
947
  msgstr ""
948
 
949
+ #: classes/Options.php:337
950
  msgid "Disabling this feature will be removed course level from the course page."
951
  msgstr ""
952
 
953
+ #: classes/Options.php:341
954
  msgid "Course Share"
955
  msgstr ""
956
 
957
+ #: classes/Options.php:344
958
  msgid "Disabling this feature will be removed course share option from the course page."
959
  msgstr ""
960
 
961
+ #: classes/Options.php:348
962
  msgid "Course Duration"
963
  msgstr ""
964
 
965
+ #: classes/Options.php:351
966
  msgid "Disabling this feature will be removed course duration from the course page."
967
  msgstr ""
968
 
969
+ #: classes/Options.php:355
970
  msgid "Course Total Enrolled"
971
  msgstr ""
972
 
973
+ #: classes/Options.php:358
974
  msgid "Disabling this feature will be removed course total enrolled from the course page."
975
  msgstr ""
976
 
977
+ #: classes/Options.php:362
978
  msgid "Course Update Date"
979
  msgstr ""
980
 
981
+ #: classes/Options.php:365
982
  msgid "Disabling this feature will be removed course update date from the course page."
983
  msgstr ""
984
 
985
+ #: classes/Options.php:369
986
  msgid "Course Progress Bar"
987
  msgstr ""
988
 
989
+ #: classes/Options.php:372
990
  msgid "Disabling this feature will be removed completing progress bar from the course page."
991
  msgstr ""
992
 
993
+ #: classes/Options.php:376
994
  msgid "Course Material"
995
  msgstr ""
996
 
997
+ #: classes/Options.php:379
998
  msgid "Disabling this feature will be removed course material from the course page."
999
  msgstr ""
1000
 
1001
+ #: classes/Options.php:383
1002
  msgid "Course About"
1003
  msgstr ""
1004
 
1005
+ #: classes/Options.php:386
1006
  msgid "Disabling this feature will be removed course about from the course page."
1007
  msgstr ""
1008
 
1009
+ #: classes/Options.php:390
1010
  msgid "Course Description"
1011
  msgstr ""
1012
 
1013
+ #: classes/Options.php:393
1014
  msgid "Disabling this feature will be removed course description from the course page."
1015
  msgstr ""
1016
 
1017
+ #: classes/Options.php:397
1018
  msgid "Course Benefits"
1019
  msgstr ""
1020
 
1021
+ #: classes/Options.php:400
1022
  msgid "Disabling this feature will be removed course benefits from the course page."
1023
  msgstr ""
1024
 
1025
+ #: classes/Options.php:404
1026
  msgid "Course Requirements"
1027
  msgstr ""
1028
 
1029
+ #: classes/Options.php:407
1030
  msgid "Disabling this feature will be removed course requirements from the course page."
1031
  msgstr ""
1032
 
1033
+ #: classes/Options.php:411
1034
  msgid "Course Target Audience"
1035
  msgstr ""
1036
 
1037
+ #: classes/Options.php:414
1038
  msgid "Disabling this feature will be removed course target audience from the course page."
1039
  msgstr ""
1040
 
1041
+ #: classes/Options.php:418
1042
  msgid "Course Announcements"
1043
  msgstr ""
1044
 
1045
+ #: classes/Options.php:421
1046
  msgid "Disabling this feature will be removed course announcements from the course page."
1047
  msgstr ""
1048
 
1049
+ #: classes/Options.php:425
1050
  msgid "Course Review"
1051
  msgstr ""
1052
 
1053
+ #: classes/Options.php:428
1054
  msgid "Disabling this feature will be removed course review system from the course page."
1055
  msgstr ""
1056
 
1057
+ #: classes/Options.php:432
1058
  msgid "Preferred Video Source"
1059
  msgstr ""
1060
 
1061
+ #: classes/Options.php:434
1062
  msgid "Choose video sources you'd like to support. Unchecking all will not disable video feature."
1063
  msgstr ""
1064
 
1065
+ #: classes/Options.php:438
1066
  msgid "Default Video Source"
1067
  msgstr ""
1068
 
1069
+ #: classes/Options.php:441
1070
  msgid "Choose video source to be selected by default."
1071
  msgstr ""
1072
 
1073
+ #: classes/Options.php:451
1074
  msgid "Lesson Settings"
1075
  msgstr ""
1076
 
1077
+ #: classes/Options.php:452
1078
  msgid "Lesson settings will be here"
1079
  msgstr ""
1080
 
1081
+ #: classes/Options.php:456, views/modal/edit-lesson.php:12
1082
  msgid "Classic Editor"
1083
  msgstr ""
1084
 
1085
+ #: classes/Options.php:458
1086
  msgid "Enable classic editor to get full support of any editor/page builder."
1087
  msgstr ""
1088
 
1089
+ #: classes/Options.php:463
1090
  msgid "Automatically load next course content."
1091
  msgstr ""
1092
 
1093
+ #: classes/Options.php:464
1094
  msgid "Enabling this feature will be load next course content automatically after finishing current video."
1095
  msgstr ""
1096
 
1097
+ #: classes/Options.php:468
1098
  msgid "Lesson Permalink Base"
1099
  msgstr ""
1100
 
1101
+ #: classes/Options.php:474
1102
  msgid "Youtube API Key"
1103
  msgstr ""
1104
 
1105
+ #: classes/Options.php:483, classes/Options.php:486, classes/Quiz_Attempts_List.php:118, classes/Tutor_Setup.php:563, views/metabox/course-contents.php:174, views/metabox/course-topics.php:68, views/pages/view_attempt.php:39, templates/single/quiz/top.php:24
1106
  msgid "Quiz"
1107
  msgstr ""
1108
 
1109
+ #: classes/Options.php:487
1110
  msgid "The values you set here define the default values that are used in the settings form when you create a new quiz."
1111
  msgstr ""
1112
 
1113
+ #: classes/Options.php:491, classes/Tutor_Setup.php:432, views/modal/edit_quiz.php:151
1114
  msgid "Time Limit"
1115
  msgstr ""
1116
 
1117
+ #: classes/Options.php:492
1118
  msgid "0 means unlimited time."
1119
  msgstr ""
1120
 
1121
+ #: classes/Options.php:503, views/modal/edit_quiz.php:163
1122
  msgid "Weeks"
1123
  msgstr ""
1124
 
1125
+ #: classes/Options.php:504, views/modal/edit_quiz.php:162
1126
  msgid "Days"
1127
  msgstr ""
1128
 
1129
+ #: classes/Options.php:505, views/modal/edit_quiz.php:161
1130
  msgid "Hours"
1131
  msgstr ""
1132
 
1133
+ #: classes/Options.php:506, views/modal/edit_quiz.php:160
1134
  msgid "Minutes"
1135
  msgstr ""
1136
 
1137
+ #: classes/Options.php:507, views/modal/edit_quiz.php:159
1138
  msgid "Seconds"
1139
  msgstr ""
1140
 
1141
+ #: classes/Options.php:514
1142
  msgid "When time expires"
1143
  msgstr ""
1144
 
1145
+ #: classes/Options.php:518, classes/Tutor_Setup.php:439
1146
  msgid "The current quiz answers are submitted automatically."
1147
  msgstr ""
1148
 
1149
+ #: classes/Options.php:519, classes/Tutor_Setup.php:440
1150
  msgid "The current quiz answers are submitted by students."
1151
  msgstr ""
1152
 
1153
+ #: classes/Options.php:520, classes/Tutor_Setup.php:441
1154
  msgid "Attempts must be submitted before time expires, otherwise they will not be counted"
1155
  msgstr ""
1156
 
1157
+ #: classes/Options.php:522
1158
  msgid "Choose which action to follow when the quiz time expires."
1159
  msgstr ""
1160
 
1161
+ #: classes/Options.php:526
1162
  msgid "Attempts allowed"
1163
  msgstr ""
1164
 
1165
+ #: classes/Options.php:528
1166
  msgid "The highest number of attempts students are allowed to take for a quiz. 0 means unlimited attempts."
1167
  msgstr ""
1168
 
1169
+ #: classes/Options.php:532
1170
  msgid "Show Previous button"
1171
  msgstr ""
1172
 
1173
+ #: classes/Options.php:535
1174
  msgid "Choose whether to show or hide previous button for single question."
1175
  msgstr ""
1176
 
1177
+ #: classes/Options.php:539
1178
  msgid "Final grade calculation"
1179
  msgstr ""
1180
 
1181
+ #: classes/Options.php:543, classes/Tutor_Setup.php:455
1182
  msgid "Highest Grade"
1183
  msgstr ""
1184
 
1185
+ #: classes/Options.php:544, classes/Tutor_Setup.php:460
1186
  msgid "Average Grade"
1187
  msgstr ""
1188
 
1189
+ #: classes/Options.php:545, classes/Tutor_Setup.php:465
1190
  msgid "First Attempt"
1191
  msgstr ""
1192
 
1193
+ #: classes/Options.php:546, classes/Tutor_Setup.php:470
1194
  msgid "Last Attempt"
1195
  msgstr ""
1196
 
1197
+ #: classes/Options.php:548
1198
  msgid "When multiple attempts are allowed, which method should be used to calculate a student's final grade for the quiz."
1199
  msgstr ""
1200
 
1201
+ #: classes/Options.php:558
1202
  msgid "Instructor Profile Settings"
1203
  msgstr ""
1204
 
1205
+ #: classes/Options.php:559, classes/Options.php:598, classes/Options.php:630
1206
  msgid "Enable Disable Option to on/off notification on various event"
1207
  msgstr ""
1208
 
1209
+ #: classes/Options.php:563
1210
  msgid "Course Marketplace"
1211
  msgstr ""
1212
 
1213
+ #: classes/Options.php:566
1214
  msgid "Allow multiple instructors to upload their courses."
1215
  msgstr ""
1216
 
1217
+ #: classes/Options.php:570, classes/Utils.php:7186
1218
  msgid "Instructor Registration Page"
1219
  msgstr ""
1220
 
1221
+ #: classes/Options.php:573
1222
  msgid "This page will be used to sign up new instructors."
1223
  msgstr ""
1224
 
1225
+ #: classes/Options.php:577
1226
  msgid "Allow publishing course"
1227
  msgstr ""
1228
 
1229
+ #: classes/Options.php:580
1230
  msgid "Enable instructors to publish course directly. <strong>Do not select</strong> if admins want to review courses before publishing."
1231
  msgstr ""
1232
 
1233
+ #: classes/Options.php:584
1234
  msgid "Become Instructor Button"
1235
  msgstr ""
1236
 
1237
+ #: classes/Options.php:587
1238
  msgid "Uncheck this option to hide the button from student dashboard."
1239
  msgstr ""
1240
 
1241
+ #: classes/Options.php:597
1242
  msgid "Student Profile settings"
1243
  msgstr ""
1244
 
1245
+ #: classes/Options.php:602, classes/Utils.php:7187
1246
  msgid "Student Registration Page"
1247
  msgstr ""
1248
 
1249
+ #: classes/Options.php:605
1250
  msgid "Choose the page for student registration page"
1251
  msgstr ""
1252
 
1253
+ #: classes/Options.php:609
1254
  msgid "Show reviews on profile"
1255
  msgstr ""
1256
 
1257
+ #: classes/Options.php:612
1258
  msgid "Enabling this will show the reviews written by each student on their profile"
1259
  msgstr ""
1260
 
1261
+ #: classes/Options.php:616
1262
  msgid "Show completed courses"
1263
  msgstr ""
1264
 
1265
+ #: classes/Options.php:619
1266
  msgid "Completed courses will be shown on student profiles. <br/> For example, you can see this link-"
1267
  msgstr ""
1268
 
1269
+ #: classes/Options.php:626, classes/Options.php:634, classes/Tutor_Setup.php:491, templates/dashboard/earning.php:123, templates/dashboard/earning/chart-body.php:17, templates/dashboard/earning/statement.php:13, templates/dashboard/earning/statements.php:131
1270
  msgid "Earning"
1271
  msgstr ""
1272
 
1273
+ #: classes/Options.php:629
1274
  msgid "Earning and commission allocation"
1275
  msgstr ""
1276
 
1277
+ #: classes/Options.php:637
1278
  msgid "If disabled, the Admin will receive 100% of the earning"
1279
  msgstr ""
1280
 
1281
+ #: classes/Options.php:641
1282
  msgid "Admin Commission Percentage"
1283
  msgstr ""
1284
 
1285
+ #: classes/Options.php:643
1286
  msgid "Define the commission of the Admin from each sale.(after deducting fees)"
1287
  msgstr ""
1288
 
1289
+ #: classes/Options.php:647
1290
  msgid "Instructor Commission Percentage"
1291
  msgstr ""
1292
 
1293
+ #: classes/Options.php:649
1294
  msgid "Define the commission for instructors from each sale.(after deducting fees)"
1295
  msgstr ""
1296
 
1297
+ #: classes/Options.php:653
1298
  msgid "Fee Deduction"
1299
  msgstr ""
1300
 
1301
+ #: classes/Options.php:654
1302
  msgid "Fees are charged from the entire sales amount. The remaining amount will be divided among admin and instructors."
1303
  msgstr ""
1304
 
1305
+ #: classes/Options.php:664
1306
  msgid "Fee Name"
1307
  msgstr ""
1308
 
1309
+ #: classes/Options.php:669
1310
  msgid "Fee Amount"
1311
  msgstr ""
1312
 
1313
+ #: classes/Options.php:677
1314
  msgid "Select Fees Type"
1315
  msgstr ""
1316
 
1317
+ #: classes/Options.php:678
1318
  msgid "Percent"
1319
  msgstr ""
1320
 
1321
+ #: classes/Options.php:679
1322
  msgid "Fixed"
1323
  msgstr ""
1324
 
1325
+ #: classes/Options.php:687
1326
  msgid "Show Statement Per Page"
1327
  msgstr ""
1328
 
1329
+ #: classes/Options.php:689
1330
  msgid "Define the number of statements to show."
1331
  msgstr ""
1332
 
1333
+ #: classes/Options.php:696, templates/dashboard/withdraw.php:42
1334
  msgid "Withdrawal"
1335
  msgstr ""
1336
 
1337
+ #: classes/Options.php:699
1338
  msgid "Withdrawal Settings"
1339
  msgstr ""
1340
 
1341
+ #: classes/Options.php:703
1342
  msgid "Minimum Withdraw Amount"
1343
  msgstr ""
1344
 
1345
+ #: classes/Options.php:705
1346
  msgid "Instructors should earn equal or above this amount to make a withdraw request."
1347
  msgstr ""
1348
 
1349
+ #: classes/Options.php:711
1350
  msgid "Withdraw Methods"
1351
  msgstr ""
1352
 
1353
+ #: classes/Options.php:712
1354
  msgid "Set withdraw settings"
1355
  msgstr ""
1356
 
1357
+ #: classes/Options.php:718
1358
  msgid "Style"
1359
  msgstr ""
1360
 
1361
+ #: classes/Options.php:721
1362
  msgid "Color Style"
1363
  msgstr ""
1364
 
1365
+ #: classes/Options.php:725
1366
  msgid "Primary Color"
1367
  msgstr ""
1368
 
1369
+ #: classes/Options.php:730
1370
  msgid "Primary Hover Color"
1371
  msgstr ""
1372
 
1373
+ #: classes/Options.php:735
1374
  msgid "Text color"
1375
  msgstr ""
1376
 
1377
+ #: classes/Options.php:740
1378
  msgid "Light color"
1379
  msgstr ""
1380
 
1381
+ #: classes/Options.php:747
1382
  msgid "Button Primary Color"
1383
  msgstr ""
1384
 
1385
+ #: classes/Options.php:753
1386
  msgid "Button Danger Color"
1387
  msgstr ""
1388
 
1389
+ #: classes/Options.php:758
1390
  msgid "Button Success Color"
1391
  msgstr ""
1392
 
1393
+ #: classes/Options.php:763
1394
  msgid "Button Warning Color"
1395
  msgstr ""
1396
 
1397
+ #: classes/Options.php:773, classes/Options.php:776
1398
  msgid "Monetization"
1399
  msgstr ""
1400
 
1401
+ #: classes/Options.php:777
1402
  msgid "You can monetize your LMS website by selling courses in a various way."
1403
  msgstr ""
1404
 
1405
+ #: classes/Options.php:782
1406
  msgid "Monetize Option"
1407
  msgstr ""
1408
 
1409
+ #: classes/Options.php:786
1410
  msgid "Disable Monetization"
1411
  msgstr ""
1412
 
1413
+ #: classes/Options.php:788
1414
  msgid "Select a monetization option to generate revenue by selling courses. Supports: WooCommerce, Easy Digital Downloads, Paid Memberships Pro"
1415
  msgstr ""
1416
 
1451
  msgid "Edit Course"
1452
  msgstr ""
1453
 
1454
+ #: classes/Post_types.php:48, templates/dashboard/create-course.php:30, templates/single/lesson/required-enroll.php:10
1455
  msgid "View Course"
1456
  msgstr ""
1457
 
1458
+ #: classes/Post_types.php:49, classes/Tutor_List_Table.php:1333, templates/student-public-profile.php:98, templates/student-public-profile.php:158, templates/dashboard/announcements.php:86, templates/dashboard/assignments.php:34, templates/dashboard/purchase_history.php:21, templates/shortcode/tutor-instructor.php:27, views/pages/announcements.php:60, templates/single/course/instructors.php:72
1459
  msgid "Courses"
1460
  msgstr ""
1461
 
1750
  msgid "View Assignment"
1751
  msgstr ""
1752
 
1753
+ #: classes/Post_types.php:287, views/metabox/course-topics.php:97
1754
  msgid "Assignments"
1755
  msgstr ""
1756
 
1820
  msgid "Preview course"
1821
  msgstr ""
1822
 
1823
+ #: classes/Question_Answers_List.php:47, classes/Question_Answers_List.php:79, classes/Quiz.php:1153, templates/dashboard/question-answer.php:28, views/modal/question_form.php:142, views/pages/answer.php:11, templates/dashboard/question-answer/answers.php:13
1824
  msgid "Answer"
1825
  msgstr ""
1826
 
1827
+ #: classes/Question_Answers_List.php:76, classes/Quiz.php:824, templates/dashboard/question-answer.php:25, views/pages/view_attempt.php:194, templates/dashboard/my-quiz-attempts/attempts-details.php:215, templates/dashboard/quiz-attempts/quiz-reviews.php:232
1828
  msgid "Question"
1829
  msgstr ""
1830
 
1831
+ #: classes/Question_Answers_List.php:77, templates/student-public-profile.php:103, templates/dashboard/question-answer.php:26, templates/dashboard/quiz-attempts.php:31, templates/dashboard/assignments/review.php:50, templates/dashboard/assignments/submitted.php:72
1832
  msgid "Student"
1833
  msgstr ""
1834
 
1835
+ #: classes/Quiz.php:542
1836
  msgid "Quiz has been timeout already"
1837
  msgstr ""
1838
 
1839
+ #: classes/Quiz.php:680, classes/Quiz.php:768, views/metabox/course-contents.php:117, views/metabox/course-contents.php:206
1840
  msgid "QUIZ"
1841
  msgstr ""
1842
 
1843
+ #: classes/Quiz.php:893
1844
  msgid "Please make sure you have added more than one option and saved them"
1845
  msgstr ""
1846
 
1847
+ #: classes/Quiz.php:889
1848
  msgid "Please select the correct answer"
1849
  msgstr ""
1850
 
1851
+ #: classes/Quiz.php:1014, views/modal/question_answer_form.php:22
1852
  msgid "True"
1853
  msgstr ""
1854
 
1855
+ #: classes/Quiz.php:1021, views/modal/question_answer_form.php:26
1856
  msgid "False"
1857
  msgstr ""
1858
 
1859
+ #: classes/Quiz.php:1137
1860
  msgid "Answer options &amp; mark correct"
1861
  msgstr ""
1862
 
1863
+ #: classes/Quiz.php:1140
1864
  msgid "Make sure you’re saving the answers in the right order. Students will have to match this order exactly."
1865
  msgstr ""
1866
 
1867
+ #: classes/Quiz.php:1175, classes/Quiz.php:1169, views/modal/question_form.php:164, views/modal/question_form.php:158, views/pages/view_attempt.php:337, templates/dashboard/quiz-attempts/quiz-reviews.php:404
1868
  msgid "Mark as correct"
1869
  msgstr ""
1870
 
1871
+ #: classes/Quiz.php:1325
1872
  msgid "Access Denied."
1873
  msgstr ""
1874
 
1875
+ #: classes/Quiz_Attempts_List.php:41
1876
  msgid "Review"
1877
  msgstr ""
1878
 
1879
+ #: classes/Quiz_Attempts_List.php:48
1880
  msgid " ago"
1881
  msgstr ""
1882
 
1883
+ #: classes/Quiz_Attempts_List.php:96
1884
  msgid " out of "
1885
  msgstr ""
1886
 
1887
+ #: classes/Quiz_Attempts_List.php:97
1888
  msgid " pass "
1889
  msgstr ""
1890
 
1891
+ #: classes/Quiz_Attempts_List.php:102, templates/dashboard/my-quiz-attempts.php:89, templates/dashboard/quiz-attempts.php:97, views/pages/view_attempt.php:101, templates/dashboard/my-quiz-attempts/attempts-details.php:176, templates/dashboard/quiz-attempts/quiz-reviews.php:162, templates/single/quiz/previous-attempts.php:75
1892
  msgid "Fail"
1893
  msgstr ""
1894
 
1895
+ #: classes/Quiz_Attempts_List.php:100, templates/dashboard/my-quiz-attempts.php:88, templates/dashboard/quiz-attempts.php:96, views/pages/view_attempt.php:99, templates/dashboard/my-quiz-attempts/attempts-details.php:174, templates/dashboard/quiz-attempts/quiz-reviews.php:160, templates/single/quiz/previous-attempts.php:75
1896
  msgid "Pass"
1897
  msgstr ""
1898
 
1899
+ #: classes/Quiz_Attempts_List.php:90, templates/dashboard/my-quiz-attempts.php:85, templates/dashboard/quiz-attempts.php:93, views/pages/view_attempt.php:92, templates/single/quiz/previous-attempts.php:73
1900
  msgid "Under Review"
1901
  msgstr ""
1902
 
1903
+ #: classes/Quiz_Attempts_List.php:120
1904
  msgid "Total Questions"
1905
  msgstr ""
1906
 
1907
+ #: classes/Quiz_Attempts_List.php:121
1908
  msgid "Earned Points"
1909
  msgstr ""
1910
 
1964
  msgid "Setup Wizard"
1965
  msgstr ""
1966
 
1967
+ #: classes/Tutor.php:519, classes/Utils.php:2554, templates/dashboard/dashboard.php:9
1968
  msgid "Dashboard"
1969
  msgstr ""
1970
 
1996
  msgid "Easy Digital Downloads"
1997
  msgstr ""
1998
 
1999
+ #: classes/TutorEDD.php:106, classes/WooCommerce.php:175
2000
  msgid "Add Product"
2001
  msgstr ""
2002
 
2003
+ #: classes/Tutor_List_Table.php:389, classes/Tutor_List_Table.php:1342, templates/dashboard/announcements.php:90, templates/dashboard/assignments.php:38, views/pages/announcements.php:69
2004
  msgid "All"
2005
  msgstr ""
2006
 
2007
+ #: classes/Tutor_List_Table.php:413, classes/Tutor_List_Table.php:1358, templates/dashboard/announcements.php:105, templates/dashboard/assignments.php:52, views/pages/announcements.php:85
2008
  msgid "Sort By"
2009
  msgstr ""
2010
 
2011
+ #: classes/Tutor_List_Table.php:538
2012
  msgid "Bulk Actions"
2013
  msgstr ""
2014
 
2015
+ #: classes/Tutor_List_Table.php:1351, templates/dashboard/announcements.php:99, templates/dashboard/assignments.php:47, views/pages/announcements.php:78, templates/dashboard/announcements/create.php:29, templates/dashboard/announcements/update.php:30
2016
  msgid "No course found"
2017
  msgstr ""
2018
 
2019
+ #: classes/Tutor_List_Table.php:1376, classes/Tutor_List_Table.php:1378, views/pages/announcements.php:52, views/pages/question_answer.php:23, views/pages/students.php:13, views/pages/withdraw_requests.php:13
2020
  msgid "Search"
2021
  msgstr ""
2022
 
2060
  msgid "weeks"
2061
  msgstr ""
2062
 
2063
+ #: classes/Tutor_Setup.php:275, classes/Tutor_Setup.php:564, classes/Utils.php:2568
2064
  msgid "Instructor"
2065
  msgstr ""
2066
 
2140
  msgid "What message to display when the quiz time expires?"
2141
  msgstr ""
2142
 
2143
+ #: classes/Tutor_Setup.php:447, views/modal/edit_quiz.php:218, templates/single/quiz/top.php:65
2144
  msgid "Attempts Allowed"
2145
  msgstr ""
2146
 
2244
  msgid "Payment"
2245
  msgstr ""
2246
 
2247
+ #: classes/Tutor_Setup.php:567, templates/single/quiz/body.php:436
2248
  msgid "Finish"
2249
  msgstr ""
2250
 
2276
  msgid "Skip This Step"
2277
  msgstr ""
2278
 
2279
+ #: classes/Tutor_Setup.php:623, classes/Tutor_Setup.php:730, templates/shortcode/tutor-instructor.php:48, views/modal/add_quiz.php:75, views/modal/add_quiz.php:98, views/modal/edit_quiz.php:137
2280
  msgid "Next"
2281
  msgstr ""
2282
 
2364
  msgid "Tutor &rsaquo; Setup Wizard"
2365
  msgstr ""
2366
 
2367
+ #: classes/User.php:195
2368
  msgid "Dismiss"
2369
  msgstr ""
2370
 
2371
+ #: classes/Utils.php:949
2372
  msgid "Nonce not matched"
2373
  msgstr ""
2374
 
2375
+ #: classes/Utils.php:1332
2376
  msgid "Q&A"
2377
  msgstr ""
2378
 
2379
+ #: classes/Utils.php:2223, templates/student-public-profile.php:115
2380
  msgid "Course Enrolled"
2381
  msgstr ""
2382
 
2383
+ #: classes/Utils.php:2555, templates/dashboard/my-profile.php:21
2384
  msgid "My Profile"
2385
  msgstr ""
2386
 
2387
+ #: classes/Utils.php:2556, templates/dashboard/dashboard.php:36, templates/dashboard/enrolled-courses.php:9
2388
  msgid "Enrolled Courses"
2389
  msgstr ""
2390
 
2391
+ #: classes/Utils.php:2557, templates/dashboard/wishlist.php:10
2392
  msgid "Wishlist"
2393
  msgstr ""
2394
 
2395
+ #: classes/Utils.php:2558
2396
  msgid "Reviews"
2397
  msgstr ""
2398
 
2399
+ #: classes/Utils.php:2559, templates/dashboard/my-quiz-attempts.php:25
2400
  msgid "My Quiz Attempts"
2401
  msgstr ""
2402
 
2403
+ #: classes/Utils.php:2560, templates/dashboard/purchase_history.php:9
2404
  msgid "Purchase History"
2405
  msgstr ""
2406
 
2407
+ #: classes/Utils.php:2573
2408
  msgid "Create Course"
2409
  msgstr ""
2410
 
2411
+ #: classes/Utils.php:2578, templates/dashboard/my-courses.php:9
2412
  msgid "My Courses"
2413
  msgstr ""
2414
 
2415
+ #: classes/Utils.php:2586
2416
  msgid "Withdrawals"
2417
  msgstr ""
2418
 
2419
+ #: classes/Utils.php:2594, templates/dashboard/question-answer.php:10, views/pages/question_answer.php:18
2420
  msgid "Question & Answer"
2421
  msgstr ""
2422
 
2423
+ #: classes/Utils.php:2615
2424
  msgid "Logout"
2425
  msgstr ""
2426
 
2427
+ #: classes/Utils.php:2630
2428
  msgid "Retrieve Password"
2429
  msgstr ""
2430
 
2431
+ #: classes/Utils.php:2739, templates/dashboard/dashboard.php:27
2432
  msgid "Pending"
2433
  msgstr ""
2434
 
2435
+ #: classes/Utils.php:2740
2436
  msgid "Approved"
2437
  msgstr ""
2438
 
2439
+ #: classes/Utils.php:2741
2440
  msgid "Blocked"
2441
  msgstr ""
2442
 
2443
+ #: classes/Utils.php:4445
2444
  msgid "True/False"
2445
  msgstr ""
2446
 
2447
+ #: classes/Utils.php:4450
2448
  msgid "Single Choice"
2449
  msgstr ""
2450
 
2451
+ #: classes/Utils.php:4455
2452
  msgid "Multiple Choice"
2453
  msgstr ""
2454
 
2455
+ #: classes/Utils.php:4460
2456
  msgid "Open Ended/Essay"
2457
  msgstr ""
2458
 
2459
+ #: classes/Utils.php:4465
2460
  msgid "Fill In The Blanks"
2461
  msgstr ""
2462
 
2463
+ #: classes/Utils.php:4470
2464
  msgid "Short Answer"
2465
  msgstr ""
2466
 
2467
+ #: classes/Utils.php:4475
2468
  msgid "Matching"
2469
  msgstr ""
2470
 
2471
+ #: classes/Utils.php:4480
2472
  msgid "Image Matching"
2473
  msgstr ""
2474
 
2475
+ #: classes/Utils.php:4485
2476
  msgid "Image Answering"
2477
  msgstr ""
2478
 
2479
+ #: classes/Utils.php:4490
2480
  msgid "Ordering"
2481
  msgstr ""
2482
 
2483
+ #: classes/Utils.php:5374
2484
  msgid "All Levels"
2485
  msgstr ""
2486
 
2487
+ #: classes/Utils.php:5375, templates/course-filter/filters.php:4
2488
  msgid "Beginner"
2489
  msgstr ""
2490
 
2491
+ #: classes/Utils.php:5376, templates/course-filter/filters.php:5
2492
  msgid "Intermediate"
2493
  msgstr ""
2494
 
2495
+ #: classes/Utils.php:5377, templates/course-filter/filters.php:6
2496
  msgid "Expert"
2497
  msgstr ""
2498
 
2499
+ #: classes/Utils.php:5401
2500
  msgid "Courses Taken"
2501
  msgstr ""
2502
 
2503
+ #: classes/Utils.php:5408
2504
  msgid "Enrolled Course"
2505
  msgstr ""
2506
 
2507
+ #: classes/Utils.php:5412
2508
  msgid "Reviews Written"
2509
  msgstr ""
2510
 
2511
+ #: classes/Utils.php:5719
2512
  msgid "Website URL"
2513
  msgstr ""
2514
 
2515
+ #: classes/Utils.php:5724
2516
  msgid "Github URL"
2517
  msgstr ""
2518
 
2519
+ #: classes/Utils.php:5729
2520
  msgid "Facebook URL"
2521
  msgstr ""
2522
 
2523
+ #: classes/Utils.php:5734
2524
  msgid "Twitter URL"
2525
  msgstr ""
2526
 
2527
+ #: classes/Utils.php:5739
2528
  msgid "Linkedin URL"
2529
  msgstr ""
2530
 
2531
+ #: classes/Utils.php:7148
2532
  msgid "Not Taken"
2533
  msgstr ""
2534
 
2535
+ #: classes/Utils.php:7146
2536
  msgid "In Progress"
2537
  msgstr ""
2538
 
2539
+ #: classes/Utils.php:7142
2540
  msgid "Completed"
2541
  msgstr ""
2542
 
2543
+ #: classes/Utils.php:7335, templates/dashboard/my-profile.php:34, templates/dashboard/registration.php:49, templates/dashboard/registration.php:52, views/pages/add_new_instructor.php:29, views/pages/add_new_instructor.php:35, templates/dashboard/instructor/registration.php:51, templates/dashboard/instructor/registration.php:54, templates/dashboard/settings/profile.php:96, templates/dashboard/settings/profile.php:98
2544
  msgid "First Name"
2545
  msgstr ""
2546
 
2547
+ #: classes/Utils.php:7336, templates/dashboard/my-profile.php:44, templates/dashboard/registration.php:59, templates/dashboard/registration.php:62, views/pages/add_new_instructor.php:43, views/pages/add_new_instructor.php:49, templates/dashboard/instructor/registration.php:61, templates/dashboard/instructor/registration.php:64, templates/dashboard/settings/profile.php:105, templates/dashboard/settings/profile.php:107
2548
  msgid "Last Name"
2549
  msgstr ""
2550
 
2551
+ #: classes/Utils.php:7337, views/metabox/user-profile-fields.php:37
2552
  msgid "Profile Photo"
2553
  msgstr ""
2554
 
2555
+ #: classes/Utils.php:7338
2556
  msgid "Withdraw Method"
2557
  msgstr ""
2558
 
2559
+ #: classes/Withdraw.php:38
2560
  msgid "Bank Transfer"
2561
  msgstr ""
2562
 
2563
+ #: classes/Withdraw.php:40
2564
  msgid "Get your payment directly into your bank account"
2565
  msgstr ""
2566
 
2567
+ #: classes/Withdraw.php:45
2568
  msgid "Instruction"
2569
  msgstr ""
2570
 
2571
+ #: classes/Withdraw.php:46
2572
  msgid "Write instruction for the instructor to fill bank information"
2573
  msgstr ""
2574
 
2575
+ #: classes/Withdraw.php:53
2576
  msgid "Account Name"
2577
  msgstr ""
2578
 
2579
+ #: classes/Withdraw.php:58
2580
  msgid "Account Number"
2581
  msgstr ""
2582
 
2583
+ #: classes/Withdraw.php:63
2584
  msgid "Bank Name"
2585
  msgstr ""
2586
 
2587
+ #: classes/Withdraw.php:67
2588
  msgid "IBAN"
2589
  msgstr ""
2590
 
2591
+ #: classes/Withdraw.php:71
2592
  msgid "BIC / SWIFT"
2593
  msgstr ""
2594
 
2595
+ #: classes/Withdraw.php:78
2596
  msgid "E-Check"
2597
  msgstr ""
2598
 
2599
+ #: classes/Withdraw.php:83
2600
  msgid "Your Physical Address"
2601
  msgstr ""
2602
 
2603
+ #: classes/Withdraw.php:84
2604
  msgid "We will send you an E-Check to this address directly."
2605
  msgstr ""
2606
 
2607
+ #: classes/Withdraw.php:90
2608
  msgid "PayPal"
2609
  msgstr ""
2610
 
2611
+ #: classes/Withdraw.php:95
2612
  msgid "PayPal E-Mail Address"
2613
  msgstr ""
2614
 
2615
+ #: classes/Withdraw.php:96
2616
  msgid "We will use this email address to send the money to your Paypal account"
2617
  msgstr ""
2618
 
2619
+ #: classes/Withdraw.php:187
2620
  msgid "Withdrawal account information saved successfully!"
2621
  msgstr ""
2622
 
2623
+ #: classes/Withdraw.php:212
2624
  msgid "Please save withdraw method "
2625
  msgstr ""
2626
 
2627
+ #: classes/Withdraw.php:217
2628
+ msgid "Minimum withdrawal amount is %1$s %2$s %3$s "
2629
  msgstr ""
2630
 
2631
+ #: classes/Withdraw.php:222
2632
  msgid "Insufficient balance."
2633
  msgstr ""
2634
 
2635
+ #: classes/Withdraw.php:255
2636
  msgid "Withdrawal Request Sent!"
2637
  msgstr ""
2638
 
2639
+ #: classes/Withdraw_Requests_List.php:60, classes/Withdraw_Requests_List.php:63
2640
  msgid "Rejected"
2641
  msgstr ""
2642
 
2643
+ #: classes/Withdraw_Requests_List.php:70
2644
  msgid "Are you Sure? It can not be undone."
2645
  msgstr ""
2646
 
2647
+ #: classes/Withdraw_Requests_List.php:70, templates/dashboard/announcements.php:157, templates/dashboard/my-courses.php:78, templates/dashboard/question-answer.php:41, views/pages/announcements.php:143, templates/dashboard/announcements/details.php:32, templates/dashboard/settings/profile.php:68, views/options/field-types/media.php:29
2648
  msgid "Delete"
2649
  msgstr ""
2650
 
2651
+ #: classes/Withdraw_Requests_List.php:103
2652
  msgid "pending"
2653
  msgstr ""
2654
 
2655
+ #: classes/Withdraw_Requests_List.php:104
2656
  msgid "approved"
2657
  msgstr ""
2658
 
2659
+ #: classes/Withdraw_Requests_List.php:105
2660
  msgid "rejected"
2661
  msgstr ""
2662
 
2663
+ #: classes/Withdraw_Requests_List.php:114
2664
  msgid "Requested By"
2665
  msgstr ""
2666
 
2667
+ #: classes/Withdraw_Requests_List.php:115, templates/dashboard/purchase_history.php:22, templates/dashboard/withdraw.php:138, templates/dashboard/withdraw.php:184
2668
  msgid "Amount"
2669
  msgstr ""
2670
 
2671
+ #: classes/Withdraw_Requests_List.php:116, templates/dashboard/withdraw.php:182
2672
  msgid "Withdrawal Method"
2673
  msgstr ""
2674
 
2675
+ #: classes/Withdraw_Requests_List.php:117
2676
  msgid "Requested Time"
2677
  msgstr ""
2678
 
2679
+ #: classes/WooCommerce.php:108
2680
  msgid ""
2681
+ " Seems like you don’t have WooCommerce plugin installed on your site. In order to use this functionality, you need to have the\n"
2682
+ " WooCommerce plugin installed. Get back on this page after installing the plugin and enable the following feature to start selling\n"
2683
  " courses with Tutor."
2684
  msgstr ""
2685
 
2686
+ #: classes/WooCommerce.php:116
2687
  msgid "This notice will disappear after activating <strong>WooCommerce</strong>"
2688
  msgstr ""
2689
 
2690
+ #: classes/WooCommerce.php:166
2691
  msgid "For Tutor"
2692
  msgstr ""
2693
 
2694
+ #: classes/WooCommerce.php:167
2695
  msgid "This checkmark ensure that you will sell a specif course via this product."
2696
  msgstr ""
2697
 
2698
+ #: classes/WooCommerce.php:290, classes/WooCommerce.php:330
2699
  msgid "WooCommerce"
2700
  msgstr ""
2701
 
2702
+ #: classes/WooCommerce.php:295
2703
  msgid "WooCommerce Settings"
2704
  msgstr ""
2705
 
2706
+ #: classes/WooCommerce.php:307
2707
  msgid "Enable add to cart feature for guest users"
2708
  msgstr ""
2709
 
2710
+ #: classes/WooCommerce.php:308
2711
  msgid "Enabling this will let an unregistered user purchase any course from the Course Details page. Head over to Documentation to know how to configure this setting."
2712
  msgstr ""
2713
 
2714
+ #: classes/WooCommerce.php:610
2715
  msgid "Since WooCommerce is disabled, your monetized courses have been set to free. Please make sure to enable Tutor LMS monetization if you decide to re-enable WooCommerce."
2716
  msgstr ""
2717
 
2761
  msgid "Count"
2762
  msgstr ""
2763
 
2764
+ #: includes/tutor-general-functions.php:135
2765
  msgid "Search Course Category. ex. Design, Development, Business"
2766
  msgstr ""
2767
 
2768
+ #: includes/tutor-general-functions.php:136
2769
  msgid "Select a category"
2770
  msgstr ""
2771
 
2772
+ #: includes/tutor-general-functions.php:180
2773
  msgid "Search Course Tags. ex. Design, Development, Business"
2774
  msgstr ""
2775
 
2776
+ #: includes/tutor-general-functions.php:181
2777
  msgid "Select a tag"
2778
  msgstr ""
2779
 
2780
+ #: includes/tutor-template-functions.php:436
2781
  msgid "Placeholder"
2782
  msgstr ""
2783
 
2784
+ #: includes/tutor-template-functions.php:1507
2785
  msgid "Share:"
2786
  msgstr ""
2787
 
2877
  msgid "Topic not found for given ID"
2878
  msgstr ""
2879
 
2880
+ #: templates/dashboard.php:68, templates/dashboard/index.php:70
2881
  msgid "%d Ratings"
2882
  msgstr ""
2883
 
2884
+ #: templates/dashboard.php:90, templates/dashboard/index.php:93
2885
  msgid "Become an instructor"
2886
  msgstr ""
2887
 
2888
+ #: templates/dashboard.php:108
2889
  msgid "Your Application is pending from"
2890
  msgstr ""
2891
 
2892
+ #: templates/dashboard.php:100, templates/dashboard/index.php:86
2893
  msgid "Add A New Course"
2894
  msgstr ""
2895
 
2896
+ #: templates/dashboard.php:132
2897
  msgid "Your application to become an instructor was rejected on"
2898
  msgstr ""
2899
 
2900
+ #: templates/instructor-setting.php:9
2901
  msgid "Instructor List Layout"
2902
  msgstr ""
2903
 
2904
+ #: templates/instructor-setting.php:29
2905
  msgid "Selected one will be used if layout is not defined as shortcode attribute."
2906
  msgstr ""
2907
 
2909
  msgid "Please Sign-In to view this section"
2910
  msgstr ""
2911
 
2912
+ #: templates/permission-denied.php:43
2913
  msgid "You don't have enough privilege to access this page"
2914
  msgstr ""
2915
 
2916
+ #: templates/permission-denied.php:46
2917
  msgid "Please make sure you are logged in to correct account if the content needs authorization."
2918
  msgstr ""
2919
 
2920
+ #: templates/public-profile-setting.php:9
2921
  msgid "Public Profile Layout"
2922
  msgstr ""
2923
 
2924
+ #: templates/public-profile-setting.php:29
2925
  msgid "Selected one will be used as public profile layout."
2926
  msgstr ""
2927
 
2928
+ #: templates/single-preview-lesson.php:72, templates/single/lesson/lesson_sidebar.php:42
2929
  msgid "Lesson List"
2930
  msgstr ""
2931
 
2932
+ #: templates/single-preview-lesson.php:199, templates/single-quiz.php:35, templates/single/assignment/content.php:32, templates/single/lesson/content.php:35, templates/single/quiz/single_quiz_contents.php:14
2933
  msgid "Go to Course Home"
2934
  msgstr ""
2935
 
2936
+ #: templates/student-public-profile.php:115
2937
  msgid "Courses Enrolled"
2938
  msgstr ""
2939
 
2940
+ #: templates/student-public-profile.php:120
2941
  msgid "Courses Completed"
2942
  msgstr ""
2943
 
2944
+ #: templates/student-public-profile.php:120
2945
  msgid "Course Completed"
2946
  msgstr ""
2947
 
2948
+ #: templates/student-public-profile.php:152
2949
  msgid "Biography"
2950
  msgstr ""
2951
 
2952
+ #: templates/course-filter/filters.php:9, templates/dashboard/create-course.php:201, templates/loop/course-continue.php:19, templates/loop/course-in-cart.php:20, templates/loop/course-price-edd.php:19, templates/loop/course-price-woocommerce.php:20, templates/loop/course-price-woocommerce.php:35, templates/loop/course-price.php:19, views/metabox/course-add-edd-product-metabox.php:61, views/metabox/course-add-product-metabox.php:71, templates/single/course/wc-price-html.php:23
2953
  msgid "Free"
2954
  msgstr ""
2955
 
2956
+ #: templates/course-filter/filters.php:10, views/metabox/course-add-edd-product-metabox.php:57, views/metabox/course-add-product-metabox.php:67
2957
  msgid "Paid"
2958
  msgstr ""
2959
 
2960
+ #: templates/course-filter/filters.php:22
2961
+ msgid "Search..."
2962
+ msgstr ""
2963
+
2964
  #: templates/course-filter/filters.php:54
2965
  msgid "Level"
2966
  msgstr ""
2967
 
2968
+ #: templates/dashboard/announcements.php:60
2969
  msgid "Announcement"
2970
  msgstr ""
2971
 
2972
+ #: templates/dashboard/announcements.php:67
2973
  msgid "Create Announcement"
2974
  msgstr ""
2975
 
2976
+ #: templates/dashboard/announcements.php:70
2977
  msgid "Notify all students of your course"
2978
  msgstr ""
2979
 
2980
+ #: templates/dashboard/announcements.php:76
2981
  msgid "Add New Announcement"
2982
  msgstr ""
2983
 
2984
+ #: templates/dashboard/announcements.php:107, templates/dashboard/assignments.php:54
2985
  msgid "ASC"
2986
  msgstr ""
2987
 
2988
+ #: templates/dashboard/announcements.php:108, templates/dashboard/assignments.php:55
2989
  msgid "DESC"
2990
  msgstr ""
2991
 
2992
+ #: templates/dashboard/announcements.php:168, views/pages/announcements.php:153
2993
  msgid "Announcements not found"
2994
  msgstr ""
2995
 
2996
+ #: templates/dashboard/announcements.php:145, templates/dashboard/assignments.php:105, templates/dashboard/quiz-attempts.php:101, templates/dashboard/assignments/submitted.php:91, templates/single/quiz/previous-attempts.php:79
2997
  msgid "Details"
2998
  msgstr ""
2999
 
3000
+ #: templates/dashboard/announcements.php:153, templates/dashboard/my-courses.php:75, views/pages/announcements.php:140, templates/dashboard/announcements/details.php:33
3001
  msgid "Edit"
3002
  msgstr ""
3003
 
3005
  msgid "Create Date"
3006
  msgstr ""
3007
 
3008
+ #: templates/dashboard/assignments.php:131
3009
  msgid "No assignment available"
3010
  msgstr ""
3011
 
3012
+ #: templates/dashboard/assignments.php:74, templates/dashboard/dashboard.php:90
3013
  msgid "Course Name"
3014
  msgstr ""
3015
 
3016
+ #: templates/dashboard/assignments.php:75, templates/dashboard/assignments/submitted.php:46, templates/dashboard/assignments/submitted.php:73
3017
  msgid "Total Points"
3018
  msgstr ""
3019
 
3020
+ #: templates/dashboard/assignments.php:76
3021
  msgid "Total Submits"
3022
  msgstr ""
3023
 
3024
+ #: templates/dashboard/create-course.php:26
 
 
 
 
3025
  msgid "You don't have the right to edit this course"
3026
  msgstr ""
3027
 
3028
+ #: templates/dashboard/create-course.php:27
3029
  msgid "Please make sure you are logged in to correct account"
3030
  msgstr ""
3031
 
3032
+ #: templates/dashboard/create-course.php:55, views/modal/edit_quiz.php:264, views/modal/edit_quiz.php:351
3033
  msgid "Save"
3034
  msgstr ""
3035
 
3036
+ #: templates/dashboard/create-course.php:61
3037
  msgid "Preview"
3038
  msgstr ""
3039
 
3040
+ #: templates/dashboard/create-course.php:69, templates/dashboard/create-course.php:258
3041
  msgid "Submit for Review"
3042
  msgstr ""
3043
 
3044
+ #: templates/dashboard/create-course.php:65, templates/dashboard/create-course.php:256
3045
  msgid "Publish Course"
3046
  msgstr ""
3047
 
3048
+ #: templates/dashboard/create-course.php:73
3049
  msgid "Exit"
3050
  msgstr ""
3051
 
3052
+ #: templates/dashboard/create-course.php:112, templates/dashboard/my-quiz-attempts.php:32, templates/dashboard/quiz-attempts.php:30, templates/dashboard/earning/statements.php:130, templates/single/quiz/previous-attempts.php:16
3053
  msgid "Course Info"
3054
  msgstr ""
3055
 
3056
+ #: templates/dashboard/create-course.php:119
3057
  msgid "Course Title"
3058
  msgstr ""
3059
 
3060
+ #: templates/dashboard/create-course.php:121
3061
  msgid "ex. Learn photoshop CS6 from scratch"
3062
  msgstr ""
3063
 
3064
+ #: templates/dashboard/create-course.php:128, views/modal/question_form.php:107, templates/single/assignment/content.php:145, templates/single/course/course-content.php:26
3065
  msgid "Description"
3066
  msgstr ""
3067
 
3068
+ #: templates/dashboard/create-course.php:147
3069
  msgid "Choose a category"
3070
  msgstr ""
3071
 
3072
+ #: templates/dashboard/create-course.php:162
3073
  msgid "Choose a tag"
3074
  msgstr ""
3075
 
3076
+ #: templates/dashboard/create-course.php:183
3077
  msgid "Course Price"
3078
  msgstr ""
3079
 
3080
+ #: templates/dashboard/create-course.php:194
3081
  msgid "Set course price"
3082
  msgstr ""
3083
 
3084
+ #: templates/dashboard/create-course.php:212
3085
  msgid "Course Thumbnail"
3086
  msgstr ""
3087
 
3088
+ #: templates/dashboard/create-course.php:236
3089
  msgid "Important Guideline: %1$s 700x430 pixels %2$s %3$s File Support: %1$s jpg, .jpeg,. gif, or .png %2$s no text on the image."
3090
  msgstr ""
3091
 
3092
+ #: templates/dashboard/create-course.php:238, views/metabox/video-metabox.php:125, views/modal/question_answer_edit_form.php:217, views/modal/question_answer_edit_form.php:180, views/modal/question_answer_edit_form.php:127, views/modal/question_answer_edit_form.php:34, views/modal/question_answer_form.php:235, views/modal/question_answer_form.php:205, views/modal/question_answer_form.php:160, views/modal/question_answer_form.php:49
3093
  msgid "Upload Image"
3094
  msgstr ""
3095
 
3096
+ #: templates/dashboard/create-course.php:254
3097
  msgid "Save course as draft"
3098
  msgstr ""
3099
 
3100
+ #: templates/dashboard/create-course.php:268
3101
  msgid "Course Upload Tips"
3102
  msgstr ""
3103
 
3104
+ #: templates/dashboard/create-course.php:270
3105
  msgid "Set the Course Price option or make it free."
3106
  msgstr ""
3107
 
3108
+ #: templates/dashboard/create-course.php:271
3109
  msgid "Standard size for the course thumbnail is 700x430."
3110
  msgstr ""
3111
 
3112
+ #: templates/dashboard/create-course.php:272
3113
  msgid "Video section controls the course overview video."
3114
  msgstr ""
3115
 
3116
+ #: templates/dashboard/create-course.php:273
3117
  msgid "Course Builder is where you create & organize a course."
3118
  msgstr ""
3119
 
3120
+ #: templates/dashboard/create-course.php:274
3121
  msgid "Add Topics in the Course Builder section to create lessons, quizzes, and assignments."
3122
  msgstr ""
3123
 
3124
+ #: templates/dashboard/create-course.php:275
3125
  msgid "Prerequisites refers to the fundamental courses to complete before taking this particular course."
3126
  msgstr ""
3127
 
3128
+ #: templates/dashboard/create-course.php:276
3129
  msgid "Information from the Additional Data section shows up on the course single page."
3130
  msgstr ""
3131
 
3149
  msgid "Total Students"
3150
  msgstr ""
3151
 
3152
+ #: templates/dashboard/dashboard.php:66
3153
  msgid "Total Courses"
3154
  msgstr ""
3155
 
3156
+ #: templates/dashboard/dashboard.php:72
3157
  msgid "Total Earnings"
3158
  msgstr ""
3159
 
3160
+ #: templates/dashboard/dashboard.php:86
3161
  msgid "Most Popular Courses"
3162
  msgstr ""
3163
 
3164
+ #: templates/dashboard/dashboard.php:91
3165
  msgid "Enrolled"
3166
  msgstr ""
3167
 
3177
  msgid "Reports"
3178
  msgstr ""
3179
 
3180
+ #: templates/dashboard/earning.php:53, templates/dashboard/earning/report.php:37, templates/dashboard/earning/statements.php:33, templates/dashboard/earning/statements.php:114
3181
  msgid "Statements"
3182
  msgstr ""
3183
 
3193
  msgid "My Earnings"
3194
  msgstr ""
3195
 
3196
+ #: templates/dashboard/earning.php:72, templates/dashboard/earning/report-date_range.php:41, templates/dashboard/earning/report-last_month.php:40, templates/dashboard/earning/report-last_week.php:44, templates/dashboard/earning/report-last_year.php:40, templates/dashboard/earning/report-this_month.php:44, templates/dashboard/earning/report-this_week.php:42, templates/dashboard/earning/report-this_year.php:38
3197
  msgid "Based on course price"
3198
  msgstr ""
3199
 
3200
+ #: templates/dashboard/earning.php:74, templates/dashboard/earning/report-date_range.php:43, templates/dashboard/earning/report-last_month.php:42, templates/dashboard/earning/report-last_week.php:46, templates/dashboard/earning/report-last_year.php:42, templates/dashboard/earning/report-this_month.php:46, templates/dashboard/earning/report-this_week.php:44, templates/dashboard/earning/report-this_year.php:40
3201
  msgid "All time sales"
3202
  msgstr ""
3203
 
3209
  msgid "All time withdrawals"
3210
  msgstr ""
3211
 
3212
+ #: templates/dashboard/earning.php:86, templates/dashboard/earning/report-date_range.php:49, templates/dashboard/earning/report-last_month.php:48, templates/dashboard/earning/report-last_week.php:52, templates/dashboard/earning/report-last_year.php:48, templates/dashboard/earning/report-this_month.php:54, templates/dashboard/earning/report-this_week.php:50, templates/dashboard/earning/report-this_year.php:46
3213
  msgid "Deducted Commissions"
3214
  msgstr ""
3215
 
3225
  msgid "All Courses"
3226
  msgstr ""
3227
 
3228
+ #: templates/dashboard/enrolled-courses.php:82
3229
  msgid "You haven't purchased any course"
3230
  msgstr ""
3231
 
3232
+ #: templates/dashboard/enrolled-courses.php:60, templates/dashboard/enrolled-courses/active-courses.php:53, templates/dashboard/enrolled-courses/completed-courses.php:53
3233
  msgid "Total Lessons:"
3234
  msgstr ""
3235
 
3236
+ #: templates/dashboard/enrolled-courses.php:66, templates/dashboard/enrolled-courses/active-courses.php:59, templates/dashboard/enrolled-courses/completed-courses.php:59
3237
  msgid "Completed Lessons:"
3238
  msgstr ""
3239
 
3241
  msgid "You are already logged in"
3242
  msgstr ""
3243
 
3244
+ #: templates/dashboard/my-courses.php:91
3245
  msgid "Not Found"
3246
  msgstr ""
3247
 
3248
+ #: templates/dashboard/my-courses.php:92, templates/dashboard/reviews.php:86, templates/dashboard/assignments/review.php:19, templates/dashboard/reviews/given-reviews.php:38
3249
  msgid "Sorry, but you are looking for something that isn't here."
3250
  msgstr ""
3251
 
3265
  msgid "View"
3266
  msgstr ""
3267
 
3268
+ #: templates/dashboard/my-courses.php:104
3269
  msgid "Delete This Course?"
3270
  msgstr ""
3271
 
3272
+ #: templates/dashboard/my-courses.php:105
3273
  msgid "You are going to delete this course, it can't be undone"
3274
  msgstr ""
3275
 
3276
+ #: templates/dashboard/my-courses.php:110, templates/dashboard/question-answer.php:75, templates/dashboard/withdraw.php:154, views/modal/add_quiz.php:58, views/modal/add_quiz.php:80, views/modal/add_quiz.php:103, views/modal/edit_quiz.php:73, views/modal/edit_quiz.php:140, views/modal/question_form.php:213, views/modal/review.php:19, views/pages/announcements.php:249, views/pages/announcements.php:331, templates/dashboard/announcements/create.php:53, templates/dashboard/announcements/details.php:29, templates/dashboard/announcements/update.php:52, templates/single/lesson/sidebar_question_and_answer.php:116, templates/single/course/enrolled/question_and_answer.php:52, templates/single/course/enrolled/question_and_answer.php:141
3277
  msgid "Cancel"
3278
  msgstr ""
3279
 
3280
+ #: templates/dashboard/my-courses.php:111
3281
  msgid "Yes, Delete Course"
3282
  msgstr ""
3283
 
3285
  msgid "Registration Date"
3286
  msgstr ""
3287
 
3288
+ #: templates/dashboard/my-profile.php:54
3289
  msgid "Username"
3290
  msgstr ""
3291
 
3292
+ #: templates/dashboard/my-profile.php:62
3293
  msgid "Email"
3294
  msgstr ""
3295
 
3296
+ #: templates/dashboard/my-profile.php:70, views/pages/add_new_instructor.php:82, views/pages/add_new_instructor.php:88, templates/dashboard/settings/profile.php:125, templates/dashboard/settings/profile.php:127
3297
  msgid "Phone Number"
3298
  msgstr ""
3299
 
3300
+ #: templates/dashboard/my-profile.php:79, views/pages/add_new_instructor.php:121, templates/dashboard/settings/profile.php:136
3301
  msgid "Bio"
3302
  msgstr ""
3303
 
3304
+ #: templates/dashboard/my-quiz-attempts.php:103
3305
  msgid "You have not attempted any quiz yet"
3306
  msgstr ""
3307
 
3308
+ #: templates/dashboard/my-quiz-attempts.php:33, templates/dashboard/quiz-attempts.php:32, templates/single/quiz/previous-attempts.php:17
3309
  msgid "Correct Answer"
3310
  msgstr ""
3311
 
3312
+ #: templates/dashboard/my-quiz-attempts.php:34, templates/dashboard/quiz-attempts.php:33, templates/single/quiz/previous-attempts.php:18
3313
  msgid "Incorrect Answer"
3314
  msgstr ""
3315
 
3316
+ #: templates/dashboard/my-quiz-attempts.php:35, templates/dashboard/my-quiz-attempts/attempts-details.php:125, templates/dashboard/quiz-attempts/quiz-reviews.php:111, templates/single/quiz/previous-attempts.php:19
3317
  msgid "Earned Marks"
3318
  msgstr ""
3319
 
3320
+ #: templates/dashboard/my-quiz-attempts.php:36, templates/dashboard/quiz-attempts.php:35, views/pages/view_attempt.php:87, templates/dashboard/assignments/submitted.php:74, templates/single/quiz/previous-attempts.php:20
3321
  msgid "Result"
3322
  msgstr ""
3323
 
3324
+ #: templates/dashboard/my-quiz-attempts.php:53, templates/dashboard/quiz-attempts.php:53, templates/single/quiz/previous-attempts.php:41
3325
  msgid "Question: "
3326
  msgstr ""
3327
 
3328
+ #: templates/dashboard/my-quiz-attempts.php:54, templates/dashboard/quiz-attempts.php:54, templates/single/quiz/previous-attempts.php:42
3329
  msgid "Total Marks: "
3330
  msgstr ""
3331
 
3333
  msgid "No purchase history available"
3334
  msgstr ""
3335
 
3336
+ #: templates/dashboard/question-answer.php:86
 
 
 
 
3337
  msgid "No question is available"
3338
  msgstr ""
3339
 
3340
+ #: templates/dashboard/question-answer.php:69
3341
  msgid "Delete This Question?"
3342
  msgstr ""
3343
 
3344
+ #: templates/dashboard/question-answer.php:70
3345
  msgid "You are going to delete this question, it can't be undone"
3346
  msgstr ""
3347
 
3348
+ #: templates/dashboard/question-answer.php:76
3349
  msgid "Yes, Delete Question"
3350
  msgstr ""
3351
 
3352
+ #: templates/dashboard/quiz-attempts.php:121
3353
  msgid "No quiz attempt yet."
3354
  msgstr ""
3355
 
3357
  msgid "Earned Mark"
3358
  msgstr ""
3359
 
3360
+ #: templates/dashboard/registration.php:71, templates/dashboard/registration.php:74, views/pages/add_new_instructor.php:56, views/pages/add_new_instructor.php:62, templates/dashboard/instructor/registration.php:76, templates/dashboard/instructor/registration.php:79, templates/dashboard/settings/profile.php:116
3361
  msgid "User Name"
3362
  msgstr ""
3363
 
3364
+ #: templates/dashboard/registration.php:92, templates/dashboard/registration.php:95, templates/global/login.php:48, templates/template-part/form-retrieve-password.php:25, views/pages/add_new_instructor.php:95, views/pages/add_new_instructor.php:101, templates/dashboard/instructor/registration.php:99, templates/dashboard/instructor/registration.php:102
3365
  msgid "Password"
3366
  msgstr ""
3367
 
3368
+ #: templates/dashboard/registration.php:102, views/pages/add_new_instructor.php:108, templates/dashboard/instructor/registration.php:109
3369
  msgid "Password confirmation"
3370
  msgstr ""
3371
 
3372
+ #: templates/dashboard/registration.php:105, views/pages/add_new_instructor.php:114, templates/dashboard/instructor/registration.php:112
3373
  msgid "Password Confirmation"
3374
  msgstr ""
3375
 
3376
+ #: templates/dashboard/registration.php:128
3377
  msgid "Register"
3378
  msgstr ""
3379
 
3398
  msgstr ""
3399
 
3400
  #: templates/dashboard/reviews.php:51
3401
+ msgid "Showing results %1$d to %2$d out of %3$d"
3402
+ msgstr ""
3403
+
3404
+ #: templates/dashboard/reviews.php:64, templates/dashboard/reviews/given-reviews.php:54
3405
+ msgid "Course: "
3406
  msgstr ""
3407
 
3408
+ #: templates/dashboard/reviews.php:72, templates/profile/reviews_wrote.php:50, views/pages/answer.php:55, views/pages/answer.php:95, templates/dashboard/question-answer/answers.php:25, templates/dashboard/question-answer/answers.php:52, templates/dashboard/reviews/given-reviews.php:68, templates/single/course/reviews.php:94, templates/single/lesson/sidebar_question_and_answer.php:54, templates/single/lesson/sidebar_question_and_answer.php:83, templates/single/course/enrolled/question_and_answer.php:77, templates/single/course/enrolled/question_and_answer.php:108
3409
  msgid "%s ago"
3410
  msgstr ""
3411
 
3421
  msgid "Withdrawal request is pending for approval, please hold tight."
3422
  msgstr ""
3423
 
3424
+ #: templates/dashboard/withdraw.php:48, templates/dashboard/withdraw.php:113
3425
  msgid "Current Balance"
3426
  msgstr ""
3427
 
3428
+ #: templates/dashboard/withdraw.php:54
3429
+ msgid "You currently have %1$s %2$s %3$s and this is insufficient balance to withdraw"
3430
  msgstr ""
3431
 
3432
+ #: templates/dashboard/withdraw.php:52
3433
+ msgid "You currently have %1$s %2$s %3$s ready to withdraw"
3434
  msgstr ""
3435
 
3436
+ #: templates/dashboard/withdraw.php:64, templates/dashboard/withdraw.php:107
3437
  msgid "Withdrawal Request"
3438
  msgstr ""
3439
 
3440
+ #: templates/dashboard/withdraw.php:76
3441
  msgid "The preferred payment method is selected as %s. "
3442
  msgstr ""
3443
 
3444
+ #: templates/dashboard/withdraw.php:77
3445
+ msgid "You can change your %1$s withdrawal preference %2$s"
3446
  msgstr ""
3447
 
3448
+ #: templates/dashboard/withdraw.php:95
3449
  msgid "Your withdrawal request has been successfully accepted"
3450
  msgstr ""
3451
 
3452
+ #: templates/dashboard/withdraw.php:96
3453
  msgid "Please check your transaction notification on your connected withdrawal method"
3454
  msgstr ""
3455
 
3456
+ #: templates/dashboard/withdraw.php:108
3457
  msgid "Please enter withdrawal amount and click the submit request button"
3458
  msgstr ""
3459
 
3460
+ #: templates/dashboard/withdraw.php:117
3461
  msgid "Selected Payment Method"
3462
  msgstr ""
3463
 
3464
+ #: templates/dashboard/withdraw.php:148
3465
  msgid "Minimum withdraw amount is"
3466
  msgstr ""
3467
 
3468
+ #: templates/dashboard/withdraw.php:155
3469
  msgid "Submit Request"
3470
  msgstr ""
3471
 
3472
+ #: templates/dashboard/withdraw.php:173
3473
  msgid "Withdrawal History"
3474
  msgstr ""
3475
 
3476
+ #: templates/dashboard/withdraw.php:263
3477
  msgid "No withdrawal yet"
3478
  msgstr ""
3479
 
3480
+ #: templates/dashboard/withdraw.php:183
3481
  msgid "Requested On"
3482
  msgstr ""
3483
 
3517
  msgid "Release Date (newest first)"
3518
  msgstr ""
3519
 
3520
+ #: templates/global/course-archive-filter-bar.php:26
3521
  msgid "Release Date (oldest first)"
3522
  msgstr ""
3523
 
3524
+ #: templates/global/course-archive-filter-bar.php:27
3525
  msgid "Course Title (a-z)"
3526
  msgstr ""
3527
 
3528
+ #: templates/global/course-archive-filter-bar.php:28
3529
  msgid "Course Title (z-a)"
3530
  msgstr ""
3531
 
3532
+ #: templates/global/login.php:47
3533
  msgid "Username or Email Address"
3534
  msgstr ""
3535
 
3536
+ #: templates/global/login.php:49
3537
  msgid "Remember Me"
3538
  msgstr ""
3539
 
3540
+ #: templates/global/login.php:50
3541
  msgid "Log In"
3542
  msgstr ""
3543
 
3544
+ #: templates/global/login.php:51
3545
  msgid "Create a new account"
3546
  msgstr ""
3547
 
3548
+ #: templates/global/login.php:61
3549
  msgid "Forgot Password?"
3550
  msgstr ""
3551
 
3552
+ #: templates/loop/course-continue.php:18, templates/single/course/course-enrolled-box.php:54
3553
  msgid "Continue Course"
3554
  msgstr ""
3555
 
3557
  msgid "View Cart"
3558
  msgstr ""
3559
 
3560
+ #: templates/loop/course-price-edd.php:18, templates/loop/course-price-woocommerce.php:19, templates/loop/course-price.php:18
3561
  msgid "Get Enrolled"
3562
  msgstr ""
3563
 
3565
  msgid "Start Learning "
3566
  msgstr ""
3567
 
3568
+ #: templates/loop/meta.php:40, templates/single/course/lead-info.php:63, templates/single/course/enrolled/lead-info.php:63
3569
  msgid "by"
3570
  msgstr ""
3571
 
3572
+ #: templates/loop/meta.php:49
3573
  msgid "In"
3574
  msgstr ""
3575
 
3581
  msgid "No course yet."
3582
  msgstr ""
3583
 
3584
+ #: templates/profile/reviews_wrote.php:25
3585
  msgid "No review yet."
3586
  msgstr ""
3587
 
3588
+ #: templates/profile/reviews_wrote.php:58
3589
  msgid "On"
3590
  msgstr ""
3591
 
3592
+ #: templates/shortcode/instructor-filter.php:30, templates/shortcode/instructor-filter.php:60
3593
  msgid "Clear All"
3594
  msgstr ""
3595
 
3596
+ #: templates/shortcode/instructor-filter.php:43, templates/shortcode/instructor-filter.php:50
3597
  msgid "Search any instructor..."
3598
  msgstr ""
3599
 
3600
+ #: templates/shortcode/instructor-filter.php:68
3601
  msgid "Apply Filter"
3602
  msgstr ""
3603
 
3633
  msgid "When selling the course"
3634
  msgstr ""
3635
 
3636
+ #: views/metabox/course-add-edd-product-metabox.php:40
3637
  msgid "Sell your product, process by EDD"
3638
  msgstr ""
3639
 
3640
+ #: views/metabox/course-add-edd-product-metabox.php:50, views/metabox/course-add-product-metabox.php:60
3641
  msgid "Course Type"
3642
  msgstr ""
3643
 
3644
+ #: views/metabox/course-add-product-metabox.php:50
3645
  msgid "Edit attached Product"
3646
  msgstr ""
3647
 
3648
+ #: views/metabox/course-add-product-metabox.php:51
3649
  msgid "Select a product if you want to sell your course. The sale will be handled by your preferred monetization option. (WooCommerce, EDD, Paid Memberships Pro)"
3650
  msgstr ""
3651
 
3653
  msgid "Total Course Duration"
3654
  msgstr ""
3655
 
3656
+ #: views/metabox/course-additional-data.php:26, views/metabox/video-metabox.php:169
3657
  msgid "HH"
3658
  msgstr ""
3659
 
3660
+ #: views/metabox/course-additional-data.php:30, views/metabox/video-metabox.php:174
3661
  msgid "MM"
3662
  msgstr ""
3663
 
3664
+ #: views/metabox/course-additional-data.php:35, views/metabox/video-metabox.php:179
3665
  msgid "SS"
3666
  msgstr ""
3667
 
3669
  msgid "Benefits of the course"
3670
  msgstr ""
3671
 
3672
+ #: views/metabox/course-additional-data.php:56
3673
  msgid ""
3674
  "List the knowledge and skills that students will learn after completing this course. (One per line)\n"
3675
  ""
3676
  msgstr ""
3677
 
3678
+ #: views/metabox/course-additional-data.php:69
3679
  msgid "Requirements/Instructions"
3680
  msgstr ""
3681
 
3682
+ #: views/metabox/course-additional-data.php:76
3683
  msgid "Additional requirements or special instructions for the students (One per line)"
3684
  msgstr ""
3685
 
3686
+ #: views/metabox/course-additional-data.php:84
3687
  msgid "Targeted Audience"
3688
  msgstr ""
3689
 
3690
+ #: views/metabox/course-additional-data.php:91
3691
  msgid "Specify the target audience that will benefit the most from the course. (One line per target audience.)"
3692
  msgstr ""
3693
 
3694
+ #: views/metabox/course-additional-data.php:100
3695
  msgid "Materials Included"
3696
  msgstr ""
3697
 
3698
+ #: views/metabox/course-additional-data.php:107
3699
  msgid "A list of assets you will be providing for the students in this course (One per line)"
3700
  msgstr ""
3701
 
3702
+ #: views/metabox/course-contents.php:28
3703
  msgid "Add a topic to build your course"
3704
  msgstr ""
3705
 
3706
+ #: views/metabox/course-contents.php:45
3707
  msgid "Delete Topic"
3708
  msgstr ""
3709
 
3710
+ #: views/metabox/course-contents.php:58, views/metabox/course-topics.php:36
3711
  msgid "Topic Name"
3712
  msgstr ""
3713
 
3714
+ #: views/metabox/course-contents.php:64
3715
  msgid "Topic title will be publicly show where required, you can call it as a section also in course"
3716
  msgstr ""
3717
 
3718
+ #: views/metabox/course-contents.php:71, views/metabox/course-topics.php:48
3719
  msgid "Topic Summary"
3720
  msgstr ""
3721
 
3722
+ #: views/metabox/course-contents.php:76, views/metabox/course-topics.php:53
3723
  msgid "The idea of a summary is a short text to prepare students for the activities within the topic or week. The text is shown on the course page under the topic name."
3724
  msgstr ""
3725
 
3726
+ #: views/metabox/course-contents.php:80
3727
  msgid "Update Topic"
3728
  msgstr ""
3729
 
3730
+ #: views/metabox/course-contents.php:170, views/metabox/course-topics.php:82
3731
  msgid "Lesson"
3732
  msgstr ""
3733
 
3734
+ #: views/metabox/course-topics.php:16
3735
  msgid "Expand all"
3736
  msgstr ""
3737
 
3738
+ #: views/metabox/course-topics.php:17
3739
  msgid "Collapse all"
3740
  msgstr ""
3741
 
3742
+ #: views/metabox/course-topics.php:28
3743
  msgid "Add new topic"
3744
  msgstr ""
3745
 
3746
+ #: views/metabox/course-topics.php:32, views/metabox/course-topics.php:59
3747
  msgid "Add Topic"
3748
  msgstr ""
3749
 
3750
+ #: views/metabox/course-topics.php:41
3751
  msgid "Topic titles are displayed publicly wherever required. Each topic may contain one or more lessons, quiz and assignments."
3752
  msgstr ""
3753
 
3754
+ #: views/metabox/course-topics.php:111
3755
  msgid "Zoom Meeting"
3756
  msgstr ""
3757
 
3763
  msgid "Add More Instructors"
3764
  msgstr ""
3765
 
3766
+ #: views/metabox/instructors-metabox.php:50
3767
  msgid "Add instructors"
3768
  msgstr ""
3769
 
3770
+ #: views/metabox/instructors-metabox.php:59
3771
  msgid "Search instructors..."
3772
  msgstr ""
3773
 
3774
+ #: views/metabox/instructors-metabox.php:64
3775
  msgid "Add Instructors"
3776
  msgstr ""
3777
 
3783
  msgid "Select a course"
3784
  msgstr ""
3785
 
3786
+ #: views/metabox/lesson-metabox.php:24
3787
  msgid "Choose the course for this lesson"
3788
  msgstr ""
3789
 
3807
  msgid "Upload"
3808
  msgstr ""
3809
 
3810
+ #: views/metabox/video-metabox.php:57
3811
  msgid "Video Source"
3812
  msgstr ""
3813
 
3814
+ #: views/metabox/video-metabox.php:55
3815
  msgid "Course Intro Video"
3816
  msgstr ""
3817
 
3818
+ #: views/metabox/video-metabox.php:66
3819
  msgid "Select Video Source"
3820
  msgstr ""
3821
 
3822
+ #: views/metabox/video-metabox.php:79
3823
  msgid "Select your preferred video type."
3824
  msgstr ""
3825
 
3826
+ #: views/metabox/video-metabox.php:92
3827
  msgid "Upload Video"
3828
  msgstr ""
3829
 
3830
+ #: views/metabox/video-metabox.php:94
3831
  msgid "Media ID"
3832
  msgstr ""
3833
 
3834
+ #: views/metabox/video-metabox.php:116
3835
  msgid "Video Poster"
3836
  msgstr ""
3837
 
3838
+ #: views/metabox/video-metabox.php:117
3839
  msgid "Thumb Size: 700x430 pixels. File Support: jpg, jpeg, or png"
3840
  msgstr ""
3841
 
3842
+ #: views/metabox/video-metabox.php:139
3843
  msgid "External Video URL"
3844
  msgstr ""
3845
 
3846
+ #: views/metabox/video-metabox.php:143
3847
  msgid "YouTube Video URL"
3848
  msgstr ""
3849
 
3850
+ #: views/metabox/video-metabox.php:146
3851
  msgid "Vimeo Video URL"
3852
  msgstr ""
3853
 
3854
+ #: views/metabox/video-metabox.php:149
3855
  msgid "Place your embedded code here"
3856
  msgstr ""
3857
 
3858
+ #: views/metabox/video-metabox.php:162
3859
  msgid "Video playback time"
3860
  msgstr ""
3861
 
3862
+ #: views/modal/add_quiz.php:16, views/modal/edit_quiz.php:29
3863
  msgid "Quiz Info"
3864
  msgstr ""
3865
 
3866
+ #: views/modal/add_quiz.php:19, views/modal/edit_quiz.php:32, templates/dashboard/my-quiz-attempts/attempts-details.php:120, templates/dashboard/quiz-attempts/quiz-reviews.php:106, templates/single/quiz/top.php:38
3867
  msgid "Questions"
3868
  msgstr ""
3869
 
3870
+ #: views/modal/add_quiz.php:25, views/modal/edit_quiz.php:38
3871
  msgid "Advanced Options"
3872
  msgstr ""
3873
 
3874
+ #: views/modal/add_quiz.php:38, views/modal/edit_quiz.php:49
3875
  msgid "Type your quiz title here"
3876
  msgstr ""
3877
 
3878
+ #: views/modal/add_quiz.php:53, views/modal/edit_quiz.php:68
3879
  msgid "Save &amp; Next"
3880
  msgstr ""
3881
 
3882
+ #: views/modal/add_quiz.php:72, views/modal/add_quiz.php:95, views/modal/edit_quiz.php:136, views/modal/edit_quiz.php:263, views/modal/edit_quiz.php:350, views/modal/question_form.php:10, templates/dashboard/assignments/review.php:34, templates/dashboard/assignments/submitted.php:21, templates/single/quiz/body.php:393
3883
  msgid "Back"
3884
  msgstr ""
3885
 
3886
+ #: views/modal/add_quiz.php:121, views/modal/edit_quiz.php:364
3887
  msgid "Knowledge Base"
3888
  msgstr ""
3889
 
3890
+ #: views/modal/add_quiz.php:123, views/modal/edit_quiz.php:366
3891
  msgid "Documentation"
3892
  msgstr ""
3893
 
3894
+ #: views/modal/add_quiz.php:124, views/modal/edit_quiz.php:367
3895
+ msgid "Need any Help? Please visit our %1$s and %2$s."
3896
  msgstr ""
3897
 
3898
  #: views/modal/edit-lesson.php:25
3919
  msgid "Update Lesson"
3920
  msgstr ""
3921
 
3922
+ #: views/modal/edit_quiz.php:128
3923
  msgid "Add Question"
3924
  msgstr ""
3925
 
3926
+ #: views/modal/edit_quiz.php:171
3927
  msgid "Hide quiz time - display"
3928
  msgstr ""
3929
 
3930
+ #: views/modal/edit_quiz.php:174
3931
  msgid "Time limit for this quiz. 0 means no time limit."
3932
  msgstr ""
3933
 
3934
+ #: views/modal/edit_quiz.php:178
3935
  msgid "Quiz Feedback Mode"
3936
  msgstr ""
3937
 
3938
+ #: views/modal/edit_quiz.php:180
3939
  msgid "Pick the quiz system\"s behaviour on choice based questions"
3940
  msgstr ""
3941
 
3942
+ #: views/modal/edit_quiz.php:188
3943
  msgid "Default"
3944
  msgstr ""
3945
 
3946
+ #: views/modal/edit_quiz.php:189
3947
  msgid "Answers shown after quiz is finished"
3948
  msgstr ""
3949
 
3950
+ #: views/modal/edit_quiz.php:198
3951
  msgid "Retry Mode"
3952
  msgstr ""
3953
 
3954
+ #: views/modal/edit_quiz.php:199
3955
  msgid "Unlimited attempts on each question."
3956
  msgstr ""
3957
 
3958
+ #: views/modal/edit_quiz.php:208
3959
  msgid "Reveal Mode"
3960
  msgstr ""
3961
 
3962
+ #: views/modal/edit_quiz.php:209
3963
  msgid "Show result after the attempt."
3964
  msgstr ""
3965
 
3966
+ #: views/modal/edit_quiz.php:218, views/modal/question_form.php:107
3967
  msgid "Optional"
3968
  msgstr ""
3969
 
3970
+ #: views/modal/edit_quiz.php:233
3971
  msgid "Restriction on the number of attempts a student is allowed to take for this quiz. 0 for no limit"
3972
  msgstr ""
3973
 
3974
+ #: views/modal/edit_quiz.php:237
3975
  msgid "Passing Grade (%)"
3976
  msgstr ""
3977
 
3978
+ #: views/modal/edit_quiz.php:243
3979
  msgid "Set the passing percentage for this quiz"
3980
  msgstr ""
3981
 
3982
+ #: views/modal/edit_quiz.php:247
3983
  msgid "Max questions allowed to answer"
3984
  msgstr ""
3985
 
3986
+ #: views/modal/edit_quiz.php:253
3987
  msgid "This amount of question will be available for students to answer, and question will comes randomly from all available questions belongs with a quiz, if this amount greater than available question, then all questions will be available for a student to answer."
3988
  msgstr ""
3989
 
3990
+ #: views/modal/edit_quiz.php:264, views/modal/edit_quiz.php:351
3991
  msgid "Saved"
3992
  msgstr ""
3993
 
3994
+ #: views/modal/edit_quiz.php:281
3995
  msgid "Quiz Auto Start"
3996
  msgstr ""
3997
 
3998
+ #: views/modal/edit_quiz.php:284
3999
  msgid "If you enable this option, the quiz will start automatically after the page is loaded."
4000
  msgstr ""
4001
 
4002
+ #: views/modal/edit_quiz.php:290
4003
  msgid "Question Layout"
4004
  msgstr ""
4005
 
4006
+ #: views/modal/edit_quiz.php:293
4007
  msgid "Set question layout view"
4008
  msgstr ""
4009
 
4010
+ #: views/modal/edit_quiz.php:294
4011
  msgid "Single Question"
4012
  msgstr ""
4013
 
4014
+ #: views/modal/edit_quiz.php:295
4015
  msgid "Question Pagination"
4016
  msgstr ""
4017
 
4018
+ #: views/modal/edit_quiz.php:296
4019
  msgid "Question below each other"
4020
  msgstr ""
4021
 
4022
+ #: views/modal/edit_quiz.php:301
4023
  msgid "Questions Order"
4024
  msgstr ""
4025
 
4026
+ #: views/modal/edit_quiz.php:304
4027
  msgid "Random"
4028
  msgstr ""
4029
 
4030
+ #: views/modal/edit_quiz.php:305
4031
  msgid "Sorting"
4032
  msgstr ""
4033
 
4034
+ #: views/modal/edit_quiz.php:307
4035
  msgid "Ascending"
4036
  msgstr ""
4037
 
4038
+ #: views/modal/edit_quiz.php:308
4039
  msgid "Descending"
4040
  msgstr ""
4041
 
4042
+ #: views/modal/edit_quiz.php:322
4043
  msgid "Hide question number"
4044
  msgstr ""
4045
 
4046
+ #: views/modal/edit_quiz.php:325
4047
  msgid "Show/hide question number during attempt."
4048
  msgstr ""
4049
 
4050
+ #: views/modal/edit_quiz.php:329
4051
  msgid "Short answer characters limit"
4052
  msgstr ""
4053
 
4054
+ #: views/modal/edit_quiz.php:335
4055
  msgid "Student will place answer in short answer question type within this characters limit."
4056
  msgstr ""
4057
 
4058
+ #: views/modal/edit_quiz.php:339
4059
  msgid "Open-Ended/Essay questions answer character limit"
4060
  msgstr ""
4061
 
4062
+ #: views/modal/edit_quiz.php:345
4063
  msgid "Students will place the answer in the Open-Ended/Essay question type within this character limit."
4064
  msgstr ""
4065
 
4066
+ #: views/modal/question_answer_edit_form.php:3, views/modal/question_answer_form.php:4
4067
  msgid "No option is necessary for this answer type"
4068
  msgstr ""
4069
 
4070
+ #: views/modal/question_answer_edit_form.php:242, views/modal/question_answer_form.php:252
4071
  msgid "Answer input value"
4072
  msgstr ""
4073
 
4074
+ #: views/modal/question_answer_edit_form.php:248, views/modal/question_answer_form.php:258
4075
  msgid "The answers that students enter should match with this text. Write in <strong>small caps</strong>"
4076
  msgstr ""
4077
 
4078
+ #: views/modal/question_answer_edit_form.php:205, views/modal/question_answer_form.php:221
4079
  msgid "Image matched text"
4080
  msgstr ""
4081
 
4082
+ #: views/modal/question_answer_edit_form.php:110, views/modal/question_answer_edit_form.php:25, views/modal/question_answer_form.php:141, views/modal/question_answer_form.php:118, views/modal/question_answer_form.php:37
4083
  msgid "Answer title"
4084
  msgstr ""
4085
 
4086
+ #: views/modal/question_answer_edit_form.php:118, views/modal/question_answer_form.php:150, views/modal/question_answer_form.php:127
4087
  msgid "Matched Answer title"
4088
  msgstr ""
4089
 
4090
+ #: views/modal/question_answer_edit_form.php:152, views/modal/question_answer_edit_form.php:58, views/modal/question_answer_form.php:176, views/modal/question_answer_form.php:66
4091
  msgid "Display format for options"
4092
  msgstr ""
4093
 
4094
+ #: views/modal/question_answer_edit_form.php:157, views/modal/question_answer_edit_form.php:63, views/modal/question_answer_form.php:181, views/modal/question_answer_form.php:71
4095
  msgid "Only text"
4096
  msgstr ""
4097
 
4098
+ #: views/modal/question_answer_edit_form.php:163, views/modal/question_answer_edit_form.php:69, views/modal/question_answer_form.php:187, views/modal/question_answer_form.php:77
4099
  msgid "Only Image"
4100
  msgstr ""
4101
 
4102
+ #: views/modal/question_answer_edit_form.php:169, views/modal/question_answer_edit_form.php:75, views/modal/question_answer_form.php:193, views/modal/question_answer_form.php:83
4103
  msgid "Text &amp; Image both"
4104
  msgstr ""
4105
 
4106
+ #: views/modal/question_answer_edit_form.php:84, views/modal/question_answer_form.php:93, templates/single/lesson/sidebar_question_and_answer.php:154, templates/single/course/enrolled/question_and_answer.php:36
4107
  msgid "Question Title"
4108
  msgstr ""
4109
 
4110
+ #: views/modal/question_answer_edit_form.php:91
4111
  msgid "Please make sure that <b>{dash}</b> variable contains in your question title to show dash, You can use multiple variable"
4112
  msgstr ""
4113
 
4114
+ #: views/modal/question_answer_edit_form.php:96, views/modal/question_answer_form.php:103
4115
  msgid "Correct Answer(s)"
4116
  msgstr ""
4117
 
4118
+ #: views/modal/question_answer_edit_form.php:102
4119
  msgid "Separate multiple answer by pipe <b>( | )</b> , 1 answer per variable assigned in question"
4120
  msgstr ""
4121
 
4122
+ #: views/modal/question_answer_edit_form.php:256
4123
  msgid "Update Answer"
4124
  msgstr ""
4125
 
4126
+ #: views/modal/question_answer_form.php:99
4127
  msgid "Please make sure to use the <strong>{dash}</strong> variable in your question title to show the blanks in your question. You can use multiple <strong>{dash}</strong> variables in one question."
4128
  msgstr ""
4129
 
4130
+ #: views/modal/question_answer_form.php:109
4131
  msgid "Separate multiple answers by a vertical bar <strong>|</strong>. 1 answer per <strong>{dash}</strong> variable is defined in the question. Example: Apple | Banana | Orange"
4132
  msgstr ""
4133
 
4134
+ #: views/modal/question_answer_form.php:17
4135
  msgid "Select the correct option"
4136
  msgstr ""
4137
 
4138
+ #: views/modal/question_answer_form.php:266
4139
  msgid "Save Answer"
4140
  msgstr ""
4141
 
4142
+ #: views/modal/question_form.php:20
4143
  msgid "Write your question here"
4144
  msgstr ""
4145
 
4146
+ #: views/modal/question_form.php:23
4147
  msgid "Type your question here"
4148
  msgstr ""
4149
 
4150
+ #: views/modal/question_form.php:29
4151
  msgid "Question Type"
4152
  msgstr ""
4153
 
4154
+ #: views/modal/question_form.php:34
4155
  msgid "True or False"
4156
  msgstr ""
4157
 
4158
+ #: views/modal/question_form.php:52
4159
  msgid "Pro version required"
4160
  msgstr ""
4161
 
4162
+ #: views/modal/question_form.php:73
4163
  msgid "Answer Required"
4164
  msgstr ""
4165
 
4166
+ #: views/modal/question_form.php:80
4167
  msgid "Randomize"
4168
  msgstr ""
4169
 
4170
+ #: views/modal/question_form.php:86
4171
  msgid "Point(s) for this answer"
4172
  msgstr ""
4173
 
4174
+ #: views/modal/question_form.php:89
4175
  msgid "set the mark ex. 10"
4176
  msgstr ""
4177
 
4178
+ #: views/modal/question_form.php:101
4179
  msgid "Display Points"
4180
  msgstr ""
4181
 
4182
+ #: views/modal/question_form.php:120
4183
  msgid "Input options for the question and select the correct answer."
4184
  msgstr ""
4185
 
4186
+ #: views/modal/question_form.php:123
4187
  msgid "Make sure you’re saving the answers in the right order. Students will have to match this order."
4188
  msgstr ""
4189
 
4190
+ #: views/modal/question_form.php:191
4191
  msgid "Add An Option"
4192
  msgstr ""
4193
 
4194
+ #: views/modal/question_form.php:210
4195
  msgid "Save &amp; Continue"
4196
  msgstr ""
4197
 
4215
  msgid "Settings Saved"
4216
  msgstr ""
4217
 
4218
+ #: views/options/options_generator.php:88
4219
  msgid "Save Settings"
4220
  msgstr ""
4221
 
4227
  msgid "Themes"
4228
  msgstr ""
4229
 
4230
+ #: views/pages/addons.php:97, views/pages/addons.php:91
4231
  msgid "No %s currently avaialable"
4232
  msgstr ""
4233
 
4234
+ #: views/pages/addons.php:59, views/pages/tutor-pro-addons.php:44
4235
  msgid "Buy Now"
4236
  msgstr ""
4237
 
4238
+ #: views/pages/addons.php:79, views/pages/enable_disable_addons.php:111, views/pages/tutor-pro-addons.php:55
4239
  msgid "Version"
4240
  msgstr ""
4241
 
4243
  msgid "Add new instructor"
4244
  msgstr ""
4245
 
4246
+ #: views/pages/announcements.php:54
4247
  msgid "Search Announcements"
4248
  msgstr ""
4249
 
4250
+ #: views/pages/announcements.php:107
4251
  msgid "Add new"
4252
  msgstr ""
4253
 
4254
+ #: views/pages/announcements.php:184, templates/dashboard/announcements/create.php:6
4255
  msgid "Create New Announcement"
4256
  msgstr ""
4257
 
4258
+ #: views/pages/announcements.php:219, views/pages/announcements.php:301, templates/dashboard/announcements/create.php:35, templates/dashboard/announcements/update.php:36
4259
  msgid "Announcement Title"
4260
  msgstr ""
4261
 
4262
+ #: views/pages/announcements.php:223, views/pages/announcements.php:305, templates/dashboard/announcements/create.php:37, templates/dashboard/announcements/update.php:38
4263
  msgid "Announcement title"
4264
  msgstr ""
4265
 
4266
+ #: views/pages/announcements.php:229, views/pages/announcements.php:311, templates/dashboard/announcements/create.php:41, templates/dashboard/announcements/update.php:42
4267
  msgid "Summary"
4268
  msgstr ""
4269
 
4270
+ #: views/pages/announcements.php:233, views/pages/announcements.php:315, templates/dashboard/announcements/create.php:43, templates/dashboard/announcements/update.php:44
4271
  msgid "Summary..."
4272
  msgstr ""
4273
 
4274
+ #: views/pages/announcements.php:246, templates/dashboard/announcements/create.php:52
4275
  msgid "Publish"
4276
  msgstr ""
4277
 
4278
+ #: views/pages/announcements.php:264, templates/dashboard/announcements/update.php:6
4279
  msgid "Update Announcement"
4280
  msgstr ""
4281
 
4282
+ #: views/pages/announcements.php:328, views/pages/view_attempt.php:360, templates/dashboard/announcements/update.php:51, templates/dashboard/quiz-attempts/quiz-reviews.php:424
4283
  msgid "Update"
4284
  msgstr ""
4285
 
4291
  msgid "Place answer"
4292
  msgstr ""
4293
 
4294
+ #: views/pages/answer.php:65
4295
  msgid "on"
4296
  msgstr ""
4297
 
4303
  msgid "Required Plugin(s)"
4304
  msgstr ""
4305
 
4306
+ #: views/pages/enable_disable_addons.php:94, templates/single/course/course-requirements.php:29
4307
+ msgid "Requirements"
4308
+ msgstr ""
4309
+
4310
  #: views/pages/get-pro.php:2
4311
  msgid "Get pro plugin from themeum.com"
4312
  msgstr ""
4331
  msgid "Completely Uninstall and erase all data"
4332
  msgstr ""
4333
 
4334
+ #: views/pages/view_attempt.php:7, templates/dashboard/my-quiz-attempts/attempts-details.php:24, templates/dashboard/my-quiz-attempts/attempts-details.php:88, templates/dashboard/quiz-attempts/quiz-reviews.php:22
4335
  msgid "Attempt not found"
4336
  msgstr ""
4337
 
4355
  msgid "Quiz Time"
4356
  msgstr ""
4357
 
4358
+ #: views/pages/view_attempt.php:157, templates/dashboard/quiz-attempts/quiz-reviews.php:198
4359
  msgid "Reminder:"
4360
  msgstr ""
4361
 
4362
+ #: views/pages/view_attempt.php:157, templates/dashboard/quiz-attempts/quiz-reviews.php:198
4363
  msgid "Please review answers for question no. %s"
4364
  msgstr ""
4365
 
4366
+ #: views/pages/view_attempt.php:170, templates/dashboard/quiz-attempts/quiz-reviews.php:209
4367
  msgid "Manually reviewed at: "
4368
  msgstr ""
4369
 
4370
+ #: views/pages/view_attempt.php:187, templates/dashboard/my-quiz-attempts/attempts-details.php:208, templates/dashboard/quiz-attempts/quiz-reviews.php:225
4371
  msgid "Quiz Overview"
4372
  msgstr ""
4373
 
4374
+ #: views/pages/view_attempt.php:192, templates/dashboard/earning/statement.php:53, templates/dashboard/earning/statement.php:60, templates/dashboard/earning/statements.php:181, templates/dashboard/earning/statements.php:188, templates/dashboard/my-quiz-attempts/attempts-details.php:214, templates/dashboard/quiz-attempts/quiz-reviews.php:231
4375
  msgid "Type"
4376
  msgstr ""
4377
 
4378
+ #: views/pages/view_attempt.php:193, templates/dashboard/my-quiz-attempts/attempts-details.php:213, templates/dashboard/quiz-attempts/quiz-reviews.php:230
4379
  msgid "No."
4380
  msgstr ""
4381
 
4382
+ #: views/pages/view_attempt.php:195, templates/dashboard/my-quiz-attempts/attempts-details.php:216, templates/dashboard/quiz-attempts/quiz-reviews.php:233
4383
  msgid "Given Answers"
4384
  msgstr ""
4385
 
4386
+ #: views/pages/view_attempt.php:196, templates/dashboard/my-quiz-attempts/attempts-details.php:218, templates/dashboard/quiz-attempts/quiz-reviews.php:235
4387
  msgid "Correct/Incorrect"
4388
  msgstr ""
4389
 
4390
+ #: views/pages/view_attempt.php:197, templates/dashboard/quiz-attempts/quiz-reviews.php:236
4391
  msgid "Manual Review"
4392
  msgstr ""
4393
 
4394
+ #: views/pages/view_attempt.php:326, views/pages/view_attempt.php:321, templates/dashboard/my-quiz-attempts/attempts-details.php:124, templates/dashboard/my-quiz-attempts/attempts-details.php:389, templates/dashboard/my-quiz-attempts/attempts-details.php:384, templates/dashboard/quiz-attempts/quiz-reviews.php:110, templates/dashboard/quiz-attempts/quiz-reviews.php:397, templates/dashboard/quiz-attempts/quiz-reviews.php:392
4395
  msgid "Incorrect"
4396
  msgstr ""
4397
 
4398
+ #: views/pages/view_attempt.php:323, views/pages/view_attempt.php:312, templates/dashboard/my-quiz-attempts/attempts-details.php:123, templates/dashboard/my-quiz-attempts/attempts-details.php:380, templates/dashboard/quiz-attempts/quiz-reviews.php:109, templates/dashboard/quiz-attempts/quiz-reviews.php:388
4399
  msgid "Correct"
4400
  msgstr ""
4401
 
4402
+ #: views/pages/view_attempt.php:318, templates/dashboard/my-quiz-attempts/attempts-details.php:386, templates/dashboard/quiz-attempts/quiz-reviews.php:394
4403
  msgid "Review Required"
4404
  msgstr ""
4405
 
4406
+ #: views/pages/view_attempt.php:338, templates/dashboard/quiz-attempts/quiz-reviews.php:405
4407
  msgid "Mark as In correct"
4408
  msgstr ""
4409
 
4410
+ #: views/pages/view_attempt.php:356, templates/dashboard/my-quiz-attempts/attempts-details.php:190, templates/dashboard/quiz-attempts/quiz-reviews.php:176, templates/dashboard/quiz-attempts/quiz-reviews.php:420
4411
  msgid "Instructor Feedback"
4412
  msgstr ""
4413
 
4414
+ #: views/pages/view_attempt.php:360, templates/dashboard/quiz-attempts/quiz-reviews.php:424
4415
  msgid "Updated"
4416
  msgstr ""
4417
 
4488
  msgstr ""
4489
 
4490
  #: templates/dashboard/assignments/submitted.php:87
4491
+ msgid "%1$s Pending %2$s"
4492
  msgstr ""
4493
 
4494
  #: templates/dashboard/assignments/submitted.php:88
4496
  msgstr ""
4497
 
4498
  #: templates/dashboard/assignments/submitted.php:90
4499
+ msgid "%1$s Pass %2$s"
4500
  msgstr ""
4501
 
4502
  #: templates/dashboard/assignments/submitted.php:90
4503
+ msgid "%1$s Fail %2$s"
4504
  msgstr ""
4505
 
4506
  #: templates/dashboard/earning/earning-report-top-menu.php:12
4535
  msgid "My Earning"
4536
  msgstr ""
4537
 
4538
+ #: templates/dashboard/earning/report-date_range.php:56, templates/dashboard/earning/report-date_range.php:58, templates/dashboard/earning/report-last_month.php:55, templates/dashboard/earning/report-last_month.php:57, templates/dashboard/earning/report-last_week.php:59, templates/dashboard/earning/report-last_week.php:61, templates/dashboard/earning/report-last_year.php:55, templates/dashboard/earning/report-last_year.php:57, templates/dashboard/earning/report-this_month.php:62, templates/dashboard/earning/report-this_month.php:64, templates/dashboard/earning/report-this_week.php:57, templates/dashboard/earning/report-this_week.php:59, templates/dashboard/earning/report-this_year.php:53, templates/dashboard/earning/report-this_year.php:55
4539
  msgid "Deducted Fees"
4540
  msgstr ""
4541
 
4542
  #: templates/dashboard/earning/report-date_range.php:67, templates/dashboard/earning/report-last_week.php:74, templates/dashboard/earning/report-this_week.php:67
4543
+ msgid "Showing Result from %1$s to %2$s"
4544
  msgstr ""
4545
 
4546
+ #: templates/dashboard/earning/report-date_range.php:74, templates/dashboard/earning/report-last_month.php:72, templates/dashboard/earning/report-last_week.php:81, templates/dashboard/earning/report-last_year.php:76, templates/dashboard/earning/report-this_month.php:84, templates/dashboard/earning/report-this_week.php:74, templates/dashboard/earning/report-this_year.php:74
4547
  msgid "Sales statements for this period"
4548
  msgstr ""
4549
 
4550
+ #: templates/dashboard/earning/report-last_month.php:65, templates/dashboard/earning/report-this_month.php:77
4551
  msgid "Earning Data for the month of %s"
4552
  msgstr ""
4553
 
4555
  msgid "Earning Data for the year of %s"
4556
  msgstr ""
4557
 
4558
+ #: templates/dashboard/earning/report.php:28
4559
  msgid "Earning Report"
4560
  msgstr ""
4561
 
4562
+ #: templates/dashboard/earning/statement.php:71, templates/dashboard/earning/statements.php:199
4563
  msgid "There is not enough sales data to generate a statement"
4564
  msgstr ""
4565
 
4566
+ #: templates/dashboard/earning/statement.php:14, templates/dashboard/earning/statements.php:133
4567
  msgid "Deduct"
4568
  msgstr ""
4569
 
4570
+ #: templates/dashboard/earning/statement.php:36, templates/dashboard/earning/statements.php:144
4571
  msgid "Date:"
4572
  msgstr ""
4573
 
4574
+ #: templates/dashboard/earning/statement.php:51, templates/dashboard/earning/statements.php:132
4575
  msgid "Commission"
4576
  msgstr ""
4577
 
4578
+ #: templates/dashboard/earning/statement.php:52, templates/dashboard/earning/statements.php:180
4579
  msgid "Rate"
4580
  msgstr ""
4581
 
4582
+ #: templates/dashboard/earning/statement.php:56
4583
  msgid "Deducted"
4584
  msgstr ""
4585
 
4586
+ #: templates/dashboard/earning/statements.php:30
4587
  msgid "Report"
4588
  msgstr ""
4589
 
4590
+ #: templates/dashboard/earning/statements.php:123
4591
+ msgid "Showing results %1$d to %2$d of %3$d"
4592
  msgstr ""
4593
 
4594
+ #: templates/dashboard/earning/statements.php:155
4595
  msgid "Price: "
4596
  msgstr ""
4597
 
4598
+ #: templates/dashboard/earning/statements.php:167
4599
  msgid "Purchaser"
4600
  msgstr ""
4601
 
4663
  msgid "Register as instructor"
4664
  msgstr ""
4665
 
4666
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:97
4667
  msgid "You have no access."
4668
  msgstr ""
4669
 
4670
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:107, templates/dashboard/quiz-attempts/quiz-reviews.php:92
4671
  msgid "Back to Attempt List"
4672
  msgstr ""
4673
 
4674
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:112, templates/dashboard/quiz-attempts/quiz-reviews.php:98
4675
  msgid "Quiz:"
4676
  msgstr ""
4677
 
4678
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:113, templates/dashboard/quiz-attempts/quiz-reviews.php:99
4679
  msgid "Course:"
4680
  msgstr ""
4681
 
4682
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:118, templates/dashboard/quiz-attempts/quiz-reviews.php:104
4683
  msgid "#"
4684
  msgstr ""
4685
 
4686
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:119, templates/dashboard/quiz-attempts/quiz-reviews.php:105
4687
  msgid "Attempts Date"
4688
  msgstr ""
4689
 
4690
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:121, templates/dashboard/quiz-attempts/quiz-reviews.php:107
4691
  msgid "Total Marks"
4692
  msgstr ""
4693
 
4694
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:122, templates/dashboard/quiz-attempts/quiz-reviews.php:108
4695
  msgid "Pass Marks"
4696
  msgstr ""
4697
 
4698
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:126, templates/dashboard/quiz-attempts/quiz-reviews.php:112
4699
  msgid "Results"
4700
  msgstr ""
4701
 
4702
+ #: templates/dashboard/my-quiz-attempts/attempts-details.php:217, templates/dashboard/quiz-attempts/quiz-reviews.php:234
4703
  msgid "Correct Answers"
4704
  msgstr ""
4705
 
4715
  msgid "Set Your"
4716
  msgstr ""
4717
 
4718
+ #: templates/dashboard/notifications/profile-completion.php:26
4719
  msgid "% Complete"
4720
  msgstr ""
4721
 
4722
+ #: templates/dashboard/notifications/profile-completion.php:28
4723
  msgid "You are almost done!"
4724
  msgstr ""
4725
 
4735
  msgid "Update Review"
4736
  msgstr ""
4737
 
4738
+ #: templates/dashboard/reviews/given-reviews.php:60
4739
  msgid "Edit Feedback"
4740
  msgstr ""
4741
 
4742
+ #: templates/dashboard/reviews/given-reviews.php:86
4743
  msgid "Edit Review"
4744
  msgstr ""
4745
 
4747
  msgid "Reset Password"
4748
  msgstr ""
4749
 
4750
+ #: templates/dashboard/settings/nav-bar.php:32
4751
  msgid "Withdraw"
4752
  msgstr ""
4753
 
4759
  msgid "Upload Cover Photo"
4760
  msgstr ""
4761
 
4762
+ #: templates/dashboard/settings/profile.php:50
4763
  msgid "Profile Photo Size"
4764
  msgstr ""
4765
 
4766
+ #: templates/dashboard/settings/profile.php:50
4767
  msgid "200x200"
4768
  msgstr ""
4769
 
4770
+ #: templates/dashboard/settings/profile.php:50, templates/dashboard/settings/profile.php:51
4771
  msgid "pixels"
4772
  msgstr ""
4773
 
4774
+ #: templates/dashboard/settings/profile.php:51
4775
  msgid "Cover Photo Size"
4776
  msgstr ""
4777
 
4778
+ #: templates/dashboard/settings/profile.php:51
4779
  msgid "700x430"
4780
  msgstr ""
4781
 
4782
+ #: templates/dashboard/settings/profile.php:52
4783
  msgid "Saving..."
4784
  msgstr ""
4785
 
4786
+ #: templates/dashboard/settings/profile.php:65
4787
  msgid "Upload Photo"
4788
  msgstr ""
4789
 
4790
+ #: templates/dashboard/settings/profile.php:147
4791
  msgid "Display name publicly as"
4792
  msgstr ""
4793
 
4794
+ #: templates/dashboard/settings/profile.php:185
4795
  msgid "The display name is shown in all public fields, such as the author name, instructor name, student name, and name that will be printed on the certificate."
4796
  msgstr ""
4797
 
4798
+ #: templates/dashboard/settings/profile.php:215
4799
  msgid "Update Profile"
4800
  msgstr ""
4801
 
4815
  msgid "Select a withdraw method"
4816
  msgstr ""
4817
 
4818
+ #: templates/dashboard/settings/withdraw-settings.php:37
4819
  msgid "Min withdraw"
4820
  msgstr ""
4821
 
4822
+ #: templates/dashboard/settings/withdraw-settings.php:107
4823
  msgid "Save Withdrawal Account"
4824
  msgstr ""
4825
 
4826
+ #: templates/single/assignment/content.php:89
4827
  msgid "Time Duration : "
4828
  msgstr ""
4829
 
4830
+ #: templates/single/assignment/content.php:90, templates/single/quiz/top.php:66, templates/single/quiz/top.php:81
4831
  msgid "No limit"
4832
  msgstr ""
4833
 
4834
+ #: templates/single/assignment/content.php:102
4835
  msgid "Deadline : "
4836
  msgstr ""
4837
 
4838
+ #: templates/single/assignment/content.php:103, templates/single/course/course-topics.php:143
4839
  msgid "Expired"
4840
  msgstr ""
4841
 
4842
+ #: templates/single/assignment/content.php:115
4843
  msgid "Total Points : "
4844
  msgstr ""
4845
 
4846
+ #: templates/single/assignment/content.php:119
4847
  msgid "Minimum Pass Points : "
4848
  msgstr ""
4849
 
4850
+ #: templates/single/assignment/content.php:137
4851
  msgid "You have missed the submission deadline. Please contact the instructor for more information."
4852
  msgstr ""
4853
 
4854
+ #: templates/single/assignment/content.php:323
4855
  msgid "Submit assignment"
4856
  msgstr ""
4857
 
4858
+ #: templates/single/assignment/content.php:239
4859
+ msgid "You received %1$s points out of %2$s"
4860
  msgstr ""
4861
 
4862
+ #: templates/single/assignment/content.php:241
4863
  msgid "Your Grade is "
4864
  msgstr ""
4865
 
4866
+ #: templates/single/assignment/content.php:252
4867
  msgid "Failed"
4868
  msgstr ""
4869
 
4870
+ #: templates/single/assignment/content.php:246
4871
  msgid "Passed"
4872
  msgstr ""
4873
 
4874
+ #: templates/single/assignment/content.php:266
4875
  msgid "Your Answers"
4876
  msgstr ""
4877
 
4878
+ #: templates/single/assignment/content.php:278
4879
  msgid "Your uploaded file(s)"
4880
  msgstr ""
4881
 
4882
+ #: templates/single/assignment/content.php:298
4883
  msgid "Instructor Note"
4884
  msgstr ""
4885
 
4886
+ #: templates/single/assignment/content.php:179
4887
  msgid "Assignment answer form"
4888
  msgstr ""
4889
 
4890
+ #: templates/single/assignment/content.php:189
4891
  msgid "Write your answer briefly"
4892
  msgstr ""
4893
 
4894
+ #: templates/single/assignment/content.php:196
4895
  msgid "Attach assignment files"
4896
  msgstr ""
4897
 
4898
+ #: templates/single/assignment/content.php:202
4899
  msgid "Upload file"
4900
  msgstr ""
4901
 
4902
+ #: templates/single/assignment/content.php:214
4903
  msgid "Submit Assignment"
4904
  msgstr ""
4905
 
4907
  msgid "Please make sure that your EDD product exists and valid for this course"
4908
  msgstr ""
4909
 
4910
+ #: templates/single/course/add-to-cart-woocommerce.php:44
4911
  msgid "Please make sure that your product exists and valid for this course"
4912
  msgstr ""
4913
 
4914
+ #: templates/single/course/add-to-cart.php:77
4915
  msgid "Enroll Now"
4916
  msgstr ""
4917
 
4918
+ #: templates/single/course/add-to-cart.php:62
4919
  msgid "Start Learning"
4920
  msgstr ""
4921
 
4931
  msgid "Complete Course"
4932
  msgstr ""
4933
 
4934
+ #: templates/single/course/continue-lesson.php:43
4935
  msgid "Continue to lesson"
4936
  msgstr ""
4937
 
4938
+ #: templates/single/course/course-benefits.php:30
4939
  msgid "What Will I Learn?"
4940
  msgstr ""
4941
 
4942
+ #: templates/single/course/course-enrolled-box.php:52
4943
  msgid "Start Course"
4944
  msgstr ""
4945
 
4946
+ #: templates/single/course/course-enrolled-box.php:50
4947
  msgid "Retake This Course"
4948
  msgstr ""
4949
 
4950
+ #: templates/single/course/course-enrolled-box.php:78
4951
  msgid "You have been enrolled on %s."
4952
  msgstr ""
4953
 
 
 
 
 
4954
  #: templates/single/course/course-target-audience.php:28
4955
  msgid "Target Audience"
4956
  msgstr ""
4957
 
4958
+ #: templates/single/course/course-topics.php:31
4959
  msgid "Topics for this course"
4960
  msgstr ""
4961
 
4962
+ #: templates/single/course/course-topics.php:145
4963
  msgid "Live"
4964
  msgstr ""
4965
 
4979
  msgid "students"
4980
  msgstr ""
4981
 
4982
+ #: templates/single/course/lead-info.php:71, templates/single/course/enrolled/lead-info.php:71
4983
  msgid "Course level:"
4984
  msgstr ""
4985
 
4986
+ #: templates/single/course/lead-info.php:112, templates/single/course/enrolled/lead-info.php:113
4987
  msgid "Duration"
4988
  msgstr ""
4989
 
4990
+ #: templates/single/course/lead-info.php:121, templates/single/course/enrolled/lead-info.php:122
4991
  msgid "Total Enrolled"
4992
  msgstr ""
4993
 
4994
+ #: templates/single/course/lead-info.php:130, templates/single/course/enrolled/lead-info.php:131
4995
  msgid "Last Update"
4996
  msgstr ""
4997
 
4998
+ #: templates/single/course/lead-info.php:146, templates/single/course/enrolled/lead-info.php:169
4999
  msgid "About Course"
5000
  msgstr ""
5001
 
5002
+ #: templates/single/course/login.php:21
5003
  msgid "Login"
5004
  msgstr ""
5005
 
5035
  msgid "Complete Lesson"
5036
  msgstr ""
5037
 
5038
+ #: templates/single/lesson/lesson_sidebar.php:44
5039
  msgid "Browse Q&A"
5040
  msgstr ""
5041
 
5047
  msgid "Course name : %s"
5048
  msgstr ""
5049
 
5050
+ #: templates/single/lesson/sidebar_question_and_answer.php:133
5051
  msgid "No questions yet"
5052
  msgstr ""
5053
 
5054
+ #: templates/single/lesson/sidebar_question_and_answer.php:134
5055
  msgid "Be the first to ask your question! You’ll be able to add details in the next step."
5056
  msgstr ""
5057
 
5058
+ #: templates/single/lesson/sidebar_question_and_answer.php:103, templates/single/course/enrolled/question_and_answer.php:128
5059
  msgid "Add an answer"
5060
  msgstr ""
5061
 
5062
+ #: templates/single/lesson/sidebar_question_and_answer.php:112, templates/single/course/enrolled/question_and_answer.php:137
5063
  msgid "Write your answer here..."
5064
  msgstr ""
5065
 
5066
+ #: templates/single/lesson/sidebar_question_and_answer.php:118, templates/single/course/enrolled/question_and_answer.php:143
5067
  msgid "Add Answer"
5068
  msgstr ""
5069
 
5070
+ #: templates/single/lesson/sidebar_question_and_answer.php:145, templates/single/course/enrolled/question_and_answer.php:25
5071
  msgid "Ask a new question"
5072
  msgstr ""
5073
 
5074
+ #: templates/single/lesson/sidebar_question_and_answer.php:170
5075
  msgid "Submit My Question"
5076
  msgstr ""
5077
 
5078
+ #: templates/single/quiz/body.php:456
5079
  msgid "Start Quiz"
5080
  msgstr ""
5081
 
5082
+ #: templates/single/quiz/body.php:51
5083
  msgid "Time remaining : "
5084
  msgstr ""
5085
 
5086
+ #: templates/single/quiz/body.php:95
5087
  msgid "Reattempt"
5088
  msgstr ""
5089
 
5090
+ #: templates/single/quiz/body.php:150
5091
  msgid "Marks : "
5092
  msgstr ""
5093
 
5094
+ #: templates/single/quiz/body.php:335, templates/single/quiz/body.php:344
5095
  msgid "characters remaining"
5096
  msgstr ""
5097
 
5098
+ #: templates/single/quiz/body.php:399
5099
  msgid "Answer &amp; Next Question"
5100
  msgstr ""
5101
 
5102
+ #: templates/single/quiz/body.php:399, templates/single/quiz/body.php:416
5103
  msgid "Submit Quiz"
5104
  msgstr ""
5105
 
5135
  msgid "Passing Grade"
5136
  msgstr ""
5137
 
5138
+ #: views/options/field-types/radio.php:3, views/options/field-types/select.php:4, views/metabox/course/field-types/select.php:4, views/options/field-types/groups/select.php:5, views/metabox/course/field-types/groups/select.php:5
5139
  msgid "Select Option"
5140
  msgstr ""
5141
 
5253
  msgid "Server environment"
5254
  msgstr ""
5255
 
5256
+ #: views/pages/tools/status.php:133
5257
  msgid "Server info"
5258
  msgstr ""
5259
 
5260
+ #: views/pages/tools/status.php:134
5261
  msgid "Information about the web server that is currently hosting your site."
5262
  msgstr ""
5263
 
5264
+ #: views/pages/tools/status.php:138
5265
  msgid "PHP version"
5266
  msgstr ""
5267
 
5268
+ #: views/pages/tools/status.php:139
5269
  msgid "The version of PHP installed on your hosting server."
5270
  msgstr ""
5271
 
5272
+ #: views/pages/tools/status.php:150
5273
  msgid "We recommend using PHP version 7.2 or above for greater performance and security."
5274
  msgstr ""
5275
 
5276
+ #: views/pages/tools/status.php:148
5277
  msgid "Tutor will run under this version of PHP, however, it has reached end of life. We recommend using PHP version 7.2 or above for greater performance and security."
5278
  msgstr ""
5279
 
5280
+ #: views/pages/tools/status.php:161
5281
  msgid "PHP post max size"
5282
  msgstr ""
5283
 
5284
+ #: views/pages/tools/status.php:162
5285
  msgid "The largest filesize that can be contained in one post."
5286
  msgstr ""
5287
 
5288
+ #: views/pages/tools/status.php:166
5289
  msgid "PHP time limit"
5290
  msgstr ""
5291
 
5292
+ #: views/pages/tools/status.php:167
5293
  msgid "The amount of time (in seconds) that your site will spend on a single operation before timing out (to avoid server lockups)"
5294
  msgstr ""
5295
 
5296
+ #: views/pages/tools/status.php:171
5297
  msgid "PHP max input vars"
5298
  msgstr ""
5299
 
5300
+ #: views/pages/tools/status.php:172
5301
  msgid "The maximum number of variables your server can use for a single function to avoid overloads."
5302
  msgstr ""
5303
 
5304
+ #: views/pages/tools/status.php:176
5305
  msgid "cURL version"
5306
  msgstr ""
5307
 
5308
+ #: views/pages/tools/status.php:177
5309
  msgid "The version of cURL installed on your server."
5310
  msgstr ""
5311
 
5312
+ #: views/pages/tools/status.php:181
5313
  msgid "SUHOSIN installed"
5314
  msgstr ""
5315
 
5316
+ #: views/pages/tools/status.php:182
5317
  msgid "Suhosin is an advanced protection system for PHP installations. It was designed to protect your servers on the one hand against a number of well known problems in PHP applications and on the other hand against potential unknown vulnerabilities within these applications or the PHP core itself. If enabled on your server, Suhosin may need to be configured to increase its data submission limits."
5318
  msgstr ""
5319
 
5320
+ #: views/pages/tools/status.php:196
5321
  msgid "MySQL version"
5322
  msgstr ""
5323
 
5324
+ #: views/pages/tools/status.php:197
5325
  msgid "The version of MySQL installed on your hosting server."
5326
  msgstr ""
5327
 
5328
+ #: views/pages/tools/status.php:204
 
5329
  msgid "%1$s - We recommend a minimum MySQL version of 5.6. See: %2$s"
5330
  msgstr ""
5331
 
5332
+ #: views/pages/tools/status.php:204
5333
  msgid "WordPress requirements"
5334
  msgstr ""
5335
 
5336
+ #: views/pages/tools/status.php:214
5337
  msgid "Max upload size"
5338
  msgstr ""
5339
 
5340
+ #: views/pages/tools/status.php:215
5341
  msgid "The largest filesize that can be uploaded to your WordPress installation."
5342
  msgstr ""
5343
 
5344
+ #: views/pages/tools/status.php:219
5345
  msgid "Default timezone is UTC"
5346
  msgstr ""
5347
 
5348
+ #: views/pages/tools/status.php:220
5349
  msgid "The default timezone for your server."
5350
  msgstr ""
5351
 
5352
  #. translators: %s: default timezone..
5353
+ #: views/pages/tools/status.php:225
5354
  msgid "Default timezone is %s - it should be UTC"
5355
  msgstr ""
5356
 
5357
+ #: views/pages/tools/status.php:233
5358
  msgid "fsockopen/cURL"
5359
  msgstr ""
5360
 
5361
+ #: views/pages/tools/status.php:234
5362
  msgid "Payment gateways can use cURL to communicate with remote servers to authorize payments, other plugins may also use it when communicating with remote services."
5363
  msgstr ""
5364
 
5365
+ #: views/pages/tools/status.php:242
5366
  msgid "Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider."
5367
  msgstr ""
5368
 
5369
+ #: views/pages/tools/status.php:249
5370
  msgid "DOMDocument"
5371
  msgstr ""
5372
 
5373
+ #: views/pages/tools/status.php:250
5374
  msgid "HTML/Multipart emails use DOMDocument to generate inline CSS in templates."
5375
  msgstr ""
5376
 
5377
+ #: views/pages/tools/status.php:259
 
5378
  msgid "Your server does not have the %s class enabled - HTML/Multipart emails, and also some extensions, will not work without DOMDocument."
5379
  msgstr ""
5380
 
5381
+ #: views/pages/tools/status.php:266
5382
  msgid "GZip"
5383
  msgstr ""
5384
 
5385
+ #: views/pages/tools/status.php:267
5386
  msgid "GZip (gzopen) is used to open the GEOIP database from MaxMind."
5387
  msgstr ""
5388
 
5389
+ #: views/pages/tools/status.php:276
 
5390
  msgid "Your server does not support the %s function - this is required to use the GeoIP database from MaxMind."
5391
  msgstr ""
5392
 
5393
+ #: views/pages/tools/status.php:283
5394
  msgid "Multibyte string"
5395
  msgstr ""
5396
 
5397
+ #: views/pages/tools/status.php:284
5398
  msgid "Multibyte String (mbstring) is used to convert character encoding, like for emails or converting characters to lowercase."
5399
  msgstr ""
5400
 
5401
+ #: views/pages/tools/status.php:295
 
5402
  msgid "Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it."
5403
  msgstr ""
5404
 
5405
+ #: views/pages/tools/tutor_pages.php:10
5406
  msgid "Page Name"
5407
  msgstr ""
5408
 
5409
+ #: views/pages/tools/tutor_pages.php:37
5410
  msgid " Page not set"
5411
  msgstr ""
5412
 
5413
+ #: views/pages/tools/tutor_pages.php:44
5414
  msgid " Page deleted, please set new one"
5415
  msgstr ""
5416
 
5417
+ #: views/pages/tools/tutor_pages.php:51
5418
  msgid "Page visibility is not public"
5419
  msgstr ""
5420
 
5421
+ #: views/pages/tools/tutor_pages.php:78
5422
  msgid "Re-Generate Tutor Pages"
5423
  msgstr ""
5424
 
5425
+ #: views/pages/tools/tutor_pages.php:83
5426
  msgid "Note: This tool will install all the missing Tutor pages. Pages already defined and set up will not be replaced."
5427
  msgstr ""
5428
 
5442
  msgid " Complete"
5443
  msgstr ""
5444
 
5445
+ #: templates/single/course/enrolled/nav.php:27
5446
  msgid "Course Page"
5447
  msgstr ""
5448
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: lms, course, elearning, education, learning management system
5
  Requires at least: 5.3
6
  Tested up to: 5.8
7
  Requires PHP: 7.0
8
- Stable tag: 1.9.12
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
11
 
@@ -241,6 +241,10 @@ Tutor enables you to use any third party plugins without facing any compatibilit
241
 
242
  == Changelog ==
243
 
 
 
 
 
244
  = 1.9.12 - December 14, 2021 =
245
 
246
  Update: Security Update
5
  Requires at least: 5.3
6
  Tested up to: 5.8
7
  Requires PHP: 7.0
8
+ Stable tag: 1.9.13
9
  License: GPLv3
10
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
11
 
241
 
242
  == Changelog ==
243
 
244
+ = 1.9.13 - January 10, 2022 =
245
+
246
+ Update: Security Update
247
+
248
  = 1.9.12 - December 14, 2021 =
249
 
250
  Update: Security Update
templates/archive-course.php CHANGED
@@ -24,7 +24,7 @@ if ($course_filter && count($supported_filters)) {
24
  <?php tutor_load_template('course-filter.filters'); ?>
25
  </div>
26
  <div>
27
- <div id="tutor-course-filter-loop-container" class="<?php tutor_container_classes(); ?> tutor-course-filter-loop-container" data-column_per_row="<?php echo tutor_utils()->get_option( 'courses_col_per_row', 4 ); ?>">
28
  <?php tutor_load_template('archive-course-init'); ?>
29
  </div><!-- .wrap -->
30
  </div>
24
  <?php tutor_load_template('course-filter.filters'); ?>
25
  </div>
26
  <div>
27
+ <div id="tutor-course-filter-loop-container" class="<?php tutor_container_classes(); ?> tutor-course-filter-loop-container" data-column_per_row="<?php echo esc_attr( tutor_utils()->get_option( 'courses_col_per_row', 4 ) ); ?>">
28
  <?php tutor_load_template('archive-course-init'); ?>
29
  </div><!-- .wrap -->
30
  </div>
templates/course-filter/filters.php CHANGED
@@ -19,7 +19,7 @@
19
  if ( in_array( 'search', $supported_filters ) ) {
20
  ?>
21
  <div class="tutor-course-search-field">
22
- <input type="text" name="keyword" placeholder="<?php echo esc_attr( 'Search...', 'tutor' ); ?>"/>
23
  <i class="tutor-icon-magnifying-glass-1"></i>
24
  </div>
25
  <?php
@@ -71,13 +71,13 @@
71
  if ( ! $is_membership && in_array( 'price_type', $supported_filters ) ) {
72
  ?>
73
  <div>
74
- <h4><?php esc_html_e( 'Price', 'tutor' ); ?></h4>
75
  <?php
76
  foreach ( $filter_prices as $value => $title ) {
77
  ?>
78
  <label>
79
  <input type="checkbox" name="tutor-course-filter-price" value="<?php echo esc_attr( $value ); ?>"/>&nbsp;
80
- <?php echo esc_html( $title ); ?>
81
  </label>
82
  <?php
83
  }
19
  if ( in_array( 'search', $supported_filters ) ) {
20
  ?>
21
  <div class="tutor-course-search-field">
22
+ <input type="text" name="keyword" placeholder="<?php _e( 'Search...', 'tutor' ); ?>"/>
23
  <i class="tutor-icon-magnifying-glass-1"></i>
24
  </div>
25
  <?php
71
  if ( ! $is_membership && in_array( 'price_type', $supported_filters ) ) {
72
  ?>
73
  <div>
74
+ <h4><?php _e( 'Price', 'tutor' ); ?></h4>
75
  <?php
76
  foreach ( $filter_prices as $value => $title ) {
77
  ?>
78
  <label>
79
  <input type="checkbox" name="tutor-course-filter-price" value="<?php echo esc_attr( $value ); ?>"/>&nbsp;
80
+ <?php echo $title; ?>
81
  </label>
82
  <?php
83
  }
templates/dashboard.php CHANGED
@@ -11,206 +11,214 @@
11
  * @version 1.4.3
12
  */
13
 
14
- $is_by_short_code = isset($is_shortcode) && $is_shortcode===true;
15
- if(!$is_by_short_code && !defined( 'OTLMS_VERSION' )) {
16
- get_header();
17
  }
18
 
19
  global $wp_query;
20
 
21
  $dashboard_page_slug = '';
22
  $dashboard_page_name = '';
23
- if (isset($wp_query->query_vars['tutor_dashboard_page']) && $wp_query->query_vars['tutor_dashboard_page']) {
24
- $dashboard_page_slug = $wp_query->query_vars['tutor_dashboard_page'];
25
- $dashboard_page_name = $wp_query->query_vars['tutor_dashboard_page'];
26
  }
27
  /**
28
  * Getting dashboard sub pages
29
  */
30
- if (isset($wp_query->query_vars['tutor_dashboard_sub_page']) && $wp_query->query_vars['tutor_dashboard_sub_page']) {
31
- $dashboard_page_name = $wp_query->query_vars['tutor_dashboard_sub_page'];
32
- if ($dashboard_page_slug){
33
- $dashboard_page_name = $dashboard_page_slug.'/'.$dashboard_page_name;
34
- }
35
  }
36
 
37
- $user_id = get_current_user_id();
38
- $user = get_user_by('ID', $user_id);
39
- $enable_profile_completion = tutils()->get_option('enable_profile_completion');
40
 
41
- do_action('tutor_dashboard/before/wrap');
42
  ?>
43
 
44
- <div class="tutor-wrap tutor-dashboard tutor-dashboard-student">
45
- <div class="tutor-container">
46
- <div class="tutor-row">
47
- <div class="tutor-col-12">
48
- <div class="tutor-dashboard-header">
49
- <div class="tutor-dashboard-header-avatar">
50
- <img src="<?php echo get_avatar_url($user_id, array('size' => 150)); ?>" />
51
- </div>
52
- <div class="tutor-dashboard-header-info">
53
- <div class="tutor-dashboard-header-display-name">
54
- <h4><strong><?php echo $user->display_name; ?></strong> </h4>
55
- </div>
56
- <?php $instructor_rating = tutils()->get_instructor_ratings($user->ID); ?>
57
- <?php
58
- if (current_user_can(tutor()->instructor_role)){
59
- ?>
60
- <div class="tutor-dashboard-header-stats">
61
- <div class="tutor-dashboard-header-ratings">
62
- <?php tutils()->star_rating_generator($instructor_rating->rating_avg); ?>
63
- <span><?php echo esc_html($instructor_rating->rating_avg); ?></span>
64
- <span> (<?php echo sprintf(__('%d Ratings', 'tutor'), $instructor_rating->rating_count); ?>) </span>
65
- </div>
66
- <!--<div class="tutor-dashboard-header-notifications">
67
- <?php /*_e('Notification'); */?> <span>9</span>
68
- </div>-->
69
- </div>
70
- <?php } ?>
71
- </div>
72
-
73
- <div class="tutor-dashboard-header-button">
74
- <?php
75
- do_action( 'tutor_dashboard/before_header_button' );
76
- $instructor_status = tutor_utils()->instructor_status();
77
- $instructor_status = is_string($instructor_status) ? strtolower($instructor_status) : '';
78
- $rejected_on = get_user_meta($user->ID , '_is_tutor_instructor_rejected', true);
79
- $info_style = 'vertical-align: middle; margin-right: 7px;';
80
- $info_message_style = 'display:inline-block; color:#7A7A7A; font-size: 15px;';
81
-
82
- ob_start();
83
- if (tutils()->get_option('enable_become_instructor_btn')) {
84
- ?>
85
- <a id="tutor-become-instructor-button" style="vertical-align:middle" class="tutor-btn bordered-btn" href="<?php echo esc_url(tutils()->instructor_register_url()); ?>">
86
- <i class="tutor-icon-man-user"></i> &nbsp; <?php _e("Become an instructor", 'tutor'); ?>
87
- </a>
88
- <?php
89
- }
90
- $become_button = ob_get_clean();
91
-
92
- if(current_user_can(tutor()->instructor_role)){
93
- $course_type = tutor()->course_post_type;
94
- ?>
95
- <a class="tutor-btn bordered-btn" href="<?php echo apply_filters('frontend_course_create_url', admin_url("post-new.php?post_type=".tutor()->course_post_type)); ?>">
96
- <i class="tutor-icon-checkbox-pen-outline"></i> &nbsp; <?php _e('Add A New Course', 'tutor'); ?>
97
- </a>
98
- <?php
99
- }
100
- else if($instructor_status=='pending'){
101
- $on = get_user_meta($user->ID, '_is_tutor_instructor', true);
102
- $on = date('d F, Y', $on);
103
- echo '<span style="'.$info_message_style.'">
104
- <i class="dashicons dashicons-info" style="color:#E53935; '.$info_style.'"></i>',
105
- __('Your Application is pending from', 'tutor'), ' <b>', $on, '</b>',
106
- '</span>';
107
- }
108
- else if($rejected_on || $instructor_status!=='blocked'){
109
- echo $become_button;
110
- }
111
- ?>
112
- </div>
113
-
114
- <?php
115
- if(
116
- $instructor_status != 'approved' &&
117
- $instructor_status != 'pending' &&
118
- $rejected_on &&
119
- get_user_meta( get_current_user_id(), 'tutor_instructor_show_rejection_message', true )
120
- ) {
121
- ?>
122
- <div class="tutor-instructor-rejection-notice">
123
- <?php
124
- $on = date('d F, Y', $rejected_on);
125
- echo '<span>
126
- <i class="dashicons dashicons-info"></i>',
127
- __('Your application to become an instructor was rejected on', 'tutor') . ' ' . $on .
128
- '</span>
129
- <a href="?tutor_action=hide_instructor_notice">✕</a>';
130
- ?>
131
- </div>
132
- <?php
133
- }
134
- ?>
135
- </div>
136
- </div>
137
- <?php do_action('tutor_dashboard/notification_area'); ?>
138
- </div>
139
-
140
- <div class="tutor-row">
141
- <div class="tutor-col-3 tutor-dashboard-left-menu">
142
- <ul class="tutor-dashboard-permalinks">
143
- <?php
144
- $dashboard_pages = tutils()->tutor_dashboard_nav_ui_items();
145
- foreach ($dashboard_pages as $dashboard_key => $dashboard_page) {
146
- $menu_title = $dashboard_page;
147
- $menu_link = tutils()->get_tutor_dashboard_page_permalink($dashboard_key);
148
- $separator = false;
149
- if (is_array($dashboard_page)){
150
- $menu_title = tutils()->array_get('title', $dashboard_page);
151
- //Add new menu item property "url" for custom link
152
- if (isset($dashboard_page['url'])) {
153
- $menu_link = $dashboard_page['url'];
154
- }
155
- if (isset($dashboard_page['type']) && $dashboard_page['type'] == 'separator') {
156
- $separator = true;
157
- }
158
- }
159
- if ($separator) {
160
- echo '<li class="tutor-dashboard-menu-divider"></li>';
161
- if ($menu_title) {
162
- echo "<li class='tutor-dashboard-menu-divider-header'>{$menu_title}</li>";
163
- }
164
- } else {
165
- $li_class = "tutor-dashboard-menu-{$dashboard_key}";
166
- if ($dashboard_key === 'index')
167
- $dashboard_key = '';
168
- $active_class = $dashboard_key == $dashboard_page_slug ? 'active' : '';
169
- echo "<li class='{$li_class} {$active_class}'><a href='".$menu_link."'> {$menu_title} </a> </li>";
170
- }
171
- }
172
- ?>
173
- </ul>
174
- </div>
175
-
176
- <div class="tutor-col-9">
177
- <div class="tutor-dashboard-content">
178
- <?php
179
-
180
- if ($dashboard_page_name){
181
- do_action('tutor_load_dashboard_template_before', $dashboard_page_name);
182
-
183
- /**
184
- * Load dashboard template part from other location
185
- *
186
- * this filter is basically added for adding templates from respective addons
187
- *
188
- * @since version 1.9.3
189
- */
190
- $other_location = '';
191
- $from_other_location = apply_filters( 'load_dashboard_template_part_from_other_location', $other_location );
192
-
193
- if ( $from_other_location == '' ) {
194
- tutor_load_template("dashboard.".$dashboard_page_name);
195
- } else {
196
- //load template from other location full abspath
197
- include_once $from_other_location;
198
- }
199
-
200
- do_action('tutor_load_dashboard_template_before', $dashboard_page_name);
201
- } else {
202
- tutor_load_template("dashboard.dashboard");
203
- }
204
- ?>
205
- </div>
206
- </div>
207
- </div>
208
- </div>
209
- </div>
210
-
211
- <?php do_action('tutor_dashboard/after/wrap'); ?>
 
 
 
 
 
 
 
 
212
 
213
  <?php
214
- if(!$is_by_short_code && !defined( 'OTLMS_VERSION' )) {
215
- get_footer();
216
- }
11
  * @version 1.4.3
12
  */
13
 
14
+ $is_by_short_code = isset( $is_shortcode ) && $is_shortcode === true;
15
+ if ( ! $is_by_short_code && ! defined( 'OTLMS_VERSION' ) ) {
16
+ get_header();
17
  }
18
 
19
  global $wp_query;
20
 
21
  $dashboard_page_slug = '';
22
  $dashboard_page_name = '';
23
+ if ( isset( $wp_query->query_vars['tutor_dashboard_page'] ) && $wp_query->query_vars['tutor_dashboard_page'] ) {
24
+ $dashboard_page_slug = $wp_query->query_vars['tutor_dashboard_page'];
25
+ $dashboard_page_name = $wp_query->query_vars['tutor_dashboard_page'];
26
  }
27
  /**
28
  * Getting dashboard sub pages
29
  */
30
+ if ( isset( $wp_query->query_vars['tutor_dashboard_sub_page'] ) && $wp_query->query_vars['tutor_dashboard_sub_page'] ) {
31
+ $dashboard_page_name = $wp_query->query_vars['tutor_dashboard_sub_page'];
32
+ if ( $dashboard_page_slug ) {
33
+ $dashboard_page_name = $dashboard_page_slug . '/' . $dashboard_page_name;
34
+ }
35
  }
36
 
37
+ $user_id = get_current_user_id();
38
+ $user = get_user_by( 'ID', $user_id );
39
+ $enable_profile_completion = tutils()->get_option( 'enable_profile_completion' );
40
 
41
+ do_action( 'tutor_dashboard/before/wrap' );
42
  ?>
43
 
44
+ <div class="tutor-wrap tutor-dashboard tutor-dashboard-student">
45
+ <div class="tutor-container">
46
+ <div class="tutor-row">
47
+ <div class="tutor-col-12">
48
+ <div class="tutor-dashboard-header">
49
+ <div class="tutor-dashboard-header-avatar">
50
+ <img src="<?php echo esc_url( get_avatar_url( $user_id, array( 'size' => 150 ) ) ); ?>" />
51
+ </div>
52
+ <div class="tutor-dashboard-header-info">
53
+ <div class="tutor-dashboard-header-display-name">
54
+ <h4>
55
+ <strong>
56
+ <?php echo $user->display_name; ?>
57
+ </strong>
58
+ </h4>
59
+ </div>
60
+ <?php $instructor_rating = tutils()->get_instructor_ratings( $user->ID ); ?>
61
+ <?php
62
+ if ( current_user_can( tutor()->instructor_role ) ) {
63
+ ?>
64
+ <div class="tutor-dashboard-header-stats">
65
+ <div class="tutor-dashboard-header-ratings">
66
+ <?php tutils()->star_rating_generator( $instructor_rating->rating_avg ); ?>
67
+ <span><?php echo esc_html( $instructor_rating->rating_avg ); ?></span>
68
+ <span> (<?php echo sprintf( __( '%d Ratings', 'tutor' ), $instructor_rating->rating_count ); ?>) </span>
69
+ </div>
70
+ <!--<div class="tutor-dashboard-header-notifications">
71
+ <?php /*_e('Notification'); */ ?> <span>9</span>
72
+ </div>-->
73
+ </div>
74
+ <?php } ?>
75
+ </div>
76
+
77
+ <div class="tutor-dashboard-header-button">
78
+ <?php
79
+ do_action( 'tutor_dashboard/before_header_button' );
80
+ $instructor_status = tutor_utils()->instructor_status();
81
+ $instructor_status = is_string( $instructor_status ) ? strtolower( $instructor_status ) : '';
82
+ $rejected_on = get_user_meta( $user->ID, '_is_tutor_instructor_rejected', true );
83
+ $info_style = 'vertical-align: middle; margin-right: 7px;';
84
+ $info_message_style = 'display:inline-block; color:#7A7A7A; font-size: 15px;';
85
+
86
+ ob_start();
87
+ if ( tutils()->get_option( 'enable_become_instructor_btn' ) ) {
88
+ ?>
89
+ <a id="tutor-become-instructor-button" style="vertical-align:middle" class="tutor-btn bordered-btn" href="<?php echo esc_url( tutils()->instructor_register_url() ); ?>">
90
+ <i class="tutor-icon-man-user"></i> &nbsp; <?php _e( 'Become an instructor', 'tutor' ); ?>
91
+ </a>
92
+ <?php
93
+ }
94
+ $become_button = ob_get_clean();
95
+
96
+ if ( current_user_can( tutor()->instructor_role ) ) {
97
+ $course_type = tutor()->course_post_type;
98
+ ?>
99
+ <a class="tutor-btn bordered-btn" href="<?php echo esc_url( apply_filters( 'frontend_course_create_url', admin_url( 'post-new.php?post_type=' . tutor()->course_post_type ) ) ); ?>">
100
+ <i class="tutor-icon-checkbox-pen-outline"></i> &nbsp; <?php _e( 'Add A New Course', 'tutor' ); ?>
101
+ </a>
102
+ <?php
103
+ } elseif ( $instructor_status == 'pending' ) {
104
+ $on = get_user_meta( $user->ID, '_is_tutor_instructor', true );
105
+ $on = date( 'd F, Y', $on );
106
+ echo '<span style="' . $info_message_style . '">
107
+ <i class="dashicons dashicons-info" style="color:#E53935; ' . $info_style . '"></i>'.
108
+ __( 'Your Application is pending from', 'tutor' ).
109
+ ' <b>'.
110
+ $on.
111
+ '</b>'.
112
+ '</span>';
113
+ } elseif ( $rejected_on || $instructor_status !== 'blocked' ) {
114
+ echo $become_button; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
115
+ }
116
+ ?>
117
+ </div>
118
+
119
+ <?php
120
+ if ( $instructor_status != 'approved'
121
+ && $instructor_status != 'pending'
122
+ && $rejected_on
123
+ && get_user_meta( get_current_user_id(), 'tutor_instructor_show_rejection_message', true )
124
+ ) {
125
+ ?>
126
+ <div class="tutor-instructor-rejection-notice">
127
+ <?php
128
+ $on = date( 'd F, Y', $rejected_on );
129
+
130
+ echo '<span>
131
+ <i class="dashicons dashicons-info"></i>',
132
+ __( 'Your application to become an instructor was rejected on', 'tutor' ) . ' ' . $on .
133
+ '</span>
134
+ <a href="?tutor_action=hide_instructor_notice">
135
+
136
+ </a>';
137
+ ?>
138
+ </div>
139
+ <?php
140
+ }
141
+ ?>
142
+ </div>
143
+ </div>
144
+ <?php do_action( 'tutor_dashboard/notification_area' ); ?>
145
+ </div>
146
+
147
+ <div class="tutor-row">
148
+ <div class="tutor-col-3 tutor-dashboard-left-menu">
149
+ <ul class="tutor-dashboard-permalinks">
150
+ <?php
151
+ $dashboard_pages = tutils()->tutor_dashboard_nav_ui_items();
152
+ foreach ( $dashboard_pages as $dashboard_key => $dashboard_page ) {
153
+ $menu_title = $dashboard_page;
154
+ $menu_link = tutils()->get_tutor_dashboard_page_permalink( $dashboard_key );
155
+ $separator = false;
156
+ if ( is_array( $dashboard_page ) ) {
157
+ $menu_title = tutils()->array_get( 'title', $dashboard_page );
158
+ // Add new menu item property "url" for custom link
159
+ if ( isset( $dashboard_page['url'] ) ) {
160
+ $menu_link = $dashboard_page['url'];
161
+ }
162
+ if ( isset( $dashboard_page['type'] ) && $dashboard_page['type'] == 'separator' ) {
163
+ $separator = true;
164
+ }
165
+ }
166
+ if ( $separator ) {
167
+ echo '<li class="tutor-dashboard-menu-divider"></li>';
168
+ if ( $menu_title ) {
169
+ echo '<li class="tutor-dashboard-menu-divider-header">' . $menu_title . '</li>';
170
+ }
171
+ } else {
172
+ $li_class = 'tutor-dashboard-menu-' . $dashboard_key;
173
+ if ( $dashboard_key === 'index' ) {
174
+ $dashboard_key = '';
175
+ }
176
+ $active_class = $dashboard_key == $dashboard_page_slug ? 'active' : '';
177
+ echo '<li class="' . $li_class . ' ' . $active_class . '"><a href="' . esc_url( $menu_link ) . '"> ' . $menu_title . ' </a> </li>';
178
+ }
179
+ }
180
+ ?>
181
+ </ul>
182
+ </div>
183
+
184
+ <div class="tutor-col-9">
185
+ <div class="tutor-dashboard-content">
186
+ <?php
187
+
188
+ if ( $dashboard_page_name ) {
189
+ do_action( 'tutor_load_dashboard_template_before', $dashboard_page_name );
190
+
191
+ /**
192
+ * Load dashboard template part from other location
193
+ *
194
+ * this filter is basically added for adding templates from respective addons
195
+ *
196
+ * @since version 1.9.3
197
+ */
198
+ $other_location = '';
199
+ $from_other_location = apply_filters( 'load_dashboard_template_part_from_other_location', $other_location );
200
+
201
+ if ( $from_other_location == '' ) {
202
+ tutor_load_template( 'dashboard.' . $dashboard_page_name );
203
+ } else {
204
+ // load template from other location full abspath
205
+ include_once $from_other_location;
206
+ }
207
+
208
+ do_action( 'tutor_load_dashboard_template_before', $dashboard_page_name );
209
+ } else {
210
+ tutor_load_template( 'dashboard.dashboard' );
211
+ }
212
+ ?>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+
219
+ <?php do_action( 'tutor_dashboard/after/wrap' ); ?>
220
 
221
  <?php
222
+ if ( ! $is_by_short_code && ! defined( 'OTLMS_VERSION' ) ) {
223
+ get_footer();
224
+ }
templates/dashboard/announcements.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
- if (!defined('ABSPATH'))
3
- exit;
 
4
  /**
5
  * Template for displaying Announcements
6
  *
@@ -12,185 +13,187 @@ if (!defined('ABSPATH'))
12
  * @package TutorLMS/Templates
13
  * @version 1.7.9
14
  */
15
- $per_page = 10;
16
- $paged = max(1, tutor_utils()->avalue_dot('current_page', $_GET));
17
 
18
- $order_filter = isset($_GET['order']) ? sanitize_text_field($_GET['order']) : 'DESC';
19
- $search_filter = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
20
- //announcement's parent
21
- $course_id = isset($_GET['course-id']) ? sanitize_text_field($_GET['course-id']) : '';
22
- $date_filter = isset($_GET['date']) ? sanitize_text_field($_GET['date']) : '';
23
 
24
- $year = date('Y', strtotime($date_filter));
25
- $month = date('m', strtotime($date_filter));
26
- $day = date('d', strtotime($date_filter));
27
 
28
  $args = array(
29
- 'post_type' => 'tutor_announcements',
30
- 'post_status' => 'publish',
31
- 's' => sanitize_text_field($search_filter),
32
- 'post_parent' => sanitize_text_field($course_id),
33
- 'posts_per_page' => sanitize_text_field($per_page),
34
- 'paged' => sanitize_text_field($paged),
35
- 'orderBy' => 'ID',
36
- 'order' => sanitize_text_field($order_filter),
37
 
38
  );
39
- if (!empty($date_filter)) {
40
- $args['date_query'] = array(
41
- array(
42
- 'year' => $year,
43
- 'month' => $month,
44
- 'day' => $day
45
- )
46
- );
47
  }
48
- if (!current_user_can('administrator')) {
49
- $args['author'] = get_current_user_id();
50
  }
51
- $the_query = new WP_Query($args);
52
 
53
- //get courses
54
- $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
55
  $image_base = tutor()->url . '/assets/images/';
56
  ?>
57
 
58
  <div class="tutor-dashboard-content-inner">
59
- <h4><?php echo __('Announcement', 'tutor'); ?></h4>
60
- <!--notice-->
61
- <div class="tutor-component-three-col-action new-announcement-wrap">
62
- <div class="tutor-announcement-big-icon">
63
- <i class="tutor-icon-speaker"></i>
64
- </div>
65
- <div>
66
- <small><?php _e('Create Announcement', 'tutor'); ?></small>
67
- <p>
68
- <strong>
69
- <?php _e('Notify all students of your course', 'tutor'); ?>
70
- </strong>
71
- </p>
72
- </div>
73
- <div class="new-announcement-button">
74
- <button type="button" class="tutor-btn tutor-announcement-add-new">
75
- <?php _e('Add New Announcement', 'tutor'); ?>
76
- </button>
77
- </div>
78
- </div>
79
- <!--notice end-->
80
  </div>
81
  <!--sorting-->
82
  <div class="tutor-dashboard-announcement-sorting-wrap">
83
- <div class="tutor-form-group">
84
- <label for="">
85
- <?php _e('Courses', 'tutor'); ?>
86
- </label>
87
- <select class="tutor-report-category tutor-announcement-course-sorting ignore-nice-select">
88
-
89
- <option value=""><?php _e('All', 'tutor'); ?></option>
90
-
91
- <?php if ($courses) : ?>
92
- <?php foreach ($courses as $course) : ?>
93
- <option value="<?php echo esc_attr($course->ID) ?>" <?php selected($course_id, $course->ID, 'selected') ?>>
94
- <?php echo $course->post_title; ?>
95
- </option>
96
- <?php endforeach; ?>
97
- <?php else : ?>
98
- <option value=""><?php _e('No course found', 'tutor'); ?></option>
99
- <?php endif; ?>
100
- </select>
101
- </div>
102
-
103
- <div class="tutor-form-group">
104
- <label><?php _e('Sort By', 'tutor'); ?></label>
105
- <select class="tutor-announcement-order-sorting ignore-nice-select">
106
- <option <?php selected($order_filter, 'ASC'); ?>><?php _e('ASC', 'tutor'); ?></option>
107
- <option <?php selected($order_filter, 'DESC'); ?>><?php _e('DESC', 'tutor'); ?></option>
108
- </select>
109
- </div>
110
-
111
- <div class="tutor-form-group tutor-announcement-datepicker">
112
- <label><?php _e('Date', 'tutor'); ?></label>
113
- <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" id="tutor-announcement-datepicker" value="<?php echo $date_filter !== '' ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" placeholder="<?php echo get_option( 'date_format' ); ?>" autocomplete="off" />
114
- <i class="tutor-icon-calendar"></i>
115
- </div>
116
  </div>
117
  <!--sorting end-->
118
  <div class="tutor-announcement-table-wrap">
119
- <table class="tutor-dashboard-announcement-table" width="100%">
120
- <thead>
121
- <tr>
122
- <th style="width:24%"><?php _e('Date', 'tutor'); ?></th>
123
- <th style="text-align:left"><?php _e('Announcements', 'tutor'); ?></th>
124
- </tr>
125
- </thead>
126
- <tbody>
127
- <?php if ($the_query->have_posts()) : ?>
128
- <?php foreach ($the_query->posts as $post) : ?>
129
- <?php
130
- $course = get_post($post->post_parent);
131
- $dateObj = date_create($post->post_date);
132
- $date_format = date_format($dateObj, 'j M, Y,<\b\r>h:i a');
133
- ?>
134
- <tr id="tutor-announcement-tr-<?php echo $post->ID; ?>">
135
- <td class="tutor-announcement-date"><?php echo $date_format; ?></td>
136
- <td class="tutor-announcement-content-wrap">
137
- <div class="tutor-announcement-content">
138
- <h4><?php echo esc_html($post->post_title); ?></h4>
139
- <p><?php echo $course ? $course->post_title : ''; ?></p>
140
- </div>
141
- <div class="tutor-announcement-buttons">
142
- <li>
143
- <button type="button" course-name="<?php echo esc_attr($course->post_title) ?>" announcement-date="<?php echo esc_attr($date_format) ?>" announcement-title="<?php echo esc_attr($post->post_title); ?>" announcement-summary="<?php echo esc_attr($post->post_content); ?>" course-id="<?php echo esc_attr($post->post_parent); ?>" announcement-id="<?php echo esc_attr($post->ID); ?>" class="tutor-btn bordered-btn tutor-announcement-details">
144
- <?php _e('Details', 'tutor'); ?>
145
- </button>
146
- </li>
147
- <li class="tutor-dropdown">
148
- <i class="tutor-icon-action"></i>
149
- <ul class="tutor-dropdown-menu">
150
- <li announcement-title="<?php echo $post->post_title; ?>" announcement-summary="<?php echo $post->post_content; ?>" course-id="<?php echo $post->post_parent; ?>" announcement-id="<?php echo $post->ID; ?>" class="tutor-announcement-edit">
151
- <i class="tutor-icon-pencil"></i>
152
- <?php _e('Edit', 'tutor'); ?>
153
- </li>
154
- <li class="tutor-announcement-delete" announcement-id="<?php echo $post->ID; ?>">
155
- <i class="tutor-icon-garbage"></i>
156
- <?php _e('Delete', 'tutor'); ?>
157
- </li>
158
- </ul>
159
- </li>
160
- </div>
161
- </td>
162
- </tr>
163
- <?php endforeach; ?>
164
- <?php else : ?>
165
- <tr>
166
- <td colspan="2">
167
- <?php _e('Announcements not found', 'tutor'); ?>
168
- </td>
169
- </tr>
170
- <?php endif; ?>
171
- </tbody>
172
- </table>
173
 
174
  </div>
175
 
176
  <!--pagination-->
177
  <div class="tutor-pagination">
178
- <?php
179
- $big = 999999999; // need an unlikely integer
180
-
181
- echo paginate_links( array(
182
-
183
- 'format' => '?current_page=%#%',
184
- 'current' => $paged,
185
- 'total' => $the_query->max_num_pages
186
- ) );
187
-
188
- ?>
 
 
189
  </div>
190
  <!--pagination end-->
191
 
192
  <?php
193
- include 'announcements/create.php';
194
- include 'announcements/update.php';
195
- include 'announcements/details.php';
196
  ?>
1
  <?php
2
+ if ( ! defined( 'ABSPATH' ) ) {
3
+ exit;
4
+ }
5
  /**
6
  * Template for displaying Announcements
7
  *
13
  * @package TutorLMS/Templates
14
  * @version 1.7.9
15
  */
16
+ $per_page = 10;
17
+ $paged = max( 1, tutor_utils()->avalue_dot( 'current_page', tutor_sanitize_data($_GET) ) );
18
 
19
+ $order_filter = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : 'DESC';
20
+ $search_filter = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
21
+ // announcement's parent
22
+ $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
23
+ $date_filter = isset( $_GET['date'] ) ? sanitize_text_field( $_GET['date'] ) : '';
24
 
25
+ $year = date( 'Y', strtotime( $date_filter ) );
26
+ $month = date( 'm', strtotime( $date_filter ) );
27
+ $day = date( 'd', strtotime( $date_filter ) );
28
 
29
  $args = array(
30
+ 'post_type' => 'tutor_announcements',
31
+ 'post_status' => 'publish',
32
+ 's' => sanitize_text_field( $search_filter ),
33
+ 'post_parent' => sanitize_text_field( $course_id ),
34
+ 'posts_per_page' => sanitize_text_field( $per_page ),
35
+ 'paged' => sanitize_text_field( $paged ),
36
+ 'orderBy' => 'ID',
37
+ 'order' => sanitize_text_field( $order_filter ),
38
 
39
  );
40
+ if ( ! empty( $date_filter ) ) {
41
+ $args['date_query'] = array(
42
+ array(
43
+ 'year' => $year,
44
+ 'month' => $month,
45
+ 'day' => $day,
46
+ ),
47
+ );
48
  }
49
+ if ( ! current_user_can( 'administrator' ) ) {
50
+ $args['author'] = get_current_user_id();
51
  }
52
+ $the_query = new WP_Query( $args );
53
 
54
+ // get courses
55
+ $courses = ( current_user_can( 'administrator' ) ) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
56
  $image_base = tutor()->url . '/assets/images/';
57
  ?>
58
 
59
  <div class="tutor-dashboard-content-inner">
60
+ <h4><?php echo __( 'Announcement', 'tutor' ); ?></h4>
61
+ <!--notice-->
62
+ <div class="tutor-component-three-col-action new-announcement-wrap">
63
+ <div class="tutor-announcement-big-icon">
64
+ <i class="tutor-icon-speaker"></i>
65
+ </div>
66
+ <div>
67
+ <small><?php _e( 'Create Announcement', 'tutor' ); ?></small>
68
+ <p>
69
+ <strong>
70
+ <?php _e( 'Notify all students of your course', 'tutor' ); ?>
71
+ </strong>
72
+ </p>
73
+ </div>
74
+ <div class="new-announcement-button">
75
+ <button type="button" class="tutor-btn tutor-announcement-add-new">
76
+ <?php _e( 'Add New Announcement', 'tutor' ); ?>
77
+ </button>
78
+ </div>
79
+ </div>
80
+ <!--notice end-->
81
  </div>
82
  <!--sorting-->
83
  <div class="tutor-dashboard-announcement-sorting-wrap">
84
+ <div class="tutor-form-group">
85
+ <label for="">
86
+ <?php _e( 'Courses', 'tutor' ); ?>
87
+ </label>
88
+ <select class="tutor-report-category tutor-announcement-course-sorting ignore-nice-select">
89
+
90
+ <option value=""><?php _e( 'All', 'tutor' ); ?></option>
91
+
92
+ <?php if ( $courses ) : ?>
93
+ <?php foreach ( $courses as $course ) : ?>
94
+ <option value="<?php echo $course->ID; ?>" <?php selected( $course_id, $course->ID, 'selected' ); ?>>
95
+ <?php echo $course->post_title; ?>
96
+ </option>
97
+ <?php endforeach; ?>
98
+ <?php else : ?>
99
+ <option value=""><?php _e( 'No course found', 'tutor' ); ?></option>
100
+ <?php endif; ?>
101
+ </select>
102
+ </div>
103
+
104
+ <div class="tutor-form-group">
105
+ <label><?php _e( 'Sort By', 'tutor' ); ?></label>
106
+ <select class="tutor-announcement-order-sorting ignore-nice-select">
107
+ <option <?php selected( $order_filter, 'ASC' ); ?>><?php _e( 'ASC', 'tutor' ); ?></option>
108
+ <option <?php selected( $order_filter, 'DESC' ); ?>><?php _e( 'DESC', 'tutor' ); ?></option>
109
+ </select>
110
+ </div>
111
+
112
+ <div class="tutor-form-group tutor-announcement-datepicker">
113
+ <label><?php _e( 'Date', 'tutor' ); ?></label>
114
+ <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" id="tutor-announcement-datepicker" value="<?php echo '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" placeholder="<?php echo get_option( 'date_format' ); ?>" autocomplete="off" />
115
+ <i class="tutor-icon-calendar"></i>
116
+ </div>
117
  </div>
118
  <!--sorting end-->
119
  <div class="tutor-announcement-table-wrap">
120
+ <table class="tutor-dashboard-announcement-table" width="100%">
121
+ <thead>
122
+ <tr>
123
+ <th style="width:24%"><?php _e( 'Date', 'tutor' ); ?></th>
124
+ <th style="text-align:left"><?php _e( 'Announcements', 'tutor' ); ?></th>
125
+ </tr>
126
+ </thead>
127
+ <tbody>
128
+ <?php if ( $the_query->have_posts() ) : ?>
129
+ <?php foreach ( $the_query->posts as $post ) : ?>
130
+ <?php
131
+ $course = get_post( $post->post_parent );
132
+ $dateObj = date_create( $post->post_date );
133
+ $date_format = date_format( $dateObj, 'j M, Y,<\b\r>h:i a' );
134
+ ?>
135
+ <tr id="tutor-announcement-tr-<?php echo $post->ID; ?>">
136
+ <td class="tutor-announcement-date"><?php echo $date_format; ?></td>
137
+ <td class="tutor-announcement-content-wrap">
138
+ <div class="tutor-announcement-content">
139
+ <h4><?php echo esc_html( $post->post_title ); ?></h4>
140
+ <p><?php echo $course ? esc_attr( $course->post_title ) : ''; ?></p>
141
+ </div>
142
+ <div class="tutor-announcement-buttons">
143
+ <li>
144
+ <button type="button" course-name="<?php echo esc_attr( $course->post_title ); ?>" announcement-date="<?php echo esc_attr( $date_format ); ?>" announcement-title="<?php echo esc_attr( $post->post_title ); ?>" announcement-summary="<?php echo esc_attr( $post->post_content ); ?>" course-id="<?php echo $post->post_parent; ?>" announcement-id="<?php echo $post->ID; ?>" class="tutor-btn bordered-btn tutor-announcement-details">
145
+ <?php _e( 'Details', 'tutor' ); ?>
146
+ </button>
147
+ </li>
148
+ <li class="tutor-dropdown">
149
+ <i class="tutor-icon-action"></i>
150
+ <ul class="tutor-dropdown-menu">
151
+ <li announcement-title="<?php echo esc_attr( $post->post_title ); ?>" announcement-summary="<?php echo esc_attr( $post->post_content ); ?>" course-id="<?php echo $post->post_parent; ?>" announcement-id="<?php echo $post->ID; ?>" class="tutor-announcement-edit">
152
+ <i class="tutor-icon-pencil"></i>
153
+ <?php _e( 'Edit', 'tutor' ); ?>
154
+ </li>
155
+ <li class="tutor-announcement-delete" announcement-id="<?php echo $post->ID; ?>">
156
+ <i class="tutor-icon-garbage"></i>
157
+ <?php _e( 'Delete', 'tutor' ); ?>
158
+ </li>
159
+ </ul>
160
+ </li>
161
+ </div>
162
+ </td>
163
+ </tr>
164
+ <?php endforeach; ?>
165
+ <?php else : ?>
166
+ <tr>
167
+ <td colspan="2">
168
+ <?php _e( 'Announcements not found', 'tutor' ); ?>
169
+ </td>
170
+ </tr>
171
+ <?php endif; ?>
172
+ </tbody>
173
+ </table>
174
 
175
  </div>
176
 
177
  <!--pagination-->
178
  <div class="tutor-pagination">
179
+ <?php
180
+ $big = 999999999; // need an unlikely integer
181
+
182
+ echo paginate_links(
183
+ array(
184
+
185
+ 'format' => '?current_page=%#%',
186
+ 'current' => $paged,
187
+ 'total' => $the_query->max_num_pages,
188
+ )
189
+ );
190
+
191
+ ?>
192
  </div>
193
  <!--pagination end-->
194
 
195
  <?php
196
+ require 'announcements/create.php';
197
+ require 'announcements/update.php';
198
+ require 'announcements/details.php';
199
  ?>
templates/dashboard/announcements/create.php CHANGED
@@ -21,12 +21,12 @@
21
  <select class="ignore-nice-select" name="tutor_announcement_course" id="" required>
22
  <?php if ( $courses ) : ?>
23
  <?php foreach ( $courses as $course ) : ?>
24
- <option value="<?php echo esc_attr( $course->ID ) ?>">
25
  <?php echo esc_html( $course->post_title ); ?>
26
  </option>
27
  <?php endforeach; ?>
28
  <?php else : ?>
29
- <option value=""><?php echo esc_attr( 'No course found', 'tutor' ); ?></option>
30
  <?php endif; ?>
31
  </select>
32
  </div>
@@ -34,13 +34,13 @@
34
  <label>
35
  <?php esc_html_e( 'Announcement Title', 'tutor' ); ?>
36
  </label>
37
- <input type="text" name="tutor_announcement_title" value="" placeholder="<?php echo esc_attr( 'Announcement title', 'tutor' ); ?>" required>
38
  </div>
39
  <div class="tutor-form-group">
40
  <label for="tutor_announcement_course">
41
  <?php esc_html_e( 'Summary', 'tutor' ); ?>
42
  </label>
43
- <textarea rows="6" type="text" name="tutor_announcement_summary" value="" placeholder="<?php echo esc_attr( 'Summary...', 'tutor' ); ?>" required></textarea>
44
  </div>
45
 
46
  <?php do_action( 'tutor_announcement_editor/after' ); ?>
21
  <select class="ignore-nice-select" name="tutor_announcement_course" id="" required>
22
  <?php if ( $courses ) : ?>
23
  <?php foreach ( $courses as $course ) : ?>
24
+ <option value="<?php echo $course->ID; ?>">
25
  <?php echo esc_html( $course->post_title ); ?>
26
  </option>
27
  <?php endforeach; ?>
28
  <?php else : ?>
29
+ <option value=""><?php echo __( 'No course found', 'tutor' ); ?></option>
30
  <?php endif; ?>
31
  </select>
32
  </div>
34
  <label>
35
  <?php esc_html_e( 'Announcement Title', 'tutor' ); ?>
36
  </label>
37
+ <input type="text" name="tutor_announcement_title" value="" placeholder="<?php echo __( 'Announcement title', 'tutor' ); ?>" required>
38
  </div>
39
  <div class="tutor-form-group">
40
  <label for="tutor_announcement_course">
41
  <?php esc_html_e( 'Summary', 'tutor' ); ?>
42
  </label>
43
+ <textarea rows="6" type="text" name="tutor_announcement_summary" value="" placeholder="<?php echo __( 'Summary...', 'tutor' ); ?>" required></textarea>
44
  </div>
45
 
46
  <?php do_action( 'tutor_announcement_editor/after' ); ?>
templates/dashboard/announcements/update.php CHANGED
@@ -22,7 +22,7 @@
22
  <select class="ignore-nice-select" name="tutor_announcement_course" id="tutor-announcement-course-id" required>
23
  <?php if ( $courses ) : ?>
24
  <?php foreach ( $courses as $course ) : ?>
25
- <option value="<?php echo esc_attr( $course->ID ) ?>">
26
  <?php echo esc_html( $course->post_title ); ?>
27
  </option>
28
  <?php endforeach; ?>
22
  <select class="ignore-nice-select" name="tutor_announcement_course" id="tutor-announcement-course-id" required>
23
  <?php if ( $courses ) : ?>
24
  <?php foreach ( $courses as $course ) : ?>
25
+ <option value="<?php echo $course->ID; ?>">
26
  <?php echo esc_html( $course->post_title ); ?>
27
  </option>
28
  <?php endforeach; ?>
templates/dashboard/assignments.php CHANGED
@@ -14,110 +14,119 @@
14
 
15
  global $wpdb;
16
 
17
- $per_page = 10;
18
- $current_page = max(1, tutor_utils()->avalue_dot('current_page', $_GET));
19
- $offset = ($current_page - 1) * $per_page;
20
 
21
- $course_id = isset($_GET['course-id']) ? sanitize_text_field($_GET['course-id']) : '';
22
- $order_filter = isset($_GET['order']) ? $_GET['order'] : 'DESC';
23
- $date_filter = isset($_GET['date']) ? $_GET['date'] : '';
24
 
25
- $current_user = get_current_user_id();
26
- $assignments = tutor_utils()->get_assignments_by_instructor(null, compact('course_id', 'order_filter', 'date_filter', 'per_page', 'offset'));
27
- $courses = (current_user_can('administrator')) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
28
 
29
  ?>
30
 
31
  <div class="tutor-dashboard-announcement-sorting-wrap">
32
- <div class="tutor-form-group">
33
- <label for="">
34
- <?php _e('Courses', 'tutor'); ?>
35
- </label>
36
- <select class="tutor-report-category tutor-announcement-course-sorting ignore-nice-select">
37
-
38
- <option value=""><?php _e('All', 'tutor'); ?></option>
39
-
40
- <?php if ($courses) : ?>
41
- <?php foreach ($courses as $course) : ?>
42
- <option value="<?php echo esc_attr($course->ID) ?>" <?php selected($course_id, $course->ID, 'selected') ?>>
43
- <?php echo $course->post_title; ?>
44
- </option>
45
- <?php endforeach; ?>
46
- <?php else : ?>
47
- <option value=""><?php _e('No course found', 'tutor'); ?></option>
48
- <?php endif; ?>
49
- </select>
50
- </div>
51
- <div class="tutor-form-group">
52
- <label><?php _e('Sort By', 'tutor'); ?></label>
53
- <select class="tutor-announcement-order-sorting ignore-nice-select">
54
- <option <?php selected($order_filter, 'ASC'); ?>><?php _e('ASC', 'tutor'); ?></option>
55
- <option <?php selected($order_filter, 'DESC'); ?>><?php _e('DESC', 'tutor'); ?></option>
56
- </select>
57
- </div>
58
- <div class="tutor-form-group tutor-announcement-datepicker">
59
- <label><?php _e('Create Date', 'tutor'); ?></label>
60
- <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" value="<?php echo $date_filter !== '' ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" placeholder="<?php echo get_option( 'date_format' ); ?>" autocomplete="off" />
61
- <i class="tutor-icon-calendar"></i>
62
- </div>
63
  </div>
64
 
65
  <?php
66
 
67
- if ($assignments->count) { ?>
68
-
69
- <div class="tutor-announcement-table-wrap">
70
- <table class="tutor-dashboard-announcement-table" width="100%">
71
- <thead>
72
- <tr>
73
- <th><?php _e('Course Name', 'tutor') ?></th>
74
- <th width="15%"><?php _e('Total Points', 'tutor') ?></th>
75
- <th width="15%"><?php _e('Total Submits', 'tutor') ?></th>
76
- <th width="10%">&nbsp;</th>
77
- </tr>
78
- </thead>
79
- <tbody>
80
- <?php
81
-
82
- $submitted_url = tutor_utils()->get_tutor_dashboard_page_permalink('assignments/submitted');
83
-
84
- foreach ($assignments->results as $item) {
85
- $max_mark = tutor_utils()->get_assignment_option($item->ID, 'total_mark');
86
- $course_id = tutor_utils()->get_course_id_by('assignment', $item->ID);
87
- $comment_count = $wpdb->get_var($wpdb->prepare("SELECT COUNT(comment_ID) FROM {$wpdb->comments} WHERE comment_type = 'tutor_assignment' AND comment_post_ID = %d", $item->ID));
88
- // @TODO: assign post_meta is empty if user don't click on update button (http://prntscr.com/oax4t8) but post status is publish
89
- ?>
90
- <tr>
91
- <td>
92
- <h4><?php echo esc_html($item->post_title); ?></h4>
93
- <p><?php echo __('Course: ', 'tutor'); ?><a href='<?php echo get_the_permalink($course_id) ?>' target="_blank"><?php echo get_the_title($course_id); ?> </a></p>
94
- </td>
95
- <td><?php echo $max_mark ?></td>
96
- <td><?php echo $comment_count ?></td>
97
- <td>
98
- <a href="<?php echo esc_url($submitted_url . '?assignment=' . $item->ID); ?>" class="tutor-btn bordered-btn tutor-announcement-details">
99
- <?php _e('Details', 'tutor'); ?>
100
- </a>
101
- </td>
102
- </tr>
103
- <?php
104
- }
105
- ?>
106
- </tbody>
107
- </table>
108
- </div>
109
-
110
- <div class="tutor-pagination">
111
- <?php
112
-
113
- echo paginate_links(array(
114
- 'format' => '?current_page=%#%',
115
- 'current' => $current_page,
116
- 'total' => ceil($assignments->count / $per_page)
117
- ));
118
- ?>
119
- </div>
120
-
121
- <?php } else {
122
- echo '<p>' . __('No assignment available', 'tutor') . '</p>';
14
 
15
  global $wpdb;
16
 
17
+ $per_page = 10;
18
+ $current_page = max( 1, tutor_utils()->avalue_dot( 'current_page', tutor_sanitize_data($_GET) ) );
19
+ $offset = ( $current_page - 1 ) * $per_page;
20
 
21
+ $course_id = isset( $_GET['course-id'] ) ? sanitize_text_field( $_GET['course-id'] ) : '';
22
+ $order_filter = isset( $_GET['order'] ) ? $_GET['order'] : 'DESC';
23
+ $date_filter = isset( $_GET['date'] ) ? $_GET['date'] : '';
24
 
25
+ $current_user = get_current_user_id();
26
+ $assignments = tutor_utils()->get_assignments_by_instructor( null, compact( 'course_id', 'order_filter', 'date_filter', 'per_page', 'offset' ) );
27
+ $courses = ( current_user_can( 'administrator' ) ) ? tutils()->get_courses() : tutils()->get_courses_by_instructor();
28
 
29
  ?>
30
 
31
  <div class="tutor-dashboard-announcement-sorting-wrap">
32
+ <div class="tutor-form-group">
33
+ <label for="">
34
+ <?php _e( 'Courses', 'tutor' ); ?>
35
+ </label>
36
+ <select class="tutor-report-category tutor-announcement-course-sorting ignore-nice-select">
37
+
38
+ <option value=""><?php _e( 'All', 'tutor' ); ?></option>
39
+
40
+ <?php if ( $courses ) : ?>
41
+ <?php foreach ( $courses as $course ) : ?>
42
+ <option value="<?php echo $course->ID; ?>" <?php selected( $course_id, $course->ID, 'selected' ); ?>>
43
+ <?php echo $course->post_title; ?>
44
+ </option>
45
+ <?php endforeach; ?>
46
+ <?php else : ?>
47
+ <option value=""><?php _e( 'No course found', 'tutor' ); ?></option>
48
+ <?php endif; ?>
49
+ </select>
50
+ </div>
51
+ <div class="tutor-form-group">
52
+ <label><?php _e( 'Sort By', 'tutor' ); ?></label>
53
+ <select class="tutor-announcement-order-sorting ignore-nice-select">
54
+ <option <?php selected( $order_filter, 'ASC' ); ?>><?php _e( 'ASC', 'tutor' ); ?></option>
55
+ <option <?php selected( $order_filter, 'DESC' ); ?>><?php _e( 'DESC', 'tutor' ); ?></option>
56
+ </select>
57
+ </div>
58
+ <div class="tutor-form-group tutor-announcement-datepicker">
59
+ <label><?php _e( 'Create Date', 'tutor' ); ?></label>
60
+ <input type="text" class="tutor_date_picker tutor-announcement-date-sorting" value="<?php echo '' !== $date_filter ? tutor_get_formated_date( get_option( 'date_format' ), $date_filter ) : ''; ?>" placeholder="<?php echo get_option( 'date_format' ); ?>" autocomplete="off" />
61
+ <i class="tutor-icon-calendar"></i>
62
+ </div>
63
  </div>
64
 
65
  <?php
66
 
67
+ if ( $assignments->count ) {
68
+ ?>
69
+
70
+ <div class="tutor-announcement-table-wrap">
71
+ <table class="tutor-dashboard-announcement-table" width="100%">
72
+ <thead>
73
+ <tr>
74
+ <th><?php _e( 'Course Name', 'tutor' ); ?></th>
75
+ <th width="15%"><?php _e( 'Total Points', 'tutor' ); ?></th>
76
+ <th width="15%"><?php _e( 'Total Submits', 'tutor' ); ?></th>
77
+ <th width="10%">&nbsp;</th>
78
+ </tr>
79
+ </thead>
80
+ <tbody>
81
+ <?php
82
+
83
+ $submitted_url = tutor_utils()->get_tutor_dashboard_page_permalink( 'assignments/submitted' );
84
+
85
+ foreach ( $assignments->results as $item ) {
86
+ $max_mark = tutor_utils()->get_assignment_option( $item->ID, 'total_mark' );
87
+ $course_id = tutor_utils()->get_course_id_by( 'assignment', $item->ID );
88
+ $comment_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM {$wpdb->comments} WHERE comment_type = 'tutor_assignment' AND comment_post_ID = %d", $item->ID ) );
89
+ // @TODO: assi