PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.1.0
Tutor LMS – eLearning and online course solution v2.1.0
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 3 years ago Admin.php 3 years ago Ajax.php 3 years ago Announcements.php 3 years ago Assets.php 3 years ago Backend_Page_Trait.php 3 years ago Course.php 3 years ago Course_Embed.php 3 years ago Course_Filter.php 3 years ago Course_List.php 3 years ago Course_Settings_Tabs.php 3 years ago Course_Widget.php 4 years ago Custom_Validation.php 4 years ago Dashboard.php 3 years ago FormHandler.php 4 years ago Frontend.php 3 years ago Gutenberg.php 3 years ago Input.php 3 years ago Instructor.php 4 years ago Instructors_List.php 3 years ago Lesson.php 3 years ago Options_V2.php 3 years ago Post_types.php 3 years ago Private_Course_Access.php 4 years ago Q_and_A.php 3 years ago Question_Answers_List.php 4 years ago Quiz.php 3 years ago Quiz_Attempts_List.php 3 years ago RestAPI.php 4 years ago Reviews.php 3 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 3 years ago Theme_Compatibility.php 5 years ago Tools.php 3 years ago Tools_V2.php 4 years ago Tutor.php 3 years ago TutorEDD.php 4 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 3 years ago Tutor_Setup.php 3 years ago Upgrader.php 4 years ago User.php 4 years ago Utils.php 3 years ago Video_Stream.php 4 years ago Withdraw.php 3 years ago Withdraw_Requests_List.php 3 years ago WooCommerce.php 3 years ago
Course.php
1400 lines
1 <?php
2 namespace TUTOR;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 use TUTOR\Input;
9 use Tutor\Models\CourseModel;
10
11 class Course extends Tutor_Base {
12
13 private $additional_meta=array(
14 '_tutor_enable_qa',
15 '_tutor_is_public_course'
16 );
17
18 public function __construct() {
19 parent::__construct();
20
21 add_action('add_meta_boxes', array($this, 'register_meta_box') );
22 add_action('save_post_'.$this->course_post_type, array($this, 'save_course_meta'), 10, 2);
23 add_action('wp_ajax_tutor_save_topic', array($this, 'tutor_save_topic'));
24
25 //Add Column
26 add_filter( "manage_{$this->course_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
27 add_action( "manage_{$this->course_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
28
29 add_action('wp_ajax_tutor_delete_topic', array($this, 'tutor_delete_topic'));
30 add_action('admin_action_tutor_delete_announcement', array($this, 'tutor_delete_announcement'));
31
32 // Frontend Action
33 add_action( 'template_redirect', array( $this, 'enroll_now' ) );
34 add_action( 'init', array( $this, 'mark_course_complete' ) );
35
36 /**
37 * Frontend Dashboard
38 */
39 add_action( 'wp_ajax_tutor_delete_dashboard_course', array( $this, 'tutor_delete_dashboard_course' ) );
40
41 /**
42 * Gutenberg author support
43 */
44 add_filter( 'wp_insert_post_data', array( $this, 'tutor_add_gutenberg_author' ), '99', 2 );
45
46 /**
47 * Frontend metabox supports for course builder
48 *
49 * @since v.1.3.4
50 */
51 add_action( 'tutor/dashboard_course_builder_form_field_after', array( $this, 'register_meta_box_in_frontend' ) );
52
53 /**
54 * Do Stuff for the course save from frontend
55 */
56 add_action( 'save_tutor_course', array( $this, 'attach_product_with_course' ), 10, 2 );
57
58 /**
59 * Add course level to course settings
60 *
61 * @since v.1.4.1
62 */
63 add_filter( 'tutor_course_settings_tabs', array($this, 'add_course_level_to_settings'));
64
65 /**
66 * Enable Disable Course Details Page Feature
67 *
68 * @since v.1.4.8
69 */
70 $this->course_elements_enable_disable();
71
72 /**
73 * @since v.1.4.8
74 * Check if course starting, set meta if starting
75 */
76 add_action( 'tutor_lesson_load_before', array( $this, 'tutor_lesson_load_before' ) );
77
78 /**
79 * @since v.1.4.9
80 * Filter product in shop page
81 */
82 $this->filter_product_in_shop_page();
83
84 /**
85 * Remove the course price if enrolled
86 * @since 1.5.8
87 */
88 add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
89
90 /**
91 * Remove course complete button if course completion is strict mode
92 * @since v.1.6.1
93 */
94 add_filter('tutor_course/single/complete_form', array($this, 'tutor_lms_hide_course_complete_btn'));
95 add_filter('get_gradebook_generate_form_html', array($this, 'get_generate_greadbook'));
96
97 /**
98 * Add social share content in header
99 * @since v.1.6.3
100 */
101 add_action('wp_head', array($this, 'social_share_content'));
102
103 /**
104 * Delete course data after deleted course
105 * @since v.1.6.6
106 */
107 add_action( 'deleted_post', array( new CourseModel, 'delete_course_data' ) );
108
109 /**
110 * Delete course data after deleted course
111 *
112 * @since v.1.8.2
113 */
114 add_action( 'before_delete_post', array( $this, 'delete_associated_enrollment' ) );
115
116 /**
117 * Show only own uploads in media library if user is instructor
118 *
119 * @since v1.8.9
120 */
121 add_filter( 'posts_where', array( $this, 'restrict_media' ) );
122
123 /**
124 * Restrict new enrol/purchase button if course member limit reached
125 *
126 * @since v1.9.0
127 */
128 add_filter( 'tutor_course_restrict_new_entry', array( $this, 'restrict_new_student_entry' ) );
129
130 /**
131 * Reset course progress on retake
132 *
133 * @since v1.9.5
134 */
135 add_action( 'wp_ajax_tutor_reset_course_progress', array( $this, 'tutor_reset_course_progress' ) );
136
137 /**
138 * Popup for review
139 *
140 * @since v1.9.7
141 */
142 add_action( 'wp_footer', array( $this, 'popup_review_form' ) );
143
144 /**
145 * Do enroll after login if guest take enroll attempt
146 *
147 * @since 1.9.8
148 */
149 add_action( 'tutor_do_enroll_after_login_if_attempt', array( $this, 'enroll_after_login_if_attempt' ), 10, 2 );
150
151 add_action( 'wp_ajax_tutor_update_course_content_order', array($this, 'tutor_update_course_content_order') );
152
153 add_action( 'wp_ajax_tutor_get_wc_product', array( $this, 'tutor_get_wc_product' ) );
154
155 add_action( 'wp_ajax_tutor_course_enrollment', array( $this, 'course_enrollment' ) );
156 }
157
158 /**
159 * Get course associate WC product info by Ajax request
160 *
161 * @return void
162 *
163 * @since 2.0.7
164 */
165 public function tutor_get_wc_product() {
166 tutor_utils()->checking_nonce();
167 $product_id = Input::post( 'product_id' );
168 $product = wc_get_product( $product_id );
169 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
170
171 $is_linked_with_course = tutor_utils()->product_belongs_with_course( $product_id );
172 /**
173 * If selected product is already linked with
174 * a course & it is not the current course the
175 * return error
176 *
177 * @since v2.1.0
178 */
179 if ( is_object( $is_linked_with_course ) && $is_linked_with_course->post_id != $course_id ) {
180 wp_send_json_error(
181 __( 'One product can not be added to multiple course!', 'tutor' )
182 );
183 }
184
185 if ( $product ) {
186 $data = array(
187 'name' => $product->get_name(),
188 'regular_price'=> $product->get_regular_price(),
189 'sale_price' => $product->get_sale_price()
190 );
191 wp_send_json_success( $data );
192 }else{
193 wp_send_json_error( __( 'Product not found', 'tutor' ) );
194 }
195 }
196
197 public function tutor_update_course_content_order() {
198 tutor_utils()->checking_nonce();
199
200 if(isset($_POST['content_parent'])) {
201 $topic_id = (int)tutor_utils()->array_get('parent_topic_id', $_POST['content_parent']);
202 $content_id = (int)tutor_utils()->array_get('content_id', $_POST['content_parent']);
203
204 if(!tutor_utils()->can_user_manage('topic', $topic_id)) {
205 wp_send_json_success(array('message' => __('Access Denied!', 'tutor')));
206 exit;
207 }
208
209 // Update the parent topic id of the content
210 global $wpdb;
211 $wpdb->update($wpdb->posts, array( 'post_parent' => $topic_id ), array( 'ID' => $content_id ));
212 }
213
214 // Save course content order
215 $this->save_course_content_order();
216
217 wp_send_json_success();
218 }
219
220 public function restrict_new_student_entry($content) {
221
222 if(!tutor_utils()->is_course_fully_booked()) {
223 // No restriction if not fully booked
224 return $content;
225 }
226
227 return '<div class="list-item-booking booking-full tutor-d-flex tutor-align-center"><div class="booking-progress tutor-d-flex"><span class="tutor-mr-8 tutor-color-warning tutor-icon-circle-info"></span></div><div class="tutor-fs-7 tutor-fw-medium">Fully Booked</div></div>';
228 }
229
230 function restrict_media( $where ) {
231
232 if ( isset( $_POST['action'] ) && $_POST['action'] == 'query-attachments' && tutor_utils()->is_instructor() ) {
233 if ( ! tutor_utils()->has_user_role( array( 'administrator', 'editor' ) ) ) {
234 $where .= ' AND post_author=' . get_current_user_id();
235 }
236 }
237
238 return $where;
239 }
240
241 /**
242 * Registering metabox
243 */
244 public function register_meta_box(){
245 $coursePostType = tutor()->course_post_type;
246
247 tutor_meta_box_wrapper( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType, 'advanced', 'default', 'tutor-admin-post-meta' );
248
249 tutor_meta_box_wrapper( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType, 'advanced', 'default', 'tutor-admin-post-meta' );
250
251 tutor_meta_box_wrapper( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType, 'advanced', 'default', 'tutor-admin-post-meta' );
252 }
253
254 public function course_meta_box( $echo = true ) {
255 ob_start();
256 include tutor()->path . 'views/metabox/course-topics.php';
257 $content = ob_get_clean();
258
259 if ( $echo ) {
260 // echo tutor_kses_html( $content ); Doesn't support SVG. It is restored in version 2 and we've got rid of SVG and used icon font instead.
261 echo $content;
262 } else {
263 return $content;
264 }
265 }
266
267 public function course_additional_data_meta_box( $echo = true ) {
268
269 ob_start();
270 include tutor()->path . 'views/metabox/course-additional-data.php';
271 $content = ob_get_clean();
272
273 if ( $echo ) {
274 echo tutor_kses_html( $content );
275 } else {
276 return $content;
277 }
278 }
279
280 public function video_metabox( $echo = true ) {
281 ob_start();
282 include tutor()->path . 'views/metabox/video-metabox.php';
283 $content = ob_get_clean();
284
285 if ( $echo ) {
286 echo tutor_kses_html( $content ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
287 } else {
288 return $content;
289 }
290 }
291
292 /**
293 * Register metabox in course builder tutor
294 *
295 * @since v.1.3.4
296 */
297 public function register_meta_box_in_frontend(){
298 global $post;
299
300 do_action('tutor_course_builder_metabox_before', get_the_ID());
301
302 course_builder_section_wrap($this->video_metabox($echo = false), __( 'Video', 'tutor' ) );
303 do_action('tutor/frontend_course_edit/after/video', $post);
304
305 course_builder_section_wrap($this->course_meta_box($echo = false), __( 'Course Builder', 'tutor' ) );
306 do_action('tutor/frontend_course_edit/after/course_builder', $post);
307
308 course_builder_section_wrap($this->course_additional_data_meta_box($echo = false), __( 'Additional Data', 'tutor' ) );
309 do_action('tutor/frontend_course_edit/after/additional_data', $post);
310
311 do_action('tutor_course_builder_metabox_after', get_the_ID());
312 }
313
314 private function save_course_content_order(){
315 global $wpdb;
316
317 if ( ! empty( $_POST['tutor_topics_lessons_sorting'] ) ) {
318 $new_order = sanitize_text_field( stripslashes( $_POST['tutor_topics_lessons_sorting'] ) );
319 $order = json_decode( $new_order, true );
320
321 if ( is_array( $order ) && count( $order ) ) {
322 $i = 0;
323 foreach ( $order as $topic ) {
324 $i++;
325 $wpdb->update(
326 $wpdb->posts,
327 array( 'menu_order' => $i ),
328 array( 'ID' => $topic['topic_id'] )
329 );
330
331 /**
332 * Removing All lesson with topic
333 */
334
335 $wpdb->update(
336 $wpdb->posts,
337 array( 'post_parent' => 0 ),
338 array( 'post_parent' => $topic['topic_id'] )
339 );
340
341 /**
342 * Lesson Attaching with topic ID
343 * sorting lesson
344 */
345 if ( isset( $topic['lesson_ids'] ) ) {
346 $lesson_ids = $topic['lesson_ids'];
347 } else {
348 $lesson_ids = array();
349 }
350 if ( count( $lesson_ids ) ) {
351 foreach ( $lesson_ids as $lesson_key => $lesson_id ) {
352 $wpdb->update(
353 $wpdb->posts,
354 array(
355 'post_parent' => $topic['topic_id'],
356 'menu_order' => $lesson_key,
357 ),
358 array( 'ID' => $lesson_id )
359 );
360 }
361 }
362 }
363 }
364 }
365 }
366
367 /**
368 * @param $post_ID
369 *
370 * Insert Topic and attached it with Course
371 */
372 public function save_course_meta( $post_ID, $post ) {
373 global $wpdb;
374
375 do_action( 'tutor_save_course', $post_ID, $post );
376
377 /**
378 * Save course price type
379 */
380 $price_type = Input::post( 'tutor_course_price_type' );
381 if ( $price_type ) {
382 update_post_meta($post_ID, '_tutor_course_price_type', $price_type);
383 }
384
385 //Course Duration
386 if ( ! empty($_POST['course_duration'])){
387 $video = tutor_utils()->sanitize_array($_POST['course_duration']);
388 update_post_meta($post_ID, '_course_duration', $video);
389 }
390
391 if ( ! empty($_POST['_tutor_course_level'])){
392 $course_level = sanitize_text_field($_POST['_tutor_course_level']);
393 update_post_meta($post_ID, '_tutor_course_level', $course_level);
394 }
395
396 $additional_data_edit = tutor_utils()->avalue_dot('_tutor_course_additional_data_edit', $_POST);
397 if ($additional_data_edit) {
398 if (!empty($_POST['course_benefits'])) {
399 $course_benefits = wp_kses_post($_POST['course_benefits']);
400 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
401 } else {
402 delete_post_meta( $post_ID, '_tutor_course_benefits' );
403 }
404
405 if ( ! empty( $_POST['course_requirements'] ) ) {
406 $requirements = wp_kses_post( $_POST['course_requirements'] );
407 update_post_meta( $post_ID, '_tutor_course_requirements', $requirements );
408 } else {
409 delete_post_meta( $post_ID, '_tutor_course_requirements' );
410 }
411
412 if ( ! empty( $_POST['course_target_audience'] ) ) {
413 $target_audience = wp_kses_post( $_POST['course_target_audience'] );
414 update_post_meta( $post_ID, '_tutor_course_target_audience', $target_audience );
415 } else {
416 delete_post_meta( $post_ID, '_tutor_course_target_audience' );
417 }
418
419 if ( ! empty( $_POST['course_material_includes'] ) ) {
420 $material_includes = wp_kses_post( $_POST['course_material_includes'] );
421 update_post_meta( $post_ID, '_tutor_course_material_includes', $material_includes );
422 } else {
423 delete_post_meta( $post_ID, '_tutor_course_material_includes' );
424 }
425 }
426
427 /**
428 * Sorting Topics and lesson
429 */
430 $this->save_course_content_order();
431
432 // Additional data like course intro video
433 if ( $additional_data_edit ) {
434 if ( ! empty( $_POST['video']['source'] ) ) { // Video
435 $video = tutor_utils()->array_get( 'video', $_POST );
436 update_post_meta( $post_ID, '_video', $video );
437 } else {
438 delete_post_meta( $post_ID, '_video' );
439 }
440 }
441
442 /**
443 * Adding author to instructor automatically
444 */
445
446 // Override post author id.
447 $author_id = isset( $_POST['post_author_override'] ) ? $_POST['post_author_override'] : $post->post_author; //phpcs:ignore
448 $attached = (int) $wpdb->get_var(
449 $wpdb->prepare(
450 "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta}
451 WHERE user_id = %d
452 AND meta_key = '_tutor_instructor_course_id'
453 AND meta_value = %d ",
454 $author_id,
455 $post_ID
456 )
457 );
458
459 if ( ! $attached ) {
460 add_user_meta( $author_id, '_tutor_instructor_course_id', $post_ID );
461 }
462
463 /**
464 * Disable question and answer for this course
465 *
466 * @since 1.7.0
467 */
468 if ( $additional_data_edit ) {
469 foreach ( $this->additional_meta as $key ) {
470 update_post_meta( $post_ID, $key, ( isset( $_POST[ $key ] ) ? 'yes' : 'no' ) );
471 }
472 }
473
474 do_action( 'tutor_save_course_after', $post_ID, $post );
475 }
476
477 /**
478 * Tutor add course topic
479 */
480 public function tutor_save_topic(){
481 tutor_utils()->checking_nonce();
482
483 // Check required fields
484 if ( empty( Input::post( 'topic_title' ) ) ) {
485 wp_send_json_error( array( 'message' => __( 'Topic title is required!', 'tutor' ) ) );
486 }
487
488 // Gather parameters
489 $course_id = Input::post( 'topic_course_id', 0, Input::TYPE_INT );
490 $topic_id = Input::post( 'topic_id', 0, Input::TYPE_INT );
491 $topic_title = Input::post( 'topic_title' );
492 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
493 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id, $topic_id);
494
495 // Validate if user can manage the topic
496 if ( ! tutor_utils()->can_user_manage( 'course', $course_id ) || ( $topic_id && !tutor_utils()->can_user_manage('topic', $topic_id ) ) ) {
497 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
498 }
499
500 // Create payload to create/update the topic
501 $post_arr = array(
502 'post_type' => 'topics',
503 'post_title' => $topic_title,
504 'post_content' => $topic_summery,
505 'post_status' => 'publish',
506 'post_author' => get_current_user_id(),
507 'post_parent' => $course_id,
508 'menu_order' => $next_topic_order_id,
509 );
510 $topic_id ? $post_arr['ID']=$topic_id : 0;
511 $current_topic_id = wp_insert_post( $post_arr );
512
513 ob_start();
514 include tutor()->path.'views/metabox/course-contents.php';
515
516 wp_send_json_success( array(
517 'topic_title' => $topic_title,
518 'course_contents' => ob_get_clean()
519 ));
520 }
521
522 /**
523 * @param $columns
524 *
525 * @return mixed
526 *
527 * Add Lesson column
528 */
529 public function add_column( $columns ) {
530 $date_col = $columns['date'];
531 unset( $columns['date'] );
532 $columns['lessons'] = __( 'Lessons', 'tutor' );
533 $columns['students'] = __( 'Students', 'tutor' );
534 $columns['price'] = __( 'Price', 'tutor' );
535 $columns['date'] = $date_col;
536
537 return $columns;
538 }
539
540 /**
541 * @param $column
542 * @param $post_id
543 */
544 public function custom_lesson_column( $column, $post_id ) {
545 if ( $column === 'lessons' ) {
546 echo tutor_utils()->get_lesson_count_by_course( $post_id );
547 }
548
549 if ( $column === 'students' ) {
550 echo tutor_utils()->count_enrolled_users_by_course( $post_id );
551 }
552
553 if ( $column === 'price' ) {
554 $price = tutor_utils()->get_course_price( $post_id );
555 if ( $price ) {
556 $monetize_by = tutils()->get_option( 'monetize_by' );
557 if ( function_exists( 'wc_price' ) && $monetize_by === 'wc' ) {
558 echo '<span class="tutor-label-success">' . wc_price( $price ) . '</span>';
559 } else {
560 echo '<span class="tutor-label-success">' . $price . '</span>';
561 }
562 } else {
563 echo apply_filters( 'tutor-loop-default-price', __( 'free', 'tutor' ) );
564 }
565 }
566 }
567
568
569 public function tutor_delete_topic() {
570
571 tutor_utils()->checking_nonce();
572
573 global $wpdb;
574 $topic_id = sanitize_text_field(!empty($_POST['topic_id']) ? $_POST['topic_id'] : '');
575
576 if(!$topic_id || !is_numeric($topic_id) || !tutor_utils()->can_user_manage('topic', $topic_id)) {
577 wp_send_json_error(array('message' => 'Access Forbidden'));
578 }
579
580 // Assign course ID to orphan content IDs since the topic will be deleted.
581 $course_id = tutor_utils()->get_course_id_by('topic', $topic_id);
582 $content_ids = tutor_utils()->get_course_content_ids_by(null, 'topic', $topic_id);
583 foreach($content_ids as $content_id) {
584 update_post_meta( $content_id, '_tutor_course_id_for_lesson', $course_id );
585 // Actually all kind of contents.
586 // This keyword '_tutor_course_id_for_lesson' used just to support backward compatibillity
587 }
588
589 // Set contents under the topic orphan
590 $wpdb->update($wpdb->posts, array('post_parent' => 0), array('post_parent' => $topic_id));
591
592 // Then delete the topic from database
593 $wpdb->delete($wpdb->postmeta, array('post_id' => $topic_id));
594 wp_delete_post($topic_id);
595
596 wp_send_json_success();
597 }
598
599 public function tutor_delete_announcement() {
600 tutor_utils()->checking_nonce( 'get' );
601
602 $announcement_id = (int) $_GET['topic_id'];
603
604 wp_delete_post( $announcement_id );
605 wp_safe_redirect( wp_get_referer() );
606 }
607
608 public function enroll_now() {
609
610 // Checking if action comes from Enroll form
611 if ( tutor_utils()->array_get( 'tutor_course_action', tutor_sanitize_data($_POST) ) !== '_tutor_course_enroll_now' || ! isset( $_POST['tutor_course_id'] ) ) {
612 return;
613 }
614
615 //Checking Nonce
616 tutor_utils()->checking_nonce();
617
618 $user_id = get_current_user_id();
619 if ( ! $user_id ) {
620 exit( __( 'Please Sign In first', 'tutor' ) );
621 }
622
623 $course_id = (int) $_POST['tutor_course_id'];
624 $user_id = get_current_user_id();
625
626 /**
627 * TODO: need to check purchase information
628 */
629
630 $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
631
632 /**
633 * If is is not purchasable, it's free, and enroll right now
634 *
635 * if purchasable, then process purchase.
636 *
637 * @since: v.1.0.0
638 */
639 if ( $is_purchasable ) {
640 // process purchase
641
642 } else {
643 // Free enroll
644 tutor_utils()->do_enroll( $course_id );
645 }
646
647 $referer_url = wp_get_referer();
648 wp_redirect( $referer_url );
649 }
650
651 /**
652 *
653 * Mark complete completed
654 *
655 * @since v.1.0.0
656 */
657 public function mark_course_complete() {
658 $tutor_action = Input::post( 'tutor_action' );
659 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
660 if ( $tutor_action !== 'tutor_complete_course' || ! $course_id ) {
661 return;
662 }
663
664 // Checking nonce
665 tutor_utils()->checking_nonce();
666
667 $user_id = get_current_user_id();
668
669 // TODO: need to show view if not signed_in
670 if ( ! $user_id ) {
671 die( __( 'Please Sign-In', 'tutor' ) );
672 }
673
674 CourseModel::mark_course_as_completed( $course_id, $user_id );
675
676 $permalink = get_the_permalink( $course_id );
677
678 // Set temporary identifier to show review pop up
679 if(get_tutor_option( 'enable_course_review' )) {
680 $rating = tutor_utils()->get_course_rating_by_user($course_id, $user_id);
681 if(!$rating || (empty($rating->rating) && empty($rating->review))) {
682 update_option( 'tutor_course_complete_popup_'.$user_id, array(
683 'course_id' => $course_id,
684 'course_url' => $permalink,
685 'expires' => time()+10
686 ));
687 }
688 }
689
690 wp_redirect( $permalink );
691 exit;
692 }
693
694 public function popup_review_form() {
695 if ( is_user_logged_in() ) {
696 $key = 'tutor_course_complete_popup_' . get_current_user_id();
697 $popup = get_option( $key );
698
699 if ( is_array( $popup ) ) {
700
701 if ( $popup['expires'] > time() ) {
702 $course_id = $popup['course_id'];
703 include tutor()->path . 'views/modal/review.php';
704 }
705
706 delete_option( $key );
707 }
708 }
709 }
710
711 /**
712 * Delete course delete from frontend dashboard
713 *
714 * @since 2.0.0
715 * @return void
716 */
717 public function tutor_delete_dashboard_course(){
718 tutor_utils()->checking_nonce();
719
720 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
721 if ( ! tutor_utils()->can_user_manage( 'course', $course_id ) ) {
722 wp_send_json_error( array( 'message'=> __( 'Access Denied', 'tutor' ) ) );
723 }
724
725 CourseModel::delete_course( $course_id );
726 wp_send_json_success();
727 }
728
729 /**
730 * Main author change from gutenberg editor
731 *
732 * @param array $data
733 * @param array $postarr
734 * @return void
735 *
736 * @since 2.0.0
737 */
738 public function tutor_add_gutenberg_author( $data, $postarr ) {
739 $gutenberg_enabled = tutor_utils()->get_option( 'enable_gutenberg_course_edit' );
740 $post_type = $postarr['post_type'];
741 $courses_post_type = tutor()->course_post_type;
742
743 if ( false === $gutenberg_enabled && $post_type !== $courses_post_type ) {
744 return $data;
745 }
746
747 /**
748 * Only admin can change main author
749 */
750 if ( $courses_post_type === $post_type && ! current_user_can( 'administrator' ) ) {
751 global $wpdb;
752 $post_ID = (int) tutor_utils()->avalue_dot( 'ID', $postarr );
753 $post_author = (int) $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID ) );
754
755 if ( $post_author > 0 ) {
756 $data['post_author'] = $post_author;
757 } else {
758 $data['post_author'] = get_current_user_id();
759 }
760 }
761
762 return $data;
763 }
764
765
766 /**
767 * Attach product with course when course save from frontend or backend.
768 *
769 * @param $post_ID course ID
770 * @param $postData cretaed course post details
771 *
772 * @return void
773 *
774 * @since v.1.3.4
775 */
776 public function attach_product_with_course( $post_ID, $postData ) {
777
778 $monetize_by = tutor_utils()->get_option( 'monetize_by' );
779
780 /**
781 * The function is_admin will check only loaded page from WP admin.
782 * It does not check any role
783 */
784 $is_admin_panel = is_admin();
785 // From backend course select box
786 $product_id = Input::post( '_tutor_course_product_id', 0, Input::TYPE_INT );
787
788 /**
789 * From Admin Panel, Free user can only select product from dropdown
790 */
791 if ( $is_admin_panel && 'wc' === $monetize_by && tutor()->has_pro === false ) {
792 if ( $product_id > 0 ) {
793 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
794 }
795 else if( $product_id === -1 ) {
796 delete_post_meta( $post_ID, '_tutor_course_product_id' );
797 }
798
799 return;
800 }
801
802 $attached_product_id = tutor_utils()->get_course_product_id( $post_ID );
803 $course_price = Input::post( 'course_price', 0, Input::TYPE_NUMERIC );
804 $sale_price = Input::post( 'course_sale_price', 0, Input::TYPE_NUMERIC );
805
806 if ( ! $course_price || $sale_price >= $course_price ) {
807 return;
808 }
809
810 $course = get_post( $post_ID );
811
812 if ( $monetize_by === 'wc' ) {
813
814 $is_update = false;
815 if ( $attached_product_id ) {
816 $wc_product = get_post_meta( $attached_product_id, '_product_version', true );
817 if ( $wc_product ) {
818 $is_update = true;
819 }
820 }
821
822 if ( $is_update || ( $product_id > 0 && $is_admin_panel ) ) {
823 /**
824 * @since 2.0.7
825 */
826 if ( $product_id > 0 && $is_admin_panel ) {
827 $attached_product_id = $product_id;
828 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
829 }
830
831 $productObj = wc_get_product( $attached_product_id );
832 $productObj->set_price( $course_price ); // set product price
833 $productObj->set_regular_price( $course_price ); // set product regular price
834
835 if ( $sale_price > 0 ) {
836 $productObj->set_sale_price( $sale_price );
837 } else {
838 //When use remove sale price ( discounted price )
839 $productObj->set_sale_price( null );
840 }
841
842 $productObj->set_sold_individually( true );
843 $product_id = $productObj->save();
844 if ( $productObj->is_type( 'subscription' ) ) {
845 update_post_meta( $attached_product_id, '_subscription_price', $course_price );
846 }
847 } else {
848 $productObj = new \WC_Product();
849 $productObj->set_name( $course->post_title );
850 $productObj->set_status( 'publish' );
851 $productObj->set_price( $course_price ); // set product price
852 $productObj->set_regular_price( $course_price ); // set product regular price
853
854 if ( $sale_price > 0 ) {
855 $productObj->set_sale_price( $sale_price );
856 }
857
858 $productObj->set_sold_individually( true );
859
860 $product_id = $productObj->save();
861 if ( $product_id ) {
862 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
863 // Mark product for woocommerce
864 update_post_meta( $product_id, '_virtual', 'yes' );
865 update_post_meta( $product_id, '_tutor_product', 'yes' );
866
867 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
868 if ( $coursePostThumbnail ) {
869 set_post_thumbnail( $product_id, $coursePostThumbnail );
870 }
871 }
872 }
873 } elseif ( $monetize_by === 'edd' ) {
874
875 $is_update = false;
876
877 if ( $attached_product_id ) {
878 $edd_price = get_post_meta( $attached_product_id, 'edd_price', true );
879 if ( $edd_price ) {
880 $is_update = true;
881 }
882 }
883
884 if ( $is_update ) {
885 // Update the product
886 update_post_meta( $attached_product_id, 'edd_price', $course_price );
887 } else {
888 // Create new product
889
890 $post_arr = array(
891 'post_type' => 'download',
892 'post_title' => $course->post_title,
893 'post_status' => 'publish',
894 'post_author' => get_current_user_id(),
895 );
896 $download_id = wp_insert_post( $post_arr );
897 if ( $download_id ) {
898 // edd_price
899 update_post_meta( $download_id, 'edd_price', $course_price );
900
901 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
902 // Mark product for EDD
903 update_post_meta( $download_id, '_tutor_product', 'yes' );
904
905 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
906 if ( $coursePostThumbnail ) {
907 set_post_thumbnail( $download_id, $coursePostThumbnail );
908 }
909 }
910 }
911 }
912 }
913
914 /**
915 * Add Course level to course settings
916 *
917 * @since v.1.4.1
918 */
919 public function add_course_level_to_settings($args){
920 $course_id = get_the_ID();
921 $levels = tutor_utils()->course_levels();
922 $course_level = get_post_meta($course_id, '_tutor_course_level', true);
923
924 $args['general']['fields']['_tutor_course_level'] = array(
925 'type' => 'select',
926 'label' => __('Difficulty Level', 'tutor'),
927 'label_title'=> __('Enable', 'tutor'),
928 'options' => $levels,
929 'value' => $course_level ? $course_level : 'intermediate',
930 'desc' => __('Course difficulty level', 'tutor'),
931 );
932
933 return $args;
934 }
935
936 /**
937 * Check if course starting
938 *
939 * @since v.1.4.8
940 */
941 public function tutor_lesson_load_before(){
942 $course_id = tutor_utils()->get_course_id_by_content(get_the_ID());
943 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
944 if (is_user_logged_in()){
945 $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
946 if ( ! $completed_lessons && ! $is_course_started){
947 update_post_meta($course_id, '_tutor_course_started', tutor_time());
948 do_action('tutor/course/started', $course_id);
949 }
950 }
951 }
952
953 /**
954 * Add Course level to course settings
955 *
956 * @since v.1.4.8
957 */
958 public function course_elements_enable_disable(){
959 add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
960 add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
961 add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
962 add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
963 add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
964 add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
965 add_filter('tutor_course/single/nav_items', array($this, 'enable_disable_course_nav_items'), 999, 2 );
966 }
967
968 /**
969 * Enable disable course progress bar
970 *
971 * @since v.1.4.8
972 */
973 public function enable_disable_course_progress_bar($html){
974 $disable_option = !(bool)tutor_utils()->get_option('enable_course_progress_bar', true, true);
975 if($disable_option){
976 return '';
977 }
978 return $html;
979 }
980
981 /**
982 * Enable disable material includes
983 *
984 * @since v.1.4.8
985 */
986 public function enable_disable_material_includes($html){
987 $disable_option = !(bool)get_tutor_option('enable_course_material', true, true);
988 if($disable_option){
989 return '';
990 }
991 return $html;
992 }
993
994 /**
995 * Enable disable course content
996 *
997 * @since v.1.4.8
998 */
999 public function enable_disable_course_content($html){
1000 $disable_option = !(bool)tutor_utils()->get_option('enable_course_description', true, true);
1001 if($disable_option){
1002 return '';
1003 }
1004 return $html;
1005 }
1006
1007 /**
1008 * Enable disable course benefits
1009 *
1010 * @since v.1.4.8
1011 */
1012 public function enable_disable_course_benefits($html){
1013 $disable_option = !(bool) tutor_utils()->get_option('enable_course_benefits', true, true);
1014 if($disable_option){
1015 return '';
1016 }
1017 return $html;
1018 }
1019
1020 /**
1021 * Enable disable course requirements
1022 *
1023 * @since v.1.4.8
1024 */
1025 public function enable_disable_course_requirements($html){
1026 $disable_option = !(bool) tutor_utils()->get_option('enable_course_requirements', true, true);
1027 if($disable_option){
1028 return '';
1029 }
1030 return $html;
1031 }
1032
1033 /**
1034 * Enable disable course target audience
1035 *
1036 * @since v.1.4.8
1037 */
1038 public function enable_disable_course_target_audience($html){
1039 $disable_option = !(bool) tutor_utils()->get_option('enable_course_target_audience', true, true);
1040 if($disable_option){
1041 return '';
1042 }
1043 return $html;
1044 }
1045
1046 /**
1047 * Enable disable course nav items
1048 *
1049 * @since v.1.4.8
1050 */
1051 public function enable_disable_course_nav_items($items, $course_id){
1052 global $wp_query, $post;
1053 $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
1054 $disable_course_announcements = !(bool) tutor_utils()->get_option('enable_course_announcements', true, true);
1055 $disable_qa_for_this_course = ($wp_query->is_single && !empty($post)) ? get_post_meta($post->ID, '_tutor_enable_qa', true)!='yes' : false;
1056
1057 // Whether Q&A enabled
1058 if(!$enable_q_and_a_on_course || $disable_qa_for_this_course) {
1059 if(tutor_utils()->array_get('questions', $items)) {
1060 unset($items['questions']);
1061 }
1062 }
1063
1064 // Whether announcment enabled
1065 if($disable_course_announcements){
1066 if(tutor_utils()->array_get('announcements', $items)) {
1067 unset($items['announcements']);
1068 }
1069 }
1070
1071 // Hide review section if disabled
1072 if(!get_tutor_option('enable_course_review')) {
1073 unset($items['reviews']);
1074 }
1075
1076 // Whether enrollment require
1077 $is_enrolled = tutor_utils()->is_enrolled();
1078
1079 return array_filter($items, function($item) use($is_enrolled) {
1080 if(isset($item['require_enrolment']) && $item['require_enrolment']) {
1081 return $is_enrolled;
1082 }
1083 return true;
1084 });
1085 }
1086
1087 /**
1088 * Filter product in shop page
1089 *
1090 * @since v.1.4.9
1091 */
1092 public function filter_product_in_shop_page() {
1093 $hide_course_from_shop_page = (bool) get_tutor_option( 'hide_course_from_shop_page' );
1094 if ( ! $hide_course_from_shop_page ) {
1095 return;
1096 }
1097 add_action( 'woocommerce_product_query', array( $this, 'filter_woocommerce_product_query' ) );
1098 add_filter( 'edd_downloads_query', array( $this, 'filter_edd_downloads_query' ), 10, 2 );
1099 add_action( 'pre_get_posts', array( $this, 'filter_archive_meta_query' ), 1 );
1100 }
1101
1102 /**
1103 * Tutor product meta query
1104 *
1105 * @since v.1.4.9
1106 */
1107 public function tutor_product_meta_query() {
1108 $meta_query = array(
1109 'key' => '_tutor_product',
1110 'compare' => 'NOT EXISTS',
1111 );
1112 return $meta_query;
1113 }
1114
1115 /**
1116 * Filter product in woocommerce shop page
1117 *
1118 * @since v.1.4.9
1119 */
1120 public function filter_woocommerce_product_query( $wp_query ) {
1121 $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1122 return $wp_query;
1123 }
1124
1125 /**
1126 * Filter product in edd downloads shortcode page
1127 *
1128 * @since v.1.4.9
1129 */
1130 public function filter_edd_downloads_query( $query ) {
1131 $query['meta_query'][] = $this->tutor_product_meta_query();
1132 return $query;
1133 }
1134
1135 /**
1136 * Filter product in edd downloads archive page
1137 *
1138 * @since v.1.4.9
1139 */
1140 public function filter_archive_meta_query( $wp_query ) {
1141 if ( ! is_admin() && $wp_query->is_archive && $wp_query->get( 'post_type' ) === 'download' ) {
1142 $wp_query->set( 'meta_query', array( $this->tutor_product_meta_query() ) );
1143 }
1144 return $wp_query;
1145 }
1146
1147 /**
1148 * @param $html
1149 * @return string
1150 *
1151 * Removed course price if already enrolled at single course
1152 *
1153 * @since v.1.5.8
1154 */
1155 public function remove_price_if_enrolled($html){
1156 $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1157
1158 if ($should_removed){
1159 $course_id = get_the_ID();
1160 $enrolled = tutor_utils()->is_enrolled($course_id);
1161 if ($enrolled){
1162 $html = '';
1163 }
1164 }
1165 return $html;
1166 }
1167
1168 /**
1169 * @param $html
1170 * @return string
1171 *
1172 * Check if all lessons and quizzes done before mark course complete.
1173 */
1174 function tutor_lms_hide_course_complete_btn($html){
1175
1176 $completion_mode = tutor_utils()->get_option('course_completion_process');
1177 if ($completion_mode !== 'strict'){
1178 return $html;
1179 }
1180
1181 $completed_lesson = tutor_utils()->get_completed_lesson_count_by_course();
1182 $lesson_count = tutor_utils()->get_lesson_count_by_course();
1183
1184 if ($completed_lesson < $lesson_count){
1185 return '<div class="tutor-alert tutor-warning tutor-mt-28">
1186 <div class="tutor-alert-text">
1187 <span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span>
1188 <span>'.__('Complete all lessons to mark this course as complete', 'tutor').'</span>
1189 </div>
1190 </div>';
1191 }
1192
1193 $quizzes = array();
1194 $assignments = array();
1195
1196 $course_contents = tutor_utils()->get_course_contents_by_id();
1197 if (tutor_utils()->count($course_contents)){
1198 foreach ($course_contents as $content){
1199 if ($content->post_type === 'tutor_quiz'){
1200 $quizzes[] = $content;
1201 }
1202 if ($content->post_type === 'tutor_assignments'){
1203 $assignments[] = $content;
1204 }
1205 }
1206 }
1207
1208 $required_assignment_pass = 0;
1209
1210 foreach( $assignments as $row ) {
1211
1212 $submitted_assignment = tutor_utils()->is_assignment_submitted( $row->ID );
1213 $is_reviewed_by_instructor = null === $submitted_assignment
1214 ? false
1215 : get_comment_meta( $submitted_assignment->comment_ID, 'evaluate_time', true );
1216
1217 if ( $submitted_assignment && $is_reviewed_by_instructor )
1218 {
1219 $pass_mark = tutor_utils()->get_assignment_option( $submitted_assignment->comment_post_ID, 'pass_mark' );
1220 $given_mark = get_comment_meta( $submitted_assignment->comment_ID, 'assignment_mark', true );
1221
1222 if ( $given_mark < $pass_mark ) {
1223 $required_assignment_pass++;
1224 }
1225 }
1226 else
1227 {
1228 $required_assignment_pass++;
1229 }
1230 }
1231
1232
1233 $is_quiz_pass = true;
1234 $required_quiz_pass = 0;
1235
1236 if (tutor_utils()->count($quizzes)){
1237 foreach ($quizzes as $quiz){
1238
1239 $attempt = tutor_utils()->get_quiz_attempt($quiz->ID);
1240 if ($attempt) {
1241 $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1242 $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1243
1244 if ($earned_percentage < $passing_grade) {
1245 $required_quiz_pass++;
1246 $is_quiz_pass = false;
1247 }
1248 }else{
1249 $required_quiz_pass++;
1250 $is_quiz_pass = false;
1251 }
1252 }
1253 }
1254
1255 if ( ! $is_quiz_pass || $required_assignment_pass > 0 ) {
1256 $_msg = '';
1257 $quiz_str = _n( 'quiz', 'quizzes', $required_quiz_pass, 'tutor' );
1258 $assignment_str = _n( 'assignment', 'assignments', $required_assignment_pass, 'tutor' );
1259
1260 if ( ! $is_quiz_pass && $required_assignment_pass == 0 ) {
1261 $_msg = sprintf(__('You have to pass %s %s to complete this course.', 'tutor'), $required_quiz_pass, $quiz_str );
1262 }
1263 if ( $is_quiz_pass && $required_assignment_pass > 0 ) {
1264 $_msg = sprintf(__('You have to pass %s %s to complete this course.', 'tutor'), $required_assignment_pass, $assignment_str );
1265 }
1266 if ( ! $is_quiz_pass && $required_assignment_pass > 0 ) {
1267 $_msg = sprintf(__('You have to pass %s %s and %s %s to complete this course.', 'tutor'), $required_quiz_pass, $quiz_str, $required_assignment_pass, $assignment_str );
1268 }
1269
1270 return '<div class="tutor-alert tutor-warning tutor-mt-28">
1271 <div class="tutor-alert-text">
1272 <span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span>
1273 <span>'.$_msg.'</span>
1274 </div>
1275 </div>';
1276 }
1277
1278 return $html;
1279 }
1280
1281 public function get_generate_greadbook($html){
1282 if ( ! tutor_utils()->is_completed_course()){
1283 return '';
1284 }
1285 return $html;
1286 }
1287
1288 /**
1289 * Add social share content in header
1290 *
1291 * @since v.1.6.3
1292 */
1293 public function social_share_content() {
1294 global $wp_query, $post;
1295 if ( $wp_query->is_single && ! empty( $wp_query->query_vars['post_type'] ) && $wp_query->query_vars['post_type'] === $this->course_post_type ) { ?>
1296 <!--Facebook-->
1297 <meta property="og:type" content="website"/>
1298 <meta property="og:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>" />
1299 <meta property="og:description" content="<?php echo esc_html( $post->post_content ); ?>" />
1300 <!--Twitter-->
1301 <meta name="twitter:image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1302 <meta name="twitter:description" content="<?php echo esc_html( $post->post_content ); ?>">
1303 <!--Google+-->
1304 <meta itemprop="image" content="<?php echo esc_url( get_tutor_course_thumbnail_src() ); ?>">
1305 <meta itemprop="description" content="<?php echo esc_html( $post->post_content ); ?>">
1306 <?php
1307 }
1308 }
1309
1310 /**
1311 * Delete associated enrollment
1312 *
1313 * @since v.1.8.2
1314 */
1315 public function delete_associated_enrollment( $post_id ) {
1316 global $wpdb;
1317
1318 $enroll_id = $wpdb->get_var(
1319 $wpdb->prepare(
1320 "SELECT
1321 post_id
1322 FROM
1323 {$wpdb->postmeta}
1324 WHERE
1325 meta_key='_tutor_enrolled_by_order_id'
1326 AND meta_value = %d
1327 ",
1328 $post_id
1329 )
1330 );
1331
1332 if ( is_numeric( $enroll_id ) && $enroll_id > 0 ) {
1333
1334 $course_id = get_post_field( 'post_parent', $enroll_id );
1335 $user_id = get_post_field( 'post_author', $enroll_id );
1336
1337 tutor_utils()->cancel_course_enrol($course_id, $user_id);
1338 }
1339 }
1340
1341 public function tutor_reset_course_progress() {
1342 tutor_utils()->checking_nonce();
1343 $course_id = tutor_utils()->array_get('course_id', $_POST);
1344
1345 if ( ! $course_id || ! is_numeric( $course_id ) || ! tutor_utils()->is_enrolled( $course_id ) ) {
1346 wp_send_json_error( array( 'message' => __( 'Invalid Course ID or Access Denied.', 'tutor' ) ) );
1347 return;
1348 }
1349
1350 tutor_utils()->delete_course_progress( $course_id );
1351 wp_send_json_success( array( 'redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ) );
1352 }
1353
1354 /**
1355 * Do enroll if guest attempt to enroll and course is free
1356 *
1357 * @param $course_id
1358 *
1359 * @since 1.9.8
1360 */
1361 public function enroll_after_login_if_attempt( int $course_id, int $user_id ) {
1362 $course_id = sanitize_text_field( $course_id );
1363 if ( $course_id ) {
1364 $is_purchasable = tutor_utils()->is_course_purchasable( $course_id );
1365 if ( ! $is_purchasable ) {
1366 tutor_utils()->do_enroll( $course_id, $order_id = 0, $user_id );
1367 do_action( 'guest_attempt_after_enrollment', $course_id );
1368 }
1369 }
1370 }
1371
1372 /**
1373 * Course enrollment
1374 *
1375 * On the course list page if user hit enroll course
1376 * button then do enrollment
1377 *
1378 * @since v.2.1.0
1379 *
1380 * @return void wp_json response
1381 */
1382 public function course_enrollment() {
1383 tutor_utils()->checking_nonce();
1384
1385 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
1386 $user_id = get_current_user_id();
1387
1388 if ( $course_id ) {
1389 $enroll = tutor_utils()->do_enroll( $course_id, 0, $user_id );
1390 if ( $enroll ) {
1391 wp_send_json_success( __( 'Enrollment successfully done!', 'tutor' ) );
1392 } else {
1393 wp_send_json_error( __( 'Enrollment failed, please try again!', 'tutor' ) );
1394 }
1395 } else {
1396 wp_send_json_error( __( 'Invalid course ID', 'tutor' ) );
1397 }
1398 }
1399 }
1400