Completed
Branch TASK/update-about-page (5cee29)
by
unknown
34:34 queued 26:08
created

EE_System::initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
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->isWordPressApi() || $this->request->isApi())
390
            && $this->request->getRequestParam('activate') !== 'true'
391
            && ! function_exists('json_basic_auth_handler')
392
            && ! function_exists('json_basic_auth_error')
393
            && ! in_array(
394
                $this->request->getRequestParam('action'),
395
                array('activate', 'activate-selected'),
396
                true
397
            )
398
        ) {
399
            include_once EE_THIRD_PARTY . 'wp-api-basic-auth' . DS . 'basic-auth.php';
400
        }
401
        do_action('AHEE__EE_System__load_espresso_addons__complete');
402
    }
403
404
405
    /**
406
     * detect_activations_or_upgrades
407
     * Checks for activation or upgrade of core first;
408
     * then also checks if any registered addons have been activated or upgraded
409
     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
410
     * which runs during the WP 'plugins_loaded' action at priority 3
411
     *
412
     * @access public
413
     * @return void
414
     */
415
    public function detect_activations_or_upgrades()
416
    {
417
        // first off: let's make sure to handle core
418
        $this->detect_if_activation_or_upgrade();
419
        foreach ($this->registry->addons as $addon) {
420
            if ($addon instanceof EE_Addon) {
421
                // detect teh request type for that addon
422
                $addon->detect_activation_or_upgrade();
423
            }
424
        }
425
    }
426
427
428
    /**
429
     * detect_if_activation_or_upgrade
430
     * Takes care of detecting whether this is a brand new install or code upgrade,
431
     * and either setting up the DB or setting up maintenance mode etc.
432
     *
433
     * @access public
434
     * @return void
435
     */
436
    public function detect_if_activation_or_upgrade()
437
    {
438
        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
439
        // check if db has been updated, or if its a brand-new installation
440
        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
441
        $request_type = $this->detect_req_type($espresso_db_update);
442
        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
443
        switch ($request_type) {
444
            case EE_System::req_type_new_activation:
445
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
446
                $this->_handle_core_version_change($espresso_db_update);
447
                break;
448
            case EE_System::req_type_reactivation:
449
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
450
                $this->_handle_core_version_change($espresso_db_update);
451
                break;
452
            case EE_System::req_type_upgrade:
453
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
454
                // migrations may be required now that we've upgraded
455
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
456
                $this->_handle_core_version_change($espresso_db_update);
457
                break;
458
            case EE_System::req_type_downgrade:
459
                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
460
                // its possible migrations are no longer required
461
                $this->maintenance_mode->set_maintenance_mode_if_db_old();
462
                $this->_handle_core_version_change($espresso_db_update);
463
                break;
464
            case EE_System::req_type_normal:
465
            default:
466
                break;
467
        }
468
        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
469
    }
470
471
472
    /**
473
     * Updates the list of installed versions and sets hooks for
474
     * initializing the database later during the request
475
     *
476
     * @param array $espresso_db_update
477
     */
478
    private function _handle_core_version_change($espresso_db_update)
479
    {
480
        $this->update_list_of_installed_versions($espresso_db_update);
481
        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
482
        add_action(
483
            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
484
            array($this, 'initialize_db_if_no_migrations_required')
485
        );
486
    }
487
488
489
    /**
490
     * standardizes the wp option 'espresso_db_upgrade' which actually stores
491
     * information about what versions of EE have been installed and activated,
492
     * NOT necessarily the state of the database
493
     *
494
     * @param mixed $espresso_db_update           the value of the WordPress option.
495
     *                                            If not supplied, fetches it from the options table
496
     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
497
     */
498
    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
499
    {
500
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
501
        if (! $espresso_db_update) {
502
            $espresso_db_update = get_option('espresso_db_update');
503
        }
504
        // check that option is an array
505
        if (! is_array($espresso_db_update)) {
506
            // if option is FALSE, then it never existed
507
            if ($espresso_db_update === false) {
508
                // make $espresso_db_update an array and save option with autoload OFF
509
                $espresso_db_update = array();
510
                add_option('espresso_db_update', $espresso_db_update, '', 'no');
511
            } else {
512
                // option is NOT FALSE but also is NOT an array, so make it an array and save it
513
                $espresso_db_update = array($espresso_db_update => array());
514
                update_option('espresso_db_update', $espresso_db_update);
515
            }
516
        } else {
517
            $corrected_db_update = array();
518
            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
519
            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
520
                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
521
                    // the key is an int, and the value IS NOT an array
522
                    // so it must be numerically-indexed, where values are versions installed...
523
                    // fix it!
524
                    $version_string = $should_be_array;
525
                    $corrected_db_update[ $version_string ] = array('unknown-date');
526
                } else {
527
                    // ok it checks out
528
                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
529
                }
530
            }
531
            $espresso_db_update = $corrected_db_update;
532
            update_option('espresso_db_update', $espresso_db_update);
533
        }
534
        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
535
        return $espresso_db_update;
536
    }
537
538
539
    /**
540
     * Does the traditional work of setting up the plugin's database and adding default data.
541
     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
542
     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
543
     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
544
     * so that it will be done when migrations are finished
545
     *
546
     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
547
     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
548
     *                                       This is a resource-intensive job
549
     *                                       so we prefer to only do it when necessary
550
     * @return void
551
     * @throws EE_Error
552
     */
553
    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
554
    {
555
        $request_type = $this->detect_req_type();
556
        // only initialize system if we're not in maintenance mode.
557
        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
558
            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
559
            $rewrite_rules = $this->loader->getShared(
560
                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
561
            );
562
            $rewrite_rules->flush();
563
            if ($verify_schema) {
564
                EEH_Activation::initialize_db_and_folders();
565
            }
566
            EEH_Activation::initialize_db_content();
567
            EEH_Activation::system_initialization();
568
            if ($initialize_addons_too) {
569
                $this->initialize_addons();
570
            }
571
        } else {
572
            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
573
        }
574
        if ($request_type === EE_System::req_type_new_activation
575
            || $request_type === EE_System::req_type_reactivation
576
            || (
577
                $request_type === EE_System::req_type_upgrade
578
                && $this->is_major_version_change()
579
            )
580
        ) {
581
            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
582
        }
583
    }
584
585
586
    /**
587
     * Initializes the db for all registered addons
588
     *
589
     * @throws EE_Error
590
     */
591
    public function initialize_addons()
592
    {
593
        // foreach registered addon, make sure its db is up-to-date too
594
        foreach ($this->registry->addons as $addon) {
595
            if ($addon instanceof EE_Addon) {
596
                $addon->initialize_db_if_no_migrations_required();
597
            }
598
        }
599
    }
600
601
602
    /**
603
     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
604
     *
605
     * @param    array  $version_history
606
     * @param    string $current_version_to_add version to be added to the version history
607
     * @return    boolean success as to whether or not this option was changed
608
     */
609
    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
610
    {
611
        if (! $version_history) {
612
            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
613
        }
614
        if ($current_version_to_add === null) {
615
            $current_version_to_add = espresso_version();
616
        }
617
        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
618
        // re-save
619
        return update_option('espresso_db_update', $version_history);
620
    }
621
622
623
    /**
624
     * Detects if the current version indicated in the has existed in the list of
625
     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
626
     *
627
     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
628
     *                                  If not supplied, fetches it from the options table.
629
     *                                  Also, caches its result so later parts of the code can also know whether
630
     *                                  there's been an update or not. This way we can add the current version to
631
     *                                  espresso_db_update, but still know if this is a new install or not
632
     * @return int one of the constants on EE_System::req_type_
633
     */
634
    public function detect_req_type($espresso_db_update = null)
635
    {
636
        if ($this->_req_type === null) {
637
            $espresso_db_update = ! empty($espresso_db_update)
638
                ? $espresso_db_update
639
                : $this->fix_espresso_db_upgrade_option();
640
            $this->_req_type = EE_System::detect_req_type_given_activation_history(
641
                $espresso_db_update,
642
                'ee_espresso_activation',
643
                espresso_version()
644
            );
645
            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
646
            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
647
        }
648
        return $this->_req_type;
649
    }
650
651
652
    /**
653
     * Returns whether or not there was a non-micro version change (ie, change in either
654
     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
655
     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
656
     *
657
     * @param $activation_history
658
     * @return bool
659
     */
660
    private function _detect_major_version_change($activation_history)
661
    {
662
        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
663
        $previous_version_parts = explode('.', $previous_version);
664
        $current_version_parts = explode('.', espresso_version());
665
        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
666
               && ($previous_version_parts[0] !== $current_version_parts[0]
667
                   || $previous_version_parts[1] !== $current_version_parts[1]
668
               );
669
    }
670
671
672
    /**
673
     * Returns true if either the major or minor version of EE changed during this request.
674
     * 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
675
     *
676
     * @return bool
677
     */
678
    public function is_major_version_change()
679
    {
680
        return $this->_major_version_change;
681
    }
682
683
684
    /**
685
     * Determines the request type for any ee addon, given three piece of info: the current array of activation
686
     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
687
     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
688
     * just activated to (for core that will always be espresso_version())
689
     *
690
     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
691
     *                                                 ee plugin. for core that's 'espresso_db_update'
692
     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
693
     *                                                 indicate that this plugin was just activated
694
     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
695
     *                                                 espresso_version())
696
     * @return int one of the constants on EE_System::req_type_*
697
     */
698
    public static function detect_req_type_given_activation_history(
699
        $activation_history_for_addon,
700
        $activation_indicator_option_name,
701
        $version_to_upgrade_to
702
    ) {
703
        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
704
        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...
705
            // it exists, so this isn't a completely new install
706
            // check if this version already in that list of previously installed versions
707
            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
708
                // it a version we haven't seen before
709
                if ($version_is_higher === 1) {
710
                    $req_type = EE_System::req_type_upgrade;
711
                } else {
712
                    $req_type = EE_System::req_type_downgrade;
713
                }
714
                delete_option($activation_indicator_option_name);
715
            } else {
716
                // its not an update. maybe a reactivation?
717
                if (get_option($activation_indicator_option_name, false)) {
718 View Code Duplication
                    if ($version_is_higher === -1) {
719
                        $req_type = EE_System::req_type_downgrade;
720
                    } elseif ($version_is_higher === 0) {
721
                        // we've seen this version before, but it's an activation. must be a reactivation
722
                        $req_type = EE_System::req_type_reactivation;
723
                    } else {// $version_is_higher === 1
724
                        $req_type = EE_System::req_type_upgrade;
725
                    }
726
                    delete_option($activation_indicator_option_name);
727 View Code Duplication
                } else {
728
                    // we've seen this version before and the activation indicate doesn't show it was just activated
729
                    if ($version_is_higher === -1) {
730
                        $req_type = EE_System::req_type_downgrade;
731
                    } elseif ($version_is_higher === 0) {
732
                        // we've seen this version before and it's not an activation. its normal request
733
                        $req_type = EE_System::req_type_normal;
734
                    } else {// $version_is_higher === 1
735
                        $req_type = EE_System::req_type_upgrade;
736
                    }
737
                }
738
            }
739
        } else {
740
            // brand new install
741
            $req_type = EE_System::req_type_new_activation;
742
            delete_option($activation_indicator_option_name);
743
        }
744
        return $req_type;
745
    }
746
747
748
    /**
749
     * Detects if the $version_to_upgrade_to is higher than the most recent version in
750
     * the $activation_history_for_addon
751
     *
752
     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
753
     *                                             sometimes containing 'unknown-date'
754
     * @param string $version_to_upgrade_to        (current version)
755
     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
756
     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
757
     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
758
     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
759
     */
760
    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
761
    {
762
        // find the most recently-activated version
763
        $most_recently_active_version =
764
            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
765
        return version_compare($version_to_upgrade_to, $most_recently_active_version);
766
    }
767
768
769
    /**
770
     * Gets the most recently active version listed in the activation history,
771
     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
772
     *
773
     * @param array $activation_history  (keys are versions, values are arrays of times activated,
774
     *                                   sometimes containing 'unknown-date'
775
     * @return string
776
     */
777
    private static function _get_most_recently_active_version_from_activation_history($activation_history)
778
    {
779
        $most_recently_active_version_activation = '1970-01-01 00:00:00';
780
        $most_recently_active_version = '0.0.0.dev.000';
781
        if (is_array($activation_history)) {
782
            foreach ($activation_history as $version => $times_activated) {
783
                // check there is a record of when this version was activated. Otherwise,
784
                // mark it as unknown
785
                if (! $times_activated) {
786
                    $times_activated = array('unknown-date');
787
                }
788
                if (is_string($times_activated)) {
789
                    $times_activated = array($times_activated);
790
                }
791
                foreach ($times_activated as $an_activation) {
792
                    if ($an_activation !== 'unknown-date'
793
                        && $an_activation
794
                           > $most_recently_active_version_activation) {
795
                        $most_recently_active_version = $version;
796
                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
797
                            ? '1970-01-01 00:00:00'
798
                            : $an_activation;
799
                    }
800
                }
801
            }
802
        }
803
        return $most_recently_active_version;
804
    }
805
806
807
    /**
808
     * This redirects to the about EE page after activation
809
     *
810
     * @return void
811
     */
812
    public function redirect_to_about_ee()
813
    {
814
        $notices = EE_Error::get_notices(false);
815
        // if current user is an admin and it's not an ajax or rest request
816
        if (! isset($notices['errors'])
817
            && $this->request->isAdmin()
818
            && apply_filters(
819
                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
820
                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
821
            )
822
        ) {
823
            $query_params = array('page' => 'espresso_about');
824
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
825
                $query_params['new_activation'] = true;
826
            }
827
            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
828
                $query_params['reactivation'] = true;
829
            }
830
            $url = add_query_arg($query_params, admin_url('admin.php'));
831
            wp_safe_redirect($url);
832
            exit();
833
        }
834
    }
835
836
837
    /**
838
     * load_core_configuration
839
     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
840
     * which runs during the WP 'plugins_loaded' action at priority 5
841
     *
842
     * @return void
843
     * @throws ReflectionException
844
     * @throws Exception
845
     */
846
    public function load_core_configuration()
847
    {
848
        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
849
        $this->loader->getShared('EE_Load_Textdomain');
850
        // load textdomain
851
        EE_Load_Textdomain::load_textdomain();
852
        // load and setup EE_Config and EE_Network_Config
853
        $config = $this->loader->getShared('EE_Config');
854
        $this->loader->getShared('EE_Network_Config');
855
        // setup autoloaders
856
        // enable logging?
857
        if ($config->admin->use_full_logging) {
858
            $this->loader->getShared('EE_Log');
859
        }
860
        // check for activation errors
861
        $activation_errors = get_option('ee_plugin_activation_errors', false);
862
        if ($activation_errors) {
863
            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
864
            update_option('ee_plugin_activation_errors', false);
865
        }
866
        // get model names
867
        $this->_parse_model_names();
868
        // load caf stuff a chance to play during the activation process too.
869
        $this->_maybe_brew_regular();
870
        // configure custom post type definitions
871
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
872
        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
873
        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
874
    }
875
876
877
    /**
878
     * cycles through all of the models/*.model.php files, and assembles an array of model names
879
     *
880
     * @return void
881
     * @throws ReflectionException
882
     */
883
    private function _parse_model_names()
884
    {
885
        // get all the files in the EE_MODELS folder that end in .model.php
886
        $models = glob(EE_MODELS . '*.model.php');
887
        $model_names = array();
888
        $non_abstract_db_models = array();
889
        foreach ($models as $model) {
890
            // get model classname
891
            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
892
            $short_name = str_replace('EEM_', '', $classname);
893
            $reflectionClass = new ReflectionClass($classname);
894
            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
895
                $non_abstract_db_models[ $short_name ] = $classname;
896
            }
897
            $model_names[ $short_name ] = $classname;
898
        }
899
        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
900
        $this->registry->non_abstract_db_models = apply_filters(
901
            'FHEE__EE_System__parse_implemented_model_names',
902
            $non_abstract_db_models
903
        );
904
    }
905
906
907
    /**
908
     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
909
     * that need to be setup before our EE_System launches.
910
     *
911
     * @return void
912
     * @throws DomainException
913
     * @throws InvalidArgumentException
914
     * @throws InvalidDataTypeException
915
     * @throws InvalidInterfaceException
916
     * @throws InvalidClassException
917
     * @throws InvalidFilePathException
918
     */
919
    private function _maybe_brew_regular()
920
    {
921
        /** @var Domain $domain */
922
        $domain = DomainFactory::getShared(
923
            new FullyQualifiedName(
924
                'EventEspresso\core\domain\Domain'
925
            ),
926
            array(
927
                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
928
                Version::fromString(espresso_version()),
929
            )
930
        );
931
        if ($domain->isCaffeinated()) {
932
            require_once EE_CAFF_PATH . 'brewing_regular.php';
933
        }
934
    }
935
936
937
    /**
938
     * @since 4.9.71.p
939
     * @throws Exception
940
     */
941
    public function loadRouteMatchSpecifications()
942
    {
943
        try {
944
            $this->loader->getShared(
945
                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
946
            );
947
        } catch (Exception $exception) {
948
            new ExceptionStackTraceDisplay($exception);
949
        }
950
        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
951
    }
952
953
954
    /**
955
     * register_shortcodes_modules_and_widgets
956
     * generate lists of shortcodes and modules, then verify paths and classes
957
     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
958
     * which runs during the WP 'plugins_loaded' action at priority 7
959
     *
960
     * @access public
961
     * @return void
962
     * @throws Exception
963
     */
964
    public function register_shortcodes_modules_and_widgets()
965
    {
966
        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
967
            try {
968
                // load, register, and add shortcodes the new way
969
                $this->loader->getShared(
970
                    'EventEspresso\core\services\shortcodes\ShortcodesManager',
971
                    array(
972
                        // and the old way, but we'll put it under control of the new system
973
                        EE_Config::getLegacyShortcodesManager(),
974
                    )
975
                );
976
            } catch (Exception $exception) {
977
                new ExceptionStackTraceDisplay($exception);
978
            }
979
        }
980
        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
981
        // check for addons using old hook point
982
        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
983
            $this->_incompatible_addon_error();
984
        }
985
    }
986
987
988
    /**
989
     * _incompatible_addon_error
990
     *
991
     * @access public
992
     * @return void
993
     */
994
    private function _incompatible_addon_error()
995
    {
996
        // get array of classes hooking into here
997
        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
998
            'AHEE__EE_System__register_shortcodes_modules_and_addons'
999
        );
1000
        if (! empty($class_names)) {
1001
            $msg = __(
1002
                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1003
                'event_espresso'
1004
            );
1005
            $msg .= '<ul>';
1006
            foreach ($class_names as $class_name) {
1007
                $msg .= '<li><b>Event Espresso - '
1008
                        . str_replace(
1009
                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1010
                            '',
1011
                            $class_name
1012
                        ) . '</b></li>';
1013
            }
1014
            $msg .= '</ul>';
1015
            $msg .= __(
1016
                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1017
                'event_espresso'
1018
            );
1019
            // save list of incompatible addons to wp-options for later use
1020
            add_option('ee_incompatible_addons', $class_names, '', 'no');
1021
            if (is_admin()) {
1022
                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1023
            }
1024
        }
1025
    }
1026
1027
1028
    /**
1029
     * brew_espresso
1030
     * begins the process of setting hooks for initializing EE in the correct order
1031
     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1032
     * which runs during the WP 'plugins_loaded' action at priority 9
1033
     *
1034
     * @return void
1035
     */
1036
    public function brew_espresso()
1037
    {
1038
        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1039
        // load some final core systems
1040
        add_action('init', array($this, 'set_hooks_for_core'), 1);
1041
        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1042
        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1043
        add_action('init', array($this, 'load_controllers'), 7);
1044
        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1045
        add_action('init', array($this, 'initialize'), 10);
1046
        add_action('init', array($this, 'initialize_last'), 100);
1047
        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1048
            // pew pew pew
1049
            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1050
            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1051
        }
1052
        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1053
    }
1054
1055
1056
    /**
1057
     *    set_hooks_for_core
1058
     *
1059
     * @access public
1060
     * @return    void
1061
     * @throws EE_Error
1062
     */
1063
    public function set_hooks_for_core()
1064
    {
1065
        $this->_deactivate_incompatible_addons();
1066
        do_action('AHEE__EE_System__set_hooks_for_core');
1067
        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1068
        // caps need to be initialized on every request so that capability maps are set.
1069
        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1070
        $this->registry->CAP->init_caps();
1071
    }
1072
1073
1074
    /**
1075
     * Using the information gathered in EE_System::_incompatible_addon_error,
1076
     * deactivates any addons considered incompatible with the current version of EE
1077
     */
1078
    private function _deactivate_incompatible_addons()
1079
    {
1080
        $incompatible_addons = get_option('ee_incompatible_addons', array());
1081
        if (! empty($incompatible_addons)) {
1082
            $active_plugins = get_option('active_plugins', array());
1083
            foreach ($active_plugins as $active_plugin) {
1084
                foreach ($incompatible_addons as $incompatible_addon) {
1085
                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1086
                        unset($_GET['activate']);
1087
                        espresso_deactivate_plugin($active_plugin);
1088
                    }
1089
                }
1090
            }
1091
        }
1092
    }
1093
1094
1095
    /**
1096
     *    perform_activations_upgrades_and_migrations
1097
     *
1098
     * @access public
1099
     * @return    void
1100
     */
1101
    public function perform_activations_upgrades_and_migrations()
1102
    {
1103
        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1104
    }
1105
1106
1107
    /**
1108
     * @return void
1109
     * @throws DomainException
1110
     */
1111
    public function load_CPTs_and_session()
1112
    {
1113
        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1114
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies $register_custom_taxonomies */
1115
        $register_custom_taxonomies = $this->loader->getShared(
1116
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
1117
        );
1118
        $register_custom_taxonomies->registerCustomTaxonomies();
1119
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes $register_custom_post_types */
1120
        $register_custom_post_types = $this->loader->getShared(
1121
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
1122
        );
1123
        $register_custom_post_types->registerCustomPostTypes();
1124
        /** @var EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms $register_custom_taxonomy_terms */
1125
        $register_custom_taxonomy_terms = $this->loader->getShared(
1126
            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
1127
        );
1128
        $register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1129
        // load legacy Custom Post Types and Taxonomies
1130
        $this->loader->getShared('EE_Register_CPTs');
1131
        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1132
    }
1133
1134
1135
    /**
1136
     * load_controllers
1137
     * this is the best place to load any additional controllers that needs access to EE core.
1138
     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1139
     * time
1140
     *
1141
     * @access public
1142
     * @return void
1143
     */
1144
    public function load_controllers()
1145
    {
1146
        do_action('AHEE__EE_System__load_controllers__start');
1147
        // let's get it started
1148
        if (! $this->maintenance_mode->level()
1149
            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1150
        ) {
1151
            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1152
            $this->loader->getShared('EE_Front_Controller');
1153
        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1154
            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1155
            $this->loader->getShared('EE_Admin');
1156
        } elseif ($this->request->isWordPressHeartbeat()) {
1157
            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1158
        }
1159
        do_action('AHEE__EE_System__load_controllers__complete');
1160
    }
1161
1162
1163
    /**
1164
     * core_loaded_and_ready
1165
     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1166
     *
1167
     * @access public
1168
     * @return void
1169
     * @throws Exception
1170
     */
1171
    public function core_loaded_and_ready()
1172
    {
1173
        if ($this->request->isAdmin()
1174
            || $this->request->isFrontend()
1175
            || $this->request->isIframe()
1176
            || $this->request->isWordPressApi()
1177
        ) {
1178
            try {
1179
                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1180
                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1181
                if ($this->canLoadBlocks()) {
1182
                    $this->loader->getShared(
1183
                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1184
                    );
1185
                }
1186
            } catch (Exception $exception) {
1187
                new ExceptionStackTraceDisplay($exception);
1188
            }
1189
        }
1190
        if ($this->request->isAdmin()
1191
            || $this->request->isEeAjax()
1192
            || $this->request->isFrontend()
1193
        ) {
1194
            $this->loader->getShared('EE_Session');
1195
        }
1196
        // integrate WP_Query with the EE models
1197
        $this->loader->getShared('EE_CPT_Strategy');
1198
        do_action('AHEE__EE_System__core_loaded_and_ready');
1199
        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1200
        // builders require these even on the front-end
1201
        require_once EE_PUBLIC . 'template_tags.php';
1202
        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1203
    }
1204
1205
1206
    /**
1207
     * initialize
1208
     * this is the best place to begin initializing client code
1209
     *
1210
     * @access public
1211
     * @return void
1212
     */
1213
    public function initialize()
1214
    {
1215
        do_action('AHEE__EE_System__initialize');
1216
    }
1217
1218
1219
    /**
1220
     * initialize_last
1221
     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1222
     * initialize has done so
1223
     *
1224
     * @access public
1225
     * @return void
1226
     */
1227
    public function initialize_last()
1228
    {
1229
        do_action('AHEE__EE_System__initialize_last');
1230
        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1231
        $rewrite_rules = $this->loader->getShared(
1232
            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1233
        );
1234
        $rewrite_rules->flushRewriteRules();
1235
        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1236
        if (($this->request->isAjax() || $this->request->isAdmin())
1237
            && $this->maintenance_mode->models_can_query()) {
1238
            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1239
            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1240
        }
1241
    }
1242
1243
1244
    /**
1245
     * @return void
1246
     * @throws EE_Error
1247
     */
1248
    public function addEspressoToolbar()
1249
    {
1250
        $this->loader->getShared(
1251
            'EventEspresso\core\domain\services\admin\AdminToolBar',
1252
            array($this->registry->CAP)
1253
        );
1254
    }
1255
1256
1257
    /**
1258
     * do_not_cache
1259
     * sets no cache headers and defines no cache constants for WP plugins
1260
     *
1261
     * @access public
1262
     * @return void
1263
     */
1264
    public static function do_not_cache()
1265
    {
1266
        // set no cache constants
1267
        if (! defined('DONOTCACHEPAGE')) {
1268
            define('DONOTCACHEPAGE', true);
1269
        }
1270
        if (! defined('DONOTCACHCEOBJECT')) {
1271
            define('DONOTCACHCEOBJECT', true);
1272
        }
1273
        if (! defined('DONOTCACHEDB')) {
1274
            define('DONOTCACHEDB', true);
1275
        }
1276
        // add no cache headers
1277
        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1278
        // plus a little extra for nginx and Google Chrome
1279
        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1280
        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1281
        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1282
    }
1283
1284
1285
    /**
1286
     *    extra_nocache_headers
1287
     *
1288
     * @access    public
1289
     * @param $headers
1290
     * @return    array
1291
     */
1292
    public static function extra_nocache_headers($headers)
1293
    {
1294
        // for NGINX
1295
        $headers['X-Accel-Expires'] = 0;
1296
        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1297
        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1298
        return $headers;
1299
    }
1300
1301
1302
    /**
1303
     *    nocache_headers
1304
     *
1305
     * @access    public
1306
     * @return    void
1307
     */
1308
    public static function nocache_headers()
1309
    {
1310
        nocache_headers();
1311
    }
1312
1313
1314
    /**
1315
     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1316
     * never returned with the function.
1317
     *
1318
     * @param  array $exclude_array any existing pages being excluded are in this array.
1319
     * @return array
1320
     */
1321
    public function remove_pages_from_wp_list_pages($exclude_array)
1322
    {
1323
        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1324
    }
1325
1326
1327
    /**
1328
     * Return whether blocks can be registered/loaded or not.
1329
     * @return bool
1330
     */
1331
    private function canLoadBlocks()
1332
    {
1333
        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1334
               && function_exists('register_block_type')
1335
               // don't load blocks if in the Divi page builder editor context
1336
               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1337
               && ! $this->request->getRequestParam('et_fb', false);
1338
    }
1339
}
1340