PluginProbe
Tutor LMS – eLearning and online course solution / 3.9.2
Tutor LMS – eLearning and online course solution v3.9.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 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 All 191 releases
tutor / classes / Tutor.php

Tutor.php in Tutor LMS – eLearning and online course solution 3.9.2, at classes/Tutor.php

1,414 lines 36.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Initialize all the dependency classes
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 use Tutor\Models\CourseModel;
14 use Tutor\Ecommerce\Ecommerce;
15 use Tutor\Migrations\Migration;
16 use Tutor\TemplateImport\TemplateImportInit;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Tutor final class
24 *
25 * @since 1.0.0
26 */
27 final class Tutor extends Singleton {
28 /**
29 * Tutor version
30 *
31 * @since 1.0.0
32 *
33 * @var string
34 */
35 public $version = TUTOR_VERSION;
36
37 /**
38 * Plugin dir path
39 *
40 * @since 1.0.0
41 *
42 * @var string
43 */
44 public $path;
45
46 /**
47 * Plugin dir path
48 *
49 * @since 1.0.0
50 *
51 * @var string
52 */
53 public $url;
54
55 /**
56 * Plugin dir name
57 *
58 * @since 1.0.0
59 *
60 * @var string
61 */
62 public $basename;
63
64 /**
65 * Utils class object
66 *
67 * @since 1.1.0
68 *
69 * @var object
70 */
71 public $utils;
72
73 /**
74 * Admin class object
75 *
76 * @since 1.1.0
77 *
78 * @var object
79 */
80 public $admin;
81
82 /**
83 * Ajax class object
84 *
85 * @since 1.1.0
86 *
87 * @var object
88 */
89 public $ajax;
90
91 /**
92 * Options class object
93 *
94 * @since 1.1.0
95 *
96 * @var object
97 */
98 public $options;
99
100 /**
101 * Short code class object
102 *
103 * @since 1.1.0
104 *
105 * @var object
106 */
107 public $shortcode;
108
109 /**
110 * Addons class object
111 *
112 * @since 1.1.0
113 *
114 * @var object
115 */
116 private $addons;
117
118 /**
119 * PostType class object
120 *
121 * @since 1.1.0
122 *
123 * @var object
124 */
125 private $post_types;
126
127 /**
128 * Taxonomies class object
129 *
130 * @since 1.1.0
131 *
132 * @var object
133 */
134 private $taxonomies;
135
136 /**
137 * Assets class object
138 *
139 * @since 1.1.0
140 *
141 * @var object
142 */
143 private $assets;
144
145 /**
146 * Course class object
147 *
148 * @since 1.1.0
149 *
150 * @var object
151 */
152 private $course;
153
154 /**
155 * Lesson class object
156 *
157 * @since 1.1.0
158 *
159 * @var object
160 */
161 public $lesson;
162
163 /**
164 * Rewrite_Rules class object
165 *
166 * @since 1.1.0
167 *
168 * @var object
169 */
170 private $rewrite_rules;
171
172 /**
173 * Template class object
174 *
175 * @since 1.1.0
176 *
177 * @var object
178 */
179 private $template;
180
181 /**
182 * Instructor class object
183 *
184 * @since 1.1.0
185 *
186 * @var object
187 */
188 private $instructor;
189
190 /**
191 * Student class object
192 *
193 * @since 1.1.0
194 *
195 * @var object
196 */
197 private $student;
198
199 /**
200 * Q_And_A class object
201 *
202 * @since 1.1.0
203 *
204 * @var object
205 */
206 private $q_and_a;
207
208 /**
209 * Quiz class object
210 *
211 * @since 1.1.0
212 *
213 * @var object
214 */
215 private $quiz;
216
217 /**
218 * Tools class object
219 *
220 * @since 1.1.0
221 *
222 * @var object
223 */
224 private $tools;
225
226 /**
227 * User class object
228 *
229 * @since 1.1.0
230 *
231 * @var object
232 */
233 private $user;
234
235 /**
236 * Theme_Compatibility class object
237 *
238 * @since 1.1.0
239 *
240 * @var object
241 */
242 private $theme_compatibility;
243
244 /**
245 * Gutenberg class object
246 *
247 * @since 1.1.0
248 *
249 * @var object
250 */
251 private $gutenberg;
252
253 /**
254 * Course_Settings_Tabs class object
255 *
256 * @since 1.1.0
257 *
258 * @var object
259 */
260 private $course_settings_tabs;
261
262 /**
263 * Withdraw class object
264 *
265 * @since 1.1.0
266 *
267 * @var object
268 */
269 private $withdraw;
270
271 /**
272 * Course_Widget class object
273 *
274 * @since 1.1.0
275 *
276 * @var object
277 */
278 private $course_widget;
279
280 /**
281 * Upgrader class object
282 *
283 * @since 1.1.0
284 *
285 * @var object
286 */
287 private $upgrader;
288
289 /**
290 * Dashboard class object
291 *
292 * @since 1.1.0
293 *
294 * @var object
295 */
296 private $dashboard;
297
298 /**
299 * FormHandler class object
300 *
301 * @since 1.1.0
302 *
303 * @var object
304 */
305 private $form_handler;
306
307 /**
308 * Frontend class object
309 *
310 * @since 1.1.0
311 *
312 * @var object
313 */
314 private $frontend;
315
316 /**
317 * Email property
318 *
319 * @since 1.1.0
320 *
321 * @var object
322 */
323 private $email;
324
325 /**
326 * WooCommerce integration class object
327 *
328 * @since 1.1.0
329 *
330 * @var object
331 */
332 private $woocommerce;
333
334 /**
335 * Tutor_EDD class object
336 *
337 * @since 1.1.0
338 *
339 * @var object
340 */
341 private $edd;
342
343 /**
344 * Announcement
345 *
346 * @since 2.0.0
347 *
348 * @var object
349 */
350 public $announcements;
351
352 /**
353 * Reviews class object
354 *
355 * @since 1.1.0
356 *
357 * @var object
358 */
359 private $reviews;
360
361 /**
362 * Withdraw_List class object
363 *
364 * @since 1.1.0
365 *
366 * @var object
367 */
368 public $withdraw_list;
369
370 /**
371 * Student_List class object
372 *
373 * @since 1.1.0
374 *
375 * @var object
376 */
377 public $student_list;
378
379 /**
380 * Instructor_List class object
381 *
382 * @since 1.1.0
383 *
384 * @var object
385 */
386 public $instructor_list;
387
388 /**
389 * Course List
390 *
391 * @var Course_List
392 *
393 * @since 2.0.0
394 */
395 public $course_list;
396
397 //phpcs:disable
398 public $q_and_a_list;
399 public $q_attempt;
400 public $rest_api;
401 public $setup;
402 public $private_course_access;
403 public $course_filter;
404 //phpcs:enable
405
406 /**
407 * Course Embed
408 *
409 * @var $course_embed
410 *
411 * @since 2.1.0
412 */
413 private $course_embed;
414
415 /**
416 * Rest Authentication
417 *
418 * @var $rest_auth
419 *
420 * @since 2.1.0
421 */
422 private $rest_auth;
423
424 /**
425 * Permalink
426 *
427 * @var Permalink
428 */
429 private $permalink;
430
431 /**
432 * Initialize props & other dependencies
433 *
434 * @since 1.0.0
435 */
436 public function __construct() {
437
438 $this->path = plugin_dir_path( TUTOR_FILE );
439 $this->url = plugin_dir_url( TUTOR_FILE );
440 $this->basename = plugin_basename( TUTOR_FILE );
441
442 /**
443 * Adding Tutor Database table to $wpdb;
444 *
445 * @since 1.4.2
446 */
447 global $wpdb;
448 $wpdb->tutor_earnings = $wpdb->prefix . 'tutor_earnings';
449 $wpdb->tutor_gradebooks = $wpdb->prefix . 'tutor_gradebooks';
450 $wpdb->tutor_gradebooks_results = $wpdb->prefix . 'tutor_gradebooks_results';
451 $wpdb->tutor_quiz_attempts = $wpdb->prefix . 'tutor_quiz_attempts';
452 $wpdb->tutor_quiz_attempt_answers = $wpdb->prefix . 'tutor_quiz_attempt_answers';
453 $wpdb->tutor_quiz_questions = $wpdb->prefix . 'tutor_quiz_questions';
454 $wpdb->tutor_quiz_question_answers = $wpdb->prefix . 'tutor_quiz_question_answers';
455 $wpdb->tutor_withdraws = $wpdb->prefix . 'tutor_withdraws';
456 $wpdb->tutor_email_queue = $wpdb->prefix . 'tutor_email_queue';
457 $wpdb->tutor_order_items = $wpdb->prefix . 'tutor_order_items';
458 $wpdb->tutor_orders = $wpdb->prefix . 'tutor_orders';
459 $wpdb->tutor_ordermeta = $wpdb->prefix . 'tutor_ordermeta';
460 $wpdb->tutor_subscription_plan_items = $wpdb->prefix . 'tutor_subscription_plan_items';
461 $wpdb->tutor_subscription_plans = $wpdb->prefix . 'tutor_subscription_plans';
462 $wpdb->tutor_subscriptions = $wpdb->prefix . 'tutor_subscriptions';
463 $wpdb->tutor_subscriptionmeta = $wpdb->prefix . 'tutor_subscriptionmeta';
464 $wpdb->tutor_order_itemmeta = $wpdb->prefix . 'tutor_order_itemmeta';
465
466 /**
467 * Changing default wp doing ajax return based on tutor ajax action
468 */
469 add_filter( 'wp_doing_ajax', array( $this, 'wp_doing_ajax' ) );
470
471 /**
472 * Include Files
473 */
474 $this->includes();
475
476 do_action( 'tutor_before_load' );
477
478 $this->addons = new Addons();
479 $this->post_types = new Post_types();
480 $this->taxonomies = new Taxonomies();
481 $this->assets = new Assets();
482 $this->admin = new Admin();
483 $this->ajax = new Ajax();
484 $this->options = new Options_V2();
485 $this->shortcode = new Shortcode();
486 $this->course = new Course();
487 $this->lesson = new Lesson();
488 $this->rewrite_rules = new Rewrite_Rules();
489 $this->template = new Template();
490 $this->instructor = new Instructor();
491 $this->student = new Student();
492 $this->q_and_a = new Q_And_A();
493 $this->q_and_a_list = new Question_Answers_List();
494 $this->q_attempt = new Quiz_Attempts_List();
495 $this->quiz = new Quiz();
496 $this->tools = new Tools();
497 $this->user = new User();
498 $this->theme_compatibility = new Theme_Compatibility();
499 $this->gutenberg = new Gutenberg();
500 $this->course_settings_tabs = new Course_Settings_Tabs();
501 $this->withdraw = new Withdraw();
502 $this->upgrader = new Upgrader();
503 $this->dashboard = new Dashboard();
504 $this->form_handler = new FormHandler();
505 $this->frontend = new Frontend();
506 $this->rest_api = new RestAPI();
507 $this->setup = new Tutor_Setup();
508 $this->private_course_access = new Private_Course_Access();
509 $this->course_filter = new Course_Filter();
510 $this->permalink = new Permalink();
511
512 // Template import.
513 new TemplateImportInit();
514
515 // Integrations.
516 $this->woocommerce = new WooCommerce();
517 $this->edd = new TutorEDD();
518
519 /**
520 * Init obj
521 *
522 * @since 2.0.0
523 */
524 $this->announcements = new Announcements();
525 $this->course_list = new Course_List();
526 $this->reviews = new Reviews();
527 $this->withdraw_list = new Withdraw_Requests_List();
528 $this->student_list = new Students_List();
529 $this->instructor_list = new Instructors_List();
530 $this->course_embed = new Course_Embed();
531 $this->rest_auth = new RestAuth();
532
533 /**
534 * New Course Builder.
535 *
536 * @since 3.0.0
537 */
538 new QuizBuilder();
539
540 /**
541 * Tutor native e-commerce
542 *
543 * @since 3.0.0
544 */
545 new Ecommerce();
546
547 /**
548 * Data migrations
549 *
550 * @since 3.8.0
551 */
552 new Migration();
553
554 /**
555 * Run Method
556 *
557 * @since 1.2.0
558 */
559 $this->run();
560
561 do_action( 'tutor_loaded' );
562
563 add_action( 'init', array( $this, 'init_action' ) );
564
565 /**
566 * Check activated plugin
567 *
568 * @since 1.5.7
569 */
570
571 add_action( 'activated_plugin', array( $this, 'activated_tutor' ), 10, 2 );
572
573 /**
574 * Redirect to setup page
575 *
576 * @since 2.8.0
577 */
578 add_action( 'admin_init', array( $this, 'redirect_to_setup_page' ) );
579 }
580
581 /**
582 * Check activated plugin
583 *
584 * @since 1.5.7
585 *
586 * @param mixed $plugin plugin.
587 * @param mixed $network_wide network wide.
588 *
589 * @return void
590 */
591 public function activated_tutor( $plugin, $network_wide = null ) {
592 if ( tutor()->basename === $plugin ) {
593 $this->redirect_to_setup_page();
594 }
595 }
596
597 /**
598 * Redirect to setup page
599 *
600 * @since 2.8.0
601 *
602 * @return void
603 */
604 public function redirect_to_setup_page() {
605 if ( ( ! get_option( 'tutor_wizard' ) ) && version_compare( TUTOR_VERSION, '1.5.6', '>' ) ) {
606 if ( ! wp_doing_ajax() ) {
607 update_option( 'tutor_wizard', 'active' );
608 $is_wp_cli = defined( 'WP_CLI' ) && WP_CLI;
609 if ( ! $is_wp_cli ) {
610 wp_safe_redirect( admin_url( 'admin.php?page=tutor-setup' ) );
611 }
612 exit;
613 }
614 }
615 }
616
617 /**
618 * Include utility functions
619 *
620 * @return void
621 */
622 public function includes() {
623 $tutor_path = plugin_dir_path( TUTOR_FILE );
624
625 include $tutor_path . 'includes/tutor-general-functions.php';
626 include $tutor_path . 'includes/tutor-template-functions.php';
627 include $tutor_path . 'includes/tutor-template-hook.php';
628 include $tutor_path . 'includes/translate-text.php';
629 include $tutor_path . 'includes/country.php';
630 include $tutor_path . 'includes/ecommerce-functions.php';
631
632 if ( ! function_exists( 'is_plugin_active' ) ) {
633 require_once ABSPATH . 'wp-admin/includes/plugin.php';
634 }
635
636 $is_droip_active = \is_plugin_active( 'droip/droip.php' );
637 $tutor_droip_path = $tutor_path . 'includes/droip/droip.php';
638 if ( $is_droip_active && file_exists( $tutor_droip_path ) ) {
639 include $tutor_droip_path;
640 }
641 }
642
643 /**
644 * Providing hooks
645 *
646 * @return void
647 */
648 public function run() {
649 do_action( 'tutor_before_run' );
650 do_action( 'tutor_after_run' );
651 }
652
653 /**
654 * Tutor Action Via do_action
655 *
656 * @since 1.2.14
657 */
658 public function init_action() {
659 $tutor_action = Input::sanitize_request_data( 'tutor_action' );
660 if ( '' !== $tutor_action ) {
661 do_action( 'tutor_action_' . $tutor_action );
662 }
663 }
664
665 /**
666 * Do some task during plugin activation
667 */
668 public static function tutor_activate() {
669 $version = get_option( 'tutor_version' );
670 if ( ! function_exists( 'tutor_time' ) ) {
671 include tutor()->path . 'includes/tutor-general-functions.php';
672 }
673
674 // Create Database.
675 self::create_database();
676
677 // Save Option.
678 if ( ! $version ) {
679
680 $options = self::default_options();
681 update_option( 'tutor_option', $options );
682
683 // Rewrite Flush.
684 Permalink::set_permalink_flag();
685 self::manage_tutor_roles_and_permissions();
686
687 // Save initial Page.
688 self::save_data();
689 update_option( 'tutor_version', TUTOR_VERSION );
690 }
691
692 // Set Schedule.
693 if ( ! wp_next_scheduled( 'tutor_once_in_day_run_schedule' ) ) {
694 wp_schedule_event( tutor_time(), 'twicedaily', 'tutor_once_in_day_run_schedule' );
695 }
696
697 /**
698 * Backward Compatibility for version < 1.2.0
699 */
700 if ( version_compare( get_option( 'tutor_version' ), '1.2.0', '<' ) ) {
701 /**
702 * Creating New Database
703 */
704 self::create_withdraw_database();
705 // Update the tutor version.
706 update_option( 'tutor_version', '1.2.0' );
707 // Rewrite Flush.
708 Permalink::set_permalink_flag();
709 }
710
711 /**
712 * Backward Compatibility to < 1.3.1 for make course plural
713 */
714 if ( version_compare( get_option( 'tutor_version' ), '1.3.1', '<' ) ) {
715 global $wpdb;
716
717 if ( ! get_option( 'is_course_post_type_updated' ) ) {
718 $wpdb->update( $wpdb->posts, array( 'post_type' => tutor()->course_post_type ), array( 'post_type' => 'course' ) );
719 update_option( 'is_course_post_type_updated', true );
720 update_option( 'tutor_version', '1.3.1' );
721 Permalink::set_permalink_flag();
722 }
723 }
724
725 /**
726 * Save First activation Time
727 */
728 $first_activation_date = get_option( 'tutor_first_activation_time' );
729 if ( ! $first_activation_date ) {
730 update_option( 'tutor_first_activation_time', tutor_time() );
731 }
732 }
733
734 /**
735 * Run task on deactivation
736 *
737 * @since 1.0.0
738 *
739 * @return void
740 */
741 public static function tutor_deactivation() {
742 wp_clear_scheduled_hook( 'tutor_once_in_day_run_schedule' );
743 }
744
745 /**
746 * Create database
747 *
748 * @return void
749 */
750 public static function create_database() {
751 global $wpdb;
752
753 $charset_collate = $wpdb->get_charset_collate();
754
755 /**
756 * Table SQL
757 *
758 * {$wpdb->prefix}tutor_quiz_attempts
759 * {$wpdb->prefix}tutor_quiz_attempt_answers
760 * {$wpdb->prefix}tutor_quiz_questions
761 * {$wpdb->prefix}tutor_quiz_question_answers
762 * {$wpdb->prefix}tutor_earnings
763 * {$wpdb->prefix}tutor_withdraws
764 *
765 * @since 1.0.0
766 */
767 $quiz_attempts_sql = "CREATE TABLE {$wpdb->prefix}tutor_quiz_attempts (
768 attempt_id bigint(20) NOT NULL AUTO_INCREMENT,
769 course_id bigint(20) DEFAULT NULL,
770 quiz_id bigint(20) DEFAULT NULL,
771 user_id bigint(20) DEFAULT NULL,
772 total_questions int(11) DEFAULT NULL,
773 total_answered_questions int(11) DEFAULT NULL,
774 total_marks decimal(9,2) DEFAULT NULL,
775 earned_marks decimal(9,2) DEFAULT NULL,
776 attempt_info text,
777 attempt_status varchar(50) DEFAULT NULL,
778 attempt_ip varchar(250) DEFAULT NULL,
779 attempt_started_at datetime DEFAULT NULL,
780 attempt_ended_at datetime DEFAULT NULL,
781 is_manually_reviewed int(1) DEFAULT NULL,
782 manually_reviewed_at datetime DEFAULT NULL,
783 result varchar(10) DEFAULT NULL,
784 PRIMARY KEY (attempt_id),
785 INDEX (course_id),
786 INDEX (quiz_id),
787 INDEX (user_id),
788 INDEX (result)
789 ) $charset_collate;";
790
791 $quiz_attempt_answers = "CREATE TABLE {$wpdb->prefix}tutor_quiz_attempt_answers (
792 attempt_answer_id bigint(20) NOT NULL AUTO_INCREMENT,
793 user_id bigint(20) DEFAULT NULL,
794 quiz_id bigint(20) DEFAULT NULL,
795 question_id bigint(20) DEFAULT NULL,
796 quiz_attempt_id bigint(20) DEFAULT NULL,
797 given_answer longtext,
798 question_mark decimal(8,2) DEFAULT NULL,
799 achieved_mark decimal(8,2) DEFAULT NULL,
800 minus_mark decimal(8,2) DEFAULT NULL,
801 is_correct tinyint(4) DEFAULT NULL,
802 PRIMARY KEY (attempt_answer_id)
803 ) $charset_collate;";
804
805 $tutor_quiz_questions = "CREATE TABLE {$wpdb->prefix}tutor_quiz_questions (
806 question_id bigint(20) NOT NULL AUTO_INCREMENT,
807 quiz_id bigint(20) DEFAULT NULL,
808 question_title text,
809 question_description longtext,
810 answer_explanation longtext DEFAULT '',
811 question_type varchar(50) DEFAULT NULL,
812 question_mark decimal(9,2) DEFAULT NULL,
813 question_settings longtext,
814 question_order int(11) DEFAULT NULL,
815 PRIMARY KEY (question_id)
816 ) $charset_collate;";
817
818 $tutor_quiz_question_answers = "CREATE TABLE {$wpdb->prefix}tutor_quiz_question_answers (
819 answer_id bigint(20) NOT NULL AUTO_INCREMENT,
820 belongs_question_id bigint(20) DEFAULT NULL,
821 belongs_question_type varchar(250) DEFAULT NULL,
822 answer_title text,
823 is_correct tinyint(4) DEFAULT NULL,
824 image_id bigint(20) DEFAULT NULL,
825 answer_two_gap_match text,
826 answer_view_format varchar(250) DEFAULT NULL,
827 answer_settings text,
828 answer_order int(11) DEFAULT '0',
829 PRIMARY KEY (answer_id)
830 ) $charset_collate;";
831
832 $earning_table = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}tutor_earnings (
833 earning_id bigint(20) NOT NULL AUTO_INCREMENT,
834 user_id bigint(20) DEFAULT NULL,
835 course_id bigint(20) DEFAULT NULL,
836 order_id bigint(20) DEFAULT NULL,
837 order_status varchar(50) DEFAULT NULL,
838 course_price_total decimal(16,2) DEFAULT NULL,
839 course_price_grand_total decimal(16,2) DEFAULT NULL,
840 instructor_amount decimal(16,2) DEFAULT NULL,
841 instructor_rate decimal(16,2) DEFAULT NULL,
842 admin_amount decimal(16,2) DEFAULT NULL,
843 admin_rate decimal(16,2) DEFAULT NULL,
844 commission_type varchar(20) DEFAULT NULL,
845 deduct_fees_amount decimal(16,2) DEFAULT NULL,
846 deduct_fees_name varchar(250) DEFAULT NULL,
847 deduct_fees_type varchar(20) DEFAULT NULL,
848 process_by varchar(20) DEFAULT NULL,
849 created_at datetime DEFAULT NULL,
850 PRIMARY KEY (earning_id),
851 INDEX (user_id),
852 INDEX (course_id),
853 INDEX (order_id),
854 INDEX (process_by)
855 ) $charset_collate;";
856
857 $withdraw_table = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}tutor_withdraws (
858 withdraw_id bigint(20) NOT NULL AUTO_INCREMENT,
859 user_id bigint(20) DEFAULT NULL,
860 amount decimal(16,2) DEFAULT NULL,
861 method_data text DEFAULT NULL,
862 status varchar(50) DEFAULT NULL,
863 updated_at datetime DEFAULT NULL,
864 created_at datetime DEFAULT NULL,
865 PRIMARY KEY (withdraw_id)
866 ) $charset_collate;";
867
868 $orders_table = "CREATE TABLE {$wpdb->prefix}tutor_orders (
869 id BIGINT(20) UNSIGNED AUTO_INCREMENT,
870 parent_id BIGINT(20) UNSIGNED DEFAULT 0, -- for subscription order, store subscription record id
871 transaction_id VARCHAR(255) COMMENT 'Transaction id from payment gateway',
872 user_id BIGINT(20) UNSIGNED NOT NULL,
873 order_type VARCHAR(50) NOT NULL, -- single_order, subscription
874 order_status VARCHAR(50) NOT NULL,
875 payment_status VARCHAR(50) NOT NULL,
876 subtotal_price DECIMAL(13, 2) NOT NULL, -- price calculation based on course sale price
877 pre_tax_price DECIMAL(13, 2) NOT NULL, -- total price before adding tax
878 tax_type VARCHAR(50),
879 tax_rate DECIMAL(13, 2) COMMENT 'Tax percentage',
880 tax_amount DECIMAL(13, 2),
881 total_price DECIMAL(13, 2) NOT NULL, -- final price
882 net_payment DECIMAL(13, 2) NOT NULL, -- calculated price if any refund is done else same as total_price
883 coupon_code VARCHAR(255),
884 coupon_amount DECIMAL(13, 2),
885 discount_type ENUM('percentage', 'flat') DEFAULT NULL,
886 discount_amount DECIMAL(13, 2),
887 discount_reason TEXT,
888 fees DECIMAL(13, 2), -- payment gateway fees
889 earnings DECIMAL(13, 2), -- net earning
890 refund_amount DECIMAL(13, 2), -- Refund amount
891 payment_method VARCHAR(255),
892 payment_payloads LONGTEXT,
893 note TEXT,
894 created_at_gmt DATETIME NOT NULL,
895 created_by BIGINT(20) UNSIGNED NOT NULL,
896 updated_at_gmt DATETIME,
897 updated_by BIGINT(20) UNSIGNED NOT NULL,
898 PRIMARY KEY (id),
899 KEY user_id (user_id),
900 KEY order_type (order_type),
901 KEY payment_status (payment_status),
902 KEY order_status (order_status),
903 KEY transaction_id (transaction_id)
904 ) $charset_collate;";
905
906 $order_meta_table = "CREATE TABLE {$wpdb->prefix}tutor_ordermeta (
907 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
908 order_id BIGINT(20) UNSIGNED NOT NULL,
909 meta_key VARCHAR(255) NOT NULL,
910 meta_value LONGTEXT NOT NULL,
911 created_at_gmt DATETIME NOT NULL,
912 created_by BIGINT(20) UNSIGNED NOT NULL,
913 updated_at_gmt DATETIME,
914 updated_by BIGINT(20) UNSIGNED NOT NULL,
915 PRIMARY KEY (id),
916 KEY order_id (order_id),
917 KEY meta_key (meta_key),
918 CONSTRAINT fk_tutor_ordermeta_order_id FOREIGN KEY (order_id) REFERENCES {$wpdb->prefix}tutor_orders(id) ON DELETE CASCADE
919 ) $charset_collate;";
920
921 $order_items_table = "CREATE TABLE {$wpdb->prefix}tutor_order_items (
922 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
923 order_id BIGINT(20) UNSIGNED NOT NULL,
924 item_id BIGINT(20) UNSIGNED NOT NULL, -- course id/plan id
925 regular_price DECIMAL(13, 2) NOT NULL, -- course regular price
926 sale_price VARCHAR(13) DEFAULT NULL, -- course sale price
927 discount_price VARCHAR(13) DEFAULT NULL, -- course discount price
928 coupon_code VARCHAR(255) DEFAULT NULL, -- coupon code
929 PRIMARY KEY (id),
930 KEY order_id (order_id),
931 KEY item_id (item_id),
932 CONSTRAINT fk_tutor_order_item_order_id FOREIGN KEY (order_id) REFERENCES {$wpdb->prefix}tutor_orders(id) ON DELETE CASCADE
933 ) $charset_collate;";
934
935 $coupons_table = "CREATE TABLE {$wpdb->prefix}tutor_coupons (
936 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
937 coupon_status VARCHAR(50),
938 coupon_type VARCHAR(100) DEFAULT 'code', -- coupon type 'code' or 'automatic'
939 coupon_code VARCHAR(50) NOT NULL,
940 coupon_title VARCHAR(255) NOT NULL,
941 coupon_description TEXT,
942 discount_type ENUM('percentage', 'flat') NOT NULL,
943 discount_amount DECIMAL(13, 2) NOT NULL,
944 applies_to VARCHAR(100) DEFAULT 'all_courses_and_bundles', -- possible values 'all_courses_and_bundles', 'all_courses', 'all_bundles', 'specific_courses', 'specific_bundles', 'specific_category'
945 total_usage_limit INT(10) UNSIGNED DEFAULT NULL, -- null for unlimited usage
946 per_user_usage_limit TINYINT(4) UNSIGNED DEFAULT NULL, -- null for unlimited usage
947 purchase_requirement VARCHAR(50) DEFAULT 'no_minimum', -- possible values 'no_minimum', 'minimum_purchase', 'minimum_quantity'
948 purchase_requirement_value DECIMAL(13, 2),
949 start_date_gmt DATETIME NOT NULL,
950 expire_date_gmt DATETIME DEFAULT NULL,
951 created_at_gmt DATETIME NOT NULL,
952 created_by BIGINT(20) UNSIGNED NOT NULL,
953 updated_at_gmt DATETIME,
954 updated_by BIGINT(20) UNSIGNED NOT NULL,
955 PRIMARY KEY (id),
956 UNIQUE KEY coupon_code (coupon_code),
957 KEY start_date_gmt (start_date_gmt),
958 KEY expire_date_gmt (expire_date_gmt)
959 ) $charset_collate;";
960
961 $coupon_applications_table = "CREATE TABLE {$wpdb->prefix}tutor_coupon_applications (
962 coupon_code VARCHAR(50) NOT NULL,
963 reference_id BIGINT(20) UNSIGNED NOT NULL,
964 KEY coupon_code (coupon_code),
965 KEY reference_id (reference_id),
966 CONSTRAINT fk_tutor_coupon_application_coupon_code FOREIGN KEY (coupon_code) REFERENCES {$wpdb->prefix}tutor_coupons(coupon_code) ON DELETE CASCADE
967 ) $charset_collate;";
968
969 $coupon_usage_table = "CREATE TABLE {$wpdb->prefix}tutor_coupon_usages (
970 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
971 coupon_code VARCHAR(50) NOT NULL,
972 user_id BIGINT(20) UNSIGNED NOT NULL,
973 PRIMARY KEY (id),
974 KEY coupon_code (coupon_code),
975 KEY user_id (user_id),
976 CONSTRAINT fk_tutor_coupon_usage_coupon_code FOREIGN KEY (coupon_code) REFERENCES {$wpdb->prefix}tutor_coupons(coupon_code) ON DELETE CASCADE,
977 CONSTRAINT fk_tutor_coupon_usage_user_id FOREIGN KEY (user_id) REFERENCES {$wpdb->prefix}users(ID) ON DELETE CASCADE
978 ) $charset_collate;";
979
980 $cart_table = "CREATE TABLE {$wpdb->prefix}tutor_carts (
981 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
982 user_id BIGINT(20) UNSIGNED DEFAULT NULL,
983 coupon_code VARCHAR(50) DEFAULT NULL,
984 created_at_gmt DATETIME NOT NULL,
985 updated_at_gmt DATETIME,
986 PRIMARY KEY (id),
987 KEY user_id (user_id),
988 KEY coupon_code (coupon_code),
989 CONSTRAINT fk_tutor_cart_user_id FOREIGN KEY (user_id) REFERENCES {$wpdb->prefix}users(ID) ON DELETE CASCADE
990 ) $charset_collate;";
991
992 $cart_items_table = "CREATE TABLE {$wpdb->prefix}tutor_cart_items (
993 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
994 cart_id BIGINT(20) UNSIGNED NOT NULL,
995 course_id BIGINT(20) UNSIGNED NOT NULL,
996 PRIMARY KEY (id),
997 KEY cart_id (cart_id),
998 KEY course_id (course_id),
999 CONSTRAINT fk_tutor_cart_item_cart_id FOREIGN KEY (cart_id) REFERENCES {$wpdb->prefix}tutor_carts(id) ON DELETE CASCADE,
1000 CONSTRAINT fk_tutor_cart_item_course_id FOREIGN KEY (course_id) REFERENCES {$wpdb->prefix}posts(ID) ON DELETE CASCADE
1001 ) $charset_collate;";
1002
1003 $customer_table = "CREATE TABLE {$wpdb->prefix}tutor_customers (
1004 id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
1005 user_id BIGINT(20) UNSIGNED DEFAULT NULL,
1006 billing_first_name VARCHAR(255) NOT NULL,
1007 billing_last_name VARCHAR(255) NOT NULL,
1008 billing_email VARCHAR(255) NOT NULL,
1009 billing_phone VARCHAR(20) NOT NULL,
1010 billing_zip_code VARCHAR(20) NOT NULL,
1011 billing_address TEXT NOT NULL,
1012 billing_country VARCHAR(100) NOT NULL,
1013 billing_state VARCHAR(100) NOT NULL,
1014 billing_city VARCHAR(100) NOT NULL,
1015 PRIMARY KEY (id),
1016 KEY user_id (user_id),
1017 KEY billing_email (billing_email)
1018 ) $charset_collate;";
1019
1020 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1021 dbDelta( $quiz_attempts_sql );
1022 dbDelta( $quiz_attempt_answers );
1023 dbDelta( $tutor_quiz_questions );
1024 dbDelta( $tutor_quiz_question_answers );
1025 dbDelta( $earning_table );
1026 dbDelta( $withdraw_table );
1027 dbDelta( $orders_table );
1028 dbDelta( $order_meta_table );
1029 dbDelta( $order_items_table );
1030 dbDelta( $coupons_table );
1031 dbDelta( $coupon_applications_table );
1032 dbDelta( $coupon_usage_table );
1033 dbDelta( $cart_table );
1034 dbDelta( $cart_items_table );
1035 dbDelta( $customer_table );
1036 }
1037
1038 /**
1039 * Manage tutor roles & permission
1040 *
1041 * @return void
1042 */
1043 public static function manage_tutor_roles_and_permissions() {
1044 /**
1045 * Add role for instructor
1046 */
1047 $instructor_role = tutor()->instructor_role;
1048
1049 remove_role( $instructor_role );
1050 add_role( $instructor_role, __( 'Tutor Instructor', 'tutor' ), array() );
1051
1052 $custom_post_type_permission = array(
1053 // Manage Instructor.
1054 'manage_tutor_instructor',
1055
1056 // Tutor Posts Type Permission.
1057 'edit_tutor_course',
1058 'read_tutor_course',
1059 'delete_tutor_course',
1060 'delete_tutor_courses',
1061 'edit_tutor_courses',
1062 'edit_others_tutor_courses',
1063 'read_private_tutor_courses',
1064 'edit_tutor_courses',
1065
1066 'edit_tutor_lesson',
1067 'read_tutor_lesson',
1068 'delete_tutor_lesson',
1069 'delete_tutor_lessons',
1070 'edit_tutor_lessons',
1071 'edit_others_tutor_lessons',
1072 'read_private_tutor_lessons',
1073 'edit_tutor_lessons',
1074 'publish_tutor_lessons',
1075
1076 'edit_tutor_quiz',
1077 'read_tutor_quiz',
1078 'delete_tutor_quiz',
1079 'delete_tutor_quizzes',
1080 'edit_tutor_quizzes',
1081 'edit_others_tutor_quizzes',
1082 'read_private_tutor_quizzes',
1083 'edit_tutor_quizzes',
1084 'publish_tutor_quizzes',
1085
1086 'edit_tutor_question',
1087 'read_tutor_question',
1088 'delete_tutor_question',
1089 'delete_tutor_questions',
1090 'edit_tutor_questions',
1091 'edit_others_tutor_questions',
1092 'publish_tutor_questions',
1093 'read_private_tutor_questions',
1094 'edit_tutor_questions',
1095 );
1096
1097 $instructor = get_role( $instructor_role );
1098 if ( $instructor ) {
1099 $instructor_cap = array(
1100 'edit_posts',
1101 'read',
1102 'upload_files',
1103 );
1104
1105 $instructor_cap = array_merge( $instructor_cap, $custom_post_type_permission );
1106
1107 $can_publish_course = (bool) tutor_utils()->get_option( 'instructor_can_publish_course' );
1108 if ( $can_publish_course ) {
1109 $instructor_cap[] = 'publish_tutor_courses';
1110 }
1111
1112 foreach ( $instructor_cap as $cap ) {
1113 $instructor->add_cap( $cap );
1114 }
1115 }
1116
1117 $administrator = get_role( 'administrator' );
1118 if ( $administrator ) {
1119
1120 $administrator_cap = array(
1121 'manage_tutor',
1122 );
1123 $administrator_cap = array_merge( $administrator_cap, $custom_post_type_permission );
1124 $administrator_cap[] = 'publish_tutor_courses';
1125
1126 foreach ( $administrator_cap as $cap ) {
1127 $administrator->add_cap( $cap );
1128 }
1129 }
1130
1131 /**
1132 * Add Instructor role to administrator
1133 */
1134 if ( current_user_can( 'administrator' ) ) {
1135 tutor_utils()->add_instructor_role( get_current_user_id() );
1136 }
1137 }
1138
1139 /**
1140 * On plugin activate save initial data
1141 * Like: generate tutor pages
1142 *
1143 * @since 1.0.0
1144 *
1145 * @return void
1146 */
1147 public static function save_data() {
1148
1149 $student_dashboard_args = array(
1150 'post_title' => __( 'Dashboard', 'tutor' ),
1151 'post_content' => '',
1152 'post_type' => 'page',
1153 'post_status' => 'publish',
1154 );
1155 $student_dashboard_page_id = wp_insert_post( $student_dashboard_args );
1156 tutor_utils()->update_option( 'tutor_dashboard_page_id', $student_dashboard_page_id );
1157
1158 $student_registration_args = array(
1159 'post_title' => __( 'Student Registration', 'tutor' ),
1160 'post_content' => '[tutor_student_registration_form]',
1161 'post_type' => 'page',
1162 'post_status' => 'publish',
1163 );
1164 $student_register_page_id = wp_insert_post( $student_registration_args );
1165 tutor_utils()->update_option( 'student_register_page', $student_register_page_id );
1166
1167 $instructor_registration_args = array(
1168 'post_title' => __( 'Instructor Registration', 'tutor' ),
1169 'post_content' => '[tutor_instructor_registration_form]',
1170 'post_type' => 'page',
1171 'post_status' => 'publish',
1172 );
1173 $instructor_registration_id = wp_insert_post( $instructor_registration_args );
1174 tutor_utils()->update_option( 'instructor_register_page', $instructor_registration_id );
1175 }
1176
1177 /**
1178 * Default options
1179 *
1180 * @since 1.0.0
1181 *
1182 * @since 3.4.1 Supported video sources added
1183 *
1184 * @return array
1185 */
1186 public static function default_options() {
1187 $options = array(
1188 'pagination_per_page' => '20',
1189 'course_allow_upload_private_files' => '1',
1190 'display_course_instructors' => '1',
1191 'enable_q_and_a_on_course' => '1',
1192 'courses_col_per_row' => '3',
1193 'courses_per_page' => '12',
1194 'course_permalink_base' => 'courses',
1195 'lesson_permalink_base' => 'lessons',
1196 'quiz_when_time_expires' => 'autosubmit',
1197 'quiz_attempts_allowed' => '10',
1198 'quiz_grade_method' => 'highest_grade',
1199 'enable_public_profile' => '1',
1200 'email_to_students' =>
1201 array(
1202 'quiz_completed' => '1',
1203 'completed_course' => '1',
1204 ),
1205 'email_to_instructors' =>
1206 array(
1207 'a_student_enrolled_in_course' => '1',
1208 'a_student_completed_course' => '1',
1209 'a_student_completed_lesson' => '1',
1210 'a_student_placed_question' => '1',
1211 ),
1212 'email_from_name' => get_option( 'blogname' ),
1213 'email_from_address' => get_option( 'admin_email' ),
1214 'email_footer_text' => '',
1215 'earning_admin_commission' => '20',
1216 'earning_instructor_commission' => '80',
1217 'color_preset_type' => 'default',
1218
1219 // Default options for tutor ecommerce.
1220 'monetize_by' => Ecommerce::MONETIZE_BY,
1221 'currency_code' => 'USD',
1222 'currency_position' => 'left',
1223 'thousand_separator' => ',',
1224 'decimal_separator' => '.',
1225 'number_of_decimals' => '2',
1226 'is_coupon_applicable' => 'on',
1227 'supported_video_sources' => array(
1228 'html5',
1229 'external_url',
1230 'youtube',
1231 'vimeo',
1232 'embedded',
1233 'shortcode',
1234 ),
1235 );
1236
1237 return $options;
1238 }
1239
1240
1241 /**
1242 * Create withdraw database
1243 *
1244 * @since 1.2.0
1245 */
1246 public static function create_withdraw_database() {
1247 global $wpdb;
1248
1249 $charset_collate = $wpdb->get_charset_collate();
1250
1251 /**
1252 * Table SQL
1253 *
1254 * {$wpdb->prefix}tutor_earnings
1255 * {$wpdb->prefix}tutor_withdraws
1256 *
1257 * @since 1.2.0
1258 */
1259
1260 $earning_table = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}tutor_earnings (
1261 earning_id bigint(20) NOT NULL AUTO_INCREMENT,
1262 user_id bigint(20) DEFAULT NULL,
1263 course_id bigint(20) DEFAULT NULL,
1264 order_id bigint(20) DEFAULT NULL,
1265 order_status varchar(50) DEFAULT NULL,
1266 course_price_total decimal(16,2) DEFAULT NULL,
1267 course_price_grand_total decimal(16,2) DEFAULT NULL,
1268 instructor_amount decimal(16,2) DEFAULT NULL,
1269 instructor_rate decimal(16,2) DEFAULT NULL,
1270 admin_amount decimal(16,2) DEFAULT NULL,
1271 admin_rate decimal(16,2) DEFAULT NULL,
1272 commission_type varchar(20) DEFAULT NULL,
1273 deduct_fees_amount decimal(16,2) DEFAULT NULL,
1274 deduct_fees_name varchar(250) DEFAULT NULL,
1275 deduct_fees_type varchar(20) DEFAULT NULL,
1276 process_by varchar(20) DEFAULT NULL,
1277 created_at datetime DEFAULT NULL,
1278 PRIMARY KEY (earning_id)
1279 ) $charset_collate;";
1280
1281 $withdraw_table = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}tutor_withdraws (
1282 withdraw_id bigint(20) NOT NULL AUTO_INCREMENT,
1283 user_id bigint(20) DEFAULT NULL,
1284 amount decimal(16,2) DEFAULT NULL,
1285 method_data text DEFAULT NULL,
1286 status varchar(50) DEFAULT NULL,
1287 updated_at datetime DEFAULT NULL,
1288 created_at datetime DEFAULT NULL,
1289 PRIMARY KEY (withdraw_id)
1290 ) $charset_collate;";
1291
1292 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1293 dbDelta( $earning_table );
1294 dbDelta( $withdraw_table );
1295
1296 /**
1297 * Setting previous dashboard to new dashboard
1298 */
1299 $previous_dashboard_page_id = (int) tutor_utils()->get_option( 'student_dashboard' );
1300 tutor_utils()->update_option( 'tutor_dashboard_page_id', $previous_dashboard_page_id );
1301 }
1302
1303 /**
1304 * Filter the wp_doing_ajax from tutor requests to get advanced
1305 * advantages from Tutor
1306 *
1307 * @since 1.3.4
1308 *
1309 * @param bool $bool default value.
1310 *
1311 * @return bool
1312 */
1313 public function wp_doing_ajax( $bool ) {
1314 // Don't use Input::has helper to avoid conflict.
1315 if ( isset( $_REQUEST['tutor_ajax_action'] ) ) {
1316 return true;
1317 }
1318 return $bool;
1319 }
1320
1321 /**
1322 * Handle plugin un-installation
1323 *
1324 * @since 2.6.2
1325 *
1326 * @return void
1327 */
1328 public static function tutor_uninstall() {
1329 self::erase_tutor_data();
1330 }
1331
1332 /**
1333 * Erase tutor data
1334 *
1335 * @since 2.6.2
1336 *
1337 * @return void
1338 */
1339 public static function erase_tutor_data() {
1340 global $wpdb;
1341
1342 $is_erase_data = tutor_utils()->get_option( 'delete_on_uninstall' );
1343 // Deleting Data.
1344
1345 if ( $is_erase_data ) {
1346 /**
1347 * Deleting Post Type, Meta Data, taxonomy
1348 */
1349 $course_post_type = tutor()->course_post_type;
1350 $lesson_post_type = tutor()->lesson_post_type;
1351
1352 $post_types = array(
1353 $course_post_type,
1354 $lesson_post_type,
1355 'tutor_quiz',
1356 'tutor_enrolled',
1357 'topics',
1358 'tutor_enrolled',
1359 'tutor_announcements',
1360 );
1361
1362 $post_type_strings = "'" . implode( "','", $post_types ) . "'";
1363 $tutor_posts = $wpdb->get_col( "SELECT ID from {$wpdb->posts} WHERE post_type in({$post_type_strings}) ;" ); //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1364
1365 if ( is_array( $tutor_posts ) && count( $tutor_posts ) ) {
1366 foreach ( $tutor_posts as $post_id ) {
1367 // Delete categories.
1368 $terms = wp_get_object_terms( $post_id, CourseModel::COURSE_CATEGORY );
1369 foreach ( $terms as $term ) {
1370 wp_remove_object_terms( $post_id, array( $term->term_id ), CourseModel::COURSE_CATEGORY );
1371 }
1372
1373 // Delete tags if available.
1374 $terms = wp_get_object_terms( $post_id, CourseModel::COURSE_TAG );
1375 foreach ( $terms as $term ) {
1376 wp_remove_object_terms( $post_id, array( $term->term_id ), CourseModel::COURSE_TAG );
1377 }
1378
1379 // Delete All Meta.
1380 $wpdb->delete( $wpdb->postmeta, array( 'post_id' => $post_id ) );
1381 $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
1382 }
1383 }
1384
1385 /**
1386 * Deleting Comments (reviews, questions, quiz_answers, etc)
1387 */
1388 $tutor_comments = $wpdb->get_col( "SELECT comment_ID from {$wpdb->comments} WHERE comment_agent = 'comment_agent' ;" );
1389 $comments_ids_strings = "'" . implode( "','", $tutor_comments ) . "'";
1390 if ( is_array( $tutor_comments ) && count( $tutor_comments ) ) {
1391 $wpdb->query( "DELETE from {$wpdb->commentmeta} WHERE comment_ID in({$comments_ids_strings}) " ); //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1392 }
1393 $wpdb->delete( $wpdb->comments, array( 'comment_agent' => 'comment_agent' ) );
1394
1395 /**
1396 * Delete Options
1397 */
1398
1399 delete_option( 'tutor_option' );
1400 $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => '_is_tutor_student' ) );
1401 $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => '_tutor_instructor_approved' ) );
1402 $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => '_tutor_instructor_status' ) );
1403 $wpdb->delete( $wpdb->usermeta, array( 'meta_key' => '_is_tutor_instructor' ) );
1404 $wpdb->query( "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE '%_tutor_completed_lesson_id_%' " );
1405
1406 // Deleting Table.
1407 $prefix = $wpdb->prefix;
1408 //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1409 $wpdb->query( "DROP TABLE IF EXISTS {$prefix}tutor_quiz_attempts, {$prefix}tutor_quiz_attempt_answers, {$prefix}tutor_quiz_questions, {$prefix}tutor_quiz_question_answers, {$prefix}tutor_earnings, {$prefix}tutor_withdraws " );
1410
1411 }
1412 }
1413 }
1414