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