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