PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.6.2
Tutor LMS – eLearning and online course solution v1.6.2
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Course.php
tutor / classes Last commit date
Addons.php 6 years ago Admin.php 6 years ago Ajax.php 6 years ago Assets.php 6 years ago Course.php 6 years ago Course_Settings_Tabs.php 6 years ago Course_Widget.php 6 years ago Dashboard.php 6 years ago Email.php 6 years ago FormHandler.php 6 years ago Frontend.php 6 years ago Gutenberg.php 6 years ago Instructor.php 6 years ago Instructors_List.php 6 years ago Lesson.php 6 years ago Options.php 6 years ago Post_types.php 6 years ago Q_and_A.php 6 years ago Question_Answers_List.php 6 years ago Quiz.php 6 years ago Quiz_Attempts_List.php 6 years ago RestAPI.php 6 years ago Rewrite_Rules.php 6 years ago Shortcode.php 6 years ago Student.php 6 years ago Students_List.php 6 years ago Taxonomies.php 6 years ago Template.php 6 years ago Theme_Compatibility.php 6 years ago Tools.php 6 years ago Tutor.php 6 years ago TutorEDD.php 6 years ago Tutor_Base.php 6 years ago Tutor_List_Table.php 6 years ago Tutor_Setup.php 6 years ago Upgrader.php 6 years ago User.php 6 years ago Utils.php 6 years ago Video_Stream.php 6 years ago Withdraw.php 6 years ago Withdraw_Requests_List.php 6 years ago WooCommerce.php 6 years ago
Course.php
1109 lines
1 <?php
2 namespace TUTOR;
3
4 if ( ! defined( 'ABSPATH' ) )
5 exit;
6
7 class Course 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->course_post_type, array($this, 'save_course_meta'), 10, 2);
13 add_action('wp_ajax_tutor_add_course_topic', array($this, 'tutor_add_course_topic'));
14 add_action('wp_ajax_tutor_update_topic', array($this, 'tutor_update_topic'));
15
16 //Add Column
17 add_filter( "manage_{$this->course_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
18 add_action( "manage_{$this->course_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
19
20 add_action('admin_action_tutor_delete_topic', array($this, 'tutor_delete_topic'));
21 add_action('admin_action_tutor_delete_announcement', array($this, 'tutor_delete_announcement'));
22
23 //Frontend Action
24 add_action('template_redirect', array($this, 'enroll_now'));
25 add_action('template_redirect', array($this, 'mark_course_complete'));
26
27 //Modal Perform
28 add_action('wp_ajax_tutor_load_instructors_modal', array($this, 'tutor_load_instructors_modal'));
29 add_action('wp_ajax_tutor_add_instructors_to_course', array($this, 'tutor_add_instructors_to_course'));
30 add_action('wp_ajax_detach_instructor_from_course', array($this, 'detach_instructor_from_course'));
31
32 /**
33 * Frontend Dashboard
34 */
35 add_action('wp_ajax_tutor_delete_dashboard_course', array($this, 'tutor_delete_dashboard_course'));
36
37 /**
38 * Gutenberg author support
39 */
40 add_filter('wp_insert_post_data', array($this, 'tutor_add_gutenberg_author'), '99', 2);
41
42 /**
43 * Frontend metabox supports for course builder
44 * @since v.1.3.4
45 */
46 add_action('tutor/dashboard_course_builder_form_field_after', array($this, 'register_meta_box_in_frontend'));
47
48
49 /**
50 * Do Stuff for the course save from frontend
51 */
52 add_action('save_tutor_course', array($this, 'attach_product_with_course'), 10, 2);
53
54 /**
55 * Add course level to course settings
56 * @since v.1.4.1
57 */
58 add_action('tutor_course/settings_tab_content/after/general', array($this, 'add_course_level_to_settings'));
59
60 /**
61 * Enable Disable Course Details Page Feature
62 * @since v.1.4.8
63 */
64 $this->course_elements_enable_disable();
65
66 /**
67 * @since v.1.4.8
68 * Check if course starting, set meta if starting
69 */
70 add_action('tutor_lesson_load_before', array($this, 'tutor_lesson_load_before'));
71
72 /**
73 * @since v.1.4.9
74 * Filter product in shop page
75 */
76 $this->filter_product_in_shop_page();
77
78 /**
79 * Remove the course price if enrolled
80 * @since 1.5.8
81 */
82 add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
83
84
85 /**
86 * Remove course complete button if course completion is strict mode
87 * @since v.1.6.1
88 */
89 add_filter('tutor_course/single/complete_form', array($this, 'tutor_lms_hide_course_complete_btn'));
90 add_filter('get_gradebook_generate_form_html', array($this, 'get_generate_greadbook'));
91 }
92
93 /**
94 * Registering metabox
95 */
96 public function register_meta_box(){
97 $coursePostType = tutor()->course_post_type;
98 $course_marketplace = tutor_utils()->get_option('enable_course_marketplace');
99 //add_meta_box( 'tutor-course-levels', __( 'Course Level', 'tutor' ), array($this, 'course_level_metabox'), $coursePostType );
100 add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
101 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
102 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
103 if ($course_marketplace) {
104 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
105 }
106 add_meta_box( 'tutor-announcements', __( 'Announcements', 'tutor' ), array($this, 'announcements_metabox'), $coursePostType );
107 }
108
109 public function course_meta_box($echo = true){
110 ob_start();
111 include tutor()->path.'views/metabox/course-topics.php';
112 $content = ob_get_clean();
113
114 if ($echo){
115 echo $content;
116 }else{
117 return $content;
118 }
119 }
120
121 public function course_additional_data_meta_box($echo = true){
122
123 ob_start();
124 include tutor()->path.'views/metabox/course-additional-data.php';
125 $content = ob_get_clean();
126
127 if ($echo){
128 echo $content;
129 }else{
130 return $content;
131 }
132 }
133
134 public function video_metabox($echo = true){
135 ob_start();
136 include tutor()->path.'views/metabox/video-metabox.php';
137 $content = ob_get_clean();
138
139 if ($echo){
140 echo $content;
141 }else{
142 return $content;
143 }
144 }
145
146 public function course_level_metabox($echo = true){
147 ob_start();
148 include tutor()->path.'views/metabox/course-level-metabox.php';
149 $content = ob_get_clean();
150
151 if ($echo){
152 echo $content;
153 }else{
154 return $content;
155 }
156 }
157
158 public function announcements_metabox($echo = true){
159 ob_start();
160 include tutor()->path.'views/metabox/announcements-metabox.php';
161 $content = ob_get_clean();
162
163 if ($echo){
164 echo $content;
165 }else{
166 return $content;
167 }
168 }
169
170 public function instructors_metabox($echo = true){
171 ob_start();
172 include tutor()->path . 'views/metabox/instructors-metabox.php';
173 $content = ob_get_clean();
174
175 if ($echo){
176 echo $content;
177 }else{
178 return $content;
179 }
180 }
181
182 /**
183 * Register metabox in course builder tutor
184 * @since v.1.3.4
185 */
186 public function register_meta_box_in_frontend(){
187 do_action('tutor_course_builder_metabox_before', get_the_ID());
188 course_builder_section_wrap($this->video_metabox($echo = false), 'Video');
189 course_builder_section_wrap($this->course_meta_box($echo = false), 'Course Builder');
190 course_builder_section_wrap($this->instructors_metabox($echo = false), 'Instructors');
191 course_builder_section_wrap($this->course_additional_data_meta_box($echo = false), 'Additional Data');
192 course_builder_section_wrap($this->announcements_metabox($echo = false), 'Announcements');
193 do_action('tutor_course_builder_metabox_after', get_the_ID());
194 }
195
196 /**
197 * @param $post_ID
198 *
199 * Insert Topic and attached it with Course
200 */
201 public function save_course_meta($post_ID, $post){
202 global $wpdb;
203
204 do_action( "tutor_save_course", $post_ID, $post);
205
206 /**
207 * Insert Topic
208 */
209 /*
210 if ( ! empty($_POST['topic_title'])) {
211 $topic_title = sanitize_text_field( $_POST['topic_title'] );
212 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
213
214 $post_arr = array(
215 'post_type' => 'topics',
216 'post_title' => $topic_title,
217 'post_content' => $topic_summery,
218 'post_status' => 'publish',
219 'post_author' => get_current_user_id(),
220 'post_parent' => $post_ID,
221 );
222 wp_insert_post( $post_arr );
223 }*/
224
225 /**
226 * Save course price type
227 */
228 $price_type = tutils()->array_get('tutor_course_price_type', $_POST);
229 if ($price_type){
230 update_post_meta($post_ID, '_tutor_course_price_type', $price_type);
231 }
232
233 //Course Duration
234 if ( ! empty($_POST['course_duration'])){
235 $video = tutor_utils()->sanitize_array($_POST['course_duration']);
236 update_post_meta($post_ID, '_course_duration', $video);
237 }
238
239 if ( ! empty($_POST['course_level'])){
240 $course_level = sanitize_text_field($_POST['course_level']);
241 update_post_meta($post_ID, '_tutor_course_level', $course_level);
242 }
243
244 if ( ! empty($_POST['course_benefits'])){
245 $course_benefits = wp_kses_post($_POST['course_benefits']);
246 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
247 }else{
248 delete_post_meta($post_ID, '_tutor_course_benefits');
249 }
250
251 if ( ! empty($_POST['course_requirements'])){
252 $requirements = wp_kses_post($_POST['course_requirements']);
253 update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
254 }else{
255 delete_post_meta($post_ID, '_tutor_course_requirements');
256 }
257
258 if ( ! empty($_POST['course_target_audience'])){
259 $target_audience = wp_kses_post($_POST['course_target_audience']);
260 update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
261 }else{
262 delete_post_meta($post_ID, '_tutor_course_target_audience');
263 }
264
265 if ( ! empty($_POST['course_material_includes'])){
266 $material_includes = wp_kses_post($_POST['course_material_includes']);
267 update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
268 }else{
269 delete_post_meta($post_ID, '_tutor_course_material_includes');
270 }
271
272
273 /**
274 * Sorting Topics and lesson
275 */
276 if ( ! empty($_POST['tutor_topics_lessons_sorting'])){
277 $new_order = sanitize_text_field(stripslashes($_POST['tutor_topics_lessons_sorting']));
278 $order = json_decode($new_order, true);
279
280 if (is_array($order) && count($order)){
281 $i = 0;
282 foreach ($order as $topic ){
283 $i++;
284 $wpdb->update(
285 $wpdb->posts,
286 array('menu_order' => $i),
287 array('ID' => $topic['topic_id'])
288 );
289
290 /**
291 * Removing All lesson with topic
292 */
293
294 $wpdb->update(
295 $wpdb->posts,
296 array('post_parent' => 0),
297 array('post_parent' => $topic['topic_id'])
298 );
299
300 /**
301 * Lesson Attaching with topic ID
302 * sorting lesson
303 */
304 if (isset($topic['lesson_ids'])){
305 $lesson_ids = $topic['lesson_ids'];
306 }else{
307 $lesson_ids = array();
308 }
309 if (count($lesson_ids)){
310 foreach ($lesson_ids as $lesson_key => $lesson_id ){
311 $wpdb->update(
312 $wpdb->posts,
313 array('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
314 array('ID' => $lesson_id)
315 );
316 }
317 }
318 }
319 }
320 }
321
322 //Video
323 if ( ! empty($_POST['video']['source'])){
324 //$video = tutor_utils()->sanitize_array($_POST['video']);
325 $video = tutor_utils()->array_get('video', $_POST);
326 update_post_meta($post_ID, '_video', $video);
327 }else{
328 delete_post_meta($post_ID, '_video');
329 }
330
331 /**
332 * Adding author to instructor automatically
333 */
334
335 $author_id = $post->post_author;
336 $attached = (int) $wpdb->get_var(" SELECT COUNT(umeta_id) FROM {$wpdb->usermeta} WHERE user_id = {$author_id} AND meta_key = '_tutor_instructor_course_id' AND meta_value = {$post_ID} ");
337 if ( ! $attached){
338 add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
339 }
340
341 //Announcements
342 if ( ! wp_doing_ajax()) {
343 $announcement_title = tutor_utils()->avalue_dot( 'announcements.title', $_POST );
344 if ( ! empty( $announcement_title ) ) {
345 $title = sanitize_text_field( tutor_utils()->avalue_dot( 'announcements.title', $_POST ) );
346 $content = wp_kses_post( tutor_utils()->avalue_dot( 'announcements.content', $_POST ) );
347
348 $post_arr = array(
349 'post_type' => 'tutor_announcements',
350 'post_title' => $title,
351 'post_content' => $content,
352 'post_status' => 'publish',
353 'post_author' => get_current_user_id(),
354 'post_parent' => $post_ID,
355 );
356 wp_insert_post( $post_arr );
357 }
358 }
359
360 do_action( "tutor_save_course_after", $post_ID, $post);
361 }
362
363 /**
364 * Tutor add course topic
365 */
366 public function tutor_add_course_topic(){
367 if (empty($_POST['topic_title']) ) {
368 wp_send_json_error();
369 }
370 $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
371 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
372
373 $topic_title = sanitize_text_field( $_POST['topic_title'] );
374 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
375
376 $post_arr = array(
377 'post_type' => 'topics',
378 'post_title' => $topic_title,
379 'post_content' => $topic_summery,
380 'post_status' => 'publish',
381 'post_author' => get_current_user_id(),
382 'post_parent' => $course_id,
383 'menu_order' => $next_topic_order_id,
384 );
385 $current_topic_id = wp_insert_post( $post_arr );
386
387 ob_start();
388 include tutor()->path.'views/metabox/course-contents.php';
389 $course_contents = ob_get_clean();
390
391 wp_send_json_success(array('course_contents' => $course_contents));
392 }
393
394 /**
395 * Update the topic
396 */
397 public function tutor_update_topic(){
398 $topic_id = (int) sanitize_text_field($_POST['topic_id']);
399 $topic_title = sanitize_text_field($_POST['topic_title']);
400 $topic_summery = wp_kses_post($_POST['topic_summery']);
401
402 $topic_attr = array(
403 'ID' => $topic_id,
404 'post_title' => $topic_title,
405 'post_content' => $topic_summery,
406 );
407 wp_update_post( $topic_attr );
408
409 wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
410 }
411
412
413 /**
414 * @param $columns
415 *
416 * @return mixed
417 *
418 * Add Lesson column
419 */
420 public function add_column($columns){
421 $date_col = $columns['date'];
422 unset($columns['date']);
423 $columns['lessons'] = __('Lessons', 'tutor');
424 $columns['students'] = __('Students', 'tutor');
425 $columns['price'] = __('Price', 'tutor');
426 $columns['date'] = $date_col;
427
428 return $columns;
429 }
430
431 /**
432 * @param $column
433 * @param $post_id
434 *
435 */
436 public function custom_lesson_column($column, $post_id ){
437 if ($column === 'lessons'){
438 echo tutor_utils()->get_lesson_count_by_course($post_id);
439 }
440
441 if ($column === 'students'){
442 echo tutor_utils()->count_enrolled_users_by_course($post_id);
443 }
444
445 if ($column === 'price'){
446 $price = tutor_utils()->get_course_price($post_id);
447 if ($price){
448 $monetize_by = tutils()->get_option('monetize_by');
449 if (function_exists('wc_price') && $monetize_by === 'wc'){
450 echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
451 }else{
452 echo '<span class="tutor-label-success">'.$price.'</span>';
453 }
454 }else{
455 echo 'free';
456 }
457 }
458 }
459
460
461 public function tutor_delete_topic(){
462 if (!isset($_GET[tutor()->nonce]) || !wp_verify_nonce($_GET[tutor()->nonce], tutor()->nonce_action)) {
463 exit();
464 }
465 if ( ! isset($_GET['topic_id'])){
466 exit();
467 }
468
469 global $wpdb;
470
471 $topic_id = (int) sanitize_text_field($_GET['topic_id']);
472 $wpdb->update(
473 $wpdb->posts,
474 array('post_parent' => 0),
475 array('post_parent' => $topic_id)
476 );
477
478 $wpdb->delete(
479 $wpdb->postmeta,
480 array('post_id' => $topic_id)
481 );
482
483 wp_delete_post($topic_id);
484 wp_safe_redirect(wp_get_referer());
485 }
486
487 public function tutor_delete_announcement(){
488 tutor_utils()->checking_nonce('get');
489
490 $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
491
492 wp_delete_post($announcement_id);
493 wp_safe_redirect(wp_get_referer());
494 }
495
496 public function enroll_now(){
497
498 //Checking if action comes from Enroll form
499 if (tutor_utils()->array_get('tutor_course_action', $_POST) !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
500 return;
501 }
502 //Checking Nonce
503 tutor_utils()->checking_nonce();
504
505 $user_id = get_current_user_id();
506 if ( ! $user_id){
507 exit(__('Please Sign In first', 'tutor'));
508 }
509
510 $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
511 $user_id = get_current_user_id();
512
513 /**
514 * TODO: need to check purchase information
515 */
516
517 $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
518
519 /**
520 * If is is not purchasable, it's free, and enroll right now
521 *
522 * if purchasable, then process purchase.
523 *
524 * @since: v.1.0.0
525 */
526 if ($is_purchasable){
527 //process purchase
528
529 }else{
530 //Free enroll
531 tutor_utils()->do_enroll($course_id);
532 }
533
534 $referer_url = wp_get_referer();
535 wp_redirect($referer_url);
536 }
537
538 /**
539 *
540 * Mark complete completed
541 *
542 * @since v.1.0.0
543 */
544 public function mark_course_complete(){
545 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
546 return;
547 }
548 //Checking nonce
549 tutor_utils()->checking_nonce();
550
551 $user_id = get_current_user_id();
552
553 //TODO: need to show view if not signed_in
554 if ( ! $user_id){
555 die(__('Please Sign-In', 'tutor'));
556 }
557
558 $course_id = (int) sanitize_text_field($_POST['course_id']);
559
560 do_action('tutor_course_complete_before', $course_id);
561 /**
562 * Marking course completed at Comment
563 */
564
565 global $wpdb;
566
567 $date = date("Y-m-d H:i:s", tutor_time());
568
569 //Making sure that, hash is unique
570 do{
571 $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
572 $hasHash = (int) $wpdb->get_var("SELECT COUNT(comment_ID) from {$wpdb->comments} WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = '{$hash}' ");
573 }while($hasHash > 0);
574
575 $data = array(
576 'comment_post_ID' => $course_id,
577 'comment_author' => $user_id,
578 'comment_date' => $date,
579 'comment_date_gmt' => get_gmt_from_date($date),
580 'comment_content' => $hash, //Identification Hash
581 'comment_approved' => 'approved',
582 'comment_agent' => 'TutorLMSPlugin',
583 'comment_type' => 'course_completed',
584 'user_id' => $user_id,
585 );
586
587 $wpdb->insert($wpdb->comments, $data);
588
589 do_action('tutor_course_complete_after', $course_id);
590
591 wp_redirect(get_the_permalink($course_id));
592 }
593
594
595 public function tutor_load_instructors_modal(){
596 global $wpdb;
597
598 $course_id = (int) sanitize_text_field($_POST['course_id']);
599 $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
600
601 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
602
603 $instructors = array();
604
605
606 $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
607
608 if ($saved_instructors){
609 $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
610 $instructor_not_in_ids = implode(',', $saved_instructors_ids);
611 $not_in_sql .= "AND ID NOT IN($instructor_not_in_ids) ";
612 }
613
614 $search_sql = '';
615 if ($search_terms){
616 $search_sql = "AND (user_login like '%{$search_terms}%' or user_nicename like '%{$search_terms}%' or display_name like '%{$search_terms}%') ";
617 }
618
619 $instructors = $wpdb->get_results("select ID, display_name from {$wpdb->users}
620 INNER JOIN {$wpdb->usermeta} ON ID = user_id AND meta_key = '_tutor_instructor_status' AND meta_value = 'approved'
621 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
622
623 $output = '';
624 if (is_array($instructors) && count($instructors)){
625 $instructor_output = '';
626 foreach ($instructors as $instructor){
627 $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
628 }
629
630 $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
631
632 }else{
633 $output .= __('<p>No instructor available or you have already added maximum instructors</p>', 'tutor');
634 }
635
636
637 if ( ! defined('TUTOR_MT_VERSION')){
638 $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>';
639 }
640
641 wp_send_json_success(array('output' => $output));
642 }
643
644 public function tutor_add_instructors_to_course(){
645 $course_id = (int) sanitize_text_field($_POST['course_id']);
646 $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
647
648 if (is_array($instructor_ids) && count($instructor_ids)){
649 foreach ($instructor_ids as $instructor_id){
650 add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
651 }
652 }
653
654 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
655 $output = '';
656
657 if ($saved_instructors){
658 foreach ($saved_instructors as $t){
659
660 $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
661 <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
662 <span class="instructor-name"> '.$t->display_name.' </span>
663 <span class="instructor-control">
664 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
665 </span>
666 </div>';
667 }
668 }
669
670 wp_send_json_success(array('output' => $output));
671 }
672
673 public function detach_instructor_from_course(){
674 global $wpdb;
675
676 $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
677 $course_id = (int) sanitize_text_field($_POST['course_id']);
678
679 $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
680 wp_send_json_success();
681 }
682
683 public function tutor_delete_dashboard_course(){
684 $course_id = intval(sanitize_text_field($_POST['course_id']));
685 wp_trash_post($course_id);
686 wp_send_json_success();
687 }
688
689
690 public function tutor_add_gutenberg_author($data , $postarr){
691 global $wpdb;
692
693 $courses_post_type = tutor()->course_post_type;
694 $post_type = tutils()->array_get('post_type', $postarr);
695
696 /*
697 $post_author = (int) tutor_utils()->avalue_dot('post_author', $data);
698
699 if ( ! $post_author){
700 $user_ID = (int) tutor_utils()->avalue_dot('user_ID', $postarr);
701 if ($user_ID){
702 $data['post_author'] = $user_ID;
703 }else{
704 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
705 $post_author = (int) $wpdb->get_var("SELECT post_author FROM {$wpdb->posts} WHERE ID = {$post_ID} ");
706
707 $data['post_author'] = $post_author;
708 }
709 }*/
710
711 if ($courses_post_type === $post_type){
712 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
713 $post_author = (int) $wpdb->get_var("SELECT post_author FROM {$wpdb->posts} WHERE ID = {$post_ID} ");
714
715 if ($post_author > 0){
716 $data['post_author'] = $post_author;
717 }else{
718 $data['post_author'] = get_current_user_id();
719 }
720 }
721
722 return $data;
723 }
724
725
726 /**
727 * @param $post_ID
728 * @param $postData
729 *
730 * Attach product during save course from the frontend course dashboard.
731 *
732 * @return string
733 *
734 * @since v.1.3.4
735 */
736 public function attach_product_with_course($post_ID, $postData){
737 $attached_product_id = tutor_utils()->get_course_product_id($post_ID);
738 $course_price = sanitize_text_field(tutor_utils()->array_get('course_price', $_POST));
739
740 if ( ! $course_price){
741 return;
742 }
743
744 $monetize_by = tutor_utils()->get_option('monetize_by');
745 $course = get_post($post_ID);
746
747 if ($monetize_by === 'wc'){
748
749 $is_update = false;
750 if ($attached_product_id){
751 $wc_product = get_post_meta($attached_product_id, '_product_version', true);
752 if ($wc_product){
753 $is_update = true;
754 }
755 }
756
757 if ($is_update){
758
759 $productObj = new \WC_Product($attached_product_id);
760 $productObj->set_price($course_price); // set product price
761 $productObj->set_regular_price($course_price); // set product regular price
762 $product_id = $productObj->save();
763
764 }else{
765
766 $productObj = new \WC_Product();
767 $productObj->set_name($course->post_title);
768 $productObj->set_status('publish');
769 $productObj->set_price($course_price); // set product price
770 $productObj->set_regular_price($course_price); // set product regular price
771
772 $product_id = $productObj->save();
773 if ($product_id) {
774 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
775 //Mark product for woocommerce
776 update_post_meta( $product_id, '_virtual', 'yes' );
777 update_post_meta( $product_id, '_tutor_product', 'yes' );
778
779 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
780 if ( $coursePostThumbnail ) {
781 set_post_thumbnail( $product_id, $coursePostThumbnail );
782 }
783 }
784 }
785
786 }elseif ($monetize_by === 'edd'){
787
788 $is_update = false;
789
790 if ($attached_product_id){
791 $edd_price = get_post_meta($attached_product_id, 'edd_price', true);
792 if ($edd_price){
793 $is_update = true;
794 }
795 }
796
797 if ($is_update){
798 //Update the product
799 update_post_meta( $attached_product_id, 'edd_price', $course_price );
800 }else{
801 //Create new product
802
803 $post_arr = array(
804 'post_type' => 'download',
805 'post_title' => $course->post_title,
806 'post_status' => 'publish',
807 'post_author' => get_current_user_id(),
808 );
809 $download_id = wp_insert_post( $post_arr );
810 if ($download_id ) {
811 //edd_price
812 update_post_meta( $download_id, 'edd_price', $course_price );
813
814 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
815 //Mark product for EDD
816 update_post_meta( $download_id, '_tutor_product', 'yes' );
817
818 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
819 if ( $coursePostThumbnail ) {
820 set_post_thumbnail( $download_id, $coursePostThumbnail );
821 }
822
823 }
824
825 }
826
827
828 }
829
830 }
831
832
833 /**
834 * Add Course level to course settings
835 * @since v.1.4.1
836 */
837 public function add_course_level_to_settings(){
838 include tutor()->path.'views/metabox/course-level-metabox.php';
839 }
840
841 /**
842 * Check if course starting
843 *
844 * @since v.1.4.8
845 */
846 public function tutor_lesson_load_before(){
847 $course_id = tutils()->get_course_id_by_content(get_the_ID());
848 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
849 if (is_user_logged_in()){
850 $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
851 if ( ! $completed_lessons && ! $is_course_started){
852 update_post_meta($course_id, '_tutor_course_started', tutor_time());
853 do_action('tutor/course/started', $course_id);
854 }
855 }
856 }
857
858 /**
859 * Add Course level to course settings
860 * @since v.1.4.8
861 */
862 public function course_elements_enable_disable(){
863 add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
864 add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
865 add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
866 add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
867 add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
868 add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
869 add_filter('tutor_course/single/enrolled/nav_items', array($this, 'enable_disable_course_nav_items') );
870 }
871
872 /**
873 * Enable disable course progress bar
874 * @since v.1.4.8
875 */
876 public function enable_disable_course_progress_bar($html){
877 $disable_option = (bool) get_tutor_option('disable_course_progress_bar');
878 if($disable_option){
879 return '';
880 }
881 return $html;
882 }
883
884 /**
885 * Enable disable material includes
886 * @since v.1.4.8
887 */
888 public function enable_disable_material_includes($html){
889 $disable_option = (bool) get_tutor_option('disable_course_material');
890 if($disable_option){
891 return '';
892 }
893 return $html;
894 }
895
896 /**
897 * Enable disable course content
898 * @since v.1.4.8
899 */
900 public function enable_disable_course_content($html){
901 $disable_option = (bool) get_tutor_option('disable_course_description');
902 if($disable_option){
903 return '';
904 }
905 return $html;
906 }
907
908 /**
909 * Enable disable course benefits
910 * @since v.1.4.8
911 */
912 public function enable_disable_course_benefits($html){
913 $disable_option = (bool) get_tutor_option('disable_course_benefits');
914 if($disable_option){
915 return '';
916 }
917 return $html;
918 }
919
920 /**
921 * Enable disable course requirements
922 * @since v.1.4.8
923 */
924 public function enable_disable_course_requirements($html){
925 $disable_option = (bool) get_tutor_option('disable_course_requirements');
926 if($disable_option){
927 return '';
928 }
929 return $html;
930 }
931
932 /**
933 * Enable disable course target audience
934 * @since v.1.4.8
935 */
936 public function enable_disable_course_target_audience($html){
937 $disable_option = (bool) get_tutor_option('disable_course_target_audience');
938 if($disable_option){
939 return '';
940 }
941 return $html;
942 }
943
944 /**
945 * Enable disable course nav items
946 * @since v.1.4.8
947 */
948 public function enable_disable_course_nav_items($items){
949 $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
950 $disable_course_announcements = (bool) get_tutor_option('disable_course_announcements');
951
952 if(! $enable_q_and_a_on_course){
953 if(tutils()->array_get('questions', $items)) {
954 unset($items['questions']);
955 }
956 }
957 if($disable_course_announcements){
958 if(tutils()->array_get('announcements', $items)) {
959 unset($items['announcements']);
960 }
961 }
962 return $items;
963 }
964
965 /**
966 * Filter product in shop page
967 * @since v.1.4.9
968 */
969 public function filter_product_in_shop_page(){
970 $hide_course_from_shop_page = (bool) get_tutor_option('hide_course_from_shop_page');
971 if(!$hide_course_from_shop_page){
972 return;
973 }
974 add_action('woocommerce_product_query', array($this, 'filter_woocommerce_product_query'));
975 add_filter('edd_downloads_query', array($this, 'filter_edd_downloads_query'), 10, 2);
976 add_action('pre_get_posts', array($this, 'filter_archive_meta_query'), 1);
977 }
978
979 /**
980 * Tutor product meta query
981 * @since v.1.4.9
982 */
983 public function tutor_product_meta_query(){
984 $meta_query = array(
985 'key' => '_tutor_product',
986 'compare' => 'NOT EXISTS'
987 );
988 return $meta_query;
989 }
990
991 /**
992 * Filter product in woocommerce shop page
993 * @since v.1.4.9
994 */
995 public function filter_woocommerce_product_query($wp_query){
996 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
997 return $wp_query;
998 }
999
1000 /**
1001 * Filter product in edd downloads shortcode page
1002 * @since v.1.4.9
1003 */
1004 public function filter_edd_downloads_query($query){
1005 $query['meta_query'][] = $this->tutor_product_meta_query();
1006 return $query;
1007 }
1008
1009 /**
1010 * Filter product in edd downloads archive page
1011 * @since v.1.4.9
1012 */
1013 public function filter_archive_meta_query($wp_query){
1014 if(!is_admin() && $wp_query->is_archive && $wp_query->get('post_type') === 'download'){
1015 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1016 }
1017 return $wp_query;
1018 }
1019
1020 /**
1021 * @param $html
1022 * @return string
1023 *
1024 * Removed course price if already enrolled at single course
1025 *
1026 * @since v.1.5.8
1027 */
1028 public function remove_price_if_enrolled($html){
1029 $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1030
1031 if ($should_removed){
1032 $course_id = get_the_ID();
1033 $enrolled = tutils()->is_enrolled($course_id);
1034 if ($enrolled){
1035 $html = '';
1036 }
1037 }
1038 return $html;
1039 }
1040
1041 /**
1042 * @param $html
1043 * @return string
1044 *
1045 * Check if all lessons and quizzes done before mark course complete.
1046 */
1047 function tutor_lms_hide_course_complete_btn($html){
1048
1049 $completion_mode = tutils()->get_option('course_completion_process');
1050 if ($completion_mode !== 'strict'){
1051 return $html;
1052 }
1053
1054 $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1055 $lesson_count = tutils()->get_lesson_count_by_course();
1056
1057 if ($completed_lesson < $lesson_count){
1058 return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
1059 }
1060
1061 $quizzes = array();
1062
1063 $course_contents = tutils()->get_course_contents_by_id();
1064 if (tutils()->count($course_contents)){
1065 foreach ($course_contents as $content){
1066 if ($content->post_type === 'tutor_quiz'){
1067 $quizzes[] = $content;
1068 }
1069 }
1070 }
1071
1072 $is_pass = true;
1073 $required_quiz_pass = 0;
1074
1075 if (tutils()->count($quizzes)){
1076 foreach ($quizzes as $quiz){
1077
1078 $attempt = tutils()->get_quiz_attempt($quiz->ID);
1079 if ($attempt) {
1080 $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1081 $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1082
1083 if ($earned_percentage < $passing_grade) {
1084 $required_quiz_pass++;
1085 $is_pass = false;
1086 }
1087 }else{
1088 $required_quiz_pass++;
1089 $is_pass = false;
1090 }
1091 }
1092 }
1093
1094 if ( ! $is_pass){
1095 return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
1096 }
1097
1098 return $html;
1099 }
1100
1101 public function get_generate_greadbook($html){
1102 if ( ! tutils()->is_completed_course()){
1103 return '';
1104 }
1105 return $html;
1106 }
1107
1108
1109 }