PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.9.6
Tutor LMS – eLearning and online course solution v1.9.6
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Course.php
tutor / classes Last commit date
Addons.php 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 5 years ago Course_Widget.php 5 years ago Custom_Validation.php 5 years ago Dashboard.php 5 years ago Email.php 5 years ago FormHandler.php 5 years ago Frontend.php 5 years ago Gutenberg.php 4 years ago Instructor.php 4 years ago Instructors_List.php 4 years ago Lesson.php 4 years ago Options.php 4 years ago Post_types.php 4 years ago Private_Course_Access.php 5 years ago Q_and_A.php 5 years ago Question_Answers_List.php 4 years ago Quiz.php 4 years ago Quiz_Attempts_List.php 4 years ago RestAPI.php 5 years ago Rewrite_Rules.php 5 years ago Shortcode.php 4 years ago Student.php 5 years ago Students_List.php 4 years ago Taxonomies.php 5 years ago Template.php 4 years ago Theme_Compatibility.php 5 years ago Tools.php 5 years ago Tutor.php 4 years ago TutorEDD.php 5 years ago Tutor_Base.php 5 years ago Tutor_List_Table.php 4 years ago Tutor_Setup.php 5 years ago Upgrader.php 5 years ago User.php 4 years ago Utils.php 4 years ago Video_Stream.php 5 years ago Withdraw.php 5 years ago Withdraw_Requests_List.php 4 years ago WooCommerce.php 4 years ago
Course.php
1337 lines
1 <?php
2 namespace TUTOR;
3
4 if ( ! defined( 'ABSPATH' ) )
5 exit;
6
7 class Course extends Tutor_Base {
8
9 private $additional_meta=array(
10 '_tutor_disable_qa',
11 '_tutor_is_public_course'
12 );
13
14 public function __construct() {
15 parent::__construct();
16
17 add_action( 'add_meta_boxes', array($this, 'register_meta_box') );
18 add_action('save_post_'.$this->course_post_type, array($this, 'save_course_meta'), 10, 2);
19 add_action('wp_ajax_tutor_add_course_topic', array($this, 'tutor_add_course_topic'));
20 add_action('wp_ajax_tutor_update_topic', array($this, 'tutor_update_topic'));
21
22 //Add Column
23 add_filter( "manage_{$this->course_post_type}_posts_columns", array($this, 'add_column'), 10,1 );
24 add_action( "manage_{$this->course_post_type}_posts_custom_column" , array($this, 'custom_lesson_column'), 10, 2 );
25
26 add_action('admin_action_tutor_delete_topic', array($this, 'tutor_delete_topic'));
27 add_action('admin_action_tutor_delete_announcement', array($this, 'tutor_delete_announcement'));
28
29 //Frontend Action
30 add_action('template_redirect', array($this, 'enroll_now'));
31 add_action('template_redirect', array($this, 'mark_course_complete'));
32
33 //Modal Perform
34 add_action('wp_ajax_tutor_load_instructors_modal', array($this, 'tutor_load_instructors_modal'));
35 add_action('wp_ajax_tutor_add_instructors_to_course', array($this, 'tutor_add_instructors_to_course'));
36 add_action('wp_ajax_detach_instructor_from_course', array($this, 'detach_instructor_from_course'));
37
38 /**
39 * Frontend Dashboard
40 */
41 add_action('wp_ajax_tutor_delete_dashboard_course', array($this, 'tutor_delete_dashboard_course'));
42
43 /**
44 * Gutenberg author support
45 */
46 add_filter('wp_insert_post_data', array($this, 'tutor_add_gutenberg_author'), '99', 2);
47
48 /**
49 * Frontend metabox supports for course builder
50 * @since v.1.3.4
51 */
52 add_action('tutor/dashboard_course_builder_form_field_after', array($this, 'register_meta_box_in_frontend'));
53
54 /**
55 * Do Stuff for the course save from frontend
56 */
57 add_action('save_tutor_course', array($this, 'attach_product_with_course'), 10, 2);
58
59 /**
60 * Add course level to course settings
61 * @since v.1.4.1
62 */
63 add_action('tutor_course/settings_tab_content/after/general', array($this, 'add_course_level_to_settings'));
64
65 /**
66 * Enable Disable Course Details Page Feature
67 * @since v.1.4.8
68 */
69 $this->course_elements_enable_disable();
70
71 /**
72 * @since v.1.4.8
73 * Check if course starting, set meta if starting
74 */
75 add_action('tutor_lesson_load_before', array($this, 'tutor_lesson_load_before'));
76
77 /**
78 * @since v.1.4.9
79 * Filter product in shop page
80 */
81 $this->filter_product_in_shop_page();
82
83 /**
84 * Remove the course price if enrolled
85 * @since 1.5.8
86 */
87 add_filter('tutor_course_price', array($this, 'remove_price_if_enrolled'));
88
89 /**
90 * Remove course complete button if course completion is strict mode
91 * @since v.1.6.1
92 */
93 add_filter('tutor_course/single/complete_form', array($this, 'tutor_lms_hide_course_complete_btn'));
94 add_filter('get_gradebook_generate_form_html', array($this, 'get_generate_greadbook'));
95
96 /**
97 * Add social share content in header
98 * @since v.1.6.3
99 */
100 add_action('wp_head', array($this, 'social_share_content'));
101
102 /**
103 * Delete course data after deleted course
104 * @since v.1.6.6
105 */
106 add_action('deleted_post', array($this, 'delete_tutor_course_data'));
107 add_action('tutor/dashboard_course_builder_form_field_after', array($this, 'tutor_course_setting_metabox_frontend'));
108
109 /**
110 * Delete course data after deleted course
111 * @since v.1.8.2
112 */
113 add_action('before_delete_post', array($this, 'delete_associated_enrollment'));
114
115 /**
116 * Show only own uploads in media library if user is instructor
117 * @since v1.8.9
118 */
119 add_filter('posts_where', array($this, 'restrict_media' ) );
120
121 /**
122 * Restrict new enrol/purchase button if course member limit reached
123 * @since v1.9.0
124 */
125 add_filter('tutor_course_restrict_new_entry', array($this, 'restrict_new_student_entry'));
126
127 /**
128 * Reset course progress on retake
129 * @since v1.9.5
130 */
131 add_action( 'wp_ajax_tutor_reset_course_progress', array($this, 'tutor_reset_course_progress') );
132 }
133
134 public function restrict_new_student_entry($content) {
135
136 if(!tutils()->is_course_fully_booked()) {
137 // No restriction if not fully booked
138 return $content;
139 }
140
141 return '<span class="tutor-course-booked-fully">
142 <img src="' . tutor()->url . '/assets/images/icon-warning-info.svg"/>
143 <span>' . __('Fully booked', 'tutor') . '</span>
144 </span>';
145 }
146
147 function restrict_media( $where ){
148
149 if( isset( $_POST['action'] ) && $_POST['action'] == 'query-attachments' && tutor_utils()->is_instructor()){
150 if(!tutor_utils()->has_user_role(array('administrator', 'editor'))) {
151 $where .= ' AND post_author=' . get_current_user_id();
152 }
153 }
154
155 return $where;
156 }
157
158 /**
159 * Registering metabox
160 */
161 public function register_meta_box(){
162 $coursePostType = tutor()->course_post_type;
163 $course_marketplace = tutor_utils()->get_option('enable_course_marketplace');
164 //add_meta_box( 'tutor-course-levels', __( 'Course Level', 'tutor' ), array($this, 'course_level_metabox'), $coursePostType );
165 add_meta_box( 'tutor-course-topics', __( 'Course Builder', 'tutor' ), array($this, 'course_meta_box'), $coursePostType );
166 add_meta_box( 'tutor-course-additional-data', __( 'Additional Data', 'tutor' ), array($this, 'course_additional_data_meta_box'), $coursePostType );
167 add_meta_box( 'tutor-course-videos', __( 'Video', 'tutor' ), array($this, 'video_metabox'), $coursePostType );
168 if ($course_marketplace) {
169 add_meta_box( 'tutor-instructors', __( 'Instructors', 'tutor' ), array( $this, 'instructors_metabox' ), $coursePostType );
170 }
171
172 /**
173 * Tutor course sidebar settings metabox
174 * @since v.1.7.0
175 */
176 add_meta_box( 'tutor-course-sidebar-settings', __( 'Tutor Settings', 'tutor' ), array($this, 'tutor_course_setting_metabox'), $coursePostType, 'side' );
177 }
178
179 public function course_meta_box($echo = true){
180 ob_start();
181 include tutor()->path.'views/metabox/course-topics.php';
182 $content = ob_get_clean();
183
184 if ($echo){
185 echo $content;
186 }else{
187 return $content;
188 }
189 }
190
191 public function course_additional_data_meta_box($echo = true){
192
193 ob_start();
194 include tutor()->path.'views/metabox/course-additional-data.php';
195 $content = ob_get_clean();
196
197 if ($echo){
198 echo $content;
199 }else{
200 return $content;
201 }
202 }
203
204 public function video_metabox($echo = true){
205 ob_start();
206 include tutor()->path.'views/metabox/video-metabox.php';
207 $content = ob_get_clean();
208
209 if ($echo){
210 echo $content;
211 }else{
212 return $content;
213 }
214 }
215
216 public function course_level_metabox($echo = true){
217 ob_start();
218 include tutor()->path.'views/metabox/course-level-metabox.php';
219 $content = ob_get_clean();
220
221 if ($echo){
222 echo $content;
223 }else{
224 return $content;
225 }
226 }
227
228 public function instructors_metabox($echo = true){
229 ob_start();
230 include tutor()->path . 'views/metabox/instructors-metabox.php';
231 $content = ob_get_clean();
232
233 if ($echo){
234 echo $content;
235 }else{
236 return $content;
237 }
238 }
239
240 /**
241 * Register metabox in course builder tutor
242 * @since v.1.3.4
243 */
244 public function register_meta_box_in_frontend(){
245 do_action('tutor_course_builder_metabox_before', get_the_ID());
246 course_builder_section_wrap($this->video_metabox($echo = false), __( 'Video', 'tutor' ) );
247 course_builder_section_wrap($this->course_meta_box($echo = false), __( 'Course Builder', 'tutor' ) );
248 course_builder_section_wrap($this->instructors_metabox($echo = false), __( 'Instructors', 'tutor' ) );
249 course_builder_section_wrap($this->course_additional_data_meta_box($echo = false), __( 'Additional Data', 'tutor' ) );
250 do_action('tutor_course_builder_metabox_after', get_the_ID());
251 }
252
253 /**
254 * @param $post_ID
255 *
256 * Insert Topic and attached it with Course
257 */
258 public function save_course_meta($post_ID, $post){
259 global $wpdb;
260
261 do_action( "tutor_save_course", $post_ID, $post);
262
263 /**
264 * Save course price type
265 */
266 $price_type = tutils()->array_get('tutor_course_price_type', $_POST);
267 if ($price_type){
268 update_post_meta($post_ID, '_tutor_course_price_type', $price_type);
269 }
270
271 //Course Duration
272 if ( ! empty($_POST['course_duration'])){
273 $video = tutils()->sanitize_array($_POST['course_duration']);
274 update_post_meta($post_ID, '_course_duration', $video);
275 }
276
277 if ( ! empty($_POST['course_level'])){
278 $course_level = sanitize_text_field($_POST['course_level']);
279 update_post_meta($post_ID, '_tutor_course_level', $course_level);
280 }
281
282 $additional_data_edit = tutils()->avalue_dot('_tutor_course_additional_data_edit', $_POST);
283 if ($additional_data_edit) {
284 if (!empty($_POST['course_benefits'])) {
285 $course_benefits = wp_kses_post($_POST['course_benefits']);
286 update_post_meta($post_ID, '_tutor_course_benefits', $course_benefits);
287 } else {
288 delete_post_meta($post_ID, '_tutor_course_benefits');
289 }
290
291 if (!empty($_POST['course_requirements'])) {
292 $requirements = wp_kses_post($_POST['course_requirements']);
293 update_post_meta($post_ID, '_tutor_course_requirements', $requirements);
294 } else {
295 delete_post_meta($post_ID, '_tutor_course_requirements');
296 }
297
298 if (!empty($_POST['course_target_audience'])) {
299 $target_audience = wp_kses_post($_POST['course_target_audience']);
300 update_post_meta($post_ID, '_tutor_course_target_audience', $target_audience);
301 } else {
302 delete_post_meta($post_ID, '_tutor_course_target_audience');
303 }
304
305 if (!empty($_POST['course_material_includes'])) {
306 $material_includes = wp_kses_post($_POST['course_material_includes']);
307 update_post_meta($post_ID, '_tutor_course_material_includes', $material_includes);
308 } else {
309 delete_post_meta($post_ID, '_tutor_course_material_includes');
310 }
311 }
312
313
314 /**
315 * Sorting Topics and lesson
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('post_parent' => $topic['topic_id'], 'menu_order' => $lesson_key),
355 array('ID' => $lesson_id)
356 );
357 }
358 }
359 }
360 }
361 }
362
363 if ($additional_data_edit) {
364 if ( ! empty($_POST['video']['source'])) { //Video
365 $video = tutor_utils()->array_get('video', $_POST);
366 update_post_meta($post_ID, '_video', $video);
367 }else{
368 delete_post_meta($post_ID, '_video');
369 }
370 }
371
372 /**
373 * Adding author to instructor automatically
374 */
375
376 $author_id = $post->post_author;
377 $attached = (int) $wpdb->get_var($wpdb->prepare(
378 "SELECT COUNT(umeta_id) FROM {$wpdb->usermeta}
379 WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ", $author_id, $post_ID));
380
381 if ( ! $attached){
382 add_user_meta($author_id, '_tutor_instructor_course_id', $post_ID);
383 }
384
385 /**
386 * Disable question and answer for this course
387 * @since 1.7.0
388 */
389 if ($additional_data_edit) {
390 foreach($this->additional_meta as $key){
391 update_post_meta($post_ID, $key, (isset($_POST[$key]) ? 'yes' : 'no'));
392 }
393 }
394
395 do_action( "tutor_save_course_after", $post_ID, $post);
396 }
397
398 /**
399 * Tutor add course topic
400 */
401 public function tutor_add_course_topic(){
402 tutils()->checking_nonce();
403
404 if (empty($_POST['topic_title']) ) {
405 wp_send_json_error();
406 }
407 $course_id = (int) tutor_utils()->avalue_dot('tutor_topic_course_ID', $_POST);
408 $next_topic_order_id = tutor_utils()->get_next_topic_order_id($course_id);
409
410 if(!tutils()->can_user_manage('course', $course_id)) {
411 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
412 }
413
414 $topic_title = sanitize_text_field( $_POST['topic_title'] );
415 $topic_summery = wp_kses_post( $_POST['topic_summery'] );
416
417 $post_arr = array(
418 'post_type' => 'topics',
419 'post_title' => $topic_title,
420 'post_content' => $topic_summery,
421 'post_status' => 'publish',
422 'post_author' => get_current_user_id(),
423 'post_parent' => $course_id,
424 'menu_order' => $next_topic_order_id,
425 );
426 $current_topic_id = wp_insert_post( $post_arr );
427
428 ob_start();
429 include tutor()->path.'views/metabox/course-contents.php';
430 $course_contents = ob_get_clean();
431
432 wp_send_json_success(array('course_contents' => $course_contents));
433 }
434
435 /**
436 * Update the topic
437 */
438 public function tutor_update_topic(){
439 tutils()->checking_nonce();
440
441 $topic_id = (int) sanitize_text_field($_POST['topic_id']);
442 $topic_title = sanitize_text_field($_POST['topic_title']);
443 $topic_summery = wp_kses_post($_POST['topic_summery']);
444
445 if(!tutils()->can_user_manage('topic', $topic_id)) {
446 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
447 }
448
449 $topic_attr = array(
450 'ID' => $topic_id,
451 'post_title' => $topic_title,
452 'post_content' => $topic_summery,
453 );
454 wp_update_post( $topic_attr );
455
456 wp_send_json_success(array('msg' => __('Topic has been updated', 'tutor') ));
457 }
458
459
460 /**
461 * @param $columns
462 *
463 * @return mixed
464 *
465 * Add Lesson column
466 */
467 public function add_column($columns){
468 $date_col = $columns['date'];
469 unset($columns['date']);
470 $columns['lessons'] = __('Lessons', 'tutor');
471 $columns['students'] = __('Students', 'tutor');
472 $columns['price'] = __('Price', 'tutor');
473 $columns['date'] = $date_col;
474
475 return $columns;
476 }
477
478 /**
479 * @param $column
480 * @param $post_id
481 *
482 */
483 public function custom_lesson_column($column, $post_id ){
484 if ($column === 'lessons'){
485 echo tutor_utils()->get_lesson_count_by_course($post_id);
486 }
487
488 if ($column === 'students'){
489 echo tutor_utils()->count_enrolled_users_by_course($post_id);
490 }
491
492 if ($column === 'price'){
493 $price = tutor_utils()->get_course_price($post_id);
494 if ($price){
495 $monetize_by = tutils()->get_option('monetize_by');
496 if (function_exists('wc_price') && $monetize_by === 'wc'){
497 echo '<span class="tutor-label-success">'.wc_price($price).'</span>';
498 }else{
499 echo '<span class="tutor-label-success">'.$price.'</span>';
500 }
501 }else{
502 echo apply_filters('tutor-loop-default-price', 'free');
503 }
504 }
505 }
506
507
508 public function tutor_delete_topic(){
509
510 tutils()->checking_nonce('get');
511
512 !isset($_GET['topic_id']) ? exit() : 0;
513
514 global $wpdb;
515
516 $topic_id = (int) sanitize_text_field($_GET['topic_id']);
517 $wpdb->update(
518 $wpdb->posts,
519 array('post_parent' => 0),
520 array('post_parent' => $topic_id)
521 );
522
523 $wpdb->delete(
524 $wpdb->postmeta,
525 array('post_id' => $topic_id)
526 );
527
528 wp_delete_post($topic_id);
529 wp_safe_redirect(wp_get_referer());
530 }
531
532 public function tutor_delete_announcement(){
533 tutor_utils()->checking_nonce('get');
534
535 $announcement_id = (int) sanitize_text_field($_GET['topic_id']);
536
537 wp_delete_post($announcement_id);
538 wp_safe_redirect(wp_get_referer());
539 }
540
541 public function enroll_now(){
542
543 //Checking if action comes from Enroll form
544 if (tutor_utils()->array_get('tutor_course_action', $_POST) !== '_tutor_course_enroll_now' || ! isset($_POST['tutor_course_id']) ){
545 return;
546 }
547 //Checking Nonce
548 tutor_utils()->checking_nonce();
549
550 $user_id = get_current_user_id();
551 if ( ! $user_id){
552 exit(__('Please Sign In first', 'tutor'));
553 }
554
555 $course_id = (int) sanitize_text_field($_POST['tutor_course_id']);
556 $user_id = get_current_user_id();
557
558 /**
559 * TODO: need to check purchase information
560 */
561
562 $is_purchasable = tutor_utils()->is_course_purchasable($course_id);
563
564 /**
565 * If is is not purchasable, it's free, and enroll right now
566 *
567 * if purchasable, then process purchase.
568 *
569 * @since: v.1.0.0
570 */
571 if ($is_purchasable){
572 //process purchase
573
574 }else{
575 //Free enroll
576 tutor_utils()->do_enroll($course_id);
577 }
578
579 $referer_url = wp_get_referer();
580 wp_redirect($referer_url);
581 }
582
583 /**
584 *
585 * Mark complete completed
586 *
587 * @since v.1.0.0
588 */
589 public function mark_course_complete(){
590 if ( ! isset($_POST['tutor_action']) || $_POST['tutor_action'] !== 'tutor_complete_course' ){
591 return;
592 }
593 //Checking nonce
594 tutor_utils()->checking_nonce();
595
596 $user_id = get_current_user_id();
597
598 //TODO: need to show view if not signed_in
599 if ( ! $user_id){
600 die(__('Please Sign-In', 'tutor'));
601 }
602
603 $course_id = (int) sanitize_text_field($_POST['course_id']);
604
605 do_action('tutor_course_complete_before', $course_id);
606 /**
607 * Marking course completed at Comment
608 */
609
610 global $wpdb;
611
612 $date = date("Y-m-d H:i:s", tutor_time());
613
614 //Making sure that, hash is unique
615 do{
616 $hash = substr(md5(wp_generate_password(32).$date.$course_id.$user_id), 0, 16);
617 $hasHash = (int) $wpdb->get_var($wpdb->prepare(
618 "SELECT COUNT(comment_ID) from {$wpdb->comments}
619 WHERE comment_agent = 'TutorLMSPlugin' AND comment_type = 'course_completed' AND comment_content = %s ", $hash));
620
621 }while($hasHash > 0);
622
623 $data = array(
624 'comment_post_ID' => $course_id,
625 'comment_author' => $user_id,
626 'comment_date' => $date,
627 'comment_date_gmt' => get_gmt_from_date($date),
628 'comment_content' => $hash, //Identification Hash
629 'comment_approved' => 'approved',
630 'comment_agent' => 'TutorLMSPlugin',
631 'comment_type' => 'course_completed',
632 'user_id' => $user_id,
633 );
634
635 $wpdb->insert($wpdb->comments, $data);
636
637 do_action('tutor_course_complete_after', $course_id, $user_id);
638
639 wp_redirect(get_the_permalink($course_id));
640 }
641
642
643 public function tutor_load_instructors_modal(){
644 tutils()->checking_nonce();
645
646 global $wpdb;
647
648 $course_id = (int) sanitize_text_field($_POST['course_id']);
649 $search_terms = sanitize_text_field(tutor_utils()->avalue_dot('search_terms', $_POST));
650
651 if(!tutils()->can_user_manage('course', $course_id)) {
652 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
653 }
654
655 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
656 $instructors = array();
657
658 $not_in_sql = apply_filters('tutor_instructor_query_when_exists', " AND ID <1 ");
659
660 if ($saved_instructors){
661 $saved_instructors_ids = wp_list_pluck($saved_instructors, 'ID');
662 $instructor_not_in_ids = implode(',', $saved_instructors_ids);
663 $not_in_sql .= "AND user.ID NOT IN($instructor_not_in_ids) ";
664 }
665
666 $search_sql = '';
667 if ($search_terms){
668 $search_sql = "AND (user.user_login like '%{$search_terms}%' or user.user_nicename like '%{$search_terms}%' or user.display_name like '%{$search_terms}%') ";
669 }
670
671 $instructors = $wpdb->get_results("SELECT user.ID, user.display_name from {$wpdb->users} user
672 INNER JOIN {$wpdb->usermeta} meta ON user.ID = meta.user_id AND meta.meta_key = '_tutor_instructor_status' AND meta.meta_value = 'approved'
673 WHERE 1=1 {$not_in_sql} {$search_sql} limit 10 ");
674
675 $output = '';
676 if (is_array($instructors) && count($instructors)){
677 $instructor_output = '';
678 foreach ($instructors as $instructor){
679 $instructor_output .= "<p><label><input type='radio' name='tutor_instructor_ids[]' value='{$instructor->ID}' > {$instructor->display_name} </label></p>";
680 }
681
682 $output .= apply_filters('tutor_course_instructors_html', $instructor_output, $instructors);
683
684 }else{
685 $output .= __('<p>No instructor available or you have already added maximum instructors</p>', 'tutor');
686 }
687
688
689 if ( ! defined('TUTOR_MT_VERSION')){
690 $output .= '<p class="tutor-notice-warning" style="margin-top: 50px; font-size: 14px;">'. sprintf( __('To add unlimited multiple instructors in your course, get %sTutor LMS Pro%s', 'tutor'), '<a href="https://www.themeum.com/product/tutor-lms" target="_blank">', "</a>" ) .'</p>';
691 }
692
693 wp_send_json_success(array('output' => $output));
694 }
695
696 public function tutor_add_instructors_to_course(){
697 tutils()->checking_nonce();
698
699 $course_id = (int) sanitize_text_field($_POST['course_id']);
700 $instructor_ids = tutor_utils()->avalue_dot('tutor_instructor_ids', $_POST);
701
702 if(!tutils()->can_user_manage('course', $course_id)) {
703 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
704 }
705
706 if (is_array($instructor_ids) && count($instructor_ids)){
707 foreach ($instructor_ids as $instructor_id){
708 add_user_meta($instructor_id, '_tutor_instructor_course_id', $course_id);
709 }
710 }
711
712 $saved_instructors = tutor_utils()->get_instructors_by_course($course_id);
713 $output = '';
714
715 if ($saved_instructors){
716 foreach ($saved_instructors as $t){
717
718 $output .= '<div id="added-instructor-id-'.$t->ID.'" class="added-instructor-item added-instructor-item-'.$t->ID.'" data-instructor-id="'.$t->ID.'">
719 <span class="instructor-icon">'.get_avatar($t->ID, 30).'</span>
720 <span class="instructor-name"> '.$t->display_name.' </span>
721 <span class="instructor-control">
722 <a href="javascript:;" class="tutor-instructor-delete-btn"><i class="tutor-icon-line-cross"></i></a>
723 </span>
724 </div>';
725 }
726 }
727
728 wp_send_json_success(array('output' => $output));
729 }
730
731 public function detach_instructor_from_course(){
732 tutils()->checking_nonce();
733
734 global $wpdb;
735
736 $instructor_id = (int) sanitize_text_field($_POST['instructor_id']);
737 $course_id = (int) sanitize_text_field($_POST['course_id']);
738
739 if(!tutils()->can_user_manage('course', $course_id)) {
740 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
741 }
742
743 $wpdb->delete($wpdb->usermeta, array('user_id' => $instructor_id, 'meta_key' => '_tutor_instructor_course_id', 'meta_value' => $course_id) );
744 wp_send_json_success();
745 }
746
747 public function tutor_delete_dashboard_course(){
748 tutils()->checking_nonce();
749
750 $course_id = intval(sanitize_text_field($_POST['course_id']));
751
752 if(!tutils()->can_user_manage('course', $course_id)) {
753 wp_send_json_error( array('message'=>__('Access Denied', 'tutor')) );
754 }
755
756 wp_trash_post($course_id);
757 wp_send_json_success(['element'=>'course']);
758 }
759
760
761 public function tutor_add_gutenberg_author($data , $postarr){
762 global $wpdb;
763
764 $courses_post_type = tutor()->course_post_type;
765 $post_type = tutils()->array_get('post_type', $postarr);
766
767 if ($courses_post_type === $post_type){
768 $post_ID = (int) tutor_utils()->avalue_dot('ID', $postarr);
769 $post_author = (int) $wpdb->get_var($wpdb->prepare("SELECT post_author FROM {$wpdb->posts} WHERE ID = %d ", $post_ID));
770
771 if ($post_author > 0){
772 $data['post_author'] = $post_author;
773 }else{
774 $data['post_author'] = get_current_user_id();
775 }
776 }
777
778 return $data;
779 }
780
781
782 /**
783 * @param $post_ID
784 * @param $postData
785 *
786 * Attach product during save course from the frontend course dashboard.
787 *
788 * @return string
789 *
790 * @since v.1.3.4
791 */
792 public function attach_product_with_course($post_ID, $postData){
793 $attached_product_id = tutor_utils()->get_course_product_id($post_ID);
794 $course_price = sanitize_text_field(tutor_utils()->array_get('course_price', $_POST));
795
796 if ( ! $course_price){
797 return;
798 }
799
800 $monetize_by = tutor_utils()->get_option('monetize_by');
801 $course = get_post($post_ID);
802
803 if ($monetize_by === 'wc'){
804
805 $is_update = false;
806 if ($attached_product_id){
807 $wc_product = get_post_meta($attached_product_id, '_product_version', true);
808 if ($wc_product){
809 $is_update = true;
810 }
811 }
812
813 if ($is_update) {
814 $productObj = wc_get_product($attached_product_id);
815 $productObj->set_price($course_price); // set product price
816 $productObj->set_regular_price($course_price); // set product regular price
817 $productObj->set_sold_individually(true);
818 $product_id = $productObj->save();
819 if($productObj->is_type('subscription')) {
820 update_post_meta( $attached_product_id, '_subscription_price', $course_price );
821 }
822 } else {
823 $productObj = new \WC_Product();
824 $productObj->set_name($course->post_title);
825 $productObj->set_status('publish');
826 $productObj->set_price($course_price); // set product price
827 $productObj->set_regular_price($course_price); // set product regular price
828 $productObj->set_sold_individually(true);
829
830 $product_id = $productObj->save();
831 if ($product_id) {
832 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
833 //Mark product for woocommerce
834 update_post_meta( $product_id, '_virtual', 'yes' );
835 update_post_meta( $product_id, '_tutor_product', 'yes' );
836
837 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
838 if ( $coursePostThumbnail ) {
839 set_post_thumbnail( $product_id, $coursePostThumbnail );
840 }
841 }
842 }
843
844 }elseif ($monetize_by === 'edd'){
845
846 $is_update = false;
847
848 if ($attached_product_id){
849 $edd_price = get_post_meta($attached_product_id, 'edd_price', true);
850 if ($edd_price){
851 $is_update = true;
852 }
853 }
854
855 if ($is_update){
856 //Update the product
857 update_post_meta( $attached_product_id, 'edd_price', $course_price );
858 }else{
859 //Create new product
860
861 $post_arr = array(
862 'post_type' => 'download',
863 'post_title' => $course->post_title,
864 'post_status' => 'publish',
865 'post_author' => get_current_user_id(),
866 );
867 $download_id = wp_insert_post( $post_arr );
868 if ($download_id ) {
869 //edd_price
870 update_post_meta( $download_id, 'edd_price', $course_price );
871
872 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
873 //Mark product for EDD
874 update_post_meta( $download_id, '_tutor_product', 'yes' );
875
876 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
877 if ( $coursePostThumbnail ) {
878 set_post_thumbnail( $download_id, $coursePostThumbnail );
879 }
880
881 }
882
883 }
884
885
886 }
887
888 }
889
890
891 /**
892 * Add Course level to course settings
893 * @since v.1.4.1
894 */
895 public function add_course_level_to_settings(){
896 include tutor()->path.'views/metabox/course-level-metabox.php';
897 }
898
899 /**
900 * Check if course starting
901 *
902 * @since v.1.4.8
903 */
904 public function tutor_lesson_load_before(){
905 $course_id = tutils()->get_course_id_by_content(get_the_ID());
906 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
907 if (is_user_logged_in()){
908 $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
909 if ( ! $completed_lessons && ! $is_course_started){
910 update_post_meta($course_id, '_tutor_course_started', tutor_time());
911 do_action('tutor/course/started', $course_id);
912 }
913 }
914 }
915
916 /**
917 * Add Course level to course settings
918 * @since v.1.4.8
919 */
920 public function course_elements_enable_disable(){
921 add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
922 add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
923 add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
924 add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
925 add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
926 add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
927 add_filter('tutor_course/single/enrolled/nav_items', array($this, 'enable_disable_course_nav_items') );
928 }
929
930 /**
931 * Enable disable course progress bar
932 * @since v.1.4.8
933 */
934 public function enable_disable_course_progress_bar($html){
935 $disable_option = (bool) get_tutor_option('disable_course_progress_bar');
936 if($disable_option){
937 return '';
938 }
939 return $html;
940 }
941
942 /**
943 * Enable disable material includes
944 * @since v.1.4.8
945 */
946 public function enable_disable_material_includes($html){
947 $disable_option = (bool) get_tutor_option('disable_course_material');
948 if($disable_option){
949 return '';
950 }
951 return $html;
952 }
953
954 /**
955 * Enable disable course content
956 * @since v.1.4.8
957 */
958 public function enable_disable_course_content($html){
959 $disable_option = (bool) get_tutor_option('disable_course_description');
960 if($disable_option){
961 return '';
962 }
963 return $html;
964 }
965
966 /**
967 * Enable disable course benefits
968 * @since v.1.4.8
969 */
970 public function enable_disable_course_benefits($html){
971 $disable_option = (bool) get_tutor_option('disable_course_benefits');
972 if($disable_option){
973 return '';
974 }
975 return $html;
976 }
977
978 /**
979 * Enable disable course requirements
980 * @since v.1.4.8
981 */
982 public function enable_disable_course_requirements($html){
983 $disable_option = (bool) get_tutor_option('disable_course_requirements');
984 if($disable_option){
985 return '';
986 }
987 return $html;
988 }
989
990 /**
991 * Enable disable course target audience
992 * @since v.1.4.8
993 */
994 public function enable_disable_course_target_audience($html){
995 $disable_option = (bool) get_tutor_option('disable_course_target_audience');
996 if($disable_option){
997 return '';
998 }
999 return $html;
1000 }
1001
1002 /**
1003 * Enable disable course nav items
1004 * @since v.1.4.8
1005 */
1006 public function enable_disable_course_nav_items($items){
1007 global $wp_query, $post;
1008 $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
1009 $disable_course_announcements = (bool) get_tutor_option('disable_course_announcements');
1010
1011 $disable_qa_for_this_course = ($wp_query->is_single && !empty($post)) ? get_post_meta($post->ID, '_tutor_disable_qa', true) : '';
1012
1013 if(!$enable_q_and_a_on_course || $disable_qa_for_this_course == 'yes') {
1014 if(tutils()->array_get('questions', $items)) {
1015 unset($items['questions']);
1016 }
1017 }
1018 if($disable_course_announcements){
1019 if(tutils()->array_get('announcements', $items)) {
1020 unset($items['announcements']);
1021 }
1022 }
1023 return $items;
1024 }
1025
1026 /**
1027 * Filter product in shop page
1028 * @since v.1.4.9
1029 */
1030 public function filter_product_in_shop_page(){
1031 $hide_course_from_shop_page = (bool) get_tutor_option('hide_course_from_shop_page');
1032 if(!$hide_course_from_shop_page){
1033 return;
1034 }
1035 add_action('woocommerce_product_query', array($this, 'filter_woocommerce_product_query'));
1036 add_filter('edd_downloads_query', array($this, 'filter_edd_downloads_query'), 10, 2);
1037 add_action('pre_get_posts', array($this, 'filter_archive_meta_query'), 1);
1038 }
1039
1040 /**
1041 * Tutor product meta query
1042 * @since v.1.4.9
1043 */
1044 public function tutor_product_meta_query(){
1045 $meta_query = array(
1046 'key' => '_tutor_product',
1047 'compare' => 'NOT EXISTS'
1048 );
1049 return $meta_query;
1050 }
1051
1052 /**
1053 * Filter product in woocommerce shop page
1054 * @since v.1.4.9
1055 */
1056 public function filter_woocommerce_product_query($wp_query){
1057 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1058 return $wp_query;
1059 }
1060
1061 /**
1062 * Filter product in edd downloads shortcode page
1063 * @since v.1.4.9
1064 */
1065 public function filter_edd_downloads_query($query){
1066 $query['meta_query'][] = $this->tutor_product_meta_query();
1067 return $query;
1068 }
1069
1070 /**
1071 * Filter product in edd downloads archive page
1072 * @since v.1.4.9
1073 */
1074 public function filter_archive_meta_query($wp_query){
1075 if(!is_admin() && $wp_query->is_archive && $wp_query->get('post_type') === 'download'){
1076 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1077 }
1078 return $wp_query;
1079 }
1080
1081 /**
1082 * @param $html
1083 * @return string
1084 *
1085 * Removed course price if already enrolled at single course
1086 *
1087 * @since v.1.5.8
1088 */
1089 public function remove_price_if_enrolled($html){
1090 $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1091
1092 if ($should_removed){
1093 $course_id = get_the_ID();
1094 $enrolled = tutils()->is_enrolled($course_id);
1095 if ($enrolled){
1096 $html = '';
1097 }
1098 }
1099 return $html;
1100 }
1101
1102 /**
1103 * @param $html
1104 * @return string
1105 *
1106 * Check if all lessons and quizzes done before mark course complete.
1107 */
1108 function tutor_lms_hide_course_complete_btn($html){
1109
1110 $completion_mode = tutils()->get_option('course_completion_process');
1111 if ($completion_mode !== 'strict'){
1112 return $html;
1113 }
1114
1115 $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1116 $lesson_count = tutils()->get_lesson_count_by_course();
1117
1118 if ($completed_lesson < $lesson_count){
1119 return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
1120 }
1121
1122 $quizzes = array();
1123
1124 $course_contents = tutils()->get_course_contents_by_id();
1125 if (tutils()->count($course_contents)){
1126 foreach ($course_contents as $content){
1127 if ($content->post_type === 'tutor_quiz'){
1128 $quizzes[] = $content;
1129 }
1130 }
1131 }
1132
1133 $is_pass = true;
1134 $required_quiz_pass = 0;
1135
1136 if (tutils()->count($quizzes)){
1137 foreach ($quizzes as $quiz){
1138
1139 $attempt = tutils()->get_quiz_attempt($quiz->ID);
1140 if ($attempt) {
1141 $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1142 $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1143
1144 if ($earned_percentage < $passing_grade) {
1145 $required_quiz_pass++;
1146 $is_pass = false;
1147 }
1148 }else{
1149 $required_quiz_pass++;
1150 $is_pass = false;
1151 }
1152 }
1153 }
1154
1155 if ( ! $is_pass){
1156 return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
1157 }
1158
1159 return $html;
1160 }
1161
1162 public function get_generate_greadbook($html){
1163 if ( ! tutils()->is_completed_course()){
1164 return '';
1165 }
1166 return $html;
1167 }
1168
1169 /**
1170 * Add social share content in header
1171 * @since v.1.6.3
1172 */
1173 public function social_share_content(){
1174 global $wp_query, $post;
1175 if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type) { ?>
1176 <!--Facebook-->
1177 <meta property="og:type" content="website"/>
1178 <meta property="og:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>" />
1179 <meta property="og:description" content="<?php echo esc_html($post->post_content); ?>" />
1180 <!--Twitter-->
1181 <meta name="twitter:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1182 <meta name="twitter:description" content="<?php echo esc_html($post->post_content); ?>">
1183 <!--Google+-->
1184 <meta itemprop="image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1185 <meta itemprop="description" content="<?php echo esc_html($post->post_content); ?>"> <?php
1186 }
1187 }
1188
1189 /**
1190 * Get posts by type and parent
1191 * @since v.1.6.6
1192 */
1193 public function tutor_get_post_ids($post_type, $post_parent) {
1194 $args = array(
1195 'fields' => 'ids',
1196 'post_type' => $post_type,
1197 'post_parent' => $post_parent,
1198 'post_status' => 'any',
1199 'posts_per_page' => -1,
1200 );
1201 return get_posts($args);
1202 }
1203
1204 /**
1205 * Delete course data when permanently deleting a course.
1206 * @since v.1.6.6
1207 */
1208 function delete_tutor_course_data( $post_id ) {
1209 $course_post_type = tutor()->course_post_type;
1210 $lesson_post_type = tutor()->lesson_post_type;
1211
1212 if (get_post_type($post_id) == $course_post_type) {
1213 global $wpdb;
1214 $topic_ids = $this->tutor_get_post_ids('topics', $post_id);
1215 if ( !empty($topic_ids) ) {
1216 foreach ($topic_ids as $topic_id) {
1217 $content_post_type = apply_filters('tutor_course_contents_post_types', array($lesson_post_type, 'tutor_quiz'));
1218 $topic_content_ids = $this->tutor_get_post_ids($content_post_type, $topic_id);
1219
1220 foreach ($topic_content_ids as $content_id) {
1221 if( get_post_type($content_id) == 'tutor_quiz') {
1222 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $content_id));
1223 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $content_id));
1224
1225 $questions_ids = $wpdb->get_col($wpdb->prepare("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id));
1226 if (is_array($questions_ids) && count($questions_ids)){
1227 $in_question_ids = "'".implode("','", $questions_ids)."'";
1228 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
1229 }
1230 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $content_id));
1231 }
1232 wp_delete_post($content_id, true);
1233 }
1234 wp_delete_post($topic_id, true);
1235 }
1236 }
1237 $child_post_ids = $this->tutor_get_post_ids(array('tutor_announcements', 'tutor_enrolled'), $post_id);
1238 if ( !empty($child_post_ids) ) {
1239 foreach ($child_post_ids as $child_post_id) {
1240 wp_delete_post($child_post_id, true);
1241 }
1242 }
1243 }
1244 }
1245
1246 /**
1247 * tutor course setting metabox
1248 * @since v.1.7.0
1249 */
1250 function tutor_course_setting_metabox( $post ) {
1251
1252 $disable_qa = $this->additional_meta[0];
1253 $is_public = $this->additional_meta[1];
1254
1255 $disable_qa_checked = get_post_meta($post->ID, $disable_qa, true)=='yes' ? 'checked="checked"' : '';
1256 $is_public_checked = get_post_meta($post->ID, $is_public, true)=='yes' ? 'checked="checked"' : '';
1257
1258 do_action('tutor_before_course_sidebar_settings_metabox', $post);
1259 ?>
1260 <div class="tutor-course-sidebar-settings-item" id="_tutor_is_course_public_meta_checkbox" style="display:none">
1261 <label for="<?php echo $is_public; ?>">
1262 <input id="<?php echo $is_public; ?>" type="checkbox" name="<?php echo $is_public; ?>" value="yes" <?php echo $is_public_checked; ?> />
1263 <?php _e('Make This Course Public', 'tutor'); ?>
1264 <small style="display:block;padding-left:24px">
1265 <?php _e('No enrollment required.', 'tutor'); ?>
1266 </small>
1267 </label>
1268 </div>
1269 <div class="tutor-course-sidebar-settings-item">
1270 <label for="<?php echo $disable_qa; ?>">
1271 <input type="hidden" name="_tutor_course_additional_data_edit" value="true" />
1272 <input id="<?php echo $disable_qa; ?>" type="checkbox" name="<?php echo $disable_qa; ?>" value="yes" <?php echo $disable_qa_checked; ?> />
1273 <?php _e('Disable Q&A', 'tutor'); ?>
1274 </label>
1275 </div>
1276 <?php
1277 do_action('tutor_after_course_sidebar_settings_metabox', $post);
1278 }
1279
1280 function tutor_course_setting_metabox_frontend( $post ){
1281 ?>
1282 <div class="tutor-course-builder-section tutor-course-builder-info">
1283 <div class="tutor-course-builder-section-title">
1284 <h3><i class="tutor-icon-down"></i><span><?php esc_html_e('Tutor Settings', 'tutor'); ?></span></h3>
1285 </div>
1286 <div class="tutor-course-builder-section-content">
1287 <div class="tutor-frontend-builder-item-scope">
1288 <div class="tutor-form-group">
1289 <?php $this->tutor_course_setting_metabox($post); ?>
1290 </div>
1291 </div>
1292 </div>
1293 </div>
1294 <?php
1295 }
1296
1297 /**
1298 * Delete associated enrollment
1299 * @since v.1.8.2
1300 */
1301 public function delete_associated_enrollment($post_id) {
1302 global $wpdb;
1303
1304 $enroll_id = $wpdb->get_var( $wpdb->prepare(
1305 "SELECT
1306 post_id
1307 FROM
1308 {$wpdb->postmeta}
1309 WHERE
1310 meta_key='_tutor_enrolled_by_order_id'
1311 AND meta_value = %d
1312 ",
1313 $post_id
1314 ) );
1315
1316 if(is_numeric($enroll_id) && $enroll_id>0) {
1317
1318 $course_id = get_post_field('post_parent', $enroll_id);
1319 $user_id = get_post_field('post_author', $enroll_id);
1320
1321 tutils()->cancel_course_enrol($course_id, $user_id);
1322 }
1323 }
1324
1325 public function tutor_reset_course_progress() {
1326 tutils()->checking_nonce();
1327 $course_id = tutor_utils()->array_get('course_id', $_POST);
1328
1329 if(!$course_id || !is_numeric($course_id) || !tutor_utils()->is_enrolled( $course_id )) {
1330 wp_send_json_error(array('message' => __('Invalid Course ID or Access Denied.', 'tutor')));
1331 return;
1332 }
1333
1334 tutor_utils()->delete_course_progress($course_id);
1335 wp_send_json_success(array('redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ));
1336 }
1337 }