Completed
Branch FET/files-data-handler (2bc4ac)
by
unknown
26:50 queued 18:10
created

EE_System::load_espresso_addons()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 2
nop 0
dl 0
loc 35
rs 9.0488
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\domain\Domain;
4
use EventEspresso\core\domain\DomainFactory;
5
use EventEspresso\core\domain\services\contexts\RequestTypeContextCheckerInterface;
6
use EventEspresso\core\domain\values\FilePath;
7
use EventEspresso\core\domain\values\FullyQualifiedName;
8
use EventEspresso\core\domain\values\Version;
9
use EventEspresso\core\exceptions\ExceptionStackTraceDisplay;
10
use EventEspresso\core\exceptions\InvalidClassException;
11
use EventEspresso\core\exceptions\InvalidDataTypeException;
12
use EventEspresso\core\exceptions\InvalidFilePathException;
13
use EventEspresso\core\exceptions\InvalidInterfaceException;
14
use EventEspresso\core\interfaces\ResettableInterface;
15
use EventEspresso\core\services\loaders\LoaderFactory;
16
use EventEspresso\core\services\loaders\LoaderInterface;
17
use EventEspresso\core\services\request\RequestInterface;
18
19
/**
20
 * EE_System
21
 * The backbone of the core application that the rest of the system builds off of once bootstrapping is complete
22
 *
23
 * @package        Event Espresso
24
 * @subpackage     core/
25
 * @author         Brent Christensen, Michael Nelson
26
 */
27
final class EE_System implements ResettableInterface
28
{
29
30
    /**
31
     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
32
     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
33
     */
34
    const req_type_normal = 0;
35
36
    /**
37
     * Indicates this is a brand new installation of EE so we should install
38
     * tables and default data etc
39
     */
40
    const req_type_new_activation = 1;
41
42
    /**
43
     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
44
     * and we just exited maintenance mode). We MUST check the database is setup properly
45
     * and that default data is setup too
46
     */
47
    const req_type_reactivation = 2;
48
49
    /**
50
     * indicates that EE has been upgraded since its previous request.
51
     * We may have data migration scripts to call and will want to trigger maintenance mode
52
     */
53
    const req_type_upgrade = 3;
54
55
    /**
56
     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
57
     */
58
    const req_type_downgrade = 4;
59
60
    /**
61
     * @deprecated since version 4.6.0.dev.006
62
     * Now whenever a new_activation is detected the request type is still just
63
     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
64
     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
65
     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
66
     * (Specifically, when the migration manager indicates migrations are finished
67
     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
68
     */
69
    const req_type_activation_but_not_installed = 5;
70
71
    /**
72
     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
73
     */
74
    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
75
76
    /**
77
     * @var EE_System $_instance
78
     */
79
    private static $_instance;
80
81
    /**
82
     * @var EE_Registry $registry
83
     */
84
    private $registry;
85
86
    /**
87
     * @var LoaderInterface $loader
88
     */
89
    private $loader;
90
91
    /**
92
     * @var EE_Capabilities $capabilities
93
     */
94
    private $capabilities;
95
96
    /**
97
     * @var RequestInterface $request
98
     */
99
    private $request;
100
101
    /**
102
     * @var EE_Maintenance_Mode $maintenance_mode
103
     */
104
    private $maintenance_mode;
105
106
    /**
107
     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
108
     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
109
     *
110
     * @var int $_req_type
111
     */
112
    private $_req_type;
113
114
    /**
115
     * Whether or not there was a non-micro version change in EE core version during this request
116
     *
117
     * @var boolean $_major_version_change
118
     */
119
    private $_major_version_change = false;
120
121
    /**
122
     * A Context DTO dedicated solely to identifying the current request type.
123
     *
124
     * @var RequestTypeContextCheckerInterface $request_type
125
     */
126
    private $request_type;
127
128
129
    /**
130
     * @singleton method used to instantiate class object
131
     * @param EE_Registry|null         $registry
132
     * @param LoaderInterface|null     $loader
133
     * @param RequestInterface|null    $request
134
     * @param EE_Maintenance_Mode|null $maintenance_mode
135
     * @return EE_System
136
     */
137
    public static function instance(
138
        EE_Registry $registry = null,
139
        LoaderInterface $loader = null,
140
        RequestInterface $request = null,
141
        EE_Maintenance_Mode $maintenance_mode = null
142
    ) {
143
        // check if class object is instantiated
144
        if (! self::$_instance instanceof EE_System) {
145
            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
0 ignored issues
show
Bug introduced by
It seems like $registry defined by parameter $registry on line 138 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $loader defined by parameter $loader on line 139 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $request defined by parameter $request on line 140 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
Bug introduced by
It seems like $maintenance_mode defined by parameter $maintenance_mode on line 141 can be null; however, EE_System::__construct() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
146
        }
147
        return self::$_instance;
148
    }
149
150
151
    /**
152
     * resets the instance and returns it
153
     *
154
     * @return EE_System
155
     */
156
    public static function reset()
157
    {
158
        self::$_instance->_req_type = null;
159
        // make sure none of the old hooks are left hanging around
160
        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
161
        // we need to reset the migration manager in order for it to detect DMSs properly
162
        EE_Data_Migration_Manager::reset();
163
        self::instance()->detect_activations_or_upgrades();
164
        self::instance()->perform_activations_upgrades_and_migrations();
165
        return self::instance();
166
    }
167
168
169
    /**
170
     * sets hooks for running rest of system
171
     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
172
     * starting EE Addons from any other point may lead to problems
173
     *
174
     * @param EE_Registry         $registry
175
     * @param LoaderInterface     $loader
176
     * @param RequestInterface    $request
177
     * @param EE_Maintenance_Mode $maintenance_mode
178
     */
179
    private function __construct(
180
        EE_Registry $registry,
181
        LoaderInterface $loader,
182
        RequestInterface $request,
183
        EE_Maintenance_Mode $maintenance_mode
184
    ) {
185
        $this->registry = $registry;
186
        $this->loader = $loader;
187
        $this->request = $request;
188
        $this->maintenance_mode = $maintenance_mode;
189
        do_action('AHEE__EE_System__construct__begin', $this);
190
        add_action(
191
            'AHEE__EE_Bootstrap__load_espresso_addons',
192
            array($this, 'loadCapabilities'),
193
            5
194
        );
195
        add_action(
196
            'AHEE__EE_Bootstrap__load_espresso_addons',
197
            array($this, 'loadCommandBus'),
198
            7
199
        );
200
        add_action(
201
            'AHEE__EE_Bootstrap__load_espresso_addons',
202
            array($this, 'loadPluginApi'),
203
            9
204
        );
205
        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
206
        add_action(
207
            'AHEE__EE_Bootstrap__load_espresso_addons',
208
            array($this, 'load_espresso_addons')
209
        );
210
        // when an ee addon is activated, we want to call the core hook(s) again
211
        // because the newly-activated addon didn't get a chance to run at all
212
        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
213
        // detect whether install or upgrade
214
        add_action(
215
            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
216
            array($this, 'detect_activations_or_upgrades'),
217
            3
218
        );
219
        // load EE_Config, EE_Textdomain, etc
220
        add_action(
221
            'AHEE__EE_Bootstrap__load_core_configuration',
222
            array($this, 'load_core_configuration'),
223
            5
224
        );
225
        // load specifications for matching routes to current request
226
        add_action(
227
            'AHEE__EE_Bootstrap__load_core_configuration',
228
            array($this, 'loadRouteMatchSpecifications')
229
        );
230
        // load EE_Config, EE_Textdomain, etc
231
        add_action(
232
            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
233
            array($this, 'register_shortcodes_modules_and_widgets'),
234
            7
235
        );
236
        // you wanna get going? I wanna get going... let's get going!
237
        add_action(
238
            'AHEE__EE_Bootstrap__brew_espresso',
239
            array($this, 'brew_espresso'),
240
            9
241
        );
242
        // other housekeeping
243
        // exclude EE critical pages from wp_list_pages
244
        add_filter(
245
            'wp_list_pages_excludes',
246
            array($this, 'remove_pages_from_wp_list_pages'),
247
            10
248
        );
249
        // ALL EE Addons should use the following hook point to attach their initial setup too
250
        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
251
        do_action('AHEE__EE_System__construct__complete', $this);
252
    }
253
254
255
    /**
256
     * load and setup EE_Capabilities
257
     *
258
     * @return void
259
     * @throws EE_Error
260
     */
261
    public function loadCapabilities()
262
    {
263
        $this->capabilities = $this->loader->getShared('EE_Capabilities');
264
        add_action(
265
            'AHEE__EE_Capabilities__init_caps__before_initialization',
266
            function () {
267
                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
268
            }
269
        );
270
    }
271
272
273
    /**
274
     * create and cache the CommandBus, and also add middleware
275
     * The CapChecker middleware requires the use of EE_Capabilities
276
     * which is why we need to load the CommandBus after Caps are set up
277
     *
278
     * @return void
279
     * @throws EE_Error
280
     */
281
    public function loadCommandBus()
282
    {
283
        $this->loader->getShared(
284
            'CommandBusInterface',
285
            array(
286
                null,
287
                apply_filters(
288
                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
289
                    array(
290
                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
291
                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
292
                    )
293
                ),
294
            )
295
        );
296
    }
297
298
299
    /**
300
     * @return void
301
     * @throws EE_Error
302
     */
303
    public function loadPluginApi()
304
    {
305
        // set autoloaders for all of the classes implementing EEI_Plugin_API
306
        // which provide helpers for EE plugin authors to more easily register certain components with EE.
307
        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
308
        $this->loader->getShared('EE_Request_Handler');
309
    }
310
311
312
    /**
313
     * @param string $addon_name
314
     * @param string $version_constant
315
     * @param string $min_version_required
316
     * @param string $load_callback
317
     * @param string $plugin_file_constant
318
     * @return void
319
     */
320
    private function deactivateIncompatibleAddon(
321
        $addon_name,
322
        $version_constant,
323
        $min_version_required,
324
        $load_callback,
325
        $plugin_file_constant
326
    ) {
327
        if (! defined($version_constant)) {
328
            return;
329
        }
330
        $addon_version = constant($version_constant);
331
        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
332
            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
333
            if (! function_exists('deactivate_plugins')) {
334
                require_once ABSPATH . 'wp-admin/includes/plugin.php';
335
            }
336
            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
337
            unset($_GET['activate'], $_REQUEST['activate'], $_GET['activate-multi'], $_REQUEST['activate-multi']);
338
            EE_Error::add_error(
339
                sprintf(
340
                    esc_html__(
341
                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
342
                        'event_espresso'
343
                    ),
344
                    $addon_name,
345
                    $min_version_required
346
                ),
347
                __FILE__,
348
                __FUNCTION__ . "({$addon_name})",
349
                __LINE__
350
            );
351
            EE_Error::get_notices(false, true);
352
        }
353
    }
354
355
356
    /**
357
     * load_espresso_addons
358
     * allow addons to load first so that they can set hooks for running DMS's, etc
359
     * this is hooked into both:
360
     *    'AHEE__EE_Bootstrap__load_core_configuration'
361
     *        which runs during the WP 'plugins_loaded' action at priority 5
362
     *    and the WP 'activate_plugin' hook point
363
     *
364
     * @access public
365
     * @return void
366
     */
367
    public function load_espresso_addons()
368
    {
369
        $this->deactivateIncompatibleAddon(
370
            'Wait Lists',
371
            'EE_WAIT_LISTS_VERSION',
372
            '1.0.0.beta.074',
373
            'load_espresso_wait_lists',
374
            'EE_WAIT_LISTS_PLUGIN_FILE'
375
        );
376
        $this->deactivateIncompatibleAddon(
377
            'Automated Upcoming Event Notifications',
378
            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
379
            '1.0.0.beta.091',
380
            'load_espresso_automated_upcoming_event_notification',
381
            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
382
        );
383
        do_action('AHEE__EE_System__load_espresso_addons');
384
        // if the WP API basic auth plugin isn't already loaded, load it now.
385
        // We want it for mobile apps. Just include the entire plugin
386
        // also, don't load the basic auth when a plugin is getting activated, because
387
        // it could be the basic auth plugin, and it doesn't check if its methods are already defined
388
        // and causes a fatal error
389
        if ($this->request->getRequestParam('activate') !== 'true'
390
            && ! function_exists('json_basic_auth_handler')
391
            && ! function_exists('json_basic_auth_error')
392
            && ! in_array(
393
                $this->request->getRequestParam('action'),
394
                array('activate', 'activate-selected'),
395
                true
396
            )
397
        ) {
398
            include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
399
        }
400
        do_action('AHEE__EE_System__load_espresso_addons__complete');
401
    }
402
403
404
    /**
405
     * detect_activations_or_upgrades
406
     * Checks for activation or upgrade of core first;
407
     * then also checks if any registered addons have been activated or upgraded
408
     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
409
     * which runs during the WP 'plugins_loaded' action at priority 3
410
     *
411
     * @access public
412
     * @return void
413
     */
414
    public function detect_activations_or_upgrades()
415
    {
416
        // first off: let's make sure to handle core
417
        $this->detect_if_activation_or_upgrade();
418
        foreach ($this->registry->addons as $addon) {
419
            if ($addon instanceof EE_Addon) {
420
                // detect teh request type for that addon
421
                $addon->detect_activation_or_upgrade();
422
            }
423
        }
424
    }
425
426
427
    /**
428
     * detect_if_activation_or_upgrade
429
     * Takes care of detecting whether this is a brand new install or code upgrade,
430
     * and either setting up the DB or setting up maintenance mode etc.
431
     *
432
     * @access public
433
     * @return void
434
     */
435
    public function detect_if_activation_or_upgrade()
436
    {
437
        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
438
        // check if db has been updated, or if its a brand-new installation
439
        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
440
        $request_type = $this->detect_req_type($espresso_db_update);
441
        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
442
        switch ($request_type) {
443
            case EE_System::req_type_new_activation:
444
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
445
                $this->_handle_core_version_change($espresso_db_update);
446
                break;
447
            case EE_System::req_type_reactivation:
448
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
449
                $this->_handle_core_version_change($espresso_db_update);
450
                break;
451
            case EE_System::req_type_upgrade:
452
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
453
                // migrations may be required now that we've upgraded
454
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
455
                $this->_handle_core_version_change($espresso_db_update);
456
                break;
457
            case EE_System::req_type_downgrade:
458
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
459
                // its possible migrations are no longer required
460
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
461
                $this->_handle_core_version_change($espresso_db_update);
462
                break;
463
            case EE_System::req_type_normal:
464
            default:
465
                break;
466
        }
467
        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
468
    }
469
470
471
    /**
472
     * Updates the list of installed versions and sets hooks for
473
     * initializing the database later during the request
474
     *
475
     * @param array $espresso_db_update
476
     */
477
    private function _handle_core_version_change($espresso_db_update)
478
    {
479
        $this->update_list_of_installed_versions($espresso_db_update);
480
        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
481
        add_action(
482
            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
483
            array($this, 'initialize_db_if_no_migrations_required')
484
        );
485
    }
486
487
488
    /**
489
     * standardizes the wp option 'espresso_db_upgrade' which actually stores
490
     * information about what versions of EE have been installed and activated,
491
     * NOT necessarily the state of the database
492
     *
493
     * @param mixed $espresso_db_update           the value of the WordPress option.
494
     *                                            If not supplied, fetches it from the options table
495
     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
496
     */
497
    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
498
    {
499
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
500
        if (! $espresso_db_update) {
501
            $espresso_db_update = get_option('espresso_db_update');
502
        }
503
        // check that option is an array
504
        if (! is_array($espresso_db_update)) {
505
            // if option is FALSE, then it never existed
506
            if ($espresso_db_update === false) {
507
                // make $espresso_db_update an array and save option with autoload OFF
508
                $espresso_db_update = array();
509
                add_option('espresso_db_update', $espresso_db_update, '', 'no');
510
            } else {
511
                // option is NOT FALSE but also is NOT an array, so make it an array and save it
512
                $espresso_db_update = array($espresso_db_update => array());
513
                update_option('espresso_db_update', $espresso_db_update);
514
            }
515
        } else {
516
            $corrected_db_update = array();
517
            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
518
            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
519
                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
520
                    // the key is an int, and the value IS NOT an array
521
                    // so it must be numerically-indexed, where values are versions installed...
522
                    // fix it!
523
                    $version_string = $should_be_array;
524
                    $corrected_db_update[ $version_string ] = array('unknown-date');
525
                } else {
526
                    // ok it checks out
527
                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
528
                }
529
            }
530
            $espresso_db_update = $corrected_db_update;
531
            update_option('espresso_db_update', $espresso_db_update);
532
        }
533
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
534
        return $espresso_db_update;
535
    }
536
537
538
    /**
539
     * Does the traditional work of setting up the plugin's database and adding default data.
540
     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
541
     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
542
     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
543
     * so that it will be done when migrations are finished
544
     *
545
     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
546
     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
547
     *                                       This is a resource-intensive job
548
     *                                       so we prefer to only do it when necessary
549
     * @return void
550
     * @throws EE_Error
551
     */
552
    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
553
    {
554
        $request_type = $this->detect_req_type();
555
        // only initialize system if we're not in maintenance mode.
556
        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
557
            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
558
            $rewrite_rules = $this->loader->getShared(
559
                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
560
            );
561
            $rewrite_rules->flush();
562
            if ($verify_schema) {
563
                EEH_Activation::initialize_db_and_folders();
564
            }
565
            EEH_Activation::initialize_db_content();
566
            EEH_Activation::system_initialization();
567
            if ($initialize_addons_too) {
568
                $this->initialize_addons();
569
            }
570
        } else {
571
            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
572
        }
573
        if ($request_type === EE_System::req_type_new_activation
574
            || $request_type === EE_System::req_type_reactivation
575
            || (
576
                $request_type === EE_System::req_type_upgrade
577
                && $this->is_major_version_change()
578
            )
579
        ) {
580
            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
581
        }
582
    }
583
584
585
    /**
586
     * Initializes the db for all registered addons
587
     *
588
     * @throws EE_Error
589
     */
590
    public function initialize_addons()
591
    {
592
        // foreach registered addon, make sure its db is up-to-date too
593
        foreach ($this->registry->addons as $addon) {
594
            if ($addon instanceof EE_Addon) {
595
                $addon->initialize_db_if_no_migrations_required();
596
            }
597
        }
598
    }
599
600
601
    /**
602
     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
603
     *
604
     * @param    array  $version_history
605
     * @param    string $current_version_to_add version to be added to the version history
606
     * @return    boolean success as to whether or not this option was changed
607
     */
608
    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
609
    {
610
        if (! $version_history) {
611
            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
612
        }
613
        if ($current_version_to_add === null) {
614
            $current_version_to_add = espresso_version();
615
        }
616
        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
617
        // re-save
618
        return update_option('espresso_db_update', $version_history);
619
    }
620
621
622
    /**
623
     * Detects if the current version indicated in the has existed in the list of
624
     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
625
     *
626
     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
627
     *                                  If not supplied, fetches it from the options table.
628
     *                                  Also, caches its result so later parts of the code can also know whether
629
     *                                  there's been an update or not. This way we can add the current version to
630
     *                                  espresso_db_update, but still know if this is a new install or not
631
     * @return int one of the constants on EE_System::req_type_
632
     */
633
    public function detect_req_type($espresso_db_update = null)
634
    {
635
        if ($this->_req_type === null) {
636
            $espresso_db_update = ! empty($espresso_db_update)
637
                ? $espresso_db_update
638
                : $this->fix_espresso_db_upgrade_option();
639
            $this->_req_type = EE_System::detect_req_type_given_activation_history(
640
                $espresso_db_update,
641
                'ee_espresso_activation',
642
                espresso_version()
643
            );
644
            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
645
            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
646
        }
647
        return $this->_req_type;
648
    }
649
650
651
    /**
652
     * Returns whether or not there was a non-micro version change (ie, change in either
653
     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
654
     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
655
     *
656
     * @param $activation_history
657
     * @return bool
658
     */
659
    private function _detect_major_version_change($activation_history)
660
    {
661
        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
662
        $previous_version_parts = explode('.', $previous_version);
663
        $current_version_parts = explode('.', espresso_version());
664
        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
665
               && ($previous_version_parts[0] !== $current_version_parts[0]
666
                   || $previous_version_parts[1] !== $current_version_parts[1]
667
               );
668
    }
669
670
671
    /**
672
     * Returns true if either the major or minor version of EE changed during this request.
673
     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
674
     *
675
     * @return bool
676
     */
677
    public function is_major_version_change()
678
    {
679
        return $this->_major_version_change;
680
    }
681
682
683
    /**
684
     * Determines the request type for any ee addon, given three piece of info: the current array of activation
685
     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
686
     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
687
     * just activated to (for core that will always be espresso_version())
688
     *
689
     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
690
     *                                                 ee plugin. for core that's 'espresso_db_update'
691
     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
692
     *                                                 indicate that this plugin was just activated
693
     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
694
     *                                                 espresso_version())
695
     * @return int one of the constants on EE_System::req_type_*
696
     */
697
    public static function detect_req_type_given_activation_history(
698
        $activation_history_for_addon,
699
        $activation_indicator_option_name,
700
        $version_to_upgrade_to
701
    ) {
702
        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
703
        if ($activation_history_for_addon) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $activation_history_for_addon of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
704
            // it exists, so this isn't a completely new install
705
            // check if this version already in that list of previously installed versions
706
            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
707
                // it a version we haven't seen before
708
                if ($version_is_higher === 1) {
709
                    $req_type = EE_System::req_type_upgrade;
710
                } else {
711
                    $req_type = EE_System::req_type_downgrade;
712
                }
713
                delete_option($activation_indicator_option_name);
714
            } else {
715
                // its not an update. maybe a reactivation?
716
                if (get_option($activation_indicator_option_name, false)) {
717 View Code Duplication
                    if ($version_is_higher === -1) {
718
                        $req_type = EE_System::req_type_downgrade;
719
                    } elseif ($version_is_higher === 0) {
720
                        // we've seen this version before, but it's an activation. must be a reactivation
721
                        $req_type = EE_System::req_type_reactivation;
722
                    } else {// $version_is_higher === 1
723
                        $req_type = EE_System::req_type_upgrade;
724
                    }
725
                    delete_option($activation_indicator_option_name);
726 View Code Duplication
                } else {
727
                    // we've seen this version before and the activation indicate doesn't show it was just activated
728
                    if ($version_is_higher === -1) {
729
                        $req_type = EE_System::req_type_downgrade;
730
                    } elseif ($version_is_higher === 0) {
731
                        // we've seen this version before and it's not an activation. its normal request
732
                        $req_type = EE_System::req_type_normal;
733
                    } else {// $version_is_higher === 1
734
                        $req_type = EE_System::req_type_upgrade;
735
                    }
736
                }
737
            }
738
        } else {
739
            // brand new install
740
            $req_type = EE_System::req_type_new_activation;
741
            delete_option($activation_indicator_option_name);
742
        }
743
        return $req_type;
744
    }
745
746
747
    /**
748
     * Detects if the $version_to_upgrade_to is higher than the most recent version in
749
     * the $activation_history_for_addon
750
     *
751
     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
752
     *                                             sometimes containing 'unknown-date'
753
     * @param string $version_to_upgrade_to        (current version)
754
     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
755
     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
756
     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
757
     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
758
     */
759
    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
760
    {
761
        // find the most recently-activated version
762
        $most_recently_active_version =
763
            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
764
        return version_compare($version_to_upgrade_to, $most_recently_active_version);
765
    }
766
767
768
    /**
769
     * Gets the most recently active version listed in the activation history,
770
     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
771
     *
772
     * @param array $activation_history  (keys are versions, values are arrays of times activated,
773
     *                                   sometimes containing 'unknown-date'
774
     * @return string
775
     */
776
    private static function _get_most_recently_active_version_from_activation_history($activation_history)
777
    {
778
        $most_recently_active_version_activation = '1970-01-01 00:00:00';
779
        $most_recently_active_version = '0.0.0.dev.000';
780
        if (is_array($activation_history)) {
781
            foreach ($activation_history as $version => $times_activated) {
782
                // check there is a record of when this version was activated. Otherwise,
783
                // mark it as unknown
784
                if (! $times_activated) {
785
                    $times_activated = array('unknown-date');
786
                }
787
                if (is_string($times_activated)) {
788
                    $times_activated = array($times_activated);
789
                }
790
                foreach ($times_activated as $an_activation) {
791
                    if ($an_activation !== 'unknown-date'
792
                        && $an_activation
793
                           > $most_recently_active_version_activation) {
794
                        $most_recently_active_version = $version;
795
                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
796
                            ? '1970-01-01 00:00:00'
797
                            : $an_activation;
798
                    }
799
                }
800
            }
801
        }
802
        return $most_recently_active_version;
803
    }
804
805
806
    /**
807
     * This redirects to the about EE page after activation
808
     *
809
     * @return void
810
     */
811
    public function redirect_to_about_ee()
812
    {
813
        $notices = EE_Error::get_notices(false);
814
        // if current user is an admin and it's not an ajax or rest request
815
        if (! isset($notices['errors'])
816
            && $this->request->isAdmin()
817
            && apply_filters(
818
                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
819
                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
820
            )
821
        ) {
822
            $query_params = array('page' => 'espresso_about');
823
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
824
                $query_params['new_activation'] = true;
825
            }
826
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
827
                $query_params['reactivation'] = true;
828
            }
829
            $url = add_query_arg($query_params, admin_url('admin.php'));
830
            wp_safe_redirect($url);
831
            exit();
832
        }
833
    }
834
835
836
    /**
837
     * load_core_configuration
838
     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
839
     * which runs during the WP 'plugins_loaded' action at priority 5
840
     *
841
     * @return void
842
     * @throws ReflectionException
843
     * @throws Exception
844
     */
845
    public function load_core_configuration()
846
    {
847
        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
848
        $this->loader->getShared('EE_Load_Textdomain');
849
        // load textdomain
850
        EE_Load_Textdomain::load_textdomain();
851
        // load and setup EE_Config and EE_Network_Config
852
        $config = $this->loader->getShared('EE_Config');
853
        $this->loader->getShared('EE_Network_Config');
854
        // setup autoloaders
855
        // enable logging?
856
        if ($config->admin->use_full_logging) {
857
            $this->loader->getShared('EE_Log');
858
        }
859
        // check for activation errors
860
        $activation_errors = get_option('ee_plugin_activation_errors', false);
861
        if ($activation_errors) {
862
            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
863
            update_option('ee_plugin_activation_errors', false);
864
        }
865
        // get model names
866
        $this->_parse_model_names();
867
        // load caf stuff a chance to play during the activation process too.
868
        $this->_maybe_brew_regular();
869
        // configure custom post type definitions
870
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
871
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
872
        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
873
    }
874
875
876
    /**
877
     * cycles through all of the models/*.model.php files, and assembles an array of model names
878
     *
879
     * @return void
880
     * @throws ReflectionException
881
     */
882
    private function _parse_model_names()
883
    {
884
        // get all the files in the EE_MODELS folder that end in .model.php
885
        $models = glob(EE_MODELS . '*.model.php');
886
        $model_names = array();
887
        $non_abstract_db_models = array();
888
        foreach ($models as $model) {
889
            // get model classname
890
            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
891
            $short_name = str_replace('EEM_', '', $classname);
892
            $reflectionClass = new ReflectionClass($classname);
893
            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
894
                $non_abstract_db_models[ $short_name ] = $classname;
895
            }
896
            $model_names[ $short_name ] = $classname;
897
        }
898
        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
899
        $this->registry->non_abstract_db_models = apply_filters(
900
            'FHEE__EE_System__parse_implemented_model_names',
901
            $non_abstract_db_models
902
        );
903
    }
904
905
906
    /**
907
     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
908
     * that need to be setup before our EE_System launches.
909
     *
910
     * @return void
911
     * @throws DomainException
912
     * @throws InvalidArgumentException
913
     * @throws InvalidDataTypeException
914
     * @throws InvalidInterfaceException
915
     * @throws InvalidClassException
916
     * @throws InvalidFilePathException
917
     */
918
    private function _maybe_brew_regular()
919
    {
920
        /** @var Domain $domain */
921
        $domain = DomainFactory::getShared(
922
            new FullyQualifiedName(
923
                'EventEspresso\core\domain\Domain'
924
            ),
925
            array(
926
                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
927
                Version::fromString(espresso_version()),
928
            )
929
        );
930
        if ($domain->isCaffeinated()) {
931
            require_once EE_CAFF_PATH . 'brewing_regular.php';
932
        }
933
    }
934
935
936
    /**
937
     * @since 4.9.71.p
938
     * @throws Exception
939
     */
940
    public function loadRouteMatchSpecifications()
941
    {
942
        try {
943
            $this->loader->getShared(
944
                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
945
            );
946
        } catch (Exception $exception) {
947
            new ExceptionStackTraceDisplay($exception);
948
        }
949
        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
950
    }
951
952
953
    /**
954
     * register_shortcodes_modules_and_widgets
955
     * generate lists of shortcodes and modules, then verify paths and classes
956
     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
957
     * which runs during the WP 'plugins_loaded' action at priority 7
958
     *
959
     * @access public
960
     * @return void
961
     * @throws Exception
962
     */
963
    public function register_shortcodes_modules_and_widgets()
964
    {
965
        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
966
            try {
967
                // load, register, and add shortcodes the new way
968
                $this->loader->getShared(
969
                    'EventEspresso\core\services\shortcodes\ShortcodesManager',
970
                    array(
971
                        // and the old way, but we'll put it under control of the new system
972
                        EE_Config::getLegacyShortcodesManager(),
973
                    )
974
                );
975
            } catch (Exception $exception) {
976
                new ExceptionStackTraceDisplay($exception);
977
            }
978
        }
979
        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
980
        // check for addons using old hook point
981
        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
982
            $this->_incompatible_addon_error();
983
        }
984
    }
985
986
987
    /**
988
     * _incompatible_addon_error
989
     *
990
     * @access public
991
     * @return void
992
     */
993
    private function _incompatible_addon_error()
994
    {
995
        // get array of classes hooking into here
996
        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
997
            'AHEE__EE_System__register_shortcodes_modules_and_addons'
998
        );
999
        if (! empty($class_names)) {
1000
            $msg = __(
1001
                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1002
                'event_espresso'
1003
            );
1004
            $msg .= '<ul>';
1005
            foreach ($class_names as $class_name) {
1006
                $msg .= '<li><b>Event Espresso - '
1007
                        . str_replace(
1008
                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1009
                            '',
1010
                            $class_name
1011
                        ) . '</b></li>';
1012
            }
1013
            $msg .= '</ul>';
1014
            $msg .= __(
1015
                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1016
                'event_espresso'
1017
            );
1018
            // save list of incompatible addons to wp-options for later use
1019
            add_option('ee_incompatible_addons', $class_names, '', 'no');
1020
            if (is_admin()) {
1021
                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1022
            }
1023
        }
1024
    }
1025
1026
1027
    /**
1028
     * brew_espresso
1029
     * begins the process of setting hooks for initializing EE in the correct order
1030
     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1031
     * which runs during the WP 'plugins_loaded' action at priority 9
1032
     *
1033
     * @return void
1034
     */
1035
    public function brew_espresso()
1036
    {
1037
        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1038
        // load some final core systems
1039
        add_action('init', array($this, 'set_hooks_for_core'), 1);
1040
        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1041
        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1042
        add_action('init', array($this, 'load_controllers'), 7);
1043
        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1044
        add_action('init', array($this, 'initialize'), 10);
1045
        add_action('init', array($this, 'initialize_last'), 100);
1046
        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1047
            // pew pew pew
1048
            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1049
            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1050
        }
1051
        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1052
    }
1053
1054
1055
    /**
1056
     *    set_hooks_for_core
1057
     *
1058
     * @access public
1059
     * @return    void
1060
     * @throws EE_Error
1061
     */
1062
    public function set_hooks_for_core()
1063
    {
1064
        $this->_deactivate_incompatible_addons();
1065
        do_action('AHEE__EE_System__set_hooks_for_core');
1066
        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1067
        // caps need to be initialized on every request so that capability maps are set.
1068
        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1069
        $this->registry->CAP->init_caps();
1070
    }
1071
1072
1073
    /**
1074
     * Using the information gathered in EE_System::_incompatible_addon_error,
1075
     * deactivates any addons considered incompatible with the current version of EE
1076
     */
1077
    private function _deactivate_incompatible_addons()
1078
    {
1079
        $incompatible_addons = get_option('ee_incompatible_addons', array());
1080
        if (! empty($incompatible_addons)) {
1081
            $active_plugins = get_option('active_plugins', array());
1082
            foreach ($active_plugins as $active_plugin) {
1083
                foreach ($incompatible_addons as $incompatible_addon) {
1084
                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1085
                        unset($_GET['activate']);
1086
                        espresso_deactivate_plugin($active_plugin);
1087
                    }
1088
                }
1089
            }
1090
        }
1091
    }
1092
1093
1094
    /**
1095
     *    perform_activations_upgrades_and_migrations
1096
     *
1097
     * @access public
1098
     * @return    void
1099
     */
1100
    public function perform_activations_upgrades_and_migrations()
1101
    {
1102
        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1103
    }
1104
1105
1106
    /**
1107
     * @return void
1108
     * @throws DomainException
1109
     */
1110
    public function load_CPTs_and_session()
1111
    {
1112
        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1113
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies $register_custom_taxonomies */
1114
        $register_custom_taxonomies = $this->loader->getShared(
1115
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
1116
        );
1117
        $register_custom_taxonomies->registerCustomTaxonomies();
1118
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes $register_custom_post_types */
1119
        $register_custom_post_types = $this->loader->getShared(
1120
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
1121
        );
1122
        $register_custom_post_types->registerCustomPostTypes();
1123
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms */
1124
        $register_custom_taxonomy_terms = $this->loader->getShared(
1125
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
1126
        );
1127
        $register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1128
        // load legacy Custom Post Types and Taxonomies
1129
        $this->loader->getShared('EE_Register_CPTs');
1130
        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1131
    }
1132
1133
1134
    /**
1135
     * load_controllers
1136
     * this is the best place to load any additional controllers that needs access to EE core.
1137
     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1138
     * time
1139
     *
1140
     * @access public
1141
     * @return void
1142
     */
1143
    public function load_controllers()
1144
    {
1145
        do_action('AHEE__EE_System__load_controllers__start');
1146
        // let's get it started
1147
        if (! $this->maintenance_mode->level()
1148
            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1149
        ) {
1150
            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1151
            $this->loader->getShared('EE_Front_Controller');
1152
        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1153
            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1154
            $this->loader->getShared('EE_Admin');
1155
        } elseif ($this->request->isWordPressHeartbeat()) {
1156
            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1157
        }
1158
        do_action('AHEE__EE_System__load_controllers__complete');
1159
    }
1160
1161
1162
    /**
1163
     * core_loaded_and_ready
1164
     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1165
     *
1166
     * @access public
1167
     * @return void
1168
     * @throws Exception
1169
     */
1170
    public function core_loaded_and_ready()
1171
    {
1172
        if ($this->request->isAdmin()
1173
            || $this->request->isFrontend()
1174
            || $this->request->isIframe()
1175
            || $this->request->isWordPressApi()
1176
        ) {
1177
            try {
1178
                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1179
                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1180
                if ($this->canLoadBlocks()) {
1181
                    $this->loader->getShared(
1182
                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1183
                    );
1184
                }
1185
            } catch (Exception $exception) {
1186
                new ExceptionStackTraceDisplay($exception);
1187
            }
1188
        }
1189
        if ($this->request->isAdmin()
1190
            || $this->request->isEeAjax()
1191
            || $this->request->isFrontend()
1192
        ) {
1193
            $this->loader->getShared('EE_Session');
1194
        }
1195
        // integrate WP_Query with the EE models
1196
        $this->loader->getShared('EE_CPT_Strategy');
1197
        do_action('AHEE__EE_System__core_loaded_and_ready');
1198
        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1199
        // builders require these even on the front-end
1200
        require_once EE_PUBLIC . 'template_tags.php';
1201
        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1202
    }
1203
1204
1205
    /**
1206
     * initialize
1207
     * this is the best place to begin initializing client code
1208
     *
1209
     * @access public
1210
     * @return void
1211
     */
1212
    public function initialize()
1213
    {
1214
        do_action('AHEE__EE_System__initialize');
1215
    }
1216
1217
1218
    /**
1219
     * initialize_last
1220
     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1221
     * initialize has done so
1222
     *
1223
     * @access public
1224
     * @return void
1225
     */
1226
    public function initialize_last()
1227
    {
1228
        do_action('AHEE__EE_System__initialize_last');
1229
        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1230
        $rewrite_rules = $this->loader->getShared(
1231
            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1232
        );
1233
        $rewrite_rules->flushRewriteRules();
1234
        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1235
        if (($this->request->isAjax() || $this->request->isAdmin())
1236
            && $this->maintenance_mode->models_can_query()) {
1237
            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1238
            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1239
        }
1240
    }
1241
1242
1243
    /**
1244
     * @return void
1245
     * @throws EE_Error
1246
     */
1247
    public function addEspressoToolbar()
1248
    {
1249
        $this->loader->getShared(
1250
            'EventEspresso\core\domain\services\admin\AdminToolBar',
1251
            array($this->registry->CAP)
1252
        );
1253
    }
1254
1255
1256
    /**
1257
     * do_not_cache
1258
     * sets no cache headers and defines no cache constants for WP plugins
1259
     *
1260
     * @access public
1261
     * @return void
1262
     */
1263
    public static function do_not_cache()
1264
    {
1265
        // set no cache constants
1266
        if (! defined('DONOTCACHEPAGE')) {
1267
            define('DONOTCACHEPAGE', true);
1268
        }
1269
        if (! defined('DONOTCACHCEOBJECT')) {
1270
            define('DONOTCACHCEOBJECT', true);
1271
        }
1272
        if (! defined('DONOTCACHEDB')) {
1273
            define('DONOTCACHEDB', true);
1274
        }
1275
        // add no cache headers
1276
        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1277
        // plus a little extra for nginx and Google Chrome
1278
        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1279
        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1280
        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1281
    }
1282
1283
1284
    /**
1285
     *    extra_nocache_headers
1286
     *
1287
     * @access    public
1288
     * @param $headers
1289
     * @return    array
1290
     */
1291
    public static function extra_nocache_headers($headers)
1292
    {
1293
        // for NGINX
1294
        $headers['X-Accel-Expires'] = 0;
1295
        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1296
        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1297
        return $headers;
1298
    }
1299
1300
1301
    /**
1302
     *    nocache_headers
1303
     *
1304
     * @access    public
1305
     * @return    void
1306
     */
1307
    public static function nocache_headers()
1308
    {
1309
        nocache_headers();
1310
    }
1311
1312
1313
    /**
1314
     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1315
     * never returned with the function.
1316
     *
1317
     * @param  array $exclude_array any existing pages being excluded are in this array.
1318
     * @return array
1319
     */
1320
    public function remove_pages_from_wp_list_pages($exclude_array)
1321
    {
1322
        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1323
    }
1324
1325
1326
    /**
1327
     * Return whether blocks can be registered/loaded or not.
1328
     * @return bool
1329
     */
1330
    private function canLoadBlocks()
1331
    {
1332
        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1333
               && function_exists('register_block_type')
1334
               // don't load blocks if in the Divi page builder editor context
1335
               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1336
               && ! $this->request->getRequestParam('et_fb', false);
1337
    }
1338
}
1339