PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.6.6
Tutor LMS – eLearning and online course solution v1.6.6
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 5 years ago Admin.php 5 years ago Ajax.php 5 years ago Assets.php 5 years ago Course.php 5 years ago Course_Settings_Tabs.php 5 years ago Course_Widget.php 5 years ago Dashboard.php 5 years ago Email.php 5 years ago FormHandler.php 5 years ago Frontend.php 5 years ago Gutenberg.php 5 years ago Instructor.php 5 years ago Instructors_List.php 5 years ago Lesson.php 5 years ago Options.php 5 years ago Post_types.php 5 years ago Q_and_A.php 5 years ago Question_Answers_List.php 5 years ago Quiz.php 5 years ago Quiz_Attempts_List.php 5 years ago RestAPI.php 5 years ago Rewrite_Rules.php 5 years ago Shortcode.php 5 years ago Student.php 5 years ago Students_List.php 5 years ago Taxonomies.php 5 years ago Template.php 5 years ago Theme_Compatibility.php 5 years ago Tools.php 5 years ago Tutor.php 5 years ago TutorEDD.php 5 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 5 years ago Tutor_Setup.php 5 years ago Upgrader.php 5 years ago User.php 5 years ago Utils.php 5 years ago Video_Stream.php 5 years ago Withdraw.php 5 years ago Withdraw_Requests_List.php 5 years ago WooCommerce.php 5 years ago
Course.php
1199 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 * Add social share content in header
94 * @since v.1.6.3
95 */
96 add_action('wp_head', array($this, 'social_share_content'));
97
98 /**
99 * Delete course data after deleted course
100 * @since v.1.6.6
101 */
102 add_action('deleted_post', array($this, 'delete_tutor_course_data'));
103 }
104
105 /**
106 * Registering metabox
107 */
108 public function register_meta_box(){
109 $coursePostType = tutor()->course_post_type;
110 $course_marketplace = tutor_utils()->get_option('enable_course_marketplace');
111 //add_meta_box( 'tutor-course-levels', __( 'Course Level', 'tutor' ), array($this, 'course_level_metabox'), $coursePostType );
112 add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
113 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
114 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
115 if ($course_marketplace) {
116 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
117 }
118 add_meta_box( 'tutor-announcements', __( 'Announcements', 'tutor' ), array($this, 'announcements_metabox'), $coursePostType );
119 }
120
121 public function course_meta_box($echo = true){
122 ob_start();
123 include tutor()->path.'views/metabox/course-topics.php';
124 $content = ob_get_clean();
125
126 if ($echo){
127 echo $content;
128 }else{
129 return $content;
130 }
131 }
132
133 public function course_additional_data_meta_box($echo = true){
134
135 ob_start();
136 include tutor()->path.'views/metabox/course-additional-data.php';
137 $content = ob_get_clean();
138
139 if ($echo){
140 echo $content;
141 }else{
142 return $content;
143 }
144 }
145
146 public function video_metabox($echo = true){
147 ob_start();
148 include tutor()->path.'views/metabox/video-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 course_level_metabox($echo = true){
159 ob_start();
160 include tutor()->path.'views/metabox/course-level-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 announcements_metabox($echo = true){
171 ob_start();
172 include tutor()->path.'views/metabox/announcements-metabox.php';
173 $content = ob_get_clean();
174
175 if ($echo){
176 echo $content;
177 }else{
178 return $content;
179 }
180 }
181
182 public function instructors_metabox($echo = true){
183 ob_start();
184 include tutor()->path . 'views/metabox/instructors-metabox.php';
185 $content = ob_get_clean();
186
187 if ($echo){
188 echo $content;
189 }else{
190 return $content;
191 }
192 }
193
194 /**
195 * Register metabox in course builder tutor
196 * @since v.1.3.4
197 */
198 public function register_meta_box_in_frontend(){
199 do_action('tutor_course_builder_metabox_before', get_the_ID());
200 course_builder_section_wrap($this->video_metabox($echo = false), __( 'Video', 'tutor' ) );
201 course_builder_section_wrap($this->course_meta_box($echo = false), __( 'Course Builder', 'tutor' ) );
202 course_builder_section_wrap($this->instructors_metabox($echo = false), __( 'Instructors', 'tutor' ) );
203 course_builder_section_wrap($this->course_additional_data_meta_box($echo = false), __( 'Additional Data', 'tutor' ) );
204 course_builder_section_wrap($this->announcements_metabox($echo = false), __( 'Announcements', 'tutor' ) );
205 do_action('tutor_course_builder_metabox_after', get_the_ID());
206 }
207
208 /**
209 * @param $post_ID
210 *
211 * Insert Topic and attached it with Course
212 */
213 public function save_course_meta($post_ID, $post){
214 global $wpdb;
215
216 do_action( "tutor_save_course", $post_ID, $post);
217
218 /**
219 * Insert Topic
220 */
221 /*
222 if ( ! empty($_POST['topic_title'])) {
223 $topic_title = sanitize_text_field( $_POST['topic_title'] );
224 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
225
226 $post_arr = array(
227 'post_type' => 'topics',
228 'post_title' => $topic_title,
229 'post_content' => $topic_summery,
230 'post_status' => 'publish',
231 'post_author' => get_current_user_id(),
232 'post_parent' => $post_ID,
233 );
234 wp_insert_post( $post_arr );
235 }*/
236
237 /**
238 * Save course price type
239 */
240 $price_type = tutils()->array_get('tutor_course_price_type', $_POST);
241 if ($price_type){
242 update_post_meta($post_ID, '_tutor_course_price_type', $price_type);
243 }
244
245 //Course Duration
246 if ( ! empty($_POST['course_duration'])){
247 $video = tutils()->sanitize_array($_POST['course_duration']);
248 update_post_meta($post_ID, '_course_duration', $video);
249 }
250
251 if ( ! empty($_POST['course_level'])){
252 $course_level = sanitize_text_field($_POST['course_level']);
253 update_post_meta($post_ID, '_tutor_course_level', $course_level);
254 }
255
256 $additional_data_edit = tutils()->avalue_dot('_tutor_course_additional_data_edit', $_POST);
257 if ($additional_data_edit) {
258 if (!empty($_POST['course_benefits'])) {
259 $course_benefits = wp_kses_post($_POST['course_benefits']);
260 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
261 } else {
262 delete_post_meta($post_ID, '_tutor_course_benefits');
263 }
264
265 if (!empty($_POST['course_requirements'])) {
266 $requirements = wp_kses_post($_POST['course_requirements']);
267 update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
268 } else {
269 delete_post_meta($post_ID, '_tutor_course_requirements');
270 }
271
272 if (!empty($_POST['course_target_audience'])) {
273 $target_audience = wp_kses_post($_POST['course_target_audience']);
274 update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
275 } else {
276 delete_post_meta($post_ID, '_tutor_course_target_audience');
277 }
278
279 if (!empty($_POST['course_material_includes'])) {
280 $material_includes = wp_kses_post($_POST['course_material_includes']);
281 update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
282 } else {
283 delete_post_meta($post_ID, '_tutor_course_material_includes');
284 }
285 }
286
287
288 /**
289 * Sorting Topics and lesson
290 */
291 if ( ! empty($_POST['tutor_topics_lessons_sorting'])){
292 $new_order = sanitize_text_field(stripslashes($_POST['tutor_topics_lessons_sorting']));
293 $order = json_decode($new_order, true);
294
295 if (is_array($order) && count($order)){
296 $i = 0;
297 foreach ($order as $topic ){
298 $i++;
299 $wpdb->update(
300 $wpdb->posts,
301 array('menu_order' => $i),
302 array('ID' => $topic['topic_id'])
303 );
304
305 /**
306 * Removing All lesson with topic
307 */
308
309 $wpdb->update(
310 $wpdb->posts,
311 array('post_parent' => 0),
312 array('post_parent' => $topic['topic_id'])
313 );
314
315 /**
316 * Lesson Attaching with topic ID
317 * sorting lesson
318 */
319 if (isset($topic['lesson_ids'])){
320 $lesson_ids = $topic['lesson_ids'];
321 }else{
322 $lesson_ids = array();
323 }
324 if (count($lesson_ids)){
325 foreach ($lesson_ids as $lesson_key => $lesson_id ){
326 $wpdb->update(
327 $wpdb->posts,
328 array('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
329 array('ID' => $lesson_id)
330 );
331 }
332 }
333 }
334 }
335 }
336
337 if ($additional_data_edit) {
338 if ( ! empty($_POST['video']['source'])) { //Video
339 $video = tutor_utils()->array_get('video', $_POST);
340 update_post_meta($post_ID, '_video', $video);
341 }else{
342 delete_post_meta($post_ID, '_video');
343 }
344 }
345
346 /**
347 * Adding author to instructor automatically
348 */
349
350 $author_id = $post->post_author;
351 $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} ");
352 if ( ! $attached){
353 add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
354 }
355
356 //Announcements
357 if ( ! wp_doing_ajax()) {
358 $announcement_title = tutor_utils()->avalue_dot( 'announcements.title', $_POST );
359 if ( ! empty( $announcement_title ) ) {
360 $title = sanitize_text_field( tutor_utils()->avalue_dot( 'announcements.title', $_POST ) );
361 $content = wp_kses_post( tutor_utils()->avalue_dot( 'announcements.content', $_POST ) );
362
363 $post_arr = array(
364 'post_type' => 'tutor_announcements',
365 'post_title' => $title,
366 'post_content' => $content,
367 'post_status' => 'publish',
368 'post_author' => get_current_user_id(),
369 'post_parent' => $post_ID,
370 );
371 wp_insert_post( $post_arr );
372 }
373 }
374
375 do_action( "tutor_save_course_after", $post_ID, $post);
376 }
377
378 /**
379 * Tutor add course topic
380 */
381 public function tutor_add_course_topic(){
382 if (empty($_POST['topic_title']) ) {
383 wp_send_json_error();
384 }
385 $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
386 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
387
388 $topic_title = sanitize_text_field( $_POST['topic_title'] );
389 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
390
391 $post_arr = array(
392 'post_type' => 'topics',
393 'post_title' => $topic_title,
394 'post_content' => $topic_summery,
395 'post_status' => 'publish',
396 'post_author' => get_current_user_id(),
397 'post_parent' => $course_id,
398 'menu_order' => $next_topic_order_id,
399 );
400 $current_topic_id = wp_insert_post( $post_arr );
401
402 ob_start();
403 include tutor()->path.'views/metabox/course-contents.php';
404 $course_contents = ob_get_clean();
405
406 wp_send_json_success(array('course_contents' => $course_contents));
407 }
408
409 /**
410 * Update the topic
411 */
412 public function tutor_update_topic(){
413 $topic_id = (int) sanitize_text_field($_POST['topic_id']);
414 $topic_title = sanitize_text_field($_POST['topic_title']);
415 $topic_summery = wp_kses_post($_POST['topic_summery']);
416
417 $topic_attr = array(
418 'ID' => $topic_id,
419 'post_title' => $topic_title,
420 'post_content' => $topic_summery,
421 );
422 wp_update_post( $topic_attr );
423
424 wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
425 }
426
427
428 /**
429 * @param $columns
430 *
431 * @return mixed
432 *
433 * Add Lesson column
434 */
435 public function add_column($columns){
436 $date_col = $columns['date'];
437 unset($columns['date']);
438 $columns['lessons'] = __('Lessons', 'tutor');
439 $columns['students'] = __('Students', 'tutor');
440 $columns['price'] = __('Price', 'tutor');
441 $columns['date'] = $date_col;
442
443 return $columns;
444 }
445
446 /**
447 * @param $column
448 * @param $post_id
449 *
450 */
451 public function custom_lesson_column($column, $post_id ){
452 if ($column === 'lessons'){
453 echo tutor_utils()->get_lesson_count_by_course($post_id);
454 }
455
456 if ($column === 'students'){
457 echo tutor_utils()->count_enrolled_users_by_course($post_id);
458 }
459
460 if ($column === 'price'){
461 $price = tutor_utils()->get_course_price($post_id);
462 if ($price){
463 $monetize_by = tutils()->get_option('monetize_by');
464 if (function_exists('wc_price') && $monetize_by === 'wc'){
465 echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
466 }else{
467 echo '<span class="tutor-label-success">'.$price.'</span>';
468 }
469 }else{
470 echo 'free';
471 }
472 }
473 }
474
475
476 public function tutor_delete_topic(){
477 if (!isset($_GET[tutor()->nonce]) || !wp_verify_nonce($_GET[tutor()->nonce], tutor()->nonce_action)) {
478 exit();
479 }
480 if ( ! isset($_GET['topic_id'])){
481 exit();
482 }
483
484 global $wpdb;
485
486 $topic_id = (int) sanitize_text_field($_GET['topic_id']);
487 $wpdb->update(
488 $wpdb->posts,
489 array('post_parent' => 0),
490 array('post_parent' => $topic_id)
491 );
492
493 $wpdb->delete(
494 $wpdb->postmeta,
495 array('post_id' => $topic_id)
496 );
497
498 wp_delete_post($topic_id);
499 wp_safe_redirect(wp_get_referer());
500 }
501
502 public function tutor_delete_announcement(){
503 tutor_utils()->checking_nonce('get');
504
505 $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
506
507 wp_delete_post($announcement_id);
508 wp_safe_redirect(wp_get_referer());
509 }
510
511 public function enroll_now(){
512
513 //Checking if action comes from Enroll form
514 if (tutor_utils()->array_get('tutor_course_action', $_POST) !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
515 return;
516 }
517 //Checking Nonce
518 tutor_utils()->checking_nonce();
519
520 $user_id = get_current_user_id();
521 if ( ! $user_id){
522 exit(__('Please Sign In first', 'tutor'));
523 }
524
525 $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
526 $user_id = get_current_user_id();
527
528 /**
529 * TODO: need to check purchase information
530 */
531
532 $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
533
534 /**
535 * If is is not purchasable, it's free, and enroll right now
536 *
537 * if purchasable, then process purchase.
538 *
539 * @since: v.1.0.0
540 */
541 if ($is_purchasable){
542 //process purchase
543
544 }else{
545 //Free enroll
546 tutor_utils()->do_enroll($course_id);
547 }
548
549 $referer_url = wp_get_referer();
550 wp_redirect($referer_url);
551 }
552
553 /**
554 *
555 * Mark complete completed
556 *
557 * @since v.1.0.0
558 */
559 public function mark_course_complete(){
560 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
561 return;
562 }
563 //Checking nonce
564 tutor_utils()->checking_nonce();
565
566 $user_id = get_current_user_id();
567
568 //TODO: need to show view if not signed_in
569 if ( ! $user_id){
570 die(__('Please Sign-In', 'tutor'));
571 }
572
573 $course_id = (int) sanitize_text_field($_POST['course_id']);
574
575 do_action('tutor_course_complete_before', $course_id);
576 /**
577 * Marking course completed at Comment
578 */
579
580 global $wpdb;
581
582 $date = date("Y-m-d H:i:s", tutor_time());
583
584 //Making sure that, hash is unique
585 do{
586 $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
587 $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}' ");
588 }while($hasHash > 0);
589
590 $data = array(
591 'comment_post_ID' => $course_id,
592 'comment_author' => $user_id,
593 'comment_date' => $date,
594 'comment_date_gmt' => get_gmt_from_date($date),
595 'comment_content' => $hash, //Identification Hash
596 'comment_approved' => 'approved',
597 'comment_agent' => 'TutorLMSPlugin',
598 'comment_type' => 'course_completed',
599 'user_id' => $user_id,
600 );
601
602 $wpdb->insert($wpdb->comments, $data);
603
604 do_action('tutor_course_complete_after', $course_id);
605
606 wp_redirect(get_the_permalink($course_id));
607 }
608
609
610 public function tutor_load_instructors_modal(){
611 global $wpdb;
612
613 $course_id = (int) sanitize_text_field($_POST['course_id']);
614 $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
615
616 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
617
618 $instructors = array();
619
620
621 $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
622
623 if ($saved_instructors){
624 $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
625 $instructor_not_in_ids = implode(',', $saved_instructors_ids);
626 $not_in_sql .= "AND ID NOT IN($instructor_not_in_ids) ";
627 }
628
629 $search_sql = '';
630 if ($search_terms){
631 $search_sql = "AND (user_login like '%{$search_terms}%' or user_nicename like '%{$search_terms}%' or display_name like '%{$search_terms}%') ";
632 }
633
634 $instructors = $wpdb->get_results("select ID, display_name from {$wpdb->users}
635 INNER JOIN {$wpdb->usermeta} ON ID = user_id AND meta_key = '_tutor_instructor_status' AND meta_value = 'approved'
636 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
637
638 $output = '';
639 if (is_array($instructors) && count($instructors)){
640 $instructor_output = '';
641 foreach ($instructors as $instructor){
642 $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
643 }
644
645 $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
646
647 }else{
648 $output .= __('<p>No instructor available or you have already added maximum instructors</p>', 'tutor');
649 }
650
651
652 if ( ! defined('TUTOR_MT_VERSION')){
653 $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>';
654 }
655
656 wp_send_json_success(array('output' => $output));
657 }
658
659 public function tutor_add_instructors_to_course(){
660 $course_id = (int) sanitize_text_field($_POST['course_id']);
661 $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
662
663 if (is_array($instructor_ids) && count($instructor_ids)){
664 foreach ($instructor_ids as $instructor_id){
665 add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
666 }
667 }
668
669 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
670 $output = '';
671
672 if ($saved_instructors){
673 foreach ($saved_instructors as $t){
674
675 $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
676 <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
677 <span class="instructor-name"> '.$t->display_name.' </span>
678 <span class="instructor-control">
679 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
680 </span>
681 </div>';
682 }
683 }
684
685 wp_send_json_success(array('output' => $output));
686 }
687
688 public function detach_instructor_from_course(){
689 global $wpdb;
690
691 $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
692 $course_id = (int) sanitize_text_field($_POST['course_id']);
693
694 $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
695 wp_send_json_success();
696 }
697
698 public function tutor_delete_dashboard_course(){
699 $course_id = intval(sanitize_text_field($_POST['course_id']));
700 wp_trash_post($course_id);
701 wp_send_json_success(['element'=>'course']);
702 }
703
704
705 public function tutor_add_gutenberg_author($data , $postarr){
706 global $wpdb;
707
708 $courses_post_type = tutor()->course_post_type;
709 $post_type = tutils()->array_get('post_type', $postarr);
710
711 /*
712 $post_author = (int) tutor_utils()->avalue_dot('post_author', $data);
713
714 if ( ! $post_author){
715 $user_ID = (int) tutor_utils()->avalue_dot('user_ID', $postarr);
716 if ($user_ID){
717 $data['post_author'] = $user_ID;
718 }else{
719 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
720 $post_author = (int) $wpdb->get_var("SELECT post_author FROM {$wpdb->posts} WHERE ID = {$post_ID} ");
721
722 $data['post_author'] = $post_author;
723 }
724 }*/
725
726 if ($courses_post_type === $post_type){
727 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
728 $post_author = (int) $wpdb->get_var("SELECT post_author FROM {$wpdb->posts} WHERE ID = {$post_ID} ");
729
730 if ($post_author > 0){
731 $data['post_author'] = $post_author;
732 }else{
733 $data['post_author'] = get_current_user_id();
734 }
735 }
736
737 return $data;
738 }
739
740
741 /**
742 * @param $post_ID
743 * @param $postData
744 *
745 * Attach product during save course from the frontend course dashboard.
746 *
747 * @return string
748 *
749 * @since v.1.3.4
750 */
751 public function attach_product_with_course($post_ID, $postData){
752 $attached_product_id = tutor_utils()->get_course_product_id($post_ID);
753 $course_price = sanitize_text_field(tutor_utils()->array_get('course_price', $_POST));
754
755 if ( ! $course_price){
756 return;
757 }
758
759 $monetize_by = tutor_utils()->get_option('monetize_by');
760 $course = get_post($post_ID);
761
762 if ($monetize_by === 'wc'){
763
764 $is_update = false;
765 if ($attached_product_id){
766 $wc_product = get_post_meta($attached_product_id, '_product_version', true);
767 if ($wc_product){
768 $is_update = true;
769 }
770 }
771
772 if ($is_update){
773
774 $productObj = new \WC_Product($attached_product_id);
775 $productObj->set_price($course_price); // set product price
776 $productObj->set_regular_price($course_price); // set product regular price
777 $product_id = $productObj->save();
778
779 }else{
780
781 $productObj = new \WC_Product();
782 $productObj->set_name($course->post_title);
783 $productObj->set_status('publish');
784 $productObj->set_price($course_price); // set product price
785 $productObj->set_regular_price($course_price); // set product regular price
786
787 $product_id = $productObj->save();
788 if ($product_id) {
789 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
790 //Mark product for woocommerce
791 update_post_meta( $product_id, '_virtual', 'yes' );
792 update_post_meta( $product_id, '_tutor_product', 'yes' );
793
794 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
795 if ( $coursePostThumbnail ) {
796 set_post_thumbnail( $product_id, $coursePostThumbnail );
797 }
798 }
799 }
800
801 }elseif ($monetize_by === 'edd'){
802
803 $is_update = false;
804
805 if ($attached_product_id){
806 $edd_price = get_post_meta($attached_product_id, 'edd_price', true);
807 if ($edd_price){
808 $is_update = true;
809 }
810 }
811
812 if ($is_update){
813 //Update the product
814 update_post_meta( $attached_product_id, 'edd_price', $course_price );
815 }else{
816 //Create new product
817
818 $post_arr = array(
819 'post_type' => 'download',
820 'post_title' => $course->post_title,
821 'post_status' => 'publish',
822 'post_author' => get_current_user_id(),
823 );
824 $download_id = wp_insert_post( $post_arr );
825 if ($download_id ) {
826 //edd_price
827 update_post_meta( $download_id, 'edd_price', $course_price );
828
829 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
830 //Mark product for EDD
831 update_post_meta( $download_id, '_tutor_product', 'yes' );
832
833 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
834 if ( $coursePostThumbnail ) {
835 set_post_thumbnail( $download_id, $coursePostThumbnail );
836 }
837
838 }
839
840 }
841
842
843 }
844
845 }
846
847
848 /**
849 * Add Course level to course settings
850 * @since v.1.4.1
851 */
852 public function add_course_level_to_settings(){
853 include tutor()->path.'views/metabox/course-level-metabox.php';
854 }
855
856 /**
857 * Check if course starting
858 *
859 * @since v.1.4.8
860 */
861 public function tutor_lesson_load_before(){
862 $course_id = tutils()->get_course_id_by_content(get_the_ID());
863 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
864 if (is_user_logged_in()){
865 $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
866 if ( ! $completed_lessons && ! $is_course_started){
867 update_post_meta($course_id, '_tutor_course_started', tutor_time());
868 do_action('tutor/course/started', $course_id);
869 }
870 }
871 }
872
873 /**
874 * Add Course level to course settings
875 * @since v.1.4.8
876 */
877 public function course_elements_enable_disable(){
878 add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
879 add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
880 add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
881 add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
882 add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
883 add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
884 add_filter('tutor_course/single/enrolled/nav_items', array($this, 'enable_disable_course_nav_items') );
885 }
886
887 /**
888 * Enable disable course progress bar
889 * @since v.1.4.8
890 */
891 public function enable_disable_course_progress_bar($html){
892 $disable_option = (bool) get_tutor_option('disable_course_progress_bar');
893 if($disable_option){
894 return '';
895 }
896 return $html;
897 }
898
899 /**
900 * Enable disable material includes
901 * @since v.1.4.8
902 */
903 public function enable_disable_material_includes($html){
904 $disable_option = (bool) get_tutor_option('disable_course_material');
905 if($disable_option){
906 return '';
907 }
908 return $html;
909 }
910
911 /**
912 * Enable disable course content
913 * @since v.1.4.8
914 */
915 public function enable_disable_course_content($html){
916 $disable_option = (bool) get_tutor_option('disable_course_description');
917 if($disable_option){
918 return '';
919 }
920 return $html;
921 }
922
923 /**
924 * Enable disable course benefits
925 * @since v.1.4.8
926 */
927 public function enable_disable_course_benefits($html){
928 $disable_option = (bool) get_tutor_option('disable_course_benefits');
929 if($disable_option){
930 return '';
931 }
932 return $html;
933 }
934
935 /**
936 * Enable disable course requirements
937 * @since v.1.4.8
938 */
939 public function enable_disable_course_requirements($html){
940 $disable_option = (bool) get_tutor_option('disable_course_requirements');
941 if($disable_option){
942 return '';
943 }
944 return $html;
945 }
946
947 /**
948 * Enable disable course target audience
949 * @since v.1.4.8
950 */
951 public function enable_disable_course_target_audience($html){
952 $disable_option = (bool) get_tutor_option('disable_course_target_audience');
953 if($disable_option){
954 return '';
955 }
956 return $html;
957 }
958
959 /**
960 * Enable disable course nav items
961 * @since v.1.4.8
962 */
963 public function enable_disable_course_nav_items($items){
964 $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
965 $disable_course_announcements = (bool) get_tutor_option('disable_course_announcements');
966
967 if(! $enable_q_and_a_on_course){
968 if(tutils()->array_get('questions', $items)) {
969 unset($items['questions']);
970 }
971 }
972 if($disable_course_announcements){
973 if(tutils()->array_get('announcements', $items)) {
974 unset($items['announcements']);
975 }
976 }
977 return $items;
978 }
979
980 /**
981 * Filter product in shop page
982 * @since v.1.4.9
983 */
984 public function filter_product_in_shop_page(){
985 $hide_course_from_shop_page = (bool) get_tutor_option('hide_course_from_shop_page');
986 if(!$hide_course_from_shop_page){
987 return;
988 }
989 add_action('woocommerce_product_query', array($this, 'filter_woocommerce_product_query'));
990 add_filter('edd_downloads_query', array($this, 'filter_edd_downloads_query'), 10, 2);
991 add_action('pre_get_posts', array($this, 'filter_archive_meta_query'), 1);
992 }
993
994 /**
995 * Tutor product meta query
996 * @since v.1.4.9
997 */
998 public function tutor_product_meta_query(){
999 $meta_query = array(
1000 'key' => '_tutor_product',
1001 'compare' => 'NOT EXISTS'
1002 );
1003 return $meta_query;
1004 }
1005
1006 /**
1007 * Filter product in woocommerce shop page
1008 * @since v.1.4.9
1009 */
1010 public function filter_woocommerce_product_query($wp_query){
1011 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1012 return $wp_query;
1013 }
1014
1015 /**
1016 * Filter product in edd downloads shortcode page
1017 * @since v.1.4.9
1018 */
1019 public function filter_edd_downloads_query($query){
1020 $query['meta_query'][] = $this->tutor_product_meta_query();
1021 return $query;
1022 }
1023
1024 /**
1025 * Filter product in edd downloads archive page
1026 * @since v.1.4.9
1027 */
1028 public function filter_archive_meta_query($wp_query){
1029 if(!is_admin() && $wp_query->is_archive && $wp_query->get('post_type') === 'download'){
1030 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1031 }
1032 return $wp_query;
1033 }
1034
1035 /**
1036 * @param $html
1037 * @return string
1038 *
1039 * Removed course price if already enrolled at single course
1040 *
1041 * @since v.1.5.8
1042 */
1043 public function remove_price_if_enrolled($html){
1044 $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1045
1046 if ($should_removed){
1047 $course_id = get_the_ID();
1048 $enrolled = tutils()->is_enrolled($course_id);
1049 if ($enrolled){
1050 $html = '';
1051 }
1052 }
1053 return $html;
1054 }
1055
1056 /**
1057 * @param $html
1058 * @return string
1059 *
1060 * Check if all lessons and quizzes done before mark course complete.
1061 */
1062 function tutor_lms_hide_course_complete_btn($html){
1063
1064 $completion_mode = tutils()->get_option('course_completion_process');
1065 if ($completion_mode !== 'strict'){
1066 return $html;
1067 }
1068
1069 $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1070 $lesson_count = tutils()->get_lesson_count_by_course();
1071
1072 if ($completed_lesson < $lesson_count){
1073 return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
1074 }
1075
1076 $quizzes = array();
1077
1078 $course_contents = tutils()->get_course_contents_by_id();
1079 if (tutils()->count($course_contents)){
1080 foreach ($course_contents as $content){
1081 if ($content->post_type === 'tutor_quiz'){
1082 $quizzes[] = $content;
1083 }
1084 }
1085 }
1086
1087 $is_pass = true;
1088 $required_quiz_pass = 0;
1089
1090 if (tutils()->count($quizzes)){
1091 foreach ($quizzes as $quiz){
1092
1093 $attempt = tutils()->get_quiz_attempt($quiz->ID);
1094 if ($attempt) {
1095 $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1096 $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1097
1098 if ($earned_percentage < $passing_grade) {
1099 $required_quiz_pass++;
1100 $is_pass = false;
1101 }
1102 }else{
1103 $required_quiz_pass++;
1104 $is_pass = false;
1105 }
1106 }
1107 }
1108
1109 if ( ! $is_pass){
1110 return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
1111 }
1112
1113 return $html;
1114 }
1115
1116 public function get_generate_greadbook($html){
1117 if ( ! tutils()->is_completed_course()){
1118 return '';
1119 }
1120 return $html;
1121 }
1122
1123 /**
1124 * Add social share content in header
1125 * @since v.1.6.3
1126 */
1127 public function social_share_content(){
1128 global $wp_query, $post;
1129 if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type) { ?>
1130 <!--Facebook-->
1131 <meta property="og:type" content="website"/>
1132 <meta property="og:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>" />
1133 <meta property="og:description" content="<?php echo esc_html($post->post_content); ?>" />
1134 <!--Twitter-->
1135 <meta name="twitter:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1136 <meta name="twitter:description" content="<?php echo esc_html($post->post_content); ?>">
1137 <!--Google+-->
1138 <meta itemprop="image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1139 <meta itemprop="description" content="<?php echo esc_html($post->post_content); ?>"> <?php
1140 }
1141 }
1142
1143 /**
1144 * Get posts by type and parent
1145 * @since v.1.6.6
1146 */
1147 public function tutor_get_post_ids($post_type, $post_parent) {
1148 $args = array(
1149 'fields' => 'ids',
1150 'post_type' => $post_type,
1151 'post_parent' => $post_parent,
1152 'post_status' => 'any',
1153 'posts_per_page' => -1,
1154 );
1155 return get_posts($args);
1156 }
1157
1158 /**
1159 * Delete course data when permanently deleting a course.
1160 * @since v.1.6.6
1161 */
1162 function delete_tutor_course_data( $post_id ) {
1163 $course_post_type = tutor()->course_post_type;
1164 $lesson_post_type = tutor()->lesson_post_type;
1165
1166 if (get_post_type($post_id) == $course_post_type) {
1167 global $wpdb;
1168 $topic_ids = $this->tutor_get_post_ids('topics', $post_id);
1169 if ( !empty($topic_ids) ) {
1170 foreach ($topic_ids as $topic_id) {
1171 $content_post_type = apply_filters('tutor_course_contents_post_types', array($lesson_post_type, 'tutor_quiz'));
1172 $topic_content_ids = $this->tutor_get_post_ids($content_post_type, $topic_id);
1173
1174 foreach ($topic_content_ids as $content_id) {
1175 if( get_post_type($content_id) == 'tutor_quiz') {
1176 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $content_id));
1177 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $content_id));
1178
1179 $questions_ids = $wpdb->get_col("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = {$content_id} ");
1180 if (is_array($questions_ids) && count($questions_ids)){
1181 $in_question_ids = "'".implode("','", $questions_ids)."'";
1182 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
1183 }
1184 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $content_id));
1185 }
1186 wp_delete_post($content_id, true);
1187 }
1188 wp_delete_post($topic_id, true);
1189 }
1190 }
1191 $child_post_ids = $this->tutor_get_post_ids(array('tutor_announcements', 'tutor_enrolled'), $post_id);
1192 if ( !empty($child_post_ids) ) {
1193 foreach ($child_post_ids as $child_post_id) {
1194 wp_delete_post($child_post_id, true);
1195 }
1196 }
1197 }
1198 }
1199 }