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