PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 1.9.5
Tutor LMS – eLearning and online course solution v1.9.5
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 5 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 5 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
1335 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 $product_id = $productObj->save();
818 if($productObj->is_type('subscription')) {
819 update_post_meta( $attached_product_id, '_subscription_price', $course_price );
820 }
821 } else {
822 $productObj = new \WC_Product();
823 $productObj->set_name($course->post_title);
824 $productObj->set_status('publish');
825 $productObj->set_price($course_price); // set product price
826 $productObj->set_regular_price($course_price); // set product regular price
827
828 $product_id = $productObj->save();
829 if ($product_id) {
830 update_post_meta( $post_ID, '_tutor_course_product_id', $product_id );
831 //Mark product for woocommerce
832 update_post_meta( $product_id, '_virtual', 'yes' );
833 update_post_meta( $product_id, '_tutor_product', 'yes' );
834
835 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
836 if ( $coursePostThumbnail ) {
837 set_post_thumbnail( $product_id, $coursePostThumbnail );
838 }
839 }
840 }
841
842 }elseif ($monetize_by === 'edd'){
843
844 $is_update = false;
845
846 if ($attached_product_id){
847 $edd_price = get_post_meta($attached_product_id, 'edd_price', true);
848 if ($edd_price){
849 $is_update = true;
850 }
851 }
852
853 if ($is_update){
854 //Update the product
855 update_post_meta( $attached_product_id, 'edd_price', $course_price );
856 }else{
857 //Create new product
858
859 $post_arr = array(
860 'post_type' => 'download',
861 'post_title' => $course->post_title,
862 'post_status' => 'publish',
863 'post_author' => get_current_user_id(),
864 );
865 $download_id = wp_insert_post( $post_arr );
866 if ($download_id ) {
867 //edd_price
868 update_post_meta( $download_id, 'edd_price', $course_price );
869
870 update_post_meta( $post_ID, '_tutor_course_product_id', $download_id );
871 //Mark product for EDD
872 update_post_meta( $download_id, '_tutor_product', 'yes' );
873
874 $coursePostThumbnail = get_post_meta( $post_ID, '_thumbnail_id', true );
875 if ( $coursePostThumbnail ) {
876 set_post_thumbnail( $download_id, $coursePostThumbnail );
877 }
878
879 }
880
881 }
882
883
884 }
885
886 }
887
888
889 /**
890 * Add Course level to course settings
891 * @since v.1.4.1
892 */
893 public function add_course_level_to_settings(){
894 include tutor()->path.'views/metabox/course-level-metabox.php';
895 }
896
897 /**
898 * Check if course starting
899 *
900 * @since v.1.4.8
901 */
902 public function tutor_lesson_load_before(){
903 $course_id = tutils()->get_course_id_by_content(get_the_ID());
904 $completed_lessons = tutor_utils()->get_completed_lesson_count_by_course($course_id);
905 if (is_user_logged_in()){
906 $is_course_started = get_post_meta($course_id, '_tutor_course_started', true);
907 if ( ! $completed_lessons && ! $is_course_started){
908 update_post_meta($course_id, '_tutor_course_started', tutor_time());
909 do_action('tutor/course/started', $course_id);
910 }
911 }
912 }
913
914 /**
915 * Add Course level to course settings
916 * @since v.1.4.8
917 */
918 public function course_elements_enable_disable(){
919 add_filter('tutor_course/single/completing-progress-bar', array($this, 'enable_disable_course_progress_bar') );
920 add_filter('tutor_course/single/material_includes', array($this, 'enable_disable_material_includes') );
921 add_filter('tutor_course/single/content', array($this, 'enable_disable_course_content') );
922 add_filter('tutor_course/single/benefits_html', array($this, 'enable_disable_course_benefits') );
923 add_filter('tutor_course/single/requirements_html', array($this, 'enable_disable_course_requirements') );
924 add_filter('tutor_course/single/audience_html', array($this, 'enable_disable_course_target_audience') );
925 add_filter('tutor_course/single/enrolled/nav_items', array($this, 'enable_disable_course_nav_items') );
926 }
927
928 /**
929 * Enable disable course progress bar
930 * @since v.1.4.8
931 */
932 public function enable_disable_course_progress_bar($html){
933 $disable_option = (bool) get_tutor_option('disable_course_progress_bar');
934 if($disable_option){
935 return '';
936 }
937 return $html;
938 }
939
940 /**
941 * Enable disable material includes
942 * @since v.1.4.8
943 */
944 public function enable_disable_material_includes($html){
945 $disable_option = (bool) get_tutor_option('disable_course_material');
946 if($disable_option){
947 return '';
948 }
949 return $html;
950 }
951
952 /**
953 * Enable disable course content
954 * @since v.1.4.8
955 */
956 public function enable_disable_course_content($html){
957 $disable_option = (bool) get_tutor_option('disable_course_description');
958 if($disable_option){
959 return '';
960 }
961 return $html;
962 }
963
964 /**
965 * Enable disable course benefits
966 * @since v.1.4.8
967 */
968 public function enable_disable_course_benefits($html){
969 $disable_option = (bool) get_tutor_option('disable_course_benefits');
970 if($disable_option){
971 return '';
972 }
973 return $html;
974 }
975
976 /**
977 * Enable disable course requirements
978 * @since v.1.4.8
979 */
980 public function enable_disable_course_requirements($html){
981 $disable_option = (bool) get_tutor_option('disable_course_requirements');
982 if($disable_option){
983 return '';
984 }
985 return $html;
986 }
987
988 /**
989 * Enable disable course target audience
990 * @since v.1.4.8
991 */
992 public function enable_disable_course_target_audience($html){
993 $disable_option = (bool) get_tutor_option('disable_course_target_audience');
994 if($disable_option){
995 return '';
996 }
997 return $html;
998 }
999
1000 /**
1001 * Enable disable course nav items
1002 * @since v.1.4.8
1003 */
1004 public function enable_disable_course_nav_items($items){
1005 global $wp_query, $post;
1006 $enable_q_and_a_on_course = (bool) get_tutor_option('enable_q_and_a_on_course');
1007 $disable_course_announcements = (bool) get_tutor_option('disable_course_announcements');
1008
1009 $disable_qa_for_this_course = ($wp_query->is_single && !empty($post)) ? get_post_meta($post->ID, '_tutor_disable_qa', true) : '';
1010
1011 if(!$enable_q_and_a_on_course || $disable_qa_for_this_course == 'yes') {
1012 if(tutils()->array_get('questions', $items)) {
1013 unset($items['questions']);
1014 }
1015 }
1016 if($disable_course_announcements){
1017 if(tutils()->array_get('announcements', $items)) {
1018 unset($items['announcements']);
1019 }
1020 }
1021 return $items;
1022 }
1023
1024 /**
1025 * Filter product in shop page
1026 * @since v.1.4.9
1027 */
1028 public function filter_product_in_shop_page(){
1029 $hide_course_from_shop_page = (bool) get_tutor_option('hide_course_from_shop_page');
1030 if(!$hide_course_from_shop_page){
1031 return;
1032 }
1033 add_action('woocommerce_product_query', array($this, 'filter_woocommerce_product_query'));
1034 add_filter('edd_downloads_query', array($this, 'filter_edd_downloads_query'), 10, 2);
1035 add_action('pre_get_posts', array($this, 'filter_archive_meta_query'), 1);
1036 }
1037
1038 /**
1039 * Tutor product meta query
1040 * @since v.1.4.9
1041 */
1042 public function tutor_product_meta_query(){
1043 $meta_query = array(
1044 'key' => '_tutor_product',
1045 'compare' => 'NOT EXISTS'
1046 );
1047 return $meta_query;
1048 }
1049
1050 /**
1051 * Filter product in woocommerce shop page
1052 * @since v.1.4.9
1053 */
1054 public function filter_woocommerce_product_query($wp_query){
1055 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1056 return $wp_query;
1057 }
1058
1059 /**
1060 * Filter product in edd downloads shortcode page
1061 * @since v.1.4.9
1062 */
1063 public function filter_edd_downloads_query($query){
1064 $query['meta_query'][] = $this->tutor_product_meta_query();
1065 return $query;
1066 }
1067
1068 /**
1069 * Filter product in edd downloads archive page
1070 * @since v.1.4.9
1071 */
1072 public function filter_archive_meta_query($wp_query){
1073 if(!is_admin() && $wp_query->is_archive && $wp_query->get('post_type') === 'download'){
1074 $wp_query->set('meta_query', array($this->tutor_product_meta_query()));
1075 }
1076 return $wp_query;
1077 }
1078
1079 /**
1080 * @param $html
1081 * @return string
1082 *
1083 * Removed course price if already enrolled at single course
1084 *
1085 * @since v.1.5.8
1086 */
1087 public function remove_price_if_enrolled($html){
1088 $should_removed = apply_filters('should_remove_price_if_enrolled', true);
1089
1090 if ($should_removed){
1091 $course_id = get_the_ID();
1092 $enrolled = tutils()->is_enrolled($course_id);
1093 if ($enrolled){
1094 $html = '';
1095 }
1096 }
1097 return $html;
1098 }
1099
1100 /**
1101 * @param $html
1102 * @return string
1103 *
1104 * Check if all lessons and quizzes done before mark course complete.
1105 */
1106 function tutor_lms_hide_course_complete_btn($html){
1107
1108 $completion_mode = tutils()->get_option('course_completion_process');
1109 if ($completion_mode !== 'strict'){
1110 return $html;
1111 }
1112
1113 $completed_lesson = tutils()->get_completed_lesson_count_by_course();
1114 $lesson_count = tutils()->get_lesson_count_by_course();
1115
1116 if ($completed_lesson < $lesson_count){
1117 return '<p class="suggestion-before-course-complete">'.__('complete all lessons to mark this course as complete', 'tutor').'</p>';
1118 }
1119
1120 $quizzes = array();
1121
1122 $course_contents = tutils()->get_course_contents_by_id();
1123 if (tutils()->count($course_contents)){
1124 foreach ($course_contents as $content){
1125 if ($content->post_type === 'tutor_quiz'){
1126 $quizzes[] = $content;
1127 }
1128 }
1129 }
1130
1131 $is_pass = true;
1132 $required_quiz_pass = 0;
1133
1134 if (tutils()->count($quizzes)){
1135 foreach ($quizzes as $quiz){
1136
1137 $attempt = tutils()->get_quiz_attempt($quiz->ID);
1138 if ($attempt) {
1139 $passing_grade = tutor_utils()->get_quiz_option($quiz->ID, 'passing_grade', 0);
1140 $earned_percentage = $attempt->earned_marks > 0 ? (number_format(($attempt->earned_marks * 100) / $attempt->total_marks)) : 0;
1141
1142 if ($earned_percentage < $passing_grade) {
1143 $required_quiz_pass++;
1144 $is_pass = false;
1145 }
1146 }else{
1147 $required_quiz_pass++;
1148 $is_pass = false;
1149 }
1150 }
1151 }
1152
1153 if ( ! $is_pass){
1154 return '<p class="suggestion-before-course-complete">'.sprintf(__('You have to pass %s quizzes to complete this course.', 'tutor'), $required_quiz_pass).'</p>';
1155 }
1156
1157 return $html;
1158 }
1159
1160 public function get_generate_greadbook($html){
1161 if ( ! tutils()->is_completed_course()){
1162 return '';
1163 }
1164 return $html;
1165 }
1166
1167 /**
1168 * Add social share content in header
1169 * @since v.1.6.3
1170 */
1171 public function social_share_content(){
1172 global $wp_query, $post;
1173 if ($wp_query->is_single && ! empty($wp_query->query_vars['post_type']) && $wp_query->query_vars['post_type'] === $this->course_post_type) { ?>
1174 <!--Facebook-->
1175 <meta property="og:type" content="website"/>
1176 <meta property="og:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>" />
1177 <meta property="og:description" content="<?php echo esc_html($post->post_content); ?>" />
1178 <!--Twitter-->
1179 <meta name="twitter:image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1180 <meta name="twitter:description" content="<?php echo esc_html($post->post_content); ?>">
1181 <!--Google+-->
1182 <meta itemprop="image" content="<?php echo get_tutor_course_thumbnail_src(); ?>">
1183 <meta itemprop="description" content="<?php echo esc_html($post->post_content); ?>"> <?php
1184 }
1185 }
1186
1187 /**
1188 * Get posts by type and parent
1189 * @since v.1.6.6
1190 */
1191 public function tutor_get_post_ids($post_type, $post_parent) {
1192 $args = array(
1193 'fields' => 'ids',
1194 'post_type' => $post_type,
1195 'post_parent' => $post_parent,
1196 'post_status' => 'any',
1197 'posts_per_page' => -1,
1198 );
1199 return get_posts($args);
1200 }
1201
1202 /**
1203 * Delete course data when permanently deleting a course.
1204 * @since v.1.6.6
1205 */
1206 function delete_tutor_course_data( $post_id ) {
1207 $course_post_type = tutor()->course_post_type;
1208 $lesson_post_type = tutor()->lesson_post_type;
1209
1210 if (get_post_type($post_id) == $course_post_type) {
1211 global $wpdb;
1212 $topic_ids = $this->tutor_get_post_ids('topics', $post_id);
1213 if ( !empty($topic_ids) ) {
1214 foreach ($topic_ids as $topic_id) {
1215 $content_post_type = apply_filters('tutor_course_contents_post_types', array($lesson_post_type, 'tutor_quiz'));
1216 $topic_content_ids = $this->tutor_get_post_ids($content_post_type, $topic_id);
1217
1218 foreach ($topic_content_ids as $content_id) {
1219 if( get_post_type($content_id) == 'tutor_quiz') {
1220 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempts', array('quiz_id' => $content_id));
1221 $wpdb->delete($wpdb->prefix.'tutor_quiz_attempt_answers', array('quiz_id' => $content_id));
1222
1223 $questions_ids = $wpdb->get_col($wpdb->prepare("SELECT question_id FROM {$wpdb->prefix}tutor_quiz_questions WHERE quiz_id = %d ", $content_id));
1224 if (is_array($questions_ids) && count($questions_ids)){
1225 $in_question_ids = "'".implode("','", $questions_ids)."'";
1226 $wpdb->query("DELETE FROM {$wpdb->prefix}tutor_quiz_question_answers WHERE belongs_question_id IN({$in_question_ids}) ");
1227 }
1228 $wpdb->delete($wpdb->prefix.'tutor_quiz_questions', array('quiz_id' => $content_id));
1229 }
1230 wp_delete_post($content_id, true);
1231 }
1232 wp_delete_post($topic_id, true);
1233 }
1234 }
1235 $child_post_ids = $this->tutor_get_post_ids(array('tutor_announcements', 'tutor_enrolled'), $post_id);
1236 if ( !empty($child_post_ids) ) {
1237 foreach ($child_post_ids as $child_post_id) {
1238 wp_delete_post($child_post_id, true);
1239 }
1240 }
1241 }
1242 }
1243
1244 /**
1245 * tutor course setting metabox
1246 * @since v.1.7.0
1247 */
1248 function tutor_course_setting_metabox( $post ) {
1249
1250 $disable_qa = $this->additional_meta[0];
1251 $is_public = $this->additional_meta[1];
1252
1253 $disable_qa_checked = get_post_meta($post->ID, $disable_qa, true)=='yes' ? 'checked="checked"' : '';
1254 $is_public_checked = get_post_meta($post->ID, $is_public, true)=='yes' ? 'checked="checked"' : '';
1255
1256 do_action('tutor_before_course_sidebar_settings_metabox', $post);
1257 ?>
1258 <div class="tutor-course-sidebar-settings-item" id="_tutor_is_course_public_meta_checkbox" style="display:none">
1259 <label for="<?php echo $is_public; ?>">
1260 <input id="<?php echo $is_public; ?>" type="checkbox" name="<?php echo $is_public; ?>" value="yes" <?php echo $is_public_checked; ?> />
1261 <?php _e('Make This Course Public', 'tutor'); ?>
1262 <small style="display:block;padding-left:24px">
1263 <?php _e('No enrollment required.', 'tutor'); ?>
1264 </small>
1265 </label>
1266 </div>
1267 <div class="tutor-course-sidebar-settings-item">
1268 <label for="<?php echo $disable_qa; ?>">
1269 <input type="hidden" name="_tutor_course_additional_data_edit" value="true" />
1270 <input id="<?php echo $disable_qa; ?>" type="checkbox" name="<?php echo $disable_qa; ?>" value="yes" <?php echo $disable_qa_checked; ?> />
1271 <?php _e('Disable Q&A', 'tutor'); ?>
1272 </label>
1273 </div>
1274 <?php
1275 do_action('tutor_after_course_sidebar_settings_metabox', $post);
1276 }
1277
1278 function tutor_course_setting_metabox_frontend( $post ){
1279 ?>
1280 <div class="tutor-course-builder-section tutor-course-builder-info">
1281 <div class="tutor-course-builder-section-title">
1282 <h3><i class="tutor-icon-down"></i><span><?php esc_html_e('Tutor Settings', 'tutor'); ?></span></h3>
1283 </div>
1284 <div class="tutor-course-builder-section-content">
1285 <div class="tutor-frontend-builder-item-scope">
1286 <div class="tutor-form-group">
1287 <?php $this->tutor_course_setting_metabox($post); ?>
1288 </div>
1289 </div>
1290 </div>
1291 </div>
1292 <?php
1293 }
1294
1295 /**
1296 * Delete associated enrollment
1297 * @since v.1.8.2
1298 */
1299 public function delete_associated_enrollment($post_id) {
1300 global $wpdb;
1301
1302 $enroll_id = $wpdb->get_var( $wpdb->prepare(
1303 "SELECT
1304 post_id
1305 FROM
1306 {$wpdb->postmeta}
1307 WHERE
1308 meta_key='_tutor_enrolled_by_order_id'
1309 AND meta_value = %d
1310 ",
1311 $post_id
1312 ) );
1313
1314 if(is_numeric($enroll_id) && $enroll_id>0) {
1315
1316 $course_id = get_post_field('post_parent', $enroll_id);
1317 $user_id = get_post_field('post_author', $enroll_id);
1318
1319 tutils()->cancel_course_enrol($course_id, $user_id);
1320 }
1321 }
1322
1323 public function tutor_reset_course_progress() {
1324 tutils()->checking_nonce();
1325 $course_id = tutor_utils()->array_get('course_id', $_POST);
1326
1327 if(!$course_id || !is_numeric($course_id) || !tutor_utils()->is_enrolled( $course_id )) {
1328 wp_send_json_error(array('message' => __('Invalid Course ID or Access Denied.', 'tutor')));
1329 return;
1330 }
1331
1332 tutor_utils()->delete_course_progress($course_id);
1333 wp_send_json_success(array('redirect_to' => tutor_utils()->get_course_first_lesson( $course_id ) ));
1334 }
1335 }