Issues (896)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/class-sensei.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 11 and the first side effect is on line 2.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
4
/**
5
 * Responsible for loading Sensei and setting up the Main WordPress hooks.
6
 *
7
 * @package Core
8
 * @author Automattic
9
 * @since 1.0.0
10
 */
11
class Sensei_Main {
12
13
    /**
14
     * @var string
15
     * Reference to the main plugin file
16
     */
17
    private $file;
18
19
    /**
20
     * @var Sensei_Main $_instance to the the main and only instance of the Sensei class.
21
     * @since 1.8.0
22
     */
23
    protected static $_instance = null;
24
25
    /**
26
     * Main reference to the plugins current version
27
     */
28
    public $version;
29
30
    /**
31
     * Public token, referencing for the text domain.
32
     */
33
    public $token = 'woothemes-sensei';
34
35
    /**
36
     * Plugin url and path for use when access resources.
37
     */
38
    public $plugin_url;
39
    public $plugin_path;
40
    public $template_url;
41
42
    /**
43
     * @var Sensei_PostTypes
44
     * All Sensei sub classes. Currently used to access functionality contained within
45
     * within Sensei sub classes e.g. Sensei()->course->all_courses()
46
     */
47
    public $post_types;
48
49
    /**
50
     * @var WooThemes_Sensei_Settings
51
     */
52
    public $settings;
53
54
    /**
55
     * @var WooThemes_Sensei_Course_Results
56
     */
57
    public $course_results;
58
59
    /**
60
     * @var Sensei_Updates
61
     */
62
    public $updates;
63
    /**
64
     * @var WooThemes_Sensei_Course
65
     */
66
    public $course;
67
68
    /**
69
     * @var WooThemes_Sensei_Lesson
70
     */
71
    public $lesson;
72
73
    /**
74
     * @var WooThemes_Sensei_Quiz
75
     */
76
    public $quiz;
77
78
    /**
79
     * @var WooThemes_Sensei_Question
80
     */
81
    public $question;
82
83
    /**
84
     * @var WooThemes_Sensei_Admin
85
     */
86
    public $admin;
87
88
    /**
89
     * @var WooThemes_Sensei_Frontend
90
     */
91
    public $frontend;
92
93
    /**
94
     * @var Sensei_Notices
95
     */
96
    public $notices;
97
98
    /**
99
     * @var WooThemes_Sensei_Grading
100
     */
101
    public $grading;
102
103
    /**
104
     * @var WooThemes_Sensei_Emails
105
     */
106
    public $emails;
107
108
    /**
109
     * @var WooThemes_Sensei_Learner_Profiles
110
     */
111
    public $learner_profiles;
112
113
    /**
114
     * @var Sensei_Teacher
115
     */
116
    public $teacher;
117
118
    /**
119
     * @var WooThemes_Sensei_Learners
120
     */
121
    public $learners;
122
123
    /**
124
     * @var array
125
     * Global instance for access to the permissions message shown
126
     * when users do not have the right privileges to access resources.
127
     */
128
    public $permissions_message;
129
130
    /**
131
     * @var Sensei_Core_Modules Sensei Modules functionality
132
     */
133
    public $modules;
134
135
    /**
136
     * @var Sensei_Analysis
137
     */
138
    public $analysis;
139
140
    /**
141
     * Constructor method.
142
     * @param  string $file The base file of the plugin.
143
     * @since  1.0.0
144
     */
145
    public function __construct ( $file ) {
146
147
        // Setup object data
148
        $this->file = $file;
149
        $this->plugin_url = trailingslashit( plugins_url( '', $plugin = $file ) );
150
        $this->plugin_path = trailingslashit( dirname( $file ) );
151
        $this->template_url	= apply_filters( 'sensei_template_url', 'sensei/' );
152
153
        // Initialize the core Sensei functionality
154
        $this->init();
155
156
        // Installation
157
        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) $this->install();
158
159
        // Run this on activation.
160
        register_activation_hook( $this->file, array( $this, 'activation' ) );
161
162
        // Image Sizes
163
        $this->init_image_sizes();
164
165
        // load all hooks
166
        $this->load_hooks();
167
168
    } // End __construct()
169
170
    /**
171
     * Load the foundations of Sensei.
172
     * @since 1.9.0
173
     */
174
    protected function init(){
175
176
        // Localisation
177
        $this->load_plugin_textdomain();
178
        add_action( 'init', array( $this, 'load_localisation' ), 0 );
179
180
        // Setup settings
181
        $this->settings = new Sensei_Settings();
182
183
        // load the shortcode loader into memory, so as to listen to all for
184
        // all shortcodes on the front end
185
        new Sensei_Shortcode_Loader();
186
187
    }
188
189
    /**
190
     * Global Sensei Instance
191
     *
192
     * Ensure that only one instance of the main Sensei class can be loaded.
193
     *
194
     * @since 1.8.0
195
     * @static
196
     * @see WC()
197
     * @return WooThemes_Sensei Instance.
198
     */
199
    public static function instance() {
200
201
        if ( is_null( self::$_instance ) ) {
202
203
            //Sensei requires a reference to the main Sensei plugin file
204
            $sensei_main_plugin_file = dirname ( dirname( __FILE__ ) ) . '/woothemes-sensei.php';
205
206
            self::$_instance = new self( $sensei_main_plugin_file  );
207
208
            // load the global class objects needed throughout Sensei
209
            self::$_instance->initialize_global_objects();
210
211
        }
212
213
        return self::$_instance;
214
215
    } // end instance()
216
217
    /**
218
     * This function is linked into the activation
219
     * hook to reset flush the urls to ensure Sensei post types show up.
220
     *
221
     * @since 1.9.0
222
     *
223
     * @param $plugin
224
     */
225
    public static function activation_flush_rules( $plugin ){
226
227
        if( strpos( $plugin, '/woothemes-sensei.php' ) > 0  ){
228
229
            flush_rewrite_rules(true);
230
231
        }
232
233
    }
234
235
    /**
236
     * Cloning is forbidden.
237
     * @since 1.8.0
238
     */
239
    public function __clone() {
240
        _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woothemes-sensei' ), '1.8' );
241
    }
242
243
    /**
244
     * Unserializing instances of this class is forbidden.
245
     * @since 1.8.0
246
     */
247
    public function __wakeup() {
248
        _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'woothemes-sensei' ), '1.8' );
249
    }
250
251
    /**
252
     * Load the properties for the main Sensei object
253
     *
254
     * @since 1.9.0
255
     */
256
    public function initialize_global_objects(){
257
258
        // Setup post types.
259
        $this->post_types = new Sensei_PostTypes();
260
261
        // Lad the updates class
262
        $this->updates = new Sensei_Updates( $this );
263
264
        // Load Course Results Class
265
        $this->course_results = new Sensei_Course_Results();
266
267
        // Load the teacher role
268
        $this->teacher = new Sensei_Teacher();
269
270
        // Add the Course class
271
        $this->course = $this->post_types->course;
272
273
        // Add the lesson class
274
        $this->lesson = $this->post_types->lesson;
275
276
        // Add the question class
277
        $this->question = $this->post_types->question;
278
279
        //Add the quiz class
280
        $this->quiz = $this->post_types->quiz;
281
282
        // load the modules class after all plugsin are loaded
283
	    $this->load_modules_class();
284
285
        // Load Learner Management Functionality
286
        $this->learners = new Sensei_Learner_Management( $this->file );
287
288
        // Differentiate between administration and frontend logic.
289
        if ( is_admin() ) {
290
291
            // Load Admin Welcome class
292
            new Sensei_Welcome();
293
294
            // Load Admin Class
295
            $this->admin = new Sensei_Admin( $this->file );
296
297
            // Load Analysis Reports
298
            $this->analysis = new Sensei_Analysis( $this->file );
299
300
        } else {
301
302
            // Load Frontend Class
303
            $this->frontend = new Sensei_Frontend();
304
305
            // Load notice Class
306
            $this->notices = new Sensei_Notices();
307
308
            // Load built in themes support integration
309
            new Sensei_Theme_Integration_Loader();
310
311
312
        }
313
314
        // Load Grading Functionality
315
        $this->grading = new Sensei_Grading( $this->file );
316
317
        // Load Email Class
318
        $this->emails = new Sensei_Emails( $this->file );
319
320
        // Load Learner Profiles Class
321
        $this->learner_profiles = new Sensei_Learner_Profiles();
322
323
    }
324
325
    /**
326
     * Initialize all Sensei hooks
327
     *
328
     * @since 1.9.0
329
     */
330
    public function load_hooks(){
331
332
        add_action( 'widgets_init', array( $this, 'register_widgets' ) );
333
        add_action( 'after_setup_theme', array( $this, 'ensure_post_thumbnails_support' ) );
334
335
        // Filter comment counts
336
        add_filter( 'wp_count_comments', array( $this, 'sensei_count_comments' ), 10, 2 );
337
338
        add_action( 'body_class', array( $this, 'body_class' ) );
339
340
        // Check for and activate JetPack LaTeX support
341
        add_action( 'plugins_loaded', array( $this, 'jetpack_latex_support'), 200 ); // Runs after Jetpack has loaded it's modules
342
343
        // check flush the rewrite rules if the option sensei_flush_rewrite_rules option is 1
344
        add_action( 'init', array( $this, 'flush_rewrite_rules'), 101 );
345
346
    }
347
348
    /**
349
     * Run Sensei updates.
350
     * @access  public
351
     * @since   1.1.0
352
     * @return  void
353
     */
354
    public function run_updates() {
355
        // Run updates if administrator
356
        if ( current_user_can( 'manage_options' ) || current_user_can( 'manage_sensei' ) ) {
357
358
            $this->updates->update();
359
360
        } // End If Statement
361
    } // End run_updates()
362
363
    /**
364
     * Register the widgets.
365
     * @access public
366
     * @since  1.0.0
367
     * @return void
368
     */
369
    public function register_widgets () {
370
        // Widget List (key => value is filename => widget class).
371
        $widget_list = apply_filters( 'sensei_registered_widgets_list', array( 	'course-component' 	=> 'Course_Component',
372
                'lesson-component' 	=> 'Lesson_Component',
373
                'course-categories' => 'Course_Categories',
374
                'category-courses' 	=> 'Category_Courses' )
375
        );
376
        foreach ( $widget_list as $key => $value ) {
377
            if ( file_exists( $this->plugin_path . 'widgets/widget-woothemes-sensei-' . $key  . '.php' ) ) {
378
                require_once( $this->plugin_path . 'widgets/widget-woothemes-sensei-' . $key  . '.php' );
379
                register_widget( 'WooThemes_Sensei_' . $value . '_Widget' );
380
            }
381
        } // End For Loop
382
383
        do_action( 'sensei_register_widgets' );
384
385
    } // End register_widgets()
386
387
    /**
388
     * Load the plugin's localisation file.
389
     * @access public
390
     * @since  1.0.0
391
     * @return void
392
     */
393
    public function load_localisation () {
394
395
        load_plugin_textdomain( 'woothemes-sensei', false, dirname( plugin_basename( $this->file ) ) . '/lang/' );
396
397
    } // End load_localisation()
398
399
    /**
400
     * Load the plugin textdomain from the main WordPress "languages" folder.
401
     * @access  public
402
     * @since   1.0.0
403
     * @return  void
404
     */
405
    public function load_plugin_textdomain () {
406
407
        $domain = 'woothemes-sensei';
408
        // The "plugin_locale" filter is also used in load_plugin_textdomain()
409
        $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
410
        load_textdomain( $domain, WP_LANG_DIR . '/' . $domain . '/' . $domain . '-' . $locale . '.mo' );
411
        load_plugin_textdomain( $domain, FALSE, dirname( plugin_basename( $this->file ) ) . '/lang/' );
412
413
    } // End load_plugin_textdomain()
414
415
    /**
416
     * Run on activation.
417
     * @access public
418
     * @since  1.0.0
419
     * @return void
420
     */
421
    public function activation () {
422
423
        $this->register_plugin_version();
424
425
    } // End activation()
426
427
428
    /**
429
     * Register activation hooks.
430
     * @access public
431
     * @since  1.0.0
432
     * @return void
433
     */
434
    public function install () {
435
436
        register_activation_hook( $this->file, array( $this, 'activate_sensei' ) );
437
        register_activation_hook( $this->file, 'flush_rewrite_rules' );
438
439
    } // End install()
440
441
442
    /**
443
     * Run on activation of the plugin.
444
     * @access public
445
     * @since  1.0.0
446
     * @return void
447
     */
448
    public function activate_sensei () {
449
450
        update_option( 'skip_install_sensei_pages', 0 );
451
        update_option( 'sensei_installed', 1 );
452
453
    } // End activate_sensei()
454
455
    /**
456
     * Register the plugin's version.
457
     * @access public
458
     * @since  1.0.0
459
     * @return void
460
     */
461
    private function register_plugin_version () {
462
        if ( $this->version != '' ) {
463
464
            update_option( 'woothemes-sensei-version', $this->version );
465
466
        }
467
    } // End register_plugin_version()
468
469
    /**
470
     * Ensure that "post-thumbnails" support is available for those themes that don't register it.
471
     * @access  public
472
     * @since   1.0.1
473
     * @return  void
474
     */
475
    public function ensure_post_thumbnails_support () {
476
477
        if ( ! current_theme_supports( 'post-thumbnails' ) ) { add_theme_support( 'post-thumbnails' ); }
478
479
    } // End ensure_post_thumbnails_support()
480
481
    /**
482
     * template_loader function.
483
     *
484
     * @access public
485
     * @param mixed $template
486
     * @return void
487
     * @deprecated
488
     */
489
    public function template_loader ( $template = '' ) {
490
491
        _deprecated_function( 'Sensei()->template_loader', '1.9.0', 'Use Sensei_Templates::template_loader( $template ) instead' );
492
        Sensei_Templates::template_loader( $template );
493
494
    } // End template_loader()
495
496
    /**
497
     * Determine the relative path to the plugin's directory.
498
     * @access public
499
     * @since  1.0.0
500
     * @return string $sensei_plugin_path
501
     */
502
    public function plugin_path () {
503
504
        if ( $this->plugin_path ) {
505
506
            $sensei_plugin_path =  $this->plugin_path;
507
508
        }else{
509
510
            $sensei_plugin_path = plugin_dir_path( __FILE__ );
511
512
        }
513
514
        return $sensei_plugin_path;
515
516
    } // End plugin_path()
517
518
    /**
519
     * Retrieve the ID of a specified page setting.
520
     * @access public
521
     * @since  1.0.0
522
     * @param  string $page
523
     * @return int
524
     */
525
    public function get_page_id ( $page ) {
526
        $page = apply_filters( 'sensei_get_' . esc_attr( $page ) . '_page_id', get_option( 'sensei_' . esc_attr( $page ) . '_page_id' ) );
527
        return ( $page ) ? $page : -1;
528
    } // End get_page_id()
529
530
    /**
531
     * check_user_permissions function.
532
     *
533
     * @access public
534
     * @param string $page (default: '')
535
     *
536
     * @return bool
537
     */
538
    public function check_user_permissions ( $page = '' ) {
539
540
        global $current_user, $post;
541
542
        $user_allowed = false;
543
544
        switch ( $page ) {
545
	        case 'course-single':
546
		        // check for prerequisite course or lesson,
547
		        $course_prerequisite_id = (int) get_post_meta( $post->ID, '_course_prerequisite', true );
548
		        $update_course          = Sensei_WC::course_update( $post->ID );
549
550
		        // Count completed lessons
551
		        if ( 0 < absint( $course_prerequisite_id ) ) {
552
553
			        $prerequisite_complete = Sensei_Utils::user_completed_course( $course_prerequisite_id, $current_user->ID );
554
555
		        } else {
556
			        $prerequisite_complete = true;
557
		        } // End If Statement
558
559
		        // Handles restrictions on the course
560
		        if ( ( ! $prerequisite_complete && 0 < absint( $course_prerequisite_id ) ) ) {
561
562
			        $user_allowed = false;
563
			        $course_link  = '<a href="' . esc_url( get_permalink( $course_prerequisite_id ) ) . '">' . __( 'course', 'woothemes-sensei' ) . '</a>';
564
			        $this->notices->add_notice( sprintf( __( 'Please complete the previous %1$s before taking this course.', 'woothemes-sensei' ), $course_link ), 'info' );
565
566
		        } elseif( Sensei_WC::is_woocommerce_active() && Sensei_WC::is_course_purchasable( $post->ID ) && ! Sensei_Utils::user_started_course( $post->ID, $current_user->ID )  ) {
567
568
			        $message = sprintf( __( 'Or %1$s login %2$s to access your purchased courses', 'woothemes-sensei' ), '<a href="'.sensei_user_login_url().'">', '</a>' );
569
			        $this->notices->add_notice( $message, 'info' );
570
571
572
		        } elseif ( ! Sensei_Utils::user_started_course( $post->ID, $current_user->ID )  ) {
573
574
					// users who haven't started the course are allowed to view it
575
			        $user_allowed                         = true;
576
577
578
579
		        } else  {
580
581
                    $user_allowed = true;
582
583
                } // End If Statement
584
                break;
585
            case 'lesson-single':
586
                // Check for WC purchase
587
                $lesson_course_id = get_post_meta( $post->ID, '_lesson_course',true );
588
589
                $update_course = Sensei_WC::course_update( $lesson_course_id );
590
                $is_preview = Sensei_Utils::is_preview_lesson( $post->ID );
591
592
                if ( $this->access_settings() && Sensei_Utils::user_started_course( $lesson_course_id, $current_user->ID ) ) {
593
                    $user_allowed = true;
594
                } elseif( $this->access_settings() && false == $is_preview ) {
595
596
                    $user_allowed = true;
597
598
                } else {
599
                    $this->permissions_message['title'] = get_the_title( $post->ID ) . ': ' . __('Restricted Access', 'woothemes-sensei' );
600
                    $course_link = '<a href="' . esc_url( get_permalink( $lesson_course_id ) ) . '">' . __( 'course', 'woothemes-sensei' ) . '</a>';
601
                    $wc_post_id = get_post_meta( $lesson_course_id, '_course_woocommerce_product',true );
602
                    if ( Sensei_WC::is_woocommerce_active() && ( 0 < $wc_post_id ) ) {
603 View Code Duplication
                        if ( $is_preview ) {
604
                            $this->permissions_message['message'] = sprintf( __('This is a preview lesson. Please purchase the %1$s to access all lessons.', 'woothemes-sensei' ), $course_link );
605
                        } else {
606
                            $this->permissions_message['message'] =  sprintf( __('Please purchase the %1$s before starting this Lesson.', 'woothemes-sensei' ), $course_link );
607
                        }
608 View Code Duplication
                    } else {
609
                        if ( $is_preview ) {
610
                            $this->permissions_message['message'] = sprintf( __('This is a preview lesson. Please sign up for the %1$s to access all lessons.', 'woothemes-sensei' ), $course_link );
611
                        } else {
612
                            /** This filter is documented in class-woothemes-sensei-frontend.php */
613
                            $this->permissions_message['message'] =  sprintf( __( 'Please sign up for the %1$s before starting the lesson.', 'woothemes-sensei' ), $course_link );
614
                        }
615
                    } // End If Statement
616
                } // End If Statement
617
                break;
618
            case 'quiz-single':
619
                $lesson_id = get_post_meta( $post->ID, '_quiz_lesson',true );
620
                $lesson_course_id = get_post_meta( $lesson_id, '_lesson_course',true );
621
622
                $update_course = Sensei_WC::course_update( $lesson_course_id );
623
                if ( ( $this->access_settings() && Sensei_Utils::user_started_course( $lesson_course_id, $current_user->ID ) ) || sensei_all_access() ) {
624
625
                    // Check for prerequisite lesson for this quiz
626
                    $lesson_prerequisite_id = (int) get_post_meta( $lesson_id, '_lesson_prerequisite', true);
627
                    $user_lesson_prerequisite_complete = Sensei_Utils::user_completed_lesson( $lesson_prerequisite_id, $current_user->ID);
628
629
                    // Handle restrictions
630
                    if( sensei_all_access() ) {
631
632
                        $user_allowed = true;
633
634
                    } else {
635
636
                        if ( 0 < absint( $lesson_prerequisite_id ) && ( !$user_lesson_prerequisite_complete ) ) {
637
638
                            $this->permissions_message['title'] = get_the_title( $post->ID ) . ': ' . __('Restricted Access', 'woothemes-sensei' );
639
                            $lesson_link = '<a href="' . esc_url( get_permalink( $lesson_prerequisite_id ) ) . '">' . __( 'lesson', 'woothemes-sensei' ) . '</a>';
640
                            $this->permissions_message['message'] = sprintf( __('Please complete the previous %1$s before taking this Quiz.', 'woothemes-sensei' ), $lesson_link );
641
642
                        } else {
643
644
                            $user_allowed = true;
645
646
                        } // End If Statement
647
                    } // End If Statement
648
                } elseif( $this->access_settings() ) {
649
                    // Check if the user has started the course
650
651
                    if ( is_user_logged_in() && ! Sensei_Utils::user_started_course( $lesson_course_id, $current_user->ID ) && ( isset( $this->settings->settings['access_permission'] ) && ( true == $this->settings->settings['access_permission'] ) ) ) {
652
653
                        $user_allowed = false;
654
                        $this->permissions_message['title'] = get_the_title( $post->ID ) . ': ' . __('Restricted Access', 'woothemes-sensei' );
655
                        $course_link = '<a href="' . esc_url( get_permalink( $lesson_course_id ) ) . '">' . __( 'course', 'woothemes-sensei' ) . '</a>';
656
                        $wc_post_id = get_post_meta( $lesson_course_id, '_course_woocommerce_product',true );
657 View Code Duplication
                        if ( Sensei_WC::is_woocommerce_active() && ( 0 < $wc_post_id ) ) {
658
                            $this->permissions_message['message'] = sprintf( __('Please purchase the %1$s before starting this Quiz.', 'woothemes-sensei' ), $course_link );
659
                        } else {
660
                            $this->permissions_message['message'] = sprintf( __('Please sign up for the %1$s before starting this Quiz.', 'woothemes-sensei' ), $course_link );
661
                        } // End If Statement
662
                    } else {
663
                        $user_allowed = true;
664
                    } // End If Statement
665
                } else {
666
                    $this->permissions_message['title'] = get_the_title( $post->ID ) . ': ' . __('Restricted Access', 'woothemes-sensei' );
667
                    $course_link = '<a href="' . esc_url( get_permalink( get_post_meta( get_post_meta( $post->ID, '_quiz_lesson', true ), '_lesson_course', true ) ) ) . '">' . __( 'course', 'woothemes-sensei' ) . '</a>';
668
                    $this->permissions_message['message'] = sprintf( __('Please sign up for the %1$s before taking this Quiz.', 'woothemes-sensei' ), $course_link );
669
                } // End If Statement
670
                break;
671
            default:
672
                $user_allowed = true;
673
                break;
674
675
        } // End Switch Statement
676
677
        /**
678
         * filter the permissions message shown on sensei post types.
679
         *
680
         * @since 1.8.7
681
         *
682
         * @param array $permissions_message{
683
         *
684
         *   @type string $title
685
         *   @type string $message
686
         *
687
         * }
688
         * @param string $post_id
689
         */
690
        $this->permissions_message = apply_filters( 'sensei_permissions_message', $this->permissions_message, $post->ID );
691
692
		// add the permissions message to the stack
693
694
        if( sensei_all_access() || Sensei_Utils::is_preview_lesson( $post->ID ) ) {
695
            $user_allowed = true;
696
        }
697
698
        /**
699
         * Filter the permissions check final result. Which determines if the user has
700
         * access to the given page.
701
         *
702
         * @since 1.0
703
         *
704
         * @param boolean $user_allowed
705
         * @param integer $user_id
706
         *
707
         */
708
        return apply_filters( 'sensei_access_permissions', $user_allowed, $current_user->ID );
709
710
    } // End get_placeholder_image()
711
712
713
    /**
714
     * Check if visitors have access permission. If the "access_permission" setting is active, do a log in check.
715
     * @since  1.0.0
716
     * @access public
717
     * @return bool
718
     */
719
    public function access_settings () {
720
721
        if( sensei_all_access() ) return true;
722
723
        if ( isset( $this->settings->settings['access_permission'] ) && ( true == $this->settings->settings['access_permission'] ) ) {
724
            if ( is_user_logged_in() ) {
725
                return true;
726
            } else {
727
                return false;
728
            } // End If Statement
729
        } else {
730
            return true;
731
        } // End If Statement
732
    } // End access_settings()
733
734
    /**
735
     * load_class loads in class files
736
     * @since   1.2.0
737
     * @access  public
738
     * @return  void
739
     */
740
    public function load_class ( $class_name = '' ) {
741
        if ( '' != $class_name && '' != $this->token ) {
742
            require_once( 'class-' . esc_attr( $this->token ) . '-' . esc_attr( $class_name ) . '.php' );
743
        } // End If Statement
744
    } // End load_class()
745
746
    /**
747
     * Filtering wp_count_comments to ensure that Sensei comments are ignored
748
     * @since   1.4.0
749
     * @access  public
750
     * @param  array   $comments
751
     * @param  integer $post_id
752
     * @return array
753
     */
754
    public function sensei_count_comments( $comments, $post_id ) {
755
        global $wpdb;
756
757
        $post_id = (int) $post_id;
758
759
        $count = wp_cache_get("comments-{$post_id}", 'counts');
760
761
        if ( false !== $count ) {
762
            return $count;
763
        }
764
765
        $statuses = array( '' ); // Default to the WP normal comments
766
        $stati = $wpdb->get_results( "SELECT comment_type FROM {$wpdb->comments} GROUP BY comment_type", ARRAY_A );
767
        foreach ( (array) $stati AS $status ) {
768
            if ( 'sensei_' != substr($status['comment_type'], 0, 7 ) ) {
769
                $statuses[] = $status['comment_type'];
770
            }
771
        }
772
        $where = "WHERE comment_type IN ('" . join("', '", array_unique( $statuses ) ) . "')";
773
774
        if ( $post_id > 0 )
775
            $where .= $wpdb->prepare( " AND comment_post_ID = %d", $post_id );
776
777
        $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
778
779
        $total = 0;
780
        $approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
781
        foreach ( (array) $count as $row ) {
782
            // Don't count post-trashed toward totals
783
            if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
784
                $total += $row['num_comments'];
785
            if ( isset( $approved[$row['comment_approved']] ) )
786
                $stats[$approved[$row['comment_approved']]] = $row['num_comments'];
787
        }
788
789
        $stats['total_comments'] = $total;
790
        foreach ( $approved as $key ) {
791
            if ( empty($stats[$key]) )
792
                $stats[$key] = 0;
793
        }
794
795
        $stats = (object) $stats;
796
        wp_cache_set("comments-{$post_id}", $stats, 'counts');
797
798
        return $stats;
799
    }
800
801
    /**
802
     * Init images.
803
     *
804
     * @since 1.4.5
805
     * @access public
806
     * @return void
807
     */
808
    public function init_image_sizes() {
809
        $course_archive_thumbnail 	= $this->get_image_size( 'course_archive_image' );
810
        $course_single_thumbnail	= $this->get_image_size( 'course_single_image' );
811
        $lesson_archive_thumbnail 	= $this->get_image_size( 'lesson_archive_image' );
812
        $lesson_single_thumbnail	= $this->get_image_size( 'lesson_single_image' );
813
814
        add_image_size( 'course_archive_thumbnail', $course_archive_thumbnail['width'], $course_archive_thumbnail['height'], $course_archive_thumbnail['crop'] );
815
        add_image_size( 'course_single_thumbnail', $course_single_thumbnail['width'], $course_single_thumbnail['height'], $course_single_thumbnail['crop'] );
816
        add_image_size( 'lesson_archive_thumbnail', $lesson_archive_thumbnail['width'], $lesson_archive_thumbnail['height'], $lesson_archive_thumbnail['crop'] );
817
        add_image_size( 'lesson_single_thumbnail', $lesson_single_thumbnail['width'], $lesson_single_thumbnail['height'], $lesson_single_thumbnail['crop'] );
818
    }
819
820
    /**
821
     * Get an image size.
822
     *
823
     * Variable is filtered by sensei_get_image_size_{image_size}
824
     *
825
     * @since 1.4.5
826
     * @access public
827
     * @param mixed $image_size
828
     * @return string
829
     */
830
    public function get_image_size( $image_size ) {
831
832
        // Only return sizes we define in settings
833
        if ( ! in_array( $image_size, array( 'course_archive_image', 'course_single_image', 'lesson_archive_image', 'lesson_single_image' ) ) )
834
            return apply_filters( 'sensei_get_image_size_' . $image_size, '' );
835
836
        if( ! isset( $this->settings->settings[ $image_size . '_width' ] ) ) {
837
            $this->settings->settings[ $image_size . '_width' ] = false;
838
        }
839
        if( ! isset( $this->settings->settings[ $image_size . '_height' ] ) ) {
840
            $this->settings->settings[ $image_size . '_height' ] = false;
841
        }
842
        if( ! isset( $this->settings->settings[ $image_size . '_hard_crop' ] ) ) {
843
            $this->settings->settings[ $image_size . '_hard_crop' ] = false;
844
        }
845
846
        $size = array_filter( array(
847
            'width' => $this->settings->settings[ $image_size . '_width' ],
848
            'height' => $this->settings->settings[ $image_size . '_height' ],
849
            'crop' => $this->settings->settings[ $image_size . '_hard_crop' ]
850
        ) );
851
852
        $size['width'] 	= isset( $size['width'] ) ? $size['width'] : '100';
853
        $size['height'] = isset( $size['height'] ) ? $size['height'] : '100';
854
        $size['crop'] 	= isset( $size['crop'] ) ? $size['crop'] : 0;
855
856
        return apply_filters( 'sensei_get_image_size_' . $image_size, $size );
857
    }
858
859
    public function body_class( $classes ) {
860
        if( is_sensei() ) {
861
            $classes[] = 'sensei';
862
        }
863
        return $classes;
864
    }
865
866
    /**
867
     * Checks that the Jetpack Beautiful Maths module has been activated to support LaTeX within question titles and answers
868
     *
869
     * @return null
870
     * @since 1.7.0
871
     */
872
    public function jetpack_latex_support() {
873
        if ( function_exists( 'latex_markup') ) {
874
            add_filter( 'sensei_question_title', 'latex_markup' );
875
            add_filter( 'sensei_answer_text', 'latex_markup' );
876
        }
877
    }
878
879
    /**
880
     * Load the module functionality.
881
     *
882
     * This function is hooked into plugins_loaded to avoid conflicts with
883
     * the retired modules extension.
884
     *
885
     * @since 1.8.0
886
     */
887
    public function load_modules_class(){
888
        global $sensei_modules;
889
890
        if( !class_exists( 'Sensei_Modules' )
891
            &&  'Sensei_Modules' != get_class( $sensei_modules ) ) {
892
893
            //Load the modules class
894
            require_once( 'class-sensei-modules.php');
895
            Sensei()->modules = new Sensei_Core_Modules( $this->file );
896
897
        }else{
898
            // fallback for people still using the modules extension.
899
            global $sensei_modules;
900
            Sensei()->modules = $sensei_modules;
901
            add_action( 'admin_notices', array( $this, 'disable_sensei_modules_extension'), 30 );
902
        }
903
    }
904
905
    /**
906
     * Tell the user to that the modules extension is no longer needed.
907
     *
908
     * @since 1.8.0
909
     */
910
    public function disable_sensei_modules_extension(){ ?>
911
        <div class="notice updated fade">
912
            <p>
913
                <?php
914
                $plugin_manage_url = admin_url().'plugins.php#sensei-modules';
915
                $plugin_link_element = '<a href="' . $plugin_manage_url . '" >plugins page</a> ';
916
                ?>
917
                <strong> Modules are now included in Sensei,</strong> so you no longer need the Sensei Modules extension.
918
                Please deactivate and delete it from your <?php echo $plugin_link_element; ?>. (This will not affect your existing modules).
919
            </p>
920
        </div>
921
922
    <?php }// end function
923
924
    /**
925
     * Sensei wide rewrite flush call.
926
     *
927
     * To use this simply update the option 'sensei_flush_rewrite_rules' to 1
928
     *
929
     * After the option is one the Rules will be flushed.
930
     *
931
     * @since 1.9.0
932
     */
933
    public function flush_rewrite_rules(){
934
935
        // ensures that the rewrite rules are flushed on the second
936
        // attempt. This ensure that the settings for any other process
937
        // have been completed and saved to the database before we refresh the
938
        // rewrite rules.
939
        $option =  get_option('sensei_flush_rewrite_rules');
940
        if( '1' == $option ) {
941
942
            update_option('sensei_flush_rewrite_rules', '2');
943
944
        }elseif( '2' == $option ) {
945
946
            flush_rewrite_rules();
947
            update_option('sensei_flush_rewrite_rules', '0');
948
949
        }
950
951
    } // end flush_rewrite_rules
952
953
    /**
954
     * Calling this function will tell Sensei to flush rewrite
955
     * rules on the next load.
956
     *
957
     * @since 1.9.0
958
     */
959
    public function initiate_rewrite_rules_flush(){
960
961
        update_option('sensei_flush_rewrite_rules', '1');
962
963
    }
964
965
    /**
966
     * sensei_woocommerce_email_course_details adds detail to email
967
     *
968
     * @deprecated since 1.9.0 use Sensei_WC::email_course_details
969
     *
970
     * @since   1.4.5
971
     * @access  public
972
     * @param   WC_Order $order
973
     *
974
     * @return  void
975
     */
976
    public function sensei_woocommerce_email_course_details( $order ) {
977
978
        Sensei_WC::email_course_details( $order );
979
980
    } // end func email course details
981
982
    /**
983
     * @deprecated since 1.9.0, movde to the Sensei_WC class
984
     * @param $user_id
985
     * @param $subscription_key
986
     */
987
    public function sensei_woocommerce_reactivate_subscription( $user_id, $subscription_key ){
988
989
        Sensei_WC::reactivate_subscription( $user_id, $subscription_key );
990
    }
991
992
    /**
993
     * @deprecated since 1.9.0, movde to the Sensei_WC class
994
     * @param $user_id
995
     * @param $subscription_key
996
     */
997
    public function sensei_woocommerce_subscription_ended( $user_id, $subscription_key ){
998
999
        Sensei_WC::end_subscription( $user_id, $subscription_key );
1000
    }
1001
1002
    /**
1003
     * sensei_woocommerce_complete_order description
1004
     *
1005
     * @deprecated since 1.9.0 use Sensei_WC::complete_order( $order_id );
1006
     * @since   1.0.3
1007
     * @access  public
1008
     * @param   int $order_id WC order ID
1009
     *
1010
     * @return  void
1011
     */
1012
    public function sensei_woocommerce_complete_order ( $order_id = 0 ) {
1013
1014
        Sensei_WC::complete_order( $order_id );
1015
1016
    } // End sensei_woocommerce_complete_order()
1017
1018
    /**
1019
     * Runs when an order is cancelled.
1020
     *
1021
     * @deprecated since 1.9.0
1022
     *
1023
     * @since   1.2.0
1024
     * @param   integer $order_id order ID
1025
     * @return  void
1026
     */
1027
    public function sensei_woocommerce_cancel_order ( $order_id ) {
1028
1029
        Sensei_WC::cancel_order( $order_id );
1030
1031
    } // End sensei_woocommerce_cancel_order()
1032
1033
    /**
1034
     * sensei_activate_subscription runs when a subscription product is purchased
1035
     * @deprecated since 1.9.0
1036
     * @since   1.2.0
1037
     * @access  public
1038
     * @param   integer $order_id order ID
1039
     * @return  void
1040
     */
1041
    public function sensei_activate_subscription(  $order_id = 0 ) {
1042
1043
        Sensei_WC::activate_subscription( $order_id );
1044
1045
    } // End sensei_activate_subscription()
1046
1047
    /**
1048
     * If WooCommerce is activated and the customer has purchased the course, update Sensei to indicate that they are taking the course.
1049
     * @deprecated since 1.9.0
1050
     * @since  1.0.0
1051
     * @param  int 			$course_id  (default: 0)
1052
     * @param  array/Object $order_user (default: array()) Specific user's data.
1053
     * @return bool|int
1054
     */
1055
    public function woocommerce_course_update ( $course_id = 0, $order_user = array()  ) {
1056
1057
        return Sensei_WC::course_update( $course_id, $order_user );
1058
1059
    } // End woocommerce_course_update()
1060
1061
    /**
1062
     * Returns the WooCommerce Product Object
1063
     *
1064
     * The code caters for pre and post WooCommerce 2.2 installations.
1065
     *
1066
     * @deprecated since 1.9.0
1067
     * @since   1.1.1
1068
     *
1069
     * @param   integer $wc_product_id Product ID or Variation ID
1070
     * @param   string  $product_type  '' or 'variation'
1071
     *
1072
     * @return   WC_Product $wc_product_object
1073
     */
1074
    public function sensei_get_woocommerce_product_object ( $wc_product_id = 0, $product_type = '' ) {
1075
1076
        return Sensei_WC::get_product_object( $wc_product_id, $product_type );
1077
1078
    } // End sensei_get_woocommerce_product_object()
1079
1080
    /**
1081
     * Setup required WooCommerce settings.
1082
     * @access  public
1083
     * @since   1.1.0
1084
     * @return  void
1085
     */
1086
    public function set_woocommerce_functionality() {
1087
1088
        _deprecated_function('Sensei()->set_woocommerce_functionality', 'Sensei 1.9.0');
1089
1090
    } // End set_woocommerce_functionality()
1091
1092
    /**
1093
     * Disable guest checkout if a course product is in the cart
1094
     * @deprecated since 1.9.0
1095
     * @param  boolean $guest_checkout Current guest checkout setting
1096
     * @return boolean                 Modified guest checkout setting
1097
     */
1098
    public function disable_guest_checkout( $guest_checkout ) {
1099
1100
        return Sensei_WC::disable_guest_checkout( $guest_checkout );
1101
1102
    }// end disable_guest_checkout
1103
1104
    /**
1105
     * Change order status with virtual products to completed
1106
     *
1107
     * @deprecated since 1.9.0 use Sensei_WC::virtual_order_payment_complete( $order_status, $order_id )
1108
     *
1109
     * @since  1.1.0
1110
     * @param string $order_status
1111
     * @param int $order_id
1112
     * @return string
1113
     **/
1114
    public function virtual_order_payment_complete( $order_status, $order_id ) {
1115
1116
        return  Sensei_WC::virtual_order_payment_complete( $order_status, $order_id );
1117
    }
1118
1119
} // End Class
1120
1121
/**
1122
 * Class Woothemes_Sensei
1123
 * @ignore only for backward compatibility
1124
 * @since 1.9.0
1125
 */
1126
class Woothemes_Sensei extends Sensei_Main{ }
1127