PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.9.14
Tutor LMS – eLearning and online course solution v1.9.14
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 4 years ago Admin.php 4 years ago Ajax.php 4 years ago Assets.php 4 years ago Course.php 4 years ago Course_Filter.php 4 years ago Course_Settings_Tabs.php 4 years ago Course_Widget.php 4 years ago Custom_Validation.php 5 years ago Dashboard.php 4 years ago Email.php 5 years ago FormHandler.php 4 years ago Frontend.php 5 years ago Gutenberg.php 4 years ago Instructor.php 4 years ago Instructors_List.php 4 years ago Lesson.php 4 years ago Options.php 4 years ago Post_types.php 4 years ago Private_Course_Access.php 5 years ago Q_and_A.php 4 years ago Question_Answers_List.php 4 years ago Quiz.php 4 years ago Quiz_Attempts_List.php 4 years ago RestAPI.php 4 years ago Rewrite_Rules.php 4 years ago Shortcode.php 4 years ago Student.php 4 years ago Students_List.php 4 years ago Taxonomies.php 4 years ago Template.php 4 years ago Theme_Compatibility.php 5 years ago Tools.php 4 years ago Tutor.php 4 years ago TutorEDD.php 4 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 4 years ago Tutor_Setup.php 4 years ago Upgrader.php 4 years ago User.php 4 years ago Utils.php 4 years ago Video_Stream.php 4 years ago Withdraw.php 4 years ago Withdraw_Requests_List.php 4 years ago WooCommerce.php 4 years ago
Course.php
1441 lines
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();
74
75 /**
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
83 * Filter product in shop page
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-topics', __( 'Course Builder', 'tutor' ), array( $this, 'course_meta_box' ), $coursePostType );
191 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array( $this, 'course_additional_data_meta_box' ), $coursePostType );
192 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array( $this, 'video_metabox' ), $coursePostType );
193 if ( $course_marketplace ) {
194 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
195 }
196
197 /**
198 * Tutor course sidebar settings metabox
199 *
200 * @since v.1.7.0
201 */
202 add_meta_box( 'tutor-course-sidebar-settings', __( 'Tutor Settings', 'tutor' ), array( $this, 'tutor_course_setting_metabox' ), $coursePostType, 'side' );
203 }
204
205 public function course_meta_box( $echo = true ) {
206 ob_start();
207 include tutor()->path . 'views/metabox/course-topics.php';
208 $content = ob_get_clean();
209
210 if ( $echo ) {
211 echo tutor_kses_html( $content );
212 } else {
213 return $content;
214 }
215 }
216
217 public function course_additional_data_meta_box( $echo = true ) {
218
219 ob_start();
220 include tutor()->path . 'views/metabox/course-additional-data.php';
221 $content = ob_get_clean();
222
223 if ( $echo ) {
224 echo tutor_kses_html( $content );
225 } else {
226 return $content;
227 }
228 }
229
230 public function video_metabox( $echo = true ) {
231 ob_start();
232 include tutor()->path . 'views/metabox/video-metabox.php';
233 $content = ob_get_clean();
234
235 if ( $echo ) {
236 echo tutor_kses_html( $content );
237 } else {
238 return $content;
239 }
240 }
241
242 public function instructors_metabox( $echo = true ) {
243 ob_start();
244 include tutor()->path . 'views/metabox/instructors-metabox.php';
245 $content = ob_get_clean();
246
247 if ( $echo ) {
248 echo tutor_kses_html( $content );
249 } else {
250 return $content;
251 }
252 }
253
254 /**
255 * Register metabox in course builder tutor
256 *
257 * @since v.1.3.4
258 */
259 public function register_meta_box_in_frontend() {
260 do_action( 'tutor_course_builder_metabox_before', get_the_ID() );
261 course_builder_section_wrap( $this->video_metabox( false ), __( 'Video', 'tutor' ) );
262 course_builder_section_wrap( $this->course_meta_box( false ), __( 'Course Builder', 'tutor' ) );
263 course_builder_section_wrap( $this->instructors_metabox( false ), __( 'Instructors', 'tutor' ) );
264 course_builder_section_wrap( $this->course_additional_data_meta_box( false ), __( 'Additional Data', 'tutor' ) );
265 do_action( 'tutor_course_builder_metabox_after', get_the_ID() );
266 }
267
268 /**
269 * @param $post_ID
270 *
271 * Insert Topic and attached it with Course
272 */
273 public function save_course_meta( $post_ID, $post ) {
274 global $wpdb;
275
276 do_action( 'tutor_save_course', $post_ID, $post );
277
278 /**
279 * Save course price type
280 */
281 $price_type = tutils()->array_get( 'tutor_course_price_type', tutor_sanitize_data($_POST) );
282 if ( $price_type ) {
283 update_post_meta( $post_ID, '_tutor_course_price_type', $price_type );
284 }
285
286 // Course Duration
287 if ( ! empty( $_POST['course_duration'] ) ) {
288 $video = tutils()->sanitize_array( $_POST['course_duration'] );
289 update_post_meta( $post_ID, '_course_duration', $video );
290 }
291
292 if ( ! empty( $_POST['course_level'] ) ) {
293 $course_level = sanitize_text_field( $_POST['course_level'] );
294 update_post_meta( $post_ID, '_tutor_course_level', $course_level );
295 }
296
297 $additional_data_edit = tutils()->avalue_dot( '_tutor_course_additional_data_edit', tutor_sanitize_data($_POST) );
298 if ( $additional_data_edit ) {
299 if ( ! empty( $_POST['course_benefits'] ) ) {
300 $course_benefits = wp_kses_post( $_POST['course_benefits'] );
301 update_post_meta( $post_ID, '_tutor_course_benefits', $course_benefits );
302 } else {
303 delete_post_meta( $post_ID, '_tutor_course_benefits' );
304 }
305
306 if ( ! empty( $_POST['course_requirements'] ) ) {
307 $requirements = wp_kses_post( $_POST['course_requirements'] );
308 update_post_meta( $post_ID, '_tutor_course_requirements', $requirements );
309 } else {
310 delete_post_meta( $post_ID, '_tutor_course_requirements' );
311 }
312
313 if ( ! empty( $_POST['course_target_audience'] ) ) {
314 $target_audience = wp_kses_post( $_POST['course_target_audience'] );
315 update_post_meta( $post_ID, '_tutor_course_target_audience', $target_audience );
316 } else {
317 delete_post_meta( $post_ID, '_tutor_course_target_audience' );
318 }
319
320 if ( ! empty( $_POST['course_material_includes'] ) ) {
321 $material_includes = wp_kses_post( $_POST['course_material_includes'] );
322 update_post_meta( $post_ID, '_tutor_course_material_includes', $material_includes );
323 } else {
324 delete_post_meta( $post_ID, '_tutor_course_material_includes' );
325 }
326 }
327
328 /**
329 * Sorting Topics and lesson
330 */
331 if ( ! empty( $_POST['tutor_topics_lessons_sorting'] ) ) {
332 $new_order = sanitize_text_field( stripslashes( $_POST['tutor_topics_lessons_sorting'] ) );
333 $order = json_decode( $new_order, true );
334
335 if ( is_array( $order ) && count( $order ) ) {
336 $i = 0;
337 foreach ( $order as $topic ) {
338 $i++;
339 $wpdb->update(
340 $wpdb->posts,
341 array( 'menu_order' => $i ),
342 array( 'ID' => $topic['topic_id'] )
343 );
344
345 /**
346 * Removing All lesson with topic
347 */
348
349 $wpdb->update(
350 $wpdb->posts,
351 array( 'post_parent' => 0 ),
352 array( 'post_parent' => $topic['topic_id'] )
353 );
354
355 /**
356 * Lesson Attaching with topic ID
357 * sorting lesson
358 */
359 if ( isset( $topic['lesson_ids'] ) ) {
360 $lesson_ids = $topic['lesson_ids'];
361 } else {
362 $lesson_ids = array();
363 }
364 if ( count( $lesson_ids ) ) {
365 foreach ( $lesson_ids as $lesson_key => $lesson_id ) {
366 $wpdb->update(
367 $wpdb->posts,
368 array(
369 'post_parent' => $topic['topic_id'],
370 'menu_order' => $lesson_key,
371 ),
372 array( 'ID' => $lesson_id )
373 );
374 }
375 }
376 }
377 }
378 }
379
380 if ( $additional_data_edit ) {
381 if ( ! empty( $_POST['video']['source'] ) ) { // Video
382 $video = tutor_utils()->array_get( 'video', $_POST );
383 update_post_meta( $post_ID, '_video', $video );
384 } else {
385 delete_post_meta( $post_ID, '_video' );
386 }
387 }
388
389 /**
390 * Adding author to instructor automatically
391 */
392
393 $author_id = $post->post_author;
394 $attached = (int) $wpdb->get_var(
395 $wpdb->prepare(
396 "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta}
397 WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ",
398 $author_id,
399 $post_ID
400 )
401 );
402
403 if ( ! $attached ) {
404 add_user_meta( $author_id, '_tutor_instructor_course_id', $post_ID );
405 }
406
407 /**
408 * Disable question and answer for this course
409 *
410 * @since 1.7.0
411 */
412 if ( $additional_data_edit ) {
413 foreach ( $this->additional_meta as $key ) {
414 update_post_meta( $post_ID, $key, ( isset( $_POST[ $key ] ) ? 'yes' : 'no' ) );
415 }
416 }
417
418 do_action( 'tutor_save_course_after', $post_ID, $post );
419 }
420
421 /**
422 * Tutor add course topic
423 */
424 public function tutor_add_course_topic() {
425 tutils()->checking_nonce();
426
427 if ( empty( $_POST['topic_title'] ) ) {
428 wp_send_json_error();
429 }
430 $course_id = (int) tutor_utils()->avalue_dot( 'tutor_topic_course_ID', tutor_sanitize_data($_POST) );
431 $next_topic_order_id = tutor_utils()->get_next_topic_order_id( $course_id );
432
433 if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
434 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
435 }
436
437 $topic_title = sanitize_text_field( $_POST['topic_title'] );
438 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
439
440 $post_arr = array(
441 'post_type' => 'topics',
442 'post_title' => $topic_title,
443 'post_content' => $topic_summery,
444 'post_status' => 'publish',
445 'post_author' => get_current_user_id(),
446 'post_parent' => $course_id,
447 'menu_order' => $next_topic_order_id,
448 );
449 $current_topic_id = wp_insert_post( $post_arr );
450
451 ob_start();
452 include tutor()->path . 'views/metabox/course-contents.php';
453 $course_contents = ob_get_clean();
454
455 wp_send_json_success( array( 'course_contents' => $course_contents ) );
456 }
457
458 /**
459 * Update the topic
460 */
461 public function tutor_update_topic() {
462 tutils()->checking_nonce();
463
464 $topic_id = (int) $_POST['topic_id'];
465 $topic_title = sanitize_text_field( $_POST['topic_title'] );
466 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
467
468 if ( ! tutils()->can_user_manage( 'topic', $topic_id ) ) {
469 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
470 }
471
472 $topic_attr = array(
473 'ID' => $topic_id,
474 'post_title' => $topic_title,
475 'post_content' => $topic_summery,
476 );
477 wp_update_post( $topic_attr );
478
479 wp_send_json_success( array( 'msg' => __( 'Topic has been updated', 'tutor' ) ) );
480 }
481
482
483 /**
484 * @param $columns
485 *
486 * @return mixed
487 *
488 * Add Lesson column
489 */
490 public function add_column( $columns ) {
491 $date_col = $columns['date'];
492 unset( $columns['date'] );
493 $columns['lessons'] = __( 'Lessons', 'tutor' );
494 $columns['students'] = __( 'Students', 'tutor' );
495 $columns['price'] = __( 'Price', 'tutor' );
496 $columns['date'] = $date_col;
497
498 return $columns;
499 }
500
501 /**
502 * @param $column
503 * @param $post_id
504 */
505 public function custom_lesson_column( $column, $post_id ) {
506 if ( $column === 'lessons' ) {
507 echo tutor_utils()->get_lesson_count_by_course( $post_id );
508 }
509
510 if ( $column === 'students' ) {
511 echo tutor_utils()->count_enrolled_users_by_course( $post_id );
512 }
513
514 if ( $column === 'price' ) {
515 $price = tutor_utils()->get_course_price( $post_id );
516 if ( $price ) {
517 $monetize_by = tutils()->get_option( 'monetize_by' );
518 if ( function_exists( 'wc_price' ) && $monetize_by === 'wc' ) {
519 echo '<span class="tutor-label-success">' . wc_price( $price ) . '</span>';
520 } else {
521 echo '<span class="tutor-label-success">' . $price . '</span>';
522 }
523 } else {
524 echo apply_filters( 'tutor-loop-default-price', __( 'free', 'tutor' ) );
525 }
526 }
527 }
528
529
530 public function tutor_delete_topic() {
531
532 tutils()->checking_nonce( 'get' );
533
534 ! isset( $_GET['topic_id'] ) ? exit() : 0;
535
536 global $wpdb;
537
538 $topic_id = (int) $_GET['topic_id'];
539 $wpdb->update(
540 $wpdb->posts,
541 array( 'post_parent' => 0 ),
542 array( 'post_parent' => $topic_id )
543 );
544
545 $wpdb->delete(
546 $wpdb->postmeta,
547 array( 'post_id' => $topic_id )
548 );
549
550 wp_delete_post( $topic_id );
551 wp_safe_redirect( wp_get_referer() );
552 }
553
554 public function tutor_delete_announcement() {
555 tutor_utils()->checking_nonce( 'get' );
556
557 $announcement_id = (int) $_GET['topic_id'];
558
559 wp_delete_post( $announcement_id );
560 wp_safe_redirect( wp_get_referer() );
561 }
562
563 public function enroll_now() {
564
565 // Checking if action comes from Enroll form
566 if ( tutor_utils()->array_get( 'tutor_course_action', tutor_sanitize_data($_POST) ) !== '_tutor_course_enroll_now' || ! isset( $_POST['tutor_course_id'] ) ) {
567 return;
568 }
569 // Checking Nonce
570 tutor_utils()->checking_nonce();
571
572 $user_id = get_current_user_id();
573 if ( ! $user_id ) {
574 exit( __( 'Please Sign In first', 'tutor' ) );
575 }
576
577 $course_id = (int) $_POST['tutor_course_id'];
578 $user_id = get_current_user_id();
579
580 /**
581 * TODO: need to check purchase information
582 */
583
584 $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
585
586 /**
587 * If is is not purchasable, it's free, and enroll right now
588 *
589 * if purchasable, then process purchase.
590 *
591 * @since: v.1.0.0
592 */
593 if ( $is_purchasable ) {
594 // process purchase
595
596 } else {
597 // Free enroll
598 tutor_utils()->do_enroll( $course_id );
599 }
600
601 $referer_url = wp_get_referer();
602 wp_redirect( $referer_url );
603 }
604
605 /**
606 *
607 * Mark complete completed
608 *
609 * @since v.1.0.0
610 */
611 public function mark_course_complete() {
612 if ( ! isset( $_POST['tutor_action'] ) || $_POST['tutor_action'] !== 'tutor_complete_course' ) {
613 return;
614 }
615 // Checking nonce
616 tutor_utils()->checking_nonce();
617
618 $user_id = get_current_user_id();
619
620 // TODO: need to show view if not signed_in
621 if ( ! $user_id ) {
622 die( __( 'Please Sign-In', 'tutor' ) );
623 }
624
625 $course_id = (int) $_POST['course_id'];
626
627 do_action( 'tutor_course_complete_before', $course_id );
628 /**
629 * Marking course completed at Comment
630 */
631
632 global $wpdb;
633
634 $date = date( 'Y-m-d H:i:s', tutor_time() );
635
636 // Making sure that, hash is unique
637 do {
638 $hash = substr( md5( wp_generate_password( 32 ) . $date . $course_id . $user_id ), 0, 16 );
639 $hasHash = (int) $wpdb->get_var(
640 $wpdb->prepare(
641 "SELECT COUNT(comment_ID) from {$wpdb->comments}
642 WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ",
643 $hash
644 )
645 );
646
647 } while ( $hasHash > 0 );
648
649 $data = array(
650 'comment_post_ID' => $course_id,
651 'comment_author' => $user_id,
652 'comment_date' => $date,
653 'comment_date_gmt' => get_gmt_from_date( $date ),
654 'comment_content' => $hash, // Identification Hash
655 'comment_approved' => 'approved',
656 'comment_agent' => 'TutorLMSPlugin',
657 'comment_type' => 'course_completed',
658 'user_id' => $user_id,
659 );
660
661 $wpdb->insert( $wpdb->comments, $data );
662
663 do_action( 'tutor_course_complete_after', $course_id, $user_id );
664
665 $permalink = get_the_permalink( $course_id );
666
667 // Set temporary identifier to show review pop up
668 if ( ! get_tutor_option( 'disable_course_review' ) ) {
669 $rating = tutor_utils()->get_course_rating_by_user( $course_id, $user_id );
670 if ( ! $rating || ( empty( $rating->rating ) && empty( $rating->review ) ) ) {
671 update_option(
672 'tutor_course_complete_popup_' . $user_id,
673 array(
674 'course_id' => $course_id,
675 'course_url' => $permalink,
676 'expires' => time() + 10,
677 )
678 );
679 }
680 }
681
682 wp_redirect( $permalink );
683 exit;
684 }
685
686 public function popup_review_form() {
687 if ( is_user_logged_in() ) {
688 $key = 'tutor_course_complete_popup_' . get_current_user_id();
689 $popup = get_option( $key );
690
691 if ( is_array( $popup ) ) {
692
693 if ( $popup['expires'] > time() ) {
694 $course_id = $popup['course_id'];
695 include tutor()->path . 'views/modal/review.php';
696 }
697
698 delete_option( $key );
699 }
700 }
701 }
702
703 public function tutor_load_instructors_modal() {
704 tutils()->checking_nonce();
705
706 global $wpdb;
707
708 $course_id = (int) $_POST['course_id'];
709 $search_terms = sanitize_text_field( tutor_utils()->avalue_dot( 'search_terms', tutor_sanitize_data($_POST) ) );
710
711 if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
712 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
713 }
714
715 $saved_instructors = tutor_utils()->get_instructors_by_course( $course_id );
716 $instructors = array();
717
718 $not_in_sql = apply_filters( 'tutor_instructor_query_when_exists', ' AND ID <1 ' );
719
720 if ( $saved_instructors ) {
721 $saved_instructors_ids = wp_list_pluck( $saved_instructors, 'ID' );
722 $instructor_not_in_ids = implode( ',', $saved_instructors_ids );
723 $not_in_sql .= "AND user.ID NOT IN($instructor_not_in_ids) ";
724 }
725
726 $search_sql = '';
727 if ( $search_terms ) {
728 $search_sql = "AND (user.user_login like '%{$search_terms}%' or user.user_nicename like '%{$search_terms}%' or user.display_name like '%{$search_terms}%') ";
729 }
730
731 $instructors = $wpdb->get_results(
732 "SELECT user.ID, user.display_name from {$wpdb->users} user
733 INNER JOIN {$wpdb->usermeta} meta ON user.ID = meta.user_id AND meta.meta_key = '_tutor_instructor_status' AND meta.meta_value = 'approved'
734 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 "
735 );
736
737 $output = '';
738 if ( is_array( $instructors ) && count( $instructors ) ) {
739 $instructor_output = '';
740 foreach ( $instructors as $instructor ) {
741 $instructor_output .= '<p><label><input type="radio" name="tutor_instructor_ids[]" value="' . $instructor->ID . '" > ' . $instructor->display_name . ' </label></p>';
742 }
743
744 $output .= apply_filters( 'tutor_course_instructors_html', $instructor_output, $instructors );
745
746 } else {
747 $output .= '<p>' . __( 'No instructor available or you have already added maximum instructors', 'tutor' ) . '</p>';
748 }
749
750 if ( ! defined( 'TUTOR_MT_VERSION' ) ) {
751 $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>';
752 }
753
754 wp_send_json_success( array( 'output' => $output ) );
755 }
756
757 public function tutor_add_instructors_to_course() {
758 tutils()->checking_nonce();
759
760 $course_id = (int) $_POST['course_id'];
761 $instructor_ids = tutor_utils()->avalue_dot( 'tutor_instructor_ids', tutor_sanitize_data($_POST) );
762
763 if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
764 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
765 }
766
767 if ( is_array( $instructor_ids ) && count( $instructor_ids ) ) {
768 foreach ( $instructor_ids as $instructor_id ) {
769 add_user_meta( $instructor_id, '_tutor_instructor_course_id', $course_id );
770 }
771 }
772
773 $saved_instructors = tutor_utils()->get_instructors_by_course( $course_id );
774 $output = '';
775
776 if ( $saved_instructors ) {
777 foreach ( $saved_instructors as $t ) {
778
779 $output .= '<div id="added-instructor-id-' . $t->ID . '" class="added-instructor-item added-instructor-item-' . $t->ID . '" data-instructor-id="' . $t->ID . '">
780 <span class="instructor-icon">' . str_replace( "'", '"', get_avatar( $t->ID, 30 ) ) . '</span>
781 <span class="instructor-name"> ' . $t->display_name . ' </span>
782 <span class="instructor-control">
783 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
784 </span>
785 </div>';
786 }
787 }
788
789 wp_send_json_success( array( 'output' => $output ) );
790 }
791
792 public function detach_instructor_from_course() {
793 tutils()->checking_nonce();
794
795 global $wpdb;
796
797 $instructor_id = (int) $_POST['instructor_id'];
798 $course_id = (int) $_POST['course_id'];
799
800 if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
801 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
802 }
803
804 $wpdb->delete(
805 $wpdb->usermeta,
806 array(
807 'user_id' => $instructor_id,
808 'meta_key' => '_tutor_instructor_course_id',
809 'meta_value' => $course_id,
810 )
811 );
812 wp_send_json_success();
813 }
814
815 public function tutor_delete_dashboard_course() {
816 tutils()->checking_nonce();
817
818 $course_id = intval( sanitize_text_field( $_POST['course_id'] ) );
819
820 if ( ! tutils()->can_user_manage( 'course', $course_id ) ) {
821 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
822 }
823
824 wp_trash_post( $course_id );
825 wp_send_json_success( array( 'element' => 'course' ) );
826 }
827
828
829 public function tutor_add_gutenberg_author( $data, $postarr ) {
830 global $wpdb;
831
832 $courses_post_type = tutor()->course_post_type;
833 $post_type = tutils()->array_get( 'post_type', $postarr );
834
835 if ( $courses_post_type === $post_type ) {
836 $post_ID = (int) tutor_utils()->avalue_dot( 'ID', $postarr );
837 $post_author = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID ) );
838
839 if ( $post_author > 0 ) {
840 $data['post_author'] = $post_author;
841 } else {
842 $data['post_author'] = get_current_user_id();
843 }
844 }
845
846 return $data;
847 }
848
849
850 /**
851 * @param $post_ID
852 * @param $postData
853 *
854 * Attach product during save course from the frontend course dashboard.
855 *
856 * @return string
857 *
858 * @since v.1.3.4
859 */
860 public function attach_product_with_course( $post_ID, $postData ) {
861 $attached_product_id = tutor_utils()->get_course_product_id( $post_ID );
862 $course_price = sanitize_text_field( tutor_utils()->array_get( 'course_price', $_POST ) );
863
864 if ( ! $course_price ) {
865 return;
866 }
867
868 $monetize_by = tutor_utils()->get_option( 'monetize_by' );
869 $course = get_post( $post_ID );
870
871 if ( $monetize_by === 'wc' ) {
872
873 $is_update = false;
874 if ( $attached_product_id ) {
875 $wc_product = get_post_meta( $attached_product_id, '_product_version', true );
876 if ( $wc_product ) {
877 $is_update = true;
878 }
879 }
880
881 if ( $is_update ) {
882 $productObj = wc_get_product( $attached_product_id );
883 $productObj->set_price( $course_price ); // set product price
884 $productObj->set_regular_price( $course_price ); // set product regular price
885 $productObj->set_sold_individually( true );
886 $product_id = $productObj->save();
887 if ( $productObj->is_type( 'subscription' ) ) {
888 update_post_meta( $attached_product_id, '_subscription_price', $course_price );
889 }
890 } else {
891 $productObj = new \WC_Product();
892 $productObj->set_name( $course->post_title );
893 $productObj->set_status( 'publish' );
894 $productObj->set_price( $course_price ); // set product price
895 $productObj->set_regular_price( $course_price ); // set product regular price
896 $productObj->set_sold_individually( true );
897
898 $product_id = $productObj->save();
899 if ( $product_id ) {
900 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
901 // Mark product for woocommerce
902 update_post_meta( $product_id, '_virtual', 'yes' );
903 update_post_meta( $product_id, '_tutor_product', 'yes' );
904
905 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
906 if ( $coursePostThumbnail ) {
907 set_post_thumbnail( $product_id, $coursePostThumbnail );
908 }
909 }
910 }
911 } elseif ( $monetize_by === 'edd' ) {
912
913 $is_update = false;
914
915 if ( $attached_product_id ) {
916 $edd_price = get_post_meta( $attached_product_id, 'edd_price', true );
917 if ( $edd_price ) {
918 $is_update = true;
919 }
920 }
921
922 if ( $is_update ) {
923 // Update the product
924 update_post_meta( $attached_product_id, 'edd_price', $course_price );
925 } else {
926 // Create new product
927
928 $post_arr = array(
929 'post_type' => 'download',
930 'post_title' => $course->post_title,
931 'post_status' => 'publish',
932 'post_author' => get_current_user_id(),
933 );
934 $download_id = wp_insert_post( $post_arr );
935 if ( $download_id ) {
936 // edd_price
937 update_post_meta( $download_id, 'edd_price', $course_price );
938
939 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
940 // Mark product for EDD
941 update_post_meta( $download_id, '_tutor_product', 'yes' );
942
943 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
944 if ( $coursePostThumbnail ) {
945 set_post_thumbnail( $download_id, $coursePostThumbnail );
946 }
947 }
948 }
949 }
950
951 }
952
953
954 /**
955 * Add Course level to course settings
956 *
957 * @since v.1.4.1
958 */
959 public function add_course_level_to_settings() {
960 include tutor()->path . 'views/metabox/course-level-metabox.php';
961 }
962
963 /**
964 * Check if course starting
965 *
966 * @since v.1.4.8
967 */
968 public function tutor_lesson_load_before() {
969 $course_id = tutils()->get_course_id_by_content( get_the_ID() );
970 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course( $course_id );
971 if ( is_user_logged_in() ) {
972 $is_course_started = get_post_meta( $course_id, '_tutor_course_started', true );
973 if ( ! $completed_lessons && ! $is_course_started ) {
974 update_post_meta( $course_id, '_tutor_course_started', tutor_time() );
975 do_action( 'tutor/course/started', $course_id );
976 }
977 }
978 }
979
980 /**
981 * Add Course level to course settings
982 *
983 * @since v.1.4.8
984 */
985 public function course_elements_enable_disable() {
986 add_filter( 'tutor_course/single/completing-progress-bar', array( $this, 'enable_disable_course_progress_bar' ) );
987 add_filter( 'tutor_course/single/material_includes', array( $this, 'enable_disable_material_includes' ) );
988 add_filter( 'tutor_course/single/content', array( $this, 'enable_disable_course_content' ) );
989 add_filter( 'tutor_course/single/benefits_html', array( $this, 'enable_disable_course_benefits' ) );
990 add_filter( 'tutor_course/single/requirements_html', array( $this, 'enable_disable_course_requirements' ) );
991 add_filter( 'tutor_course/single/audience_html', array( $this, 'enable_disable_course_target_audience' ) );
992 add_filter( 'tutor_course/single/enrolled/nav_items', array( $this, 'enable_disable_course_nav_items' ) );
993 }
994
995 /**
996 * Enable disable course progress bar
997 *
998 * @since v.1.4.8
999 */
1000 public function enable_disable_course_progress_bar( $html ) {
1001 $disable_option = (bool) get_tutor_option( 'disable_course_progress_bar' );
1002 if ( $disable_option ) {
1003 return '';
1004 }
1005 return $html;
1006 }
1007
1008 /**
1009 * Enable disable material includes
1010 *
1011 * @since v.1.4.8
1012 */
1013 public function enable_disable_material_includes( $html ) {
1014 $disable_option = (bool) get_tutor_option( 'disable_course_material' );
1015 if ( $disable_option ) {
1016 return '';
1017 }
1018 return $html;
1019 }
1020
1021 /**
1022 * Enable disable course content
1023 *
1024 * @since v.1.4.8
1025 */
1026 public function enable_disable_course_content( $html ) {
1027 $disable_option = (bool) get_tutor_option( 'disable_course_description' );
1028 if ( $disable_option ) {
1029 return '';
1030 }
1031 return $html;
1032 }
1033
1034 /**
1035 * Enable disable course benefits
1036 *
1037 * @since v.1.4.8
1038 */
1039 public function enable_disable_course_benefits( $html ) {
1040 $disable_option = (bool) get_tutor_option( 'disable_course_benefits' );
1041 if ( $disable_option ) {
1042 return '';
1043 }
1044 return $html;
1045 }
1046
1047 /**
1048 * Enable disable course requirements
1049 *
1050 * @since v.1.4.8
1051 */
1052 public function enable_disable_course_requirements( $html ) {
1053 $disable_option = (bool) get_tutor_option( 'disable_course_requirements' );
1054 if ( $disable_option ) {
1055 return '';
1056 }
1057 return $html;
1058 }
1059
1060 /**
1061 * Enable disable course target audience
1062 *
1063 * @since v.1.4.8
1064 */
1065 public function enable_disable_course_target_audience( $html ) {
1066 $disable_option = (bool) get_tutor_option( 'disable_course_target_audience' );
1067 if ( $disable_option ) {
1068 return '';
1069 }
1070 return $html;
1071 }
1072
1073 /**
1074 * Enable disable course nav items
1075 *
1076 * @since v.1.4.8
1077 */
1078 public function enable_disable_course_nav_items( $items ) {
1079 global $wp_query, $post;
1080 $enable_q_and_a_on_course = (bool) get_tutor_option( 'enable_q_and_a_on_course' );
1081 $disable_course_announcements = (bool) get_tutor_option( 'disable_course_announcements' );
1082
1083 $disable_qa_for_this_course = ( $wp_query->is_single && ! empty( $post ) ) ? get_post_meta( $post->ID, '_tutor_disable_qa', true ) : '';
1084
1085 if ( ! $enable_q_and_a_on_course || $disable_qa_for_this_course == 'yes' ) {
1086 if ( tutils()->array_get( 'questions', $items ) ) {
1087 unset( $items['questions'] );
1088 }
1089 }
1090 if ( $disable_course_announcements ) {
1091 if ( tutils()->array_get( 'announcements', $items ) ) {
1092 unset( $items['announcements'] );
1093 }
1094 }
1095 return $items;
1096 }
1097
1098 /**
1099 * Filter product in shop page
1100 *
1101 * @since v.1.4.9
1102 */
1103 public function filter_product_in_shop_page() {
1104 $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' );
1105 if ( ! $hide_course_from_shop_page ) {
1106 return;
1107 }
1108 add_action( 'woocommerce_product_query', array( $this, 'filter_woocommerce_product_query' ) );
1109 add_filter( 'edd_downloads_query', array( $this, 'filter_edd_downloads_query' ), 10, 2 );
1110 add_action( 'pre_get_posts', array( $this, 'filter_archive_meta_query' ), 1 );
1111 }
1112
1113 /**
1114 * Tutor product meta query
1115 *
1116 * @since v.1.4.9
1117 */
1118 public function tutor_product_meta_query() {
1119 $meta_query = array(
1120 'key' => '_tutor_product',
1121 'compare' => 'NOT EXISTS',
1122 );
1123 return $meta_query;
1124 }
1125
1126 /**
1127 * Filter product in woocommerce shop page
1128 *
1129 * @since v.1.4.9
1130 */
1131 public function filter_woocommerce_product_query( $wp_query ) {
1132 $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1133 return $wp_query;
1134 }
1135
1136 /**
1137 * Filter product in edd downloads shortcode page
1138 *
1139 * @since v.1.4.9
1140 */
1141 public function filter_edd_downloads_query( $query ) {
1142 $query['meta_query'][] = $this->tutor_product_meta_query();
1143 return $query;
1144 }
1145
1146 /**
1147 * Filter product in edd downloads archive page
1148 *
1149 * @since v.1.4.9
1150 */
1151 public function filter_archive_meta_query( $wp_query ) {
1152 if ( ! is_admin() && $wp_query->is_archive && $wp_query->get( 'post_type' ) === 'download' ) {
1153 $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1154 }
1155 return $wp_query;
1156 }
1157
1158 /**
1159 * @param $html
1160 * @return string
1161 *
1162 * Removed course price if already enrolled at single course
1163 *
1164 * @since v.1.5.8
1165 */
1166 public function remove_price_if_enrolled( $html ) {
1167 $should_removed = apply_filters( 'should_remove_price_if_enrolled', true );
1168
1169 if ( $should_removed ) {
1170 $course_id = get_the_ID();
1171 $enrolled = tutils()->is_enrolled( $course_id );
1172 if ( $enrolled ) {
1173 $html = '';
1174 }
1175 }
1176 return $html;
1177 }
1178
1179 /**
1180 * @param $html
1181 * @return string
1182 *
1183 * Check if all lessons and quizzes done before mark course complete.
1184 */
1185 function tutor_lms_hide_course_complete_btn( $html ) {
1186
1187 $completion_mode = tutils()->get_option( 'course_completion_process' );
1188 if ( $completion_mode !== 'strict' ) {
1189 return $html;
1190 }
1191
1192 $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1193 $lesson_count = tutils()->get_lesson_count_by_course();
1194
1195 if ( $completed_lesson < $lesson_count ) {
1196 return '<p class="suggestion-before-course-complete">' . __( 'complete all lessons to mark this course as complete', 'tutor' ) . '</p>';
1197 }
1198
1199 $quizzes = array();
1200
1201 $course_contents = tutils()->get_course_contents_by_id();
1202 if ( tutils()->count( $course_contents ) ) {
1203 foreach ( $course_contents as $content ) {
1204 if ( $content->post_type === 'tutor_quiz' ) {
1205 $quizzes[] = $content;
1206 }
1207 }
1208 }
1209
1210 $is_pass = true;
1211 $required_quiz_pass = 0;
1212
1213 if ( tutils()->count( $quizzes ) ) {
1214 foreach ( $quizzes as $quiz ) {
1215
1216 $attempt = tutils()->get_quiz_attempt( $quiz->ID );
1217 if ( $attempt ) {
1218 $passing_grade = tutor_utils()->get_quiz_option( $quiz->ID, 'passing_grade', 0 );
1219 $earned_percentage = $attempt->earned_marks > 0 ? ( number_format( ( $attempt->earned_marks * 100 ) / $attempt->total_marks ) ) : 0;
1220
1221 if ( $earned_percentage < $passing_grade ) {
1222 $required_quiz_pass++;
1223 $is_pass = false;
1224 }
1225 } else {
1226 $required_quiz_pass++;
1227 $is_pass = false;
1228 }
1229 }
1230 }
1231
1232 if ( ! $is_pass ) {
1233 return '<p class="suggestion-before-course-complete">' . sprintf( __( 'You have to pass %s quizzes to complete this course.', 'tutor' ), $required_quiz_pass ) . '</p>';
1234 }
1235
1236 return $html;
1237 }
1238
1239 public function get_generate_greadbook( $html ) {
1240 if ( ! tutils()->is_completed_course() ) {
1241 return '';
1242 }
1243 return $html;
1244 }
1245
1246 /**
1247 * Add social share content in header
1248 *
1249 * @since v.1.6.3
1250 */
1251 public function social_share_content() {
1252 global $wp_query, $post;
1253 if ( $wp_query->is_single && ! empty( $wp_query->query_vars['post_type'] ) && $wp_query->query_vars['post_type'] === $this->course_post_type ) { ?>
1254 <!--Facebook-->
1255 <meta property="og:type" content="website"/>
1256 <meta property="og:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>" />
1257 <meta property="og:description" content="<?php echo esc_html( $post->post_content ); ?>" />
1258 <!--Twitter-->
1259 <meta name="twitter:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1260 <meta name="twitter:description" content="<?php echo esc_html( $post->post_content ); ?>">
1261 <!--Google+-->
1262 <meta itemprop="image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1263 <meta itemprop="description" content="<?php echo esc_html( $post->post_content ); ?>">
1264 <?php
1265 }
1266 }
1267
1268 /**
1269 * Get posts by type and parent
1270 *
1271 * @since v.1.6.6
1272 */
1273 public function tutor_get_post_ids( $post_type, $post_parent ) {
1274 $args = array(
1275 'fields' => 'ids',
1276 'post_type' => $post_type,
1277 'post_parent' => $post_parent,
1278 'post_status' => 'any',
1279 'posts_per_page' => -1,
1280 );
1281 return get_posts( $args );
1282 }
1283
1284 /**
1285 * Delete course data when permanently deleting a course.
1286 *
1287 * @since v.1.6.6
1288 */
1289 function delete_tutor_course_data( $post_id ) {
1290 $course_post_type = tutor()->course_post_type;
1291 $lesson_post_type = tutor()->lesson_post_type;
1292
1293 if ( get_post_type( $post_id ) == $course_post_type ) {
1294 global $wpdb;
1295 $topic_ids = $this->tutor_get_post_ids( 'topics', $post_id );
1296 if ( ! empty( $topic_ids ) ) {
1297 foreach ( $topic_ids as $topic_id ) {
1298 $content_post_type = apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) );
1299 $topic_content_ids = $this->tutor_get_post_ids( $content_post_type, $topic_id );
1300
1301 foreach ( $topic_content_ids as $content_id ) {
1302 if ( get_post_type( $content_id ) == 'tutor_quiz' ) {
1303 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempts', array( 'quiz_id' => $content_id ) );
1304 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_attempt_answers', array( 'quiz_id' => $content_id ) );
1305
1306 $questions_ids = $wpdb->get_col( $wpdb->prepare( "SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id ) );
1307 if ( is_array( $questions_ids ) && count( $questions_ids ) ) {
1308 $in_question_ids = "'" . implode( "','", $questions_ids ) . "'";
1309 $wpdb->query( "DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) " );
1310 }
1311 $wpdb->delete( $wpdb->prefix . 'tutor_quiz_questions', array( 'quiz_id' => $content_id ) );
1312 }
1313 wp_delete_post( $content_id, true );
1314 }
1315 wp_delete_post( $topic_id, true );
1316 }
1317 }
1318 $child_post_ids = $this->tutor_get_post_ids( array( 'tutor_announcements', 'tutor_enrolled' ), $post_id );
1319 if ( ! empty( $child_post_ids ) ) {
1320 foreach ( $child_post_ids as $child_post_id ) {
1321 wp_delete_post( $child_post_id, true );
1322 }
1323 }
1324 }
1325 }
1326
1327 /**
1328 * tutor course setting metabox
1329 *
1330 * @since v.1.7.0
1331 */
1332 function tutor_course_setting_metabox( $post ) {
1333
1334 $disable_qa = $this->additional_meta[0];
1335 $is_public = $this->additional_meta[1];
1336
1337 $disable_qa_checked = get_post_meta( $post->ID, $disable_qa, true ) == 'yes' ? 'checked="checked"' : '';
1338 $is_public_checked = get_post_meta( $post->ID, $is_public, true ) == 'yes' ? 'checked="checked"' : '';
1339
1340 do_action( 'tutor_before_course_sidebar_settings_metabox', $post );
1341 ?>
1342 <div class="tutor-course-sidebar-settings-item" id="_tutor_is_course_public_meta_checkbox" style="display:none">
1343 <label for="<?php echo esc_attr( $is_public ); ?>">
1344 <input id="<?php echo esc_attr( $is_public ); ?>" type="checkbox" name="<?php echo esc_attr( $is_public ); ?>" value="yes" <?php echo $is_public_checked; ?> />
1345 <?php _e( 'Make This Course Public', 'tutor' ); ?>
1346 <small style="display:block;padding-left:24px">
1347 <?php _e( 'No enrollment required.', 'tutor' ); ?>
1348 </small>
1349 </label>
1350 </div>
1351 <div class="tutor-course-sidebar-settings-item">
1352 <label for="<?php echo esc_attr( $disable_qa ); ?>">
1353 <input type="hidden" name="_tutor_course_additional_data_edit" value="true" />
1354 <input id="<?php echo esc_attr( $disable_qa ); ?>" type="checkbox" name="<?php echo esc_attr( $disable_qa ); ?>" value="yes" <?php echo $disable_qa_checked; ?> />
1355 <?php _e( 'Disable Q&A', 'tutor' ); ?>
1356 </label>
1357 </div>
1358 <?php
1359 do_action( 'tutor_after_course_sidebar_settings_metabox', $post );
1360 }
1361
1362 function tutor_course_setting_metabox_frontend( $post ) {
1363 ?>
1364 <div class="tutor-course-builder-section tutor-course-builder-info">
1365 <div class="tutor-course-builder-section-title">
1366 <h3><i class="tutor-icon-down"></i><span><?php esc_html_e( 'Tutor Settings', 'tutor' ); ?></span></h3>
1367 </div>
1368 <div class="tutor-course-builder-section-content">
1369 <div class="tutor-frontend-builder-item-scope">
1370 <div class="tutor-form-group">
1371 <?php $this->tutor_course_setting_metabox( $post ); ?>
1372 </div>
1373 </div>
1374 </div>
1375 </div>
1376 <?php
1377 }
1378
1379 /**
1380 * Delete associated enrollment
1381 *
1382 * @since v.1.8.2
1383 */
1384 public function delete_associated_enrollment( $post_id ) {
1385 global $wpdb;
1386
1387 $enroll_id = $wpdb->get_var(
1388 $wpdb->prepare(
1389 "SELECT
1390 post_id
1391 FROM
1392 {$wpdb->postmeta}
1393 WHERE
1394 meta_key='_tutor_enrolled_by_order_id'
1395 AND meta_value = %d
1396 ",
1397 $post_id
1398 )
1399 );
1400
1401 if ( is_numeric( $enroll_id ) && $enroll_id > 0 ) {
1402
1403 $course_id = get_post_field( 'post_parent', $enroll_id );
1404 $user_id = get_post_field( 'post_author', $enroll_id );
1405
1406 tutils()->cancel_course_enrol( $course_id, $user_id );
1407 }
1408 }
1409
1410 public function tutor_reset_course_progress() {
1411 tutils()->checking_nonce();
1412 $course_id = tutor_utils()->array_get( 'course_id', tutor_sanitize_data($_POST) );
1413
1414 if ( ! $course_id || ! is_numeric( $course_id ) || ! tutor_utils()->is_enrolled( $course_id ) ) {
1415 wp_send_json_error( array( 'message' => __( 'Invalid Course ID or Access Denied.', 'tutor' ) ) );
1416 return;
1417 }
1418
1419 tutor_utils()->delete_course_progress( $course_id );
1420 wp_send_json_success( array( 'redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ) );
1421 }
1422
1423 /**
1424 * Do enroll if guest attempt to enroll and course is free
1425 *
1426 * @param $course_id
1427 *
1428 * @since 1.9.8
1429 */
1430 public function enroll_after_login_if_attempt( $course_id ) {
1431 $course_id = sanitize_text_field( $course_id );
1432 if ( $course_id ) {
1433 $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
1434 if ( ! $is_purchasable ) {
1435 tutor_utils()->do_enroll( $course_id );
1436 do_action( 'guest_attempt_after_enrollment', $course_id );
1437 }
1438 }
1439 }
1440 }
1441