Completed
Branch master (465a38)
by
unknown
27:45 queued 22:40
created
core/domain/entities/routing/handlers/frontend/FrontendRequests.php 1 patch
Indentation   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -15,47 +15,47 @@
 block discarded – undo
15 15
  */
16 16
 class FrontendRequests extends PublicRoute
17 17
 {
18
-    /**
19
-     * returns true if the current request matches this route
20
-     * child classes can override and use Request directly to match route with request
21
-     * or supply a RouteMatchSpecification class and just use the below
22
-     *
23
-     * @return bool
24
-     * @since   5.0.0.p
25
-     */
26
-    public function matchesCurrentRequest(): bool
27
-    {
28
-        return ($this->request->isFrontend() || $this->request->isFrontAjax() || $this->request->isIframe())
29
-               && MaintenanceStatus::isDisabled();
30
-    }
18
+	/**
19
+	 * returns true if the current request matches this route
20
+	 * child classes can override and use Request directly to match route with request
21
+	 * or supply a RouteMatchSpecification class and just use the below
22
+	 *
23
+	 * @return bool
24
+	 * @since   5.0.0.p
25
+	 */
26
+	public function matchesCurrentRequest(): bool
27
+	{
28
+		return ($this->request->isFrontend() || $this->request->isFrontAjax() || $this->request->isIframe())
29
+			   && MaintenanceStatus::isDisabled();
30
+	}
31 31
 
32 32
 
33
-    /**
34
-     * @since 5.0.0.p
35
-     */
36
-    protected function registerDependencies()
37
-    {
38
-        $this->dependency_map->registerDependencies(
39
-            'EE_Front_Controller',
40
-            [
41
-                'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
42
-                'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
43
-                'EE_Module_Request_Router'                        => EE_Dependency_Map::load_from_cache,
44
-            ]
45
-        );
46
-    }
33
+	/**
34
+	 * @since 5.0.0.p
35
+	 */
36
+	protected function registerDependencies()
37
+	{
38
+		$this->dependency_map->registerDependencies(
39
+			'EE_Front_Controller',
40
+			[
41
+				'EE_Registry'                                     => EE_Dependency_Map::load_from_cache,
42
+				'EventEspresso\core\services\request\CurrentPage' => EE_Dependency_Map::load_from_cache,
43
+				'EE_Module_Request_Router'                        => EE_Dependency_Map::load_from_cache,
44
+			]
45
+		);
46
+	}
47 47
 
48 48
 
49
-    /**
50
-     * implements logic required to run during request
51
-     *
52
-     * @return bool
53
-     * @since   5.0.0.p
54
-     */
55
-    protected function requestHandler(): bool
56
-    {
57
-        do_action('AHEE__EE_System__load_controllers__load_front_controllers');
58
-        $this->loader->getShared('EE_Front_Controller');
59
-        return true;
60
-    }
49
+	/**
50
+	 * implements logic required to run during request
51
+	 *
52
+	 * @return bool
53
+	 * @since   5.0.0.p
54
+	 */
55
+	protected function requestHandler(): bool
56
+	{
57
+		do_action('AHEE__EE_System__load_controllers__load_front_controllers');
58
+		$this->loader->getShared('EE_Front_Controller');
59
+		return true;
60
+	}
61 61
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin.core.php 1 patch
Indentation   +987 added lines, -987 removed lines patch added patch discarded remove patch
@@ -22,991 +22,991 @@
 block discarded – undo
22 22
  */
23 23
 final class EE_Admin implements InterminableInterface
24 24
 {
25
-    private static ?EE_Admin $_instance = null;
26
-
27
-    private ?PersistentAdminNoticeManager $persistent_admin_notice_manager = null;
28
-
29
-    protected LoaderInterface $loader;
30
-
31
-    protected RequestInterface $request;
32
-
33
-
34
-    /**
35
-     * @singleton method used to instantiate class object
36
-     * @param LoaderInterface|null  $loader
37
-     * @param RequestInterface|null $request
38
-     * @return EE_Admin|null
39
-     * @throws EE_Error
40
-     */
41
-    public static function instance(?LoaderInterface $loader = null, ?RequestInterface $request = null): ?EE_Admin
42
-    {
43
-        // check if class object is instantiated
44
-        if (! EE_Admin::$_instance instanceof EE_Admin) {
45
-            EE_Admin::$_instance = new EE_Admin($loader, $request);
46
-        }
47
-        return EE_Admin::$_instance;
48
-    }
49
-
50
-
51
-    /**
52
-     * @return EE_Admin|null
53
-     * @throws EE_Error
54
-     */
55
-    public static function reset(): ?EE_Admin
56
-    {
57
-        EE_Admin::$_instance = null;
58
-        $loader = LoaderFactory::getLoader();
59
-        $request = $loader->getShared('EventEspresso\core\services\request\Request');
60
-        return EE_Admin::instance($loader, $request);
61
-    }
62
-
63
-
64
-    /**
65
-     * @param LoaderInterface  $loader
66
-     * @param RequestInterface $request
67
-     * @throws EE_Error
68
-     * @throws InvalidDataTypeException
69
-     * @throws InvalidInterfaceException
70
-     * @throws InvalidArgumentException
71
-     */
72
-    protected function __construct(LoaderInterface $loader, RequestInterface $request)
73
-    {
74
-        $this->loader = $loader;
75
-        $this->request = $request;
76
-        // define global EE_Admin constants
77
-        $this->_define_all_constants();
78
-        // set autoloaders for our admin page classes based on included path information
79
-        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
80
-        // reset Environment config (we only do this on admin page loads);
81
-        EE_Registry::instance()->CFG->environment->recheck_values();
82
-        // load EE_Request_Handler early
83
-        add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
84
-        add_action('admin_init', [$this, 'admin_init'], 100);
85
-        if (! $this->request->isAjax()) {
86
-            // admin hooks
87
-            add_action('admin_notices', [$this, 'display_admin_notices']);
88
-            add_action('network_admin_notices', [$this, 'display_admin_notices']);
89
-            add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
90
-            add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
91
-            add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
92
-            add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
93
-            add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
94
-        }
95
-        do_action('AHEE__EE_Admin__loaded');
96
-    }
97
-
98
-
99
-    /**
100
-     * _define_all_constants
101
-     * define constants that are set globally for all admin pages
102
-     *
103
-     * @return void
104
-     */
105
-    private function _define_all_constants()
106
-    {
107
-        if (! defined('EE_ADMIN_URL')) {
108
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
109
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
110
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
111
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
112
-            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
113
-        }
114
-    }
115
-
116
-
117
-    /**
118
-     * filter_plugin_actions - adds links to the Plugins page listing
119
-     *
120
-     * @param array  $links
121
-     * @param string $plugin
122
-     * @return    array
123
-     */
124
-    public function filter_plugin_actions($links, $plugin)
125
-    {
126
-        // set $main_file in stone
127
-        static $main_file;
128
-        // if $main_file is not set yet
129
-        if (! $main_file) {
130
-            $main_file = EE_PLUGIN_BASENAME;
131
-        }
132
-        if ($plugin === $main_file) {
133
-            // compare current plugin to this one
134
-            if (MaintenanceStatus::isFullSite()) {
135
-                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
136
-                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
137
-                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
138
-                                    . '</a>';
139
-                array_unshift($links, $maintenance_link);
140
-            } else {
141
-                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
142
-                                     . esc_html__('Settings', 'event_espresso')
143
-                                     . '</a>';
144
-                $events_link       = '<a href="admin.php?page=espresso_events">'
145
-                                     . esc_html__('Events', 'event_espresso')
146
-                                     . '</a>';
147
-                // add before other links
148
-                array_unshift($links, $org_settings_link, $events_link);
149
-            }
150
-        }
151
-        return $links;
152
-    }
153
-
154
-
155
-    /**
156
-     * hide_admin_pages_except_maintenance_mode
157
-     *
158
-     * @param array $admin_page_folder_names
159
-     * @return array
160
-     */
161
-    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
162
-    {
163
-        return [
164
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
165
-            'about'       => EE_ADMIN_PAGES . 'about/',
166
-            'support'     => EE_ADMIN_PAGES . 'support/',
167
-        ];
168
-    }
169
-
170
-
171
-    /**
172
-     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
173
-     * EE_Front_Controller's init phases have run
174
-     *
175
-     * @return void
176
-     * @throws EE_Error
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     * @throws ReflectionException
181
-     * @throws ServiceNotFoundException
182
-     */
183
-    public function init()
184
-    {
185
-        // only enable most of the EE_Admin IF we're not in full maintenance mode
186
-        if (DbStatus::isOnline()) {
187
-            $this->initModelsReady();
188
-        }
189
-        // run the admin page factory but ONLY if:
190
-        // - it is a regular non ajax admin request
191
-        // - we are doing an ee admin ajax request
192
-        if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
193
-            try {
194
-                // this loads the controller for the admin pages which will setup routing etc
195
-                $admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
196
-                /** @var EE_Admin_Page_Loader $admin_page_loader */
197
-                $admin_page_loader->init();
198
-            } catch (EE_Error $e) {
199
-                $e->get_error();
200
-            }
201
-        }
202
-        if ($this->request->isAjax()) {
203
-            return;
204
-        }
205
-        add_filter('content_save_pre', [$this, 'its_eSpresso']);
206
-        // make sure our CPTs and custom taxonomy metaboxes get shown for first time users
207
-        add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes']);
208
-        add_action('admin_head', [$this, 'register_custom_nav_menu_boxes']);
209
-        // exclude EE critical pages from all nav menus and wp_list_pages
210
-        add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu']);
211
-    }
212
-
213
-
214
-    /**
215
-     * Gets the loader (and if it wasn't previously set, sets it)
216
-     *
217
-     * @return LoaderInterface
218
-     * @throws InvalidArgumentException
219
-     * @throws InvalidDataTypeException
220
-     * @throws InvalidInterfaceException
221
-     */
222
-    protected function getLoader()
223
-    {
224
-        return $this->loader;
225
-    }
226
-
227
-
228
-    /**
229
-     * Method that's fired on admin requests (including admin ajax) but only when the models are usable
230
-     * (ie, the site isn't in maintenance mode)
231
-     *
232
-     * @return void
233
-     * @throws EE_Error
234
-     * @since 4.9.63.p
235
-     */
236
-    protected function initModelsReady()
237
-    {
238
-        // ok so we want to enable the entire admin
239
-        $this->persistent_admin_notice_manager = $this->loader->getShared(
240
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
241
-        );
242
-        $this->persistent_admin_notice_manager->setReturnUrl(
243
-            EE_Admin_Page::add_query_args_and_nonce(
244
-                [
245
-                    'page'   => $this->request->getRequestParam('page', ''),
246
-                    'action' => $this->request->getRequestParam('action', ''),
247
-                ],
248
-                EE_ADMIN_URL
249
-            )
250
-        );
251
-        $this->maybeSetDatetimeWarningNotice();
252
-        // at a glance dashboard widget
253
-        add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items']);
254
-        // filter for get_edit_post_link used on comments for custom post types
255
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
256
-    }
257
-
258
-
259
-    /**
260
-     *    get_persistent_admin_notices
261
-     *
262
-     * @access    public
263
-     * @return void
264
-     * @throws EE_Error
265
-     * @throws InvalidArgumentException
266
-     * @throws InvalidDataTypeException
267
-     * @throws InvalidInterfaceException
268
-     * @throws ReflectionException
269
-     */
270
-    public function maybeSetDatetimeWarningNotice()
271
-    {
272
-        // add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
273
-        // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
274
-        // with this.  But after enough time (indeterminate at this point) we can just remove this notice.
275
-        // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
276
-        if (
277
-            apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
278
-            && ! get_option('timezone_string')
279
-            && EEM_Event::instance()->count() > 0
280
-        ) {
281
-            new PersistentAdminNotice(
282
-                'datetime_fix_notice',
283
-                sprintf(
284
-                    esc_html__(
285
-                        '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
286
-                        'event_espresso'
287
-                    ),
288
-                    '<strong>',
289
-                    '</strong>',
290
-                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
291
-                    '</a>',
292
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
293
-                        [
294
-                            'page'   => 'espresso_maintenance_settings',
295
-                            'action' => 'datetime_tools',
296
-                        ],
297
-                        admin_url('admin.php')
298
-                    ) . '">'
299
-                ),
300
-                false,
301
-                'manage_options',
302
-                'datetime_fix_persistent_notice'
303
-            );
304
-        }
305
-    }
306
-
307
-
308
-    /**
309
-     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
310
-     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
311
-     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
312
-     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
313
-     * normal property on the post_type object.  It's found ONLY in this particular context.
314
-     *
315
-     * @param WP_Post $post_type WP post type object
316
-     * @return WP_Post
317
-     * @throws InvalidArgumentException
318
-     * @throws InvalidDataTypeException
319
-     * @throws InvalidInterfaceException
320
-     */
321
-    public function remove_pages_from_nav_menu($post_type)
322
-    {
323
-        // if this isn't the "pages" post type let's get out
324
-        if ($post_type->name !== 'page') {
325
-            return $post_type;
326
-        }
327
-        $critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
328
-        $post_type->_default_query = [
329
-            'post__not_in' => $critical_pages,
330
-        ];
331
-        return $post_type;
332
-    }
333
-
334
-
335
-    /**
336
-     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
337
-     * We want to make sure our metaboxes get shown as well
338
-     *
339
-     * @return void
340
-     */
341
-    public function enable_hidden_ee_nav_menu_metaboxes()
342
-    {
343
-        global $wp_meta_boxes, $pagenow;
344
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
345
-            return;
346
-        }
347
-        $user = wp_get_current_user();
348
-        // has this been done yet?
349
-        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
350
-            return;
351
-        }
352
-
353
-        $hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
354
-        $initial_meta_boxes = apply_filters(
355
-            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
356
-            [
357
-                'nav-menu-theme-locations',
358
-                'add-page',
359
-                'add-custom-links',
360
-                'add-category',
361
-                'add-espresso_events',
362
-                'add-espresso_venues',
363
-                'add-espresso_event_categories',
364
-                'add-espresso_venue_categories',
365
-                'add-post-type-post',
366
-                'add-post-type-page',
367
-            ]
368
-        );
369
-
370
-        if (is_array($hidden_meta_boxes)) {
371
-            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
372
-                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
373
-                    unset($hidden_meta_boxes[ $key ]);
374
-                }
375
-            }
376
-        }
377
-        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
378
-        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
379
-    }
380
-
381
-
382
-    /**
383
-     * This method simply registers custom nav menu boxes for "nav_menus.php route"
384
-     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
385
-     *
386
-     * @return void
387
-     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
388
-     *         addons etc.
389
-     */
390
-    public function register_custom_nav_menu_boxes()
391
-    {
392
-        add_meta_box(
393
-            'add-extra-nav-menu-pages',
394
-            esc_html__('Event Espresso Pages', 'event_espresso'),
395
-            [$this, 'ee_cpt_archive_pages'],
396
-            'nav-menus',
397
-            'side',
398
-            'core'
399
-        );
400
-        add_filter(
401
-            "postbox_classes_nav-menus_add-extra-nav-menu-pages",
402
-            function ($classes) {
403
-                $classes[] = 'ee-admin-container';
404
-                return $classes;
405
-            }
406
-        );
407
-    }
408
-
409
-
410
-    /**
411
-     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
412
-     *
413
-     * @param string $link the original link generated by wp
414
-     * @param int    $id   post id
415
-     * @return string  the (maybe) modified link
416
-     * @since   4.3.0
417
-     */
418
-    public function modify_edit_post_link($link, $id)
419
-    {
420
-        if (! $post = get_post($id)) {
421
-            return $link;
422
-        }
423
-        if ($post->post_type === 'espresso_attendees') {
424
-            $query_args = [
425
-                'action' => 'edit_attendee',
426
-                'post'   => $id,
427
-            ];
428
-            return EEH_URL::add_query_args_and_nonce(
429
-                $query_args,
430
-                admin_url('admin.php?page=espresso_registrations')
431
-            );
432
-        }
433
-        return $link;
434
-    }
435
-
436
-
437
-    public function ee_cpt_archive_pages()
438
-    {
439
-        global $nav_menu_selected_id;
440
-        $removed_args = [
441
-            'action',
442
-            'customlink-tab',
443
-            'edit-menu-item',
444
-            'menu-item',
445
-            'page-tab',
446
-            '_wpnonce',
447
-        ];
448
-        $nav_tab_link = $nav_menu_selected_id
449
-            ? esc_url(
450
-                add_query_arg(
451
-                    'extra-nav-menu-pages-tab',
452
-                    'event-archives',
453
-                    remove_query_arg($removed_args)
454
-                )
455
-            )
456
-            : '';
457
-        $select_all_link = esc_url(
458
-            add_query_arg(
459
-                [
460
-                    'extra-nav-menu-pages-tab' => 'event-archives',
461
-                    'selectall'                => 1,
462
-                ],
463
-                remove_query_arg($removed_args)
464
-            )
465
-        );
466
-        $pages = $this->_get_extra_nav_menu_pages_items();
467
-        $args['walker'] = new Walker_Nav_Menu_Checklist(false);
468
-        $nav_menu_pages_items = walk_nav_menu_tree(
469
-            array_map(
470
-                [$this, '_setup_extra_nav_menu_pages_items'],
471
-                $pages
472
-            ),
473
-            0,
474
-            (object) $args
475
-        );
476
-        EEH_Template::display_template(
477
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
478
-            [
479
-                'nav_menu_selected_id' => $nav_menu_selected_id,
480
-                'nav_menu_pages_items' => $nav_menu_pages_items,
481
-                'nav_tab_link'         => $nav_tab_link,
482
-                'select_all_link'      => $select_all_link,
483
-            ]
484
-        );
485
-    }
486
-
487
-
488
-    /**
489
-     * Returns an array of event archive nav items.
490
-     *
491
-     * @return array
492
-     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
493
-     *        method we use for getting the extra nav menu items
494
-     */
495
-    private function _get_extra_nav_menu_pages_items()
496
-    {
497
-        $menuitems[] = [
498
-            'title'       => esc_html__('Event List', 'event_espresso'),
499
-            'url'         => get_post_type_archive_link('espresso_events'),
500
-            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
501
-        ];
502
-        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
503
-    }
504
-
505
-
506
-    /**
507
-     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
508
-     * the properties and converts it to the menu item object.
509
-     *
510
-     * @param $menu_item_values
511
-     * @return stdClass
512
-     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
513
-     */
514
-    private function _setup_extra_nav_menu_pages_items($menu_item_values)
515
-    {
516
-        $menu_item = new stdClass();
517
-        $keys      = [
518
-            'ID'               => 0,
519
-            'db_id'            => 0,
520
-            'menu_item_parent' => 0,
521
-            'object_id'        => -1,
522
-            'post_parent'      => 0,
523
-            'type'             => 'custom',
524
-            'object'           => '',
525
-            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
526
-            'title'            => '',
527
-            'url'              => '',
528
-            'target'           => '',
529
-            'attr_title'       => '',
530
-            'description'      => '',
531
-            'classes'          => [],
532
-            'xfn'              => '',
533
-        ];
534
-        foreach ($keys as $key => $value) {
535
-            $menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
536
-        }
537
-        return $menu_item;
538
-    }
539
-
540
-
541
-    /**
542
-     * admin_init
543
-     *
544
-     * @return void
545
-     * @throws InvalidArgumentException
546
-     * @throws InvalidDataTypeException
547
-     * @throws InvalidInterfaceException
548
-     */
549
-    public function admin_init()
550
-    {
551
-        /**
552
-         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
553
-         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
554
-         * - check if doing post processing.
555
-         * - check if doing post processing of one of EE CPTs
556
-         * - instantiate the corresponding EE CPT model for the post_type being processed.
557
-         */
558
-        $action    = $this->request->getRequestParam('action');
559
-        $post_type = $this->request->getRequestParam('post_type');
560
-        if ($post_type && $action === 'editpost') {
561
-            /** @var CustomPostTypeDefinitions $custom_post_types */
562
-            $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
563
-            $custom_post_types->getCustomPostTypeModels($post_type);
564
-        }
565
-
566
-
567
-        if (! $this->request->isAjax()) {
568
-            /**
569
-             * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
570
-             * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
571
-             * Pages" tab in the EE General Settings Admin page.
572
-             * This is for user-proofing.
573
-             */
574
-            add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
575
-            if (DbStatus::isOnline()) {
576
-                $this->adminInitModelsReady();
577
-            }
578
-        }
579
-    }
580
-
581
-
582
-    /**
583
-     * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
584
-     */
585
-    protected function adminInitModelsReady()
586
-    {
587
-        if (function_exists('wp_add_privacy_policy_content')) {
588
-            $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
589
-        }
590
-    }
591
-
592
-
593
-    /**
594
-     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
595
-     *
596
-     * @param string $output Current output.
597
-     * @return string
598
-     * @throws InvalidArgumentException
599
-     * @throws InvalidDataTypeException
600
-     * @throws InvalidInterfaceException
601
-     */
602
-    public function modify_dropdown_pages($output)
603
-    {
604
-        // get critical pages
605
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
606
-
607
-        // split current output by line break for easier parsing.
608
-        $split_output = explode("\n", $output);
609
-
610
-        // loop through to remove any critical pages from the array.
611
-        foreach ($critical_pages as $page_id) {
612
-            $needle = 'value="' . $page_id . '"';
613
-            foreach ($split_output as $key => $haystack) {
614
-                if (strpos($haystack, $needle) !== false) {
615
-                    unset($split_output[ $key ]);
616
-                }
617
-            }
618
-        }
619
-        // replace output with the new contents
620
-        return implode("\n", $split_output);
621
-    }
622
-
623
-
624
-    /**
625
-     * display_admin_notices
626
-     *
627
-     * @return void
628
-     */
629
-    public function display_admin_notices()
630
-    {
631
-        echo EE_Error::get_notices(); // already escaped
632
-    }
633
-
634
-
635
-    /**
636
-     * @param array $elements
637
-     * @return array
638
-     * @throws EE_Error
639
-     * @throws InvalidArgumentException
640
-     * @throws InvalidDataTypeException
641
-     * @throws InvalidInterfaceException
642
-     * @throws ReflectionException
643
-     */
644
-    public function dashboard_glance_items($elements)
645
-    {
646
-        $elements                        = is_array($elements) ? $elements : [$elements];
647
-        $events                          = EEM_Event::instance()->count();
648
-        $items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
649
-            ['page' => 'espresso_events'],
650
-            admin_url('admin.php')
651
-        );
652
-        $items['events']['text']         = sprintf(
653
-            esc_html(
654
-                _n('%s Event', '%s Events', $events, 'event_espresso')
655
-            ),
656
-            number_format_i18n($events)
657
-        );
658
-        $items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
659
-        $registrations                   = EEM_Registration::instance()->count(
660
-            [
661
-                [
662
-                    'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
663
-                ],
664
-            ]
665
-        );
666
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
667
-            ['page' => 'espresso_registrations'],
668
-            admin_url('admin.php')
669
-        );
670
-        $items['registrations']['text']  = sprintf(
671
-            esc_html(
672
-                _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
673
-            ),
674
-            number_format_i18n($registrations)
675
-        );
676
-        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
677
-
678
-        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
679
-
680
-        foreach ($items as $type => $item_properties) {
681
-            $elements[] = sprintf(
682
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
683
-                $item_properties['url'],
684
-                $item_properties['title'],
685
-                $item_properties['text']
686
-            );
687
-        }
688
-        return $elements;
689
-    }
690
-
691
-
692
-    /**
693
-     * check_for_invalid_datetime_formats
694
-     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
695
-     * their selected format can be parsed by PHP
696
-     *
697
-     * @param    $value
698
-     * @param    $option
699
-     * @return    string
700
-     */
701
-    public function check_for_invalid_datetime_formats($value, $option)
702
-    {
703
-        // check for date_format or time_format
704
-        switch ($option) {
705
-            case 'date_format':
706
-                $date_time_format = $value . ' ' . get_option('time_format');
707
-                break;
708
-            case 'time_format':
709
-                $date_time_format = get_option('date_format') . ' ' . $value;
710
-                break;
711
-            default:
712
-                $date_time_format = false;
713
-        }
714
-        // do we have a date_time format to check ?
715
-        if ($date_time_format) {
716
-            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
717
-
718
-            if (is_array($error_msg)) {
719
-                $msg = '<p>'
720
-                       . sprintf(
721
-                           esc_html__(
722
-                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
723
-                               'event_espresso'
724
-                           ),
725
-                           date($date_time_format),
726
-                           $date_time_format
727
-                       )
728
-                       . '</p><p><ul>';
729
-
730
-
731
-                foreach ($error_msg as $error) {
732
-                    $msg .= '<li>' . $error . '</li>';
733
-                }
734
-
735
-                $msg .= '</ul></p><p>'
736
-                        . sprintf(
737
-                            esc_html__(
738
-                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
739
-                                'event_espresso'
740
-                            ),
741
-                            '<span style="color:#D54E21;">',
742
-                            '</span>'
743
-                        )
744
-                        . '</p>';
745
-
746
-                // trigger WP settings error
747
-                add_settings_error(
748
-                    'date_format',
749
-                    'date_format',
750
-                    $msg
751
-                );
752
-
753
-                // set format to something valid
754
-                switch ($option) {
755
-                    case 'date_format':
756
-                        $value = 'F j, Y';
757
-                        break;
758
-                    case 'time_format':
759
-                        $value = 'g:i a';
760
-                        break;
761
-                }
762
-            }
763
-        }
764
-        return $value;
765
-    }
766
-
767
-
768
-    /**
769
-     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
770
-     *
771
-     * @param $content
772
-     * @return    string
773
-     */
774
-    public function its_eSpresso($content)
775
-    {
776
-        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
777
-    }
778
-
779
-
780
-    /**
781
-     * espresso_admin_footer
782
-     *
783
-     * @return    string
784
-     */
785
-    public function espresso_admin_footer()
786
-    {
787
-        return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
788
-    }
789
-
790
-
791
-    /**
792
-     * Hooks into the "post states" filter in a wp post type list table.
793
-     *
794
-     * @param array   $post_states
795
-     * @param WP_Post $post
796
-     * @return array
797
-     * @throws InvalidArgumentException
798
-     * @throws InvalidDataTypeException
799
-     * @throws InvalidInterfaceException
800
-     */
801
-    public function displayStateForCriticalPages($post_states, $post)
802
-    {
803
-        $post_states = (array) $post_states;
804
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
805
-            return $post_states;
806
-        }
807
-        /** @var EE_Core_Config $config */
808
-        $config = $this->loader->getShared('EE_Config')->core;
809
-        if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
810
-            $post_states[] = sprintf(
811
-            /* Translators: Using company name - Event Espresso Critical Page */
812
-                esc_html__('%s Critical Page', 'event_espresso'),
813
-                'Event Espresso'
814
-            );
815
-        }
816
-        return $post_states;
817
-    }
818
-
819
-
820
-    /**
821
-     * Show documentation links on the plugins page
822
-     *
823
-     * @param mixed $meta Plugin Row Meta
824
-     * @param mixed $file Plugin Base file
825
-     * @return array
826
-     */
827
-    public function addLinksToPluginRowMeta($meta, $file)
828
-    {
829
-        if (EE_PLUGIN_BASENAME === $file) {
830
-            $row_meta = [
831
-                'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
832
-                          . ' aria-label="'
833
-                          . esc_attr__('View Event Espresso documentation', 'event_espresso')
834
-                          . '">'
835
-                          . esc_html__('Docs', 'event_espresso')
836
-                          . '</a>',
837
-                'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
838
-                          . ' aria-label="'
839
-                          . esc_attr__('View Event Espresso API docs', 'event_espresso')
840
-                          . '">'
841
-                          . esc_html__('API docs', 'event_espresso')
842
-                          . '</a>',
843
-            ];
844
-            return array_merge($meta, $row_meta);
845
-        }
846
-        return (array) $meta;
847
-    }
848
-
849
-     /**************************************************************************************/
850
-     /************************************* DEPRECATED *************************************/
851
-     /**************************************************************************************/
852
-
853
-
854
-    /**
855
-     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
856
-     * EE_Admin_Page route is called.
857
-     *
858
-     * @return void
859
-     */
860
-    public function route_admin_request()
861
-    {
862
-    }
863
-
864
-
865
-    /**
866
-     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
867
-     *
868
-     * @return void
869
-     */
870
-    public function wp_loaded()
871
-    {
872
-    }
873
-
874
-
875
-    /**
876
-     * static method for registering ee admin page.
877
-     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
878
-     *
879
-     * @param       $page_basename
880
-     * @param       $page_path
881
-     * @param array $config
882
-     * @return void
883
-     * @throws EE_Error
884
-     * @see        EE_Register_Admin_Page::register()
885
-     * @since      4.3.0
886
-     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
887
-     */
888
-    public static function register_ee_admin_page($page_basename, $page_path, $config = [])
889
-    {
890
-        EE_Error::doing_it_wrong(
891
-            __METHOD__,
892
-            sprintf(
893
-                esc_html__(
894
-                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
895
-                    'event_espresso'
896
-                ),
897
-                $page_basename
898
-            ),
899
-            '4.3'
900
-        );
901
-        if (class_exists('EE_Register_Admin_Page')) {
902
-            $config['page_path'] = $page_path;
903
-        }
904
-        EE_Register_Admin_Page::register($page_basename, $config);
905
-    }
906
-
907
-
908
-    /**
909
-     * @param int     $post_ID
910
-     * @param WP_Post $post
911
-     * @return void
912
-     * @deprecated 4.8.41
913
-     */
914
-    public static function parse_post_content_on_save($post_ID, $post)
915
-    {
916
-        EE_Error::doing_it_wrong(
917
-            __METHOD__,
918
-            esc_html__('Usage is deprecated', 'event_espresso'),
919
-            '4.8.41'
920
-        );
921
-    }
922
-
923
-
924
-    /**
925
-     * @param  $option
926
-     * @param  $old_value
927
-     * @param  $value
928
-     * @return void
929
-     * @deprecated 4.8.41
930
-     */
931
-    public function reset_page_for_posts_on_change($option, $old_value, $value)
932
-    {
933
-        EE_Error::doing_it_wrong(
934
-            __METHOD__,
935
-            esc_html__('Usage is deprecated', 'event_espresso'),
936
-            '4.8.41'
937
-        );
938
-    }
939
-
940
-
941
-    /**
942
-     * @return void
943
-     * @deprecated 4.9.27
944
-     */
945
-    public function get_persistent_admin_notices()
946
-    {
947
-        EE_Error::doing_it_wrong(
948
-            __METHOD__,
949
-            sprintf(
950
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
951
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
952
-            ),
953
-            '4.9.27'
954
-        );
955
-    }
956
-
957
-
958
-    /**
959
-     * @throws InvalidInterfaceException
960
-     * @throws InvalidDataTypeException
961
-     * @throws DomainException
962
-     * @deprecated 4.9.27
963
-     */
964
-    public function dismiss_ee_nag_notice_callback()
965
-    {
966
-        EE_Error::doing_it_wrong(
967
-            __METHOD__,
968
-            sprintf(
969
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
970
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
971
-            ),
972
-            '4.9.27'
973
-        );
974
-        $this->persistent_admin_notice_manager->dismissNotice();
975
-    }
976
-
977
-
978
-    /**
979
-     * @return void
980
-     * @deprecated 5.0.0.p
981
-     */
982
-    public function enqueue_admin_scripts()
983
-    {
984
-    }
985
-
986
-
987
-
988
-    /**
989
-     * @return RequestInterface
990
-     * @deprecated 5.0.0.p
991
-     */
992
-    public function get_request()
993
-    {
994
-        EE_Error::doing_it_wrong(
995
-            __METHOD__,
996
-            sprintf(
997
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
998
-                'EventEspresso\core\services\request\Request'
999
-            ),
1000
-            '5.0.0.p'
1001
-        );
1002
-        return $this->request;
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * @deprecated 5.0.0.p
1008
-     */
1009
-    public function hookIntoWpPluginsPage()
1010
-    {
1011
-    }
25
+	private static ?EE_Admin $_instance = null;
26
+
27
+	private ?PersistentAdminNoticeManager $persistent_admin_notice_manager = null;
28
+
29
+	protected LoaderInterface $loader;
30
+
31
+	protected RequestInterface $request;
32
+
33
+
34
+	/**
35
+	 * @singleton method used to instantiate class object
36
+	 * @param LoaderInterface|null  $loader
37
+	 * @param RequestInterface|null $request
38
+	 * @return EE_Admin|null
39
+	 * @throws EE_Error
40
+	 */
41
+	public static function instance(?LoaderInterface $loader = null, ?RequestInterface $request = null): ?EE_Admin
42
+	{
43
+		// check if class object is instantiated
44
+		if (! EE_Admin::$_instance instanceof EE_Admin) {
45
+			EE_Admin::$_instance = new EE_Admin($loader, $request);
46
+		}
47
+		return EE_Admin::$_instance;
48
+	}
49
+
50
+
51
+	/**
52
+	 * @return EE_Admin|null
53
+	 * @throws EE_Error
54
+	 */
55
+	public static function reset(): ?EE_Admin
56
+	{
57
+		EE_Admin::$_instance = null;
58
+		$loader = LoaderFactory::getLoader();
59
+		$request = $loader->getShared('EventEspresso\core\services\request\Request');
60
+		return EE_Admin::instance($loader, $request);
61
+	}
62
+
63
+
64
+	/**
65
+	 * @param LoaderInterface  $loader
66
+	 * @param RequestInterface $request
67
+	 * @throws EE_Error
68
+	 * @throws InvalidDataTypeException
69
+	 * @throws InvalidInterfaceException
70
+	 * @throws InvalidArgumentException
71
+	 */
72
+	protected function __construct(LoaderInterface $loader, RequestInterface $request)
73
+	{
74
+		$this->loader = $loader;
75
+		$this->request = $request;
76
+		// define global EE_Admin constants
77
+		$this->_define_all_constants();
78
+		// set autoloaders for our admin page classes based on included path information
79
+		EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
80
+		// reset Environment config (we only do this on admin page loads);
81
+		EE_Registry::instance()->CFG->environment->recheck_values();
82
+		// load EE_Request_Handler early
83
+		add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
84
+		add_action('admin_init', [$this, 'admin_init'], 100);
85
+		if (! $this->request->isAjax()) {
86
+			// admin hooks
87
+			add_action('admin_notices', [$this, 'display_admin_notices']);
88
+			add_action('network_admin_notices', [$this, 'display_admin_notices']);
89
+			add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
90
+			add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
91
+			add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
92
+			add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
93
+			add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
94
+		}
95
+		do_action('AHEE__EE_Admin__loaded');
96
+	}
97
+
98
+
99
+	/**
100
+	 * _define_all_constants
101
+	 * define constants that are set globally for all admin pages
102
+	 *
103
+	 * @return void
104
+	 */
105
+	private function _define_all_constants()
106
+	{
107
+		if (! defined('EE_ADMIN_URL')) {
108
+			define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
109
+			define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
110
+			define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
111
+			define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
112
+			define('WP_AJAX_URL', admin_url('admin-ajax.php'));
113
+		}
114
+	}
115
+
116
+
117
+	/**
118
+	 * filter_plugin_actions - adds links to the Plugins page listing
119
+	 *
120
+	 * @param array  $links
121
+	 * @param string $plugin
122
+	 * @return    array
123
+	 */
124
+	public function filter_plugin_actions($links, $plugin)
125
+	{
126
+		// set $main_file in stone
127
+		static $main_file;
128
+		// if $main_file is not set yet
129
+		if (! $main_file) {
130
+			$main_file = EE_PLUGIN_BASENAME;
131
+		}
132
+		if ($plugin === $main_file) {
133
+			// compare current plugin to this one
134
+			if (MaintenanceStatus::isFullSite()) {
135
+				$maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
136
+									. ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
137
+									. esc_html__('Maintenance Mode Active', 'event_espresso')
138
+									. '</a>';
139
+				array_unshift($links, $maintenance_link);
140
+			} else {
141
+				$org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
142
+									 . esc_html__('Settings', 'event_espresso')
143
+									 . '</a>';
144
+				$events_link       = '<a href="admin.php?page=espresso_events">'
145
+									 . esc_html__('Events', 'event_espresso')
146
+									 . '</a>';
147
+				// add before other links
148
+				array_unshift($links, $org_settings_link, $events_link);
149
+			}
150
+		}
151
+		return $links;
152
+	}
153
+
154
+
155
+	/**
156
+	 * hide_admin_pages_except_maintenance_mode
157
+	 *
158
+	 * @param array $admin_page_folder_names
159
+	 * @return array
160
+	 */
161
+	public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
162
+	{
163
+		return [
164
+			'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
165
+			'about'       => EE_ADMIN_PAGES . 'about/',
166
+			'support'     => EE_ADMIN_PAGES . 'support/',
167
+		];
168
+	}
169
+
170
+
171
+	/**
172
+	 * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
173
+	 * EE_Front_Controller's init phases have run
174
+	 *
175
+	 * @return void
176
+	 * @throws EE_Error
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 * @throws ReflectionException
181
+	 * @throws ServiceNotFoundException
182
+	 */
183
+	public function init()
184
+	{
185
+		// only enable most of the EE_Admin IF we're not in full maintenance mode
186
+		if (DbStatus::isOnline()) {
187
+			$this->initModelsReady();
188
+		}
189
+		// run the admin page factory but ONLY if:
190
+		// - it is a regular non ajax admin request
191
+		// - we are doing an ee admin ajax request
192
+		if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
193
+			try {
194
+				// this loads the controller for the admin pages which will setup routing etc
195
+				$admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
196
+				/** @var EE_Admin_Page_Loader $admin_page_loader */
197
+				$admin_page_loader->init();
198
+			} catch (EE_Error $e) {
199
+				$e->get_error();
200
+			}
201
+		}
202
+		if ($this->request->isAjax()) {
203
+			return;
204
+		}
205
+		add_filter('content_save_pre', [$this, 'its_eSpresso']);
206
+		// make sure our CPTs and custom taxonomy metaboxes get shown for first time users
207
+		add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes']);
208
+		add_action('admin_head', [$this, 'register_custom_nav_menu_boxes']);
209
+		// exclude EE critical pages from all nav menus and wp_list_pages
210
+		add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu']);
211
+	}
212
+
213
+
214
+	/**
215
+	 * Gets the loader (and if it wasn't previously set, sets it)
216
+	 *
217
+	 * @return LoaderInterface
218
+	 * @throws InvalidArgumentException
219
+	 * @throws InvalidDataTypeException
220
+	 * @throws InvalidInterfaceException
221
+	 */
222
+	protected function getLoader()
223
+	{
224
+		return $this->loader;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Method that's fired on admin requests (including admin ajax) but only when the models are usable
230
+	 * (ie, the site isn't in maintenance mode)
231
+	 *
232
+	 * @return void
233
+	 * @throws EE_Error
234
+	 * @since 4.9.63.p
235
+	 */
236
+	protected function initModelsReady()
237
+	{
238
+		// ok so we want to enable the entire admin
239
+		$this->persistent_admin_notice_manager = $this->loader->getShared(
240
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
241
+		);
242
+		$this->persistent_admin_notice_manager->setReturnUrl(
243
+			EE_Admin_Page::add_query_args_and_nonce(
244
+				[
245
+					'page'   => $this->request->getRequestParam('page', ''),
246
+					'action' => $this->request->getRequestParam('action', ''),
247
+				],
248
+				EE_ADMIN_URL
249
+			)
250
+		);
251
+		$this->maybeSetDatetimeWarningNotice();
252
+		// at a glance dashboard widget
253
+		add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items']);
254
+		// filter for get_edit_post_link used on comments for custom post types
255
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
256
+	}
257
+
258
+
259
+	/**
260
+	 *    get_persistent_admin_notices
261
+	 *
262
+	 * @access    public
263
+	 * @return void
264
+	 * @throws EE_Error
265
+	 * @throws InvalidArgumentException
266
+	 * @throws InvalidDataTypeException
267
+	 * @throws InvalidInterfaceException
268
+	 * @throws ReflectionException
269
+	 */
270
+	public function maybeSetDatetimeWarningNotice()
271
+	{
272
+		// add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
273
+		// @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
274
+		// with this.  But after enough time (indeterminate at this point) we can just remove this notice.
275
+		// this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
276
+		if (
277
+			apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
278
+			&& ! get_option('timezone_string')
279
+			&& EEM_Event::instance()->count() > 0
280
+		) {
281
+			new PersistentAdminNotice(
282
+				'datetime_fix_notice',
283
+				sprintf(
284
+					esc_html__(
285
+						'%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
286
+						'event_espresso'
287
+					),
288
+					'<strong>',
289
+					'</strong>',
290
+					'<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
291
+					'</a>',
292
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
293
+						[
294
+							'page'   => 'espresso_maintenance_settings',
295
+							'action' => 'datetime_tools',
296
+						],
297
+						admin_url('admin.php')
298
+					) . '">'
299
+				),
300
+				false,
301
+				'manage_options',
302
+				'datetime_fix_persistent_notice'
303
+			);
304
+		}
305
+	}
306
+
307
+
308
+	/**
309
+	 * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
310
+	 * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
311
+	 * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
312
+	 * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
313
+	 * normal property on the post_type object.  It's found ONLY in this particular context.
314
+	 *
315
+	 * @param WP_Post $post_type WP post type object
316
+	 * @return WP_Post
317
+	 * @throws InvalidArgumentException
318
+	 * @throws InvalidDataTypeException
319
+	 * @throws InvalidInterfaceException
320
+	 */
321
+	public function remove_pages_from_nav_menu($post_type)
322
+	{
323
+		// if this isn't the "pages" post type let's get out
324
+		if ($post_type->name !== 'page') {
325
+			return $post_type;
326
+		}
327
+		$critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
328
+		$post_type->_default_query = [
329
+			'post__not_in' => $critical_pages,
330
+		];
331
+		return $post_type;
332
+	}
333
+
334
+
335
+	/**
336
+	 * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
337
+	 * We want to make sure our metaboxes get shown as well
338
+	 *
339
+	 * @return void
340
+	 */
341
+	public function enable_hidden_ee_nav_menu_metaboxes()
342
+	{
343
+		global $wp_meta_boxes, $pagenow;
344
+		if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
345
+			return;
346
+		}
347
+		$user = wp_get_current_user();
348
+		// has this been done yet?
349
+		if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
350
+			return;
351
+		}
352
+
353
+		$hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
354
+		$initial_meta_boxes = apply_filters(
355
+			'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
356
+			[
357
+				'nav-menu-theme-locations',
358
+				'add-page',
359
+				'add-custom-links',
360
+				'add-category',
361
+				'add-espresso_events',
362
+				'add-espresso_venues',
363
+				'add-espresso_event_categories',
364
+				'add-espresso_venue_categories',
365
+				'add-post-type-post',
366
+				'add-post-type-page',
367
+			]
368
+		);
369
+
370
+		if (is_array($hidden_meta_boxes)) {
371
+			foreach ($hidden_meta_boxes as $key => $meta_box_id) {
372
+				if (in_array($meta_box_id, $initial_meta_boxes, true)) {
373
+					unset($hidden_meta_boxes[ $key ]);
374
+				}
375
+			}
376
+		}
377
+		update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
378
+		update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
379
+	}
380
+
381
+
382
+	/**
383
+	 * This method simply registers custom nav menu boxes for "nav_menus.php route"
384
+	 * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
385
+	 *
386
+	 * @return void
387
+	 * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
388
+	 *         addons etc.
389
+	 */
390
+	public function register_custom_nav_menu_boxes()
391
+	{
392
+		add_meta_box(
393
+			'add-extra-nav-menu-pages',
394
+			esc_html__('Event Espresso Pages', 'event_espresso'),
395
+			[$this, 'ee_cpt_archive_pages'],
396
+			'nav-menus',
397
+			'side',
398
+			'core'
399
+		);
400
+		add_filter(
401
+			"postbox_classes_nav-menus_add-extra-nav-menu-pages",
402
+			function ($classes) {
403
+				$classes[] = 'ee-admin-container';
404
+				return $classes;
405
+			}
406
+		);
407
+	}
408
+
409
+
410
+	/**
411
+	 * Use this to edit the post link for our cpts so that the edit link points to the correct page.
412
+	 *
413
+	 * @param string $link the original link generated by wp
414
+	 * @param int    $id   post id
415
+	 * @return string  the (maybe) modified link
416
+	 * @since   4.3.0
417
+	 */
418
+	public function modify_edit_post_link($link, $id)
419
+	{
420
+		if (! $post = get_post($id)) {
421
+			return $link;
422
+		}
423
+		if ($post->post_type === 'espresso_attendees') {
424
+			$query_args = [
425
+				'action' => 'edit_attendee',
426
+				'post'   => $id,
427
+			];
428
+			return EEH_URL::add_query_args_and_nonce(
429
+				$query_args,
430
+				admin_url('admin.php?page=espresso_registrations')
431
+			);
432
+		}
433
+		return $link;
434
+	}
435
+
436
+
437
+	public function ee_cpt_archive_pages()
438
+	{
439
+		global $nav_menu_selected_id;
440
+		$removed_args = [
441
+			'action',
442
+			'customlink-tab',
443
+			'edit-menu-item',
444
+			'menu-item',
445
+			'page-tab',
446
+			'_wpnonce',
447
+		];
448
+		$nav_tab_link = $nav_menu_selected_id
449
+			? esc_url(
450
+				add_query_arg(
451
+					'extra-nav-menu-pages-tab',
452
+					'event-archives',
453
+					remove_query_arg($removed_args)
454
+				)
455
+			)
456
+			: '';
457
+		$select_all_link = esc_url(
458
+			add_query_arg(
459
+				[
460
+					'extra-nav-menu-pages-tab' => 'event-archives',
461
+					'selectall'                => 1,
462
+				],
463
+				remove_query_arg($removed_args)
464
+			)
465
+		);
466
+		$pages = $this->_get_extra_nav_menu_pages_items();
467
+		$args['walker'] = new Walker_Nav_Menu_Checklist(false);
468
+		$nav_menu_pages_items = walk_nav_menu_tree(
469
+			array_map(
470
+				[$this, '_setup_extra_nav_menu_pages_items'],
471
+				$pages
472
+			),
473
+			0,
474
+			(object) $args
475
+		);
476
+		EEH_Template::display_template(
477
+			EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
478
+			[
479
+				'nav_menu_selected_id' => $nav_menu_selected_id,
480
+				'nav_menu_pages_items' => $nav_menu_pages_items,
481
+				'nav_tab_link'         => $nav_tab_link,
482
+				'select_all_link'      => $select_all_link,
483
+			]
484
+		);
485
+	}
486
+
487
+
488
+	/**
489
+	 * Returns an array of event archive nav items.
490
+	 *
491
+	 * @return array
492
+	 * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
493
+	 *        method we use for getting the extra nav menu items
494
+	 */
495
+	private function _get_extra_nav_menu_pages_items()
496
+	{
497
+		$menuitems[] = [
498
+			'title'       => esc_html__('Event List', 'event_espresso'),
499
+			'url'         => get_post_type_archive_link('espresso_events'),
500
+			'description' => esc_html__('Archive page for all events.', 'event_espresso'),
501
+		];
502
+		return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
503
+	}
504
+
505
+
506
+	/**
507
+	 * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
508
+	 * the properties and converts it to the menu item object.
509
+	 *
510
+	 * @param $menu_item_values
511
+	 * @return stdClass
512
+	 * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
513
+	 */
514
+	private function _setup_extra_nav_menu_pages_items($menu_item_values)
515
+	{
516
+		$menu_item = new stdClass();
517
+		$keys      = [
518
+			'ID'               => 0,
519
+			'db_id'            => 0,
520
+			'menu_item_parent' => 0,
521
+			'object_id'        => -1,
522
+			'post_parent'      => 0,
523
+			'type'             => 'custom',
524
+			'object'           => '',
525
+			'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
526
+			'title'            => '',
527
+			'url'              => '',
528
+			'target'           => '',
529
+			'attr_title'       => '',
530
+			'description'      => '',
531
+			'classes'          => [],
532
+			'xfn'              => '',
533
+		];
534
+		foreach ($keys as $key => $value) {
535
+			$menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
536
+		}
537
+		return $menu_item;
538
+	}
539
+
540
+
541
+	/**
542
+	 * admin_init
543
+	 *
544
+	 * @return void
545
+	 * @throws InvalidArgumentException
546
+	 * @throws InvalidDataTypeException
547
+	 * @throws InvalidInterfaceException
548
+	 */
549
+	public function admin_init()
550
+	{
551
+		/**
552
+		 * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
553
+		 * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
554
+		 * - check if doing post processing.
555
+		 * - check if doing post processing of one of EE CPTs
556
+		 * - instantiate the corresponding EE CPT model for the post_type being processed.
557
+		 */
558
+		$action    = $this->request->getRequestParam('action');
559
+		$post_type = $this->request->getRequestParam('post_type');
560
+		if ($post_type && $action === 'editpost') {
561
+			/** @var CustomPostTypeDefinitions $custom_post_types */
562
+			$custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
563
+			$custom_post_types->getCustomPostTypeModels($post_type);
564
+		}
565
+
566
+
567
+		if (! $this->request->isAjax()) {
568
+			/**
569
+			 * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
570
+			 * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
571
+			 * Pages" tab in the EE General Settings Admin page.
572
+			 * This is for user-proofing.
573
+			 */
574
+			add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
575
+			if (DbStatus::isOnline()) {
576
+				$this->adminInitModelsReady();
577
+			}
578
+		}
579
+	}
580
+
581
+
582
+	/**
583
+	 * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
584
+	 */
585
+	protected function adminInitModelsReady()
586
+	{
587
+		if (function_exists('wp_add_privacy_policy_content')) {
588
+			$this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
589
+		}
590
+	}
591
+
592
+
593
+	/**
594
+	 * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
595
+	 *
596
+	 * @param string $output Current output.
597
+	 * @return string
598
+	 * @throws InvalidArgumentException
599
+	 * @throws InvalidDataTypeException
600
+	 * @throws InvalidInterfaceException
601
+	 */
602
+	public function modify_dropdown_pages($output)
603
+	{
604
+		// get critical pages
605
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
606
+
607
+		// split current output by line break for easier parsing.
608
+		$split_output = explode("\n", $output);
609
+
610
+		// loop through to remove any critical pages from the array.
611
+		foreach ($critical_pages as $page_id) {
612
+			$needle = 'value="' . $page_id . '"';
613
+			foreach ($split_output as $key => $haystack) {
614
+				if (strpos($haystack, $needle) !== false) {
615
+					unset($split_output[ $key ]);
616
+				}
617
+			}
618
+		}
619
+		// replace output with the new contents
620
+		return implode("\n", $split_output);
621
+	}
622
+
623
+
624
+	/**
625
+	 * display_admin_notices
626
+	 *
627
+	 * @return void
628
+	 */
629
+	public function display_admin_notices()
630
+	{
631
+		echo EE_Error::get_notices(); // already escaped
632
+	}
633
+
634
+
635
+	/**
636
+	 * @param array $elements
637
+	 * @return array
638
+	 * @throws EE_Error
639
+	 * @throws InvalidArgumentException
640
+	 * @throws InvalidDataTypeException
641
+	 * @throws InvalidInterfaceException
642
+	 * @throws ReflectionException
643
+	 */
644
+	public function dashboard_glance_items($elements)
645
+	{
646
+		$elements                        = is_array($elements) ? $elements : [$elements];
647
+		$events                          = EEM_Event::instance()->count();
648
+		$items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
649
+			['page' => 'espresso_events'],
650
+			admin_url('admin.php')
651
+		);
652
+		$items['events']['text']         = sprintf(
653
+			esc_html(
654
+				_n('%s Event', '%s Events', $events, 'event_espresso')
655
+			),
656
+			number_format_i18n($events)
657
+		);
658
+		$items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
659
+		$registrations                   = EEM_Registration::instance()->count(
660
+			[
661
+				[
662
+					'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
663
+				],
664
+			]
665
+		);
666
+		$items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
667
+			['page' => 'espresso_registrations'],
668
+			admin_url('admin.php')
669
+		);
670
+		$items['registrations']['text']  = sprintf(
671
+			esc_html(
672
+				_n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
673
+			),
674
+			number_format_i18n($registrations)
675
+		);
676
+		$items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
677
+
678
+		$items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
679
+
680
+		foreach ($items as $type => $item_properties) {
681
+			$elements[] = sprintf(
682
+				'<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
683
+				$item_properties['url'],
684
+				$item_properties['title'],
685
+				$item_properties['text']
686
+			);
687
+		}
688
+		return $elements;
689
+	}
690
+
691
+
692
+	/**
693
+	 * check_for_invalid_datetime_formats
694
+	 * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
695
+	 * their selected format can be parsed by PHP
696
+	 *
697
+	 * @param    $value
698
+	 * @param    $option
699
+	 * @return    string
700
+	 */
701
+	public function check_for_invalid_datetime_formats($value, $option)
702
+	{
703
+		// check for date_format or time_format
704
+		switch ($option) {
705
+			case 'date_format':
706
+				$date_time_format = $value . ' ' . get_option('time_format');
707
+				break;
708
+			case 'time_format':
709
+				$date_time_format = get_option('date_format') . ' ' . $value;
710
+				break;
711
+			default:
712
+				$date_time_format = false;
713
+		}
714
+		// do we have a date_time format to check ?
715
+		if ($date_time_format) {
716
+			$error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
717
+
718
+			if (is_array($error_msg)) {
719
+				$msg = '<p>'
720
+					   . sprintf(
721
+						   esc_html__(
722
+							   'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
723
+							   'event_espresso'
724
+						   ),
725
+						   date($date_time_format),
726
+						   $date_time_format
727
+					   )
728
+					   . '</p><p><ul>';
729
+
730
+
731
+				foreach ($error_msg as $error) {
732
+					$msg .= '<li>' . $error . '</li>';
733
+				}
734
+
735
+				$msg .= '</ul></p><p>'
736
+						. sprintf(
737
+							esc_html__(
738
+								'%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
739
+								'event_espresso'
740
+							),
741
+							'<span style="color:#D54E21;">',
742
+							'</span>'
743
+						)
744
+						. '</p>';
745
+
746
+				// trigger WP settings error
747
+				add_settings_error(
748
+					'date_format',
749
+					'date_format',
750
+					$msg
751
+				);
752
+
753
+				// set format to something valid
754
+				switch ($option) {
755
+					case 'date_format':
756
+						$value = 'F j, Y';
757
+						break;
758
+					case 'time_format':
759
+						$value = 'g:i a';
760
+						break;
761
+				}
762
+			}
763
+		}
764
+		return $value;
765
+	}
766
+
767
+
768
+	/**
769
+	 * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
770
+	 *
771
+	 * @param $content
772
+	 * @return    string
773
+	 */
774
+	public function its_eSpresso($content)
775
+	{
776
+		return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
777
+	}
778
+
779
+
780
+	/**
781
+	 * espresso_admin_footer
782
+	 *
783
+	 * @return    string
784
+	 */
785
+	public function espresso_admin_footer()
786
+	{
787
+		return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Hooks into the "post states" filter in a wp post type list table.
793
+	 *
794
+	 * @param array   $post_states
795
+	 * @param WP_Post $post
796
+	 * @return array
797
+	 * @throws InvalidArgumentException
798
+	 * @throws InvalidDataTypeException
799
+	 * @throws InvalidInterfaceException
800
+	 */
801
+	public function displayStateForCriticalPages($post_states, $post)
802
+	{
803
+		$post_states = (array) $post_states;
804
+		if (! $post instanceof WP_Post || $post->post_type !== 'page') {
805
+			return $post_states;
806
+		}
807
+		/** @var EE_Core_Config $config */
808
+		$config = $this->loader->getShared('EE_Config')->core;
809
+		if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
810
+			$post_states[] = sprintf(
811
+			/* Translators: Using company name - Event Espresso Critical Page */
812
+				esc_html__('%s Critical Page', 'event_espresso'),
813
+				'Event Espresso'
814
+			);
815
+		}
816
+		return $post_states;
817
+	}
818
+
819
+
820
+	/**
821
+	 * Show documentation links on the plugins page
822
+	 *
823
+	 * @param mixed $meta Plugin Row Meta
824
+	 * @param mixed $file Plugin Base file
825
+	 * @return array
826
+	 */
827
+	public function addLinksToPluginRowMeta($meta, $file)
828
+	{
829
+		if (EE_PLUGIN_BASENAME === $file) {
830
+			$row_meta = [
831
+				'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
832
+						  . ' aria-label="'
833
+						  . esc_attr__('View Event Espresso documentation', 'event_espresso')
834
+						  . '">'
835
+						  . esc_html__('Docs', 'event_espresso')
836
+						  . '</a>',
837
+				'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
838
+						  . ' aria-label="'
839
+						  . esc_attr__('View Event Espresso API docs', 'event_espresso')
840
+						  . '">'
841
+						  . esc_html__('API docs', 'event_espresso')
842
+						  . '</a>',
843
+			];
844
+			return array_merge($meta, $row_meta);
845
+		}
846
+		return (array) $meta;
847
+	}
848
+
849
+	 /**************************************************************************************/
850
+	 /************************************* DEPRECATED *************************************/
851
+	 /**************************************************************************************/
852
+
853
+
854
+	/**
855
+	 * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
856
+	 * EE_Admin_Page route is called.
857
+	 *
858
+	 * @return void
859
+	 */
860
+	public function route_admin_request()
861
+	{
862
+	}
863
+
864
+
865
+	/**
866
+	 * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
867
+	 *
868
+	 * @return void
869
+	 */
870
+	public function wp_loaded()
871
+	{
872
+	}
873
+
874
+
875
+	/**
876
+	 * static method for registering ee admin page.
877
+	 * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
878
+	 *
879
+	 * @param       $page_basename
880
+	 * @param       $page_path
881
+	 * @param array $config
882
+	 * @return void
883
+	 * @throws EE_Error
884
+	 * @see        EE_Register_Admin_Page::register()
885
+	 * @since      4.3.0
886
+	 * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
887
+	 */
888
+	public static function register_ee_admin_page($page_basename, $page_path, $config = [])
889
+	{
890
+		EE_Error::doing_it_wrong(
891
+			__METHOD__,
892
+			sprintf(
893
+				esc_html__(
894
+					'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
895
+					'event_espresso'
896
+				),
897
+				$page_basename
898
+			),
899
+			'4.3'
900
+		);
901
+		if (class_exists('EE_Register_Admin_Page')) {
902
+			$config['page_path'] = $page_path;
903
+		}
904
+		EE_Register_Admin_Page::register($page_basename, $config);
905
+	}
906
+
907
+
908
+	/**
909
+	 * @param int     $post_ID
910
+	 * @param WP_Post $post
911
+	 * @return void
912
+	 * @deprecated 4.8.41
913
+	 */
914
+	public static function parse_post_content_on_save($post_ID, $post)
915
+	{
916
+		EE_Error::doing_it_wrong(
917
+			__METHOD__,
918
+			esc_html__('Usage is deprecated', 'event_espresso'),
919
+			'4.8.41'
920
+		);
921
+	}
922
+
923
+
924
+	/**
925
+	 * @param  $option
926
+	 * @param  $old_value
927
+	 * @param  $value
928
+	 * @return void
929
+	 * @deprecated 4.8.41
930
+	 */
931
+	public function reset_page_for_posts_on_change($option, $old_value, $value)
932
+	{
933
+		EE_Error::doing_it_wrong(
934
+			__METHOD__,
935
+			esc_html__('Usage is deprecated', 'event_espresso'),
936
+			'4.8.41'
937
+		);
938
+	}
939
+
940
+
941
+	/**
942
+	 * @return void
943
+	 * @deprecated 4.9.27
944
+	 */
945
+	public function get_persistent_admin_notices()
946
+	{
947
+		EE_Error::doing_it_wrong(
948
+			__METHOD__,
949
+			sprintf(
950
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
951
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
952
+			),
953
+			'4.9.27'
954
+		);
955
+	}
956
+
957
+
958
+	/**
959
+	 * @throws InvalidInterfaceException
960
+	 * @throws InvalidDataTypeException
961
+	 * @throws DomainException
962
+	 * @deprecated 4.9.27
963
+	 */
964
+	public function dismiss_ee_nag_notice_callback()
965
+	{
966
+		EE_Error::doing_it_wrong(
967
+			__METHOD__,
968
+			sprintf(
969
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
970
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
971
+			),
972
+			'4.9.27'
973
+		);
974
+		$this->persistent_admin_notice_manager->dismissNotice();
975
+	}
976
+
977
+
978
+	/**
979
+	 * @return void
980
+	 * @deprecated 5.0.0.p
981
+	 */
982
+	public function enqueue_admin_scripts()
983
+	{
984
+	}
985
+
986
+
987
+
988
+	/**
989
+	 * @return RequestInterface
990
+	 * @deprecated 5.0.0.p
991
+	 */
992
+	public function get_request()
993
+	{
994
+		EE_Error::doing_it_wrong(
995
+			__METHOD__,
996
+			sprintf(
997
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
998
+				'EventEspresso\core\services\request\Request'
999
+			),
1000
+			'5.0.0.p'
1001
+		);
1002
+		return $this->request;
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * @deprecated 5.0.0.p
1008
+	 */
1009
+	public function hookIntoWpPluginsPage()
1010
+	{
1011
+	}
1012 1012
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_List_Table.core.php 2 patches
Indentation   +949 added lines, -949 removed lines patch added patch discarded remove patch
@@ -6,7 +6,7 @@  discard block
 block discarded – undo
6 6
 use EventEspresso\core\services\request\sanitizers\AllowedTags;
7 7
 
8 8
 if (! class_exists('WP_List_Table')) {
9
-    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
9
+	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10 10
 }
11 11
 
12 12
 
@@ -24,931 +24,931 @@  discard block
 block discarded – undo
24 24
  */
25 25
 abstract class EE_Admin_List_Table extends WP_List_Table
26 26
 {
27
-    const ACTION_COPY    = 'duplicate';
28
-
29
-    const ACTION_DELETE  = 'delete';
30
-
31
-    const ACTION_EDIT    = 'edit';
32
-
33
-    const ACTION_RESTORE = 'restore';
34
-
35
-    const ACTION_TRASH   = 'trash';
36
-
37
-    protected static array $actions = [
38
-        self::ACTION_COPY,
39
-        self::ACTION_DELETE,
40
-        self::ACTION_EDIT,
41
-        self::ACTION_RESTORE,
42
-        self::ACTION_TRASH,
43
-    ];
44
-
45
-    /**
46
-     * holds the data that will be processed for the table
47
-     *
48
-     * @var array $_data
49
-     */
50
-    protected array $_data;
51
-
52
-
53
-    /**
54
-     * This holds the value of all the data available for the given view (for all pages).
55
-     *
56
-     * @var int $_all_data_count
57
-     */
58
-    protected int $_all_data_count;
59
-
60
-
61
-    /**
62
-     * Will contain the count of trashed items for the view label.
63
-     *
64
-     * @var int $_trashed_count
65
-     */
66
-    protected int $_trashed_count;
67
-
68
-
69
-    /**
70
-     * This is what will be referenced as the slug for the current screen
71
-     *
72
-     * @var string $_screen
73
-     */
74
-    protected string $_screen;
75
-
76
-
77
-    /**
78
-     * this is the EE_Admin_Page object
79
-     *
80
-     * @var EE_Admin_Page $_admin_page
81
-     */
82
-    protected EE_Admin_Page $_admin_page;
83
-
84
-
85
-    /**
86
-     * The current view
87
-     *
88
-     * @var string $_view
89
-     */
90
-    protected string $_view;
91
-
92
-
93
-    /**
94
-     * array of possible views for this table
95
-     *
96
-     * @var array $_views
97
-     */
98
-    protected array $_views;
99
-
100
-
101
-    /**
102
-     * An array of key => value pairs containing information about the current table
103
-     * array(
104
-     *        'plural' => 'plural label',
105
-     *        'singular' => 'singular label',
106
-     *        'ajax' => false, //whether to use ajax or not
107
-     *        'screen' => null, //string used to reference what screen this is
108
-     *        (WP_List_table converts to screen object)
109
-     * )
110
-     *
111
-     * @var array $_wp_list_args
112
-     */
113
-    protected array $_wp_list_args;
114
-
115
-    /**
116
-     * an array of column names
117
-     * array(
118
-     *    'internal-name' => 'Title'
119
-     * )
120
-     *
121
-     * @var array $_columns
122
-     */
123
-    protected array $_columns;
124
-
125
-    /**
126
-     * An array of sortable columns
127
-     * array(
128
-     *    'internal-name' => 'orderby' //or
129
-     *    'internal-name' => array( 'orderby', true )
130
-     * )
131
-     *
132
-     * @var array $_sortable_columns
133
-     */
134
-    protected array $_sortable_columns;
135
-
136
-    /**
137
-     * callback method used to perform AJAX row reordering
138
-     *
139
-     * @var string|null $_ajax_sorting_callback
140
-     */
141
-    protected ?string $_ajax_sorting_callback = null;
142
-
143
-    /**
144
-     * An array of hidden columns (if needed)
145
-     * array('internal-name', 'internal-name')
146
-     *
147
-     * @var array $_hidden_columns
148
-     */
149
-    protected array $_hidden_columns;
150
-
151
-    /**
152
-     * holds the per_page value
153
-     *
154
-     * @var int $_per_page
155
-     */
156
-    protected int $_per_page;
157
-
158
-    /**
159
-     * holds what page number is currently being viewed
160
-     *
161
-     * @var int $_current_page
162
-     */
163
-    protected int $_current_page;
164
-
165
-    /**
166
-     * the reference string for the nonce_action
167
-     *
168
-     * @var string $_nonce_action_ref
169
-     */
170
-    protected string $_nonce_action_ref;
171
-
172
-    /**
173
-     * property to hold incoming request data (as set by the admin_page_core)
174
-     *
175
-     * @var array $_req_data
176
-     */
177
-    protected array $_req_data;
178
-
179
-
180
-    /**
181
-     * yes / no array for admin form fields
182
-     *
183
-     * @var array $_yes_no
184
-     */
185
-    protected array $_yes_no = [];
186
-
187
-    /**
188
-     * Array describing buttons that should appear at the bottom of the page
189
-     * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
190
-     * and the values are another array with the following keys
191
-     * array(
192
-     *    'route' => 'page_route',
193
-     *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
194
-     * )
195
-     *
196
-     * @var array $_bottom_buttons
197
-     */
198
-    protected array $_bottom_buttons = [];
199
-
200
-
201
-    /**
202
-     * Used to indicate what should be the primary column for the list table.
203
-     * If not present then falls back to what WP calculates
204
-     * as the primary column.
205
-     *
206
-     * @type string $_primary_column
207
-     */
208
-    protected string $_primary_column = '';
209
-
210
-
211
-    /**
212
-     * Used to indicate whether the table has a checkbox column or not.
213
-     *
214
-     * @type bool $_has_checkbox_column
215
-     */
216
-    protected bool $_has_checkbox_column = false;
217
-
218
-    /**
219
-     * @var AdminListTableFilters|null
220
-     */
221
-    protected ?AdminListTableFilters $admin_list_table_filters = null;
222
-
223
-    protected ?RequestInterface    $request            = null;
224
-
225
-
226
-    /**
227
-     * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
228
-     * @param AdminListTableFilters|null $filters    to display list table filters
229
-     */
230
-    public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
231
-    {
232
-        $this->request       = LoaderFactory::getShared(RequestInterface::class);
233
-        $this->_admin_page   = $admin_page;
234
-        $this->_req_data     = $this->_admin_page->get_request_data();
235
-        $this->_view         = $this->_admin_page->get_view();
236
-        $this->_views        = $this->_admin_page->get_list_table_view_RLs();
237
-        $this->_current_page = $this->get_pagenum();
238
-        $this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
239
-        $this->_yes_no       = [
240
-            esc_html__('No', 'event_espresso'),
241
-            esc_html__('Yes', 'event_espresso')
242
-        ];
243
-
244
-        $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
245
-
246
-        $this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247
-            ? $filters
248
-            : LoaderFactory::getShared(AdminListTableFilters::class);
249
-
250
-        $this->_setup_data();
251
-        $this->_add_view_counts();
252
-
253
-        $this->_nonce_action_ref = $this->_view;
254
-
255
-        $this->_set_properties();
256
-
257
-        // set primary column
258
-        add_filter('list_table_primary_column', [$this, 'set_primary_column']);
259
-
260
-        // set parent defaults
261
-        parent::__construct($this->_wp_list_args);
262
-
263
-        $this->prepare_items();
264
-    }
265
-
266
-
267
-    /**
268
-     * _setup_data
269
-     * this method is used to setup the $_data, $_all_data_count, and _per_page properties
270
-     *
271
-     * @return void
272
-     * @uses $this->_admin_page
273
-     */
274
-    abstract protected function _setup_data();
275
-
276
-
277
-    /**
278
-     * set the properties that this class needs to be able to execute wp_list_table properly
279
-     * properties set:
280
-     * _wp_list_args = what the arguments required for the parent _wp_list_table.
281
-     * _columns = set the columns in an array.
282
-     * _sortable_columns = columns that are sortable (array).
283
-     * _hidden_columns = columns that are hidden (array)
284
-     * _default_orderby = the default orderby for sorting.
285
-     *
286
-     * @abstract
287
-     * @access protected
288
-     * @return void
289
-     */
290
-    abstract protected function _set_properties();
291
-
292
-
293
-    /**
294
-     * _get_table_filters
295
-     * We use this to assemble and return any filters that are associated with this table that help further refine what
296
-     * gets shown in the table.
297
-     *
298
-     * @abstract
299
-     * @access protected
300
-     * @return string[]
301
-     */
302
-    abstract protected function _get_table_filters();
303
-
304
-
305
-    /**
306
-     * this is a method that child class will do to add counts to the views array so when views are displayed the
307
-     * counts of the views is accurate.
308
-     *
309
-     * @abstract
310
-     * @access protected
311
-     * @return void
312
-     */
313
-    abstract protected function _add_view_counts();
314
-
315
-
316
-    /**
317
-     * _get_hidden_fields
318
-     * returns a html string of hidden fields so if any table filters are used the current view will be respected.
319
-     *
320
-     * @return string
321
-     */
322
-    protected function _get_hidden_fields()
323
-    {
324
-        $action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
325
-        $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
326
-        // if action is STILL empty, then we set it to default
327
-        $action = empty($action) ? 'default' : $action;
328
-        $field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
329
-        $field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
330
-        $field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
331
-
332
-        $bulk_actions = $this->_get_bulk_actions();
333
-        foreach ($bulk_actions as $bulk_action => $label) {
334
-            $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
335
-                      . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
336
-        }
337
-
338
-        return $field;
339
-    }
340
-
341
-
342
-    /**
343
-     * _set_column_info
344
-     * we're using this to set the column headers property.
345
-     *
346
-     * @access protected
347
-     * @return void
348
-     */
349
-    protected function _set_column_info()
350
-    {
351
-        $columns   = $this->get_columns();
352
-        $hidden    = $this->get_hidden_columns();
353
-        $_sortable = $this->get_sortable_columns();
354
-
355
-        /**
356
-         * Dynamic hook allowing for adding sortable columns in this list table.
357
-         * Note that $this->screen->id is in the format
358
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
359
-         * table it is: event-espresso_page_espresso_messages.
360
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
361
-         * hook prefix ("event-espresso") will be different.
362
-         *
363
-         * @var array
364
-         */
365
-        $_sortable = apply_filters(
366
-            "FHEE_manage_{$this->screen->id}_sortable_columns",
367
-            $_sortable,
368
-            $this->_screen,
369
-            $this
370
-        );
371
-
372
-        $sortable = [];
373
-        foreach ($_sortable as $id => $data) {
374
-            if (empty($data)) {
375
-                continue;
376
-            }
377
-            // fix for offset errors with WP_List_Table default get_columninfo()
378
-            if (is_array($data)) {
379
-                $_data[0] = key($data);
380
-                $_data[1] = isset($data[1]) ? $data[1] : false;
381
-            } else {
382
-                $_data[0] = $data;
383
-            }
384
-
385
-            $data = (array) $data;
386
-
387
-            if (! isset($data[1])) {
388
-                $_data[1] = false;
389
-            }
390
-
391
-            $sortable[ $id ] = $_data;
392
-        }
393
-        $primary               = $this->get_primary_column_name();
394
-        $this->_column_headers = [$columns, $hidden, $sortable, $primary];
395
-    }
396
-
397
-
398
-    /**
399
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
400
-     *
401
-     * @return string
402
-     */
403
-    protected function get_primary_column_name()
404
-    {
405
-        foreach (class_parents($this) as $parent) {
406
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
407
-                return parent::get_primary_column_name();
408
-            }
409
-        }
410
-        return $this->_primary_column;
411
-    }
412
-
413
-
414
-    /**
415
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
416
-     *
417
-     * @param EE_Base_Class $item
418
-     * @param string        $column_name
419
-     * @param string        $primary
420
-     * @return string
421
-     */
422
-    protected function handle_row_actions($item, $column_name, $primary)
423
-    {
424
-        foreach (class_parents($this) as $parent) {
425
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
426
-                return parent::handle_row_actions($item, $column_name, $primary);
427
-            }
428
-        }
429
-        return '';
430
-    }
431
-
432
-
433
-    /**
434
-     * _get_bulk_actions
435
-     * This is a wrapper called by WP_List_Table::get_bulk_actions()
436
-     *
437
-     * @access protected
438
-     * @return array bulk_actions
439
-     */
440
-    protected function _get_bulk_actions(): array
441
-    {
442
-        $actions = [];
443
-        // the _views property should have the bulk_actions, so let's go through and extract them into a properly
444
-        // formatted array for the wp_list_table();
445
-        foreach ($this->_views as $view => $args) {
446
-            if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
447
-                // each bulk action will correspond with a admin page route, so we can check whatever the capability is
448
-                // for that page route and skip adding the bulk action if no access for the current logged in user.
449
-                foreach ($args['bulk_action'] as $route => $label) {
450
-                    if ($this->_admin_page->check_user_access($route, true)) {
451
-                        $actions[ $route ] = $label;
452
-                    }
453
-                }
454
-            }
455
-        }
456
-        return $actions;
457
-    }
458
-
459
-
460
-    /**
461
-     * Generate the table navigation above or below the table.
462
-     * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
463
-     *
464
-     * @throws EE_Error
465
-     * @since 4.9.44.rc.001
466
-     */
467
-    public function display_tablenav($which)
468
-    {
469
-        if ('top' === $which) {
470
-            wp_nonce_field('bulk-' . $this->_args['plural']);
471
-        }
472
-        ?>
27
+	const ACTION_COPY    = 'duplicate';
28
+
29
+	const ACTION_DELETE  = 'delete';
30
+
31
+	const ACTION_EDIT    = 'edit';
32
+
33
+	const ACTION_RESTORE = 'restore';
34
+
35
+	const ACTION_TRASH   = 'trash';
36
+
37
+	protected static array $actions = [
38
+		self::ACTION_COPY,
39
+		self::ACTION_DELETE,
40
+		self::ACTION_EDIT,
41
+		self::ACTION_RESTORE,
42
+		self::ACTION_TRASH,
43
+	];
44
+
45
+	/**
46
+	 * holds the data that will be processed for the table
47
+	 *
48
+	 * @var array $_data
49
+	 */
50
+	protected array $_data;
51
+
52
+
53
+	/**
54
+	 * This holds the value of all the data available for the given view (for all pages).
55
+	 *
56
+	 * @var int $_all_data_count
57
+	 */
58
+	protected int $_all_data_count;
59
+
60
+
61
+	/**
62
+	 * Will contain the count of trashed items for the view label.
63
+	 *
64
+	 * @var int $_trashed_count
65
+	 */
66
+	protected int $_trashed_count;
67
+
68
+
69
+	/**
70
+	 * This is what will be referenced as the slug for the current screen
71
+	 *
72
+	 * @var string $_screen
73
+	 */
74
+	protected string $_screen;
75
+
76
+
77
+	/**
78
+	 * this is the EE_Admin_Page object
79
+	 *
80
+	 * @var EE_Admin_Page $_admin_page
81
+	 */
82
+	protected EE_Admin_Page $_admin_page;
83
+
84
+
85
+	/**
86
+	 * The current view
87
+	 *
88
+	 * @var string $_view
89
+	 */
90
+	protected string $_view;
91
+
92
+
93
+	/**
94
+	 * array of possible views for this table
95
+	 *
96
+	 * @var array $_views
97
+	 */
98
+	protected array $_views;
99
+
100
+
101
+	/**
102
+	 * An array of key => value pairs containing information about the current table
103
+	 * array(
104
+	 *        'plural' => 'plural label',
105
+	 *        'singular' => 'singular label',
106
+	 *        'ajax' => false, //whether to use ajax or not
107
+	 *        'screen' => null, //string used to reference what screen this is
108
+	 *        (WP_List_table converts to screen object)
109
+	 * )
110
+	 *
111
+	 * @var array $_wp_list_args
112
+	 */
113
+	protected array $_wp_list_args;
114
+
115
+	/**
116
+	 * an array of column names
117
+	 * array(
118
+	 *    'internal-name' => 'Title'
119
+	 * )
120
+	 *
121
+	 * @var array $_columns
122
+	 */
123
+	protected array $_columns;
124
+
125
+	/**
126
+	 * An array of sortable columns
127
+	 * array(
128
+	 *    'internal-name' => 'orderby' //or
129
+	 *    'internal-name' => array( 'orderby', true )
130
+	 * )
131
+	 *
132
+	 * @var array $_sortable_columns
133
+	 */
134
+	protected array $_sortable_columns;
135
+
136
+	/**
137
+	 * callback method used to perform AJAX row reordering
138
+	 *
139
+	 * @var string|null $_ajax_sorting_callback
140
+	 */
141
+	protected ?string $_ajax_sorting_callback = null;
142
+
143
+	/**
144
+	 * An array of hidden columns (if needed)
145
+	 * array('internal-name', 'internal-name')
146
+	 *
147
+	 * @var array $_hidden_columns
148
+	 */
149
+	protected array $_hidden_columns;
150
+
151
+	/**
152
+	 * holds the per_page value
153
+	 *
154
+	 * @var int $_per_page
155
+	 */
156
+	protected int $_per_page;
157
+
158
+	/**
159
+	 * holds what page number is currently being viewed
160
+	 *
161
+	 * @var int $_current_page
162
+	 */
163
+	protected int $_current_page;
164
+
165
+	/**
166
+	 * the reference string for the nonce_action
167
+	 *
168
+	 * @var string $_nonce_action_ref
169
+	 */
170
+	protected string $_nonce_action_ref;
171
+
172
+	/**
173
+	 * property to hold incoming request data (as set by the admin_page_core)
174
+	 *
175
+	 * @var array $_req_data
176
+	 */
177
+	protected array $_req_data;
178
+
179
+
180
+	/**
181
+	 * yes / no array for admin form fields
182
+	 *
183
+	 * @var array $_yes_no
184
+	 */
185
+	protected array $_yes_no = [];
186
+
187
+	/**
188
+	 * Array describing buttons that should appear at the bottom of the page
189
+	 * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
190
+	 * and the values are another array with the following keys
191
+	 * array(
192
+	 *    'route' => 'page_route',
193
+	 *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
194
+	 * )
195
+	 *
196
+	 * @var array $_bottom_buttons
197
+	 */
198
+	protected array $_bottom_buttons = [];
199
+
200
+
201
+	/**
202
+	 * Used to indicate what should be the primary column for the list table.
203
+	 * If not present then falls back to what WP calculates
204
+	 * as the primary column.
205
+	 *
206
+	 * @type string $_primary_column
207
+	 */
208
+	protected string $_primary_column = '';
209
+
210
+
211
+	/**
212
+	 * Used to indicate whether the table has a checkbox column or not.
213
+	 *
214
+	 * @type bool $_has_checkbox_column
215
+	 */
216
+	protected bool $_has_checkbox_column = false;
217
+
218
+	/**
219
+	 * @var AdminListTableFilters|null
220
+	 */
221
+	protected ?AdminListTableFilters $admin_list_table_filters = null;
222
+
223
+	protected ?RequestInterface    $request            = null;
224
+
225
+
226
+	/**
227
+	 * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
228
+	 * @param AdminListTableFilters|null $filters    to display list table filters
229
+	 */
230
+	public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
231
+	{
232
+		$this->request       = LoaderFactory::getShared(RequestInterface::class);
233
+		$this->_admin_page   = $admin_page;
234
+		$this->_req_data     = $this->_admin_page->get_request_data();
235
+		$this->_view         = $this->_admin_page->get_view();
236
+		$this->_views        = $this->_admin_page->get_list_table_view_RLs();
237
+		$this->_current_page = $this->get_pagenum();
238
+		$this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
239
+		$this->_yes_no       = [
240
+			esc_html__('No', 'event_espresso'),
241
+			esc_html__('Yes', 'event_espresso')
242
+		];
243
+
244
+		$this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
245
+
246
+		$this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247
+			? $filters
248
+			: LoaderFactory::getShared(AdminListTableFilters::class);
249
+
250
+		$this->_setup_data();
251
+		$this->_add_view_counts();
252
+
253
+		$this->_nonce_action_ref = $this->_view;
254
+
255
+		$this->_set_properties();
256
+
257
+		// set primary column
258
+		add_filter('list_table_primary_column', [$this, 'set_primary_column']);
259
+
260
+		// set parent defaults
261
+		parent::__construct($this->_wp_list_args);
262
+
263
+		$this->prepare_items();
264
+	}
265
+
266
+
267
+	/**
268
+	 * _setup_data
269
+	 * this method is used to setup the $_data, $_all_data_count, and _per_page properties
270
+	 *
271
+	 * @return void
272
+	 * @uses $this->_admin_page
273
+	 */
274
+	abstract protected function _setup_data();
275
+
276
+
277
+	/**
278
+	 * set the properties that this class needs to be able to execute wp_list_table properly
279
+	 * properties set:
280
+	 * _wp_list_args = what the arguments required for the parent _wp_list_table.
281
+	 * _columns = set the columns in an array.
282
+	 * _sortable_columns = columns that are sortable (array).
283
+	 * _hidden_columns = columns that are hidden (array)
284
+	 * _default_orderby = the default orderby for sorting.
285
+	 *
286
+	 * @abstract
287
+	 * @access protected
288
+	 * @return void
289
+	 */
290
+	abstract protected function _set_properties();
291
+
292
+
293
+	/**
294
+	 * _get_table_filters
295
+	 * We use this to assemble and return any filters that are associated with this table that help further refine what
296
+	 * gets shown in the table.
297
+	 *
298
+	 * @abstract
299
+	 * @access protected
300
+	 * @return string[]
301
+	 */
302
+	abstract protected function _get_table_filters();
303
+
304
+
305
+	/**
306
+	 * this is a method that child class will do to add counts to the views array so when views are displayed the
307
+	 * counts of the views is accurate.
308
+	 *
309
+	 * @abstract
310
+	 * @access protected
311
+	 * @return void
312
+	 */
313
+	abstract protected function _add_view_counts();
314
+
315
+
316
+	/**
317
+	 * _get_hidden_fields
318
+	 * returns a html string of hidden fields so if any table filters are used the current view will be respected.
319
+	 *
320
+	 * @return string
321
+	 */
322
+	protected function _get_hidden_fields()
323
+	{
324
+		$action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
325
+		$action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
326
+		// if action is STILL empty, then we set it to default
327
+		$action = empty($action) ? 'default' : $action;
328
+		$field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
329
+		$field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
330
+		$field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
331
+
332
+		$bulk_actions = $this->_get_bulk_actions();
333
+		foreach ($bulk_actions as $bulk_action => $label) {
334
+			$field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
335
+					  . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
336
+		}
337
+
338
+		return $field;
339
+	}
340
+
341
+
342
+	/**
343
+	 * _set_column_info
344
+	 * we're using this to set the column headers property.
345
+	 *
346
+	 * @access protected
347
+	 * @return void
348
+	 */
349
+	protected function _set_column_info()
350
+	{
351
+		$columns   = $this->get_columns();
352
+		$hidden    = $this->get_hidden_columns();
353
+		$_sortable = $this->get_sortable_columns();
354
+
355
+		/**
356
+		 * Dynamic hook allowing for adding sortable columns in this list table.
357
+		 * Note that $this->screen->id is in the format
358
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
359
+		 * table it is: event-espresso_page_espresso_messages.
360
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
361
+		 * hook prefix ("event-espresso") will be different.
362
+		 *
363
+		 * @var array
364
+		 */
365
+		$_sortable = apply_filters(
366
+			"FHEE_manage_{$this->screen->id}_sortable_columns",
367
+			$_sortable,
368
+			$this->_screen,
369
+			$this
370
+		);
371
+
372
+		$sortable = [];
373
+		foreach ($_sortable as $id => $data) {
374
+			if (empty($data)) {
375
+				continue;
376
+			}
377
+			// fix for offset errors with WP_List_Table default get_columninfo()
378
+			if (is_array($data)) {
379
+				$_data[0] = key($data);
380
+				$_data[1] = isset($data[1]) ? $data[1] : false;
381
+			} else {
382
+				$_data[0] = $data;
383
+			}
384
+
385
+			$data = (array) $data;
386
+
387
+			if (! isset($data[1])) {
388
+				$_data[1] = false;
389
+			}
390
+
391
+			$sortable[ $id ] = $_data;
392
+		}
393
+		$primary               = $this->get_primary_column_name();
394
+		$this->_column_headers = [$columns, $hidden, $sortable, $primary];
395
+	}
396
+
397
+
398
+	/**
399
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
400
+	 *
401
+	 * @return string
402
+	 */
403
+	protected function get_primary_column_name()
404
+	{
405
+		foreach (class_parents($this) as $parent) {
406
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
407
+				return parent::get_primary_column_name();
408
+			}
409
+		}
410
+		return $this->_primary_column;
411
+	}
412
+
413
+
414
+	/**
415
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
416
+	 *
417
+	 * @param EE_Base_Class $item
418
+	 * @param string        $column_name
419
+	 * @param string        $primary
420
+	 * @return string
421
+	 */
422
+	protected function handle_row_actions($item, $column_name, $primary)
423
+	{
424
+		foreach (class_parents($this) as $parent) {
425
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
426
+				return parent::handle_row_actions($item, $column_name, $primary);
427
+			}
428
+		}
429
+		return '';
430
+	}
431
+
432
+
433
+	/**
434
+	 * _get_bulk_actions
435
+	 * This is a wrapper called by WP_List_Table::get_bulk_actions()
436
+	 *
437
+	 * @access protected
438
+	 * @return array bulk_actions
439
+	 */
440
+	protected function _get_bulk_actions(): array
441
+	{
442
+		$actions = [];
443
+		// the _views property should have the bulk_actions, so let's go through and extract them into a properly
444
+		// formatted array for the wp_list_table();
445
+		foreach ($this->_views as $view => $args) {
446
+			if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
447
+				// each bulk action will correspond with a admin page route, so we can check whatever the capability is
448
+				// for that page route and skip adding the bulk action if no access for the current logged in user.
449
+				foreach ($args['bulk_action'] as $route => $label) {
450
+					if ($this->_admin_page->check_user_access($route, true)) {
451
+						$actions[ $route ] = $label;
452
+					}
453
+				}
454
+			}
455
+		}
456
+		return $actions;
457
+	}
458
+
459
+
460
+	/**
461
+	 * Generate the table navigation above or below the table.
462
+	 * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
463
+	 *
464
+	 * @throws EE_Error
465
+	 * @since 4.9.44.rc.001
466
+	 */
467
+	public function display_tablenav($which)
468
+	{
469
+		if ('top' === $which) {
470
+			wp_nonce_field('bulk-' . $this->_args['plural']);
471
+		}
472
+		?>
473 473
         <div class="tablenav <?php echo esc_attr($which); ?>">
474 474
             <?php if ($this->_get_bulk_actions()) { ?>
475 475
                 <div class="alignleft actions bulkactions">
476 476
                     <?php $this->bulk_actions(); ?>
477 477
                 </div>
478 478
             <?php }
479
-            $this->extra_tablenav($which);
480
-            $this->pagination($which);
481
-            ?>
479
+			$this->extra_tablenav($which);
480
+			$this->pagination($which);
481
+			?>
482 482
 
483 483
             <br class="clear" />
484 484
         </div>
485 485
         <?php
486
-    }
487
-
488
-
489
-    /**
490
-     * _filters
491
-     * This receives the filters array from children _get_table_filters() and assembles the string including the filter
492
-     * button.
493
-     *
494
-     * @access private
495
-     * @return void  echos html showing filters
496
-     */
497
-    private function _filters(): void
498
-    {
499
-        $classname = get_class($this);
500
-        $filters   = apply_filters(
501
-            "FHEE__{$classname}__filters",
502
-            $this->_get_table_filters(),
503
-            $this,
504
-            $this->_screen
505
-        );
506
-
507
-        if (empty($filters)) {
508
-            return;
509
-        }
510
-
511
-        $this->admin_list_table_filters->filters(
512
-            $filters,
513
-            $this->get_admin_page()->get_current_page_view_url()
514
-        );
515
-    }
516
-
517
-
518
-    /**
519
-     * Callback for 'list_table_primary_column' WordPress filter
520
-     * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
521
-     * column when class is instantiated.
522
-     *
523
-     * @param string $column_name
524
-     * @return string
525
-     * @see WP_List_Table::get_primary_column_name
526
-     */
527
-    public function set_primary_column($column_name)
528
-    {
529
-        return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
530
-    }
531
-
532
-
533
-    /**
534
-     *
535
-     */
536
-    public function prepare_items()
537
-    {
538
-        $this->_set_column_info();
539
-        $this->process_bulk_action();
540
-
541
-        $this->items = $this->_data;
542
-        $this->set_pagination_args(
543
-            [
544
-                'total_items' => $this->_all_data_count,
545
-                'per_page'    => $this->_per_page,
546
-                'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
547
-            ]
548
-        );
549
-    }
550
-
551
-
552
-    /**
553
-     * @param object|array $item
554
-     * @return string html content for the column
555
-     */
556
-    protected function column_cb($item)
557
-    {
558
-        return '';
559
-    }
560
-
561
-
562
-    /**
563
-     * This column is the default for when there is no defined column method for a registered column.
564
-     * This can be overridden by child classes, but allows for hooking in for custom columns.
565
-     *
566
-     * @param EE_Base_Class $item
567
-     * @param string        $column_name The column being called.
568
-     * @return string html content for the column
569
-     */
570
-    public function column_default($item, $column_name)
571
-    {
572
-        /**
573
-         * Dynamic hook allowing for adding additional column content in this list table.
574
-         * Note that $this->screen->id is in the format
575
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
576
-         * table it is: event-espresso_page_espresso_messages.
577
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
578
-         * hook prefix ("event-espresso") will be different.
579
-         */
580
-        ob_start();
581
-        do_action(
582
-            'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
583
-            $item,
584
-            $this->_screen
585
-        );
586
-        $content = ob_get_clean();
587
-        return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
588
-    }
589
-
590
-
591
-    /**
592
-     * Get a list of columns. The format is:
593
-     * 'internal-name' => 'Title'
594
-     *
595
-     * @return array
596
-     * @since  3.1.0
597
-     * @access public
598
-     * @abstract
599
-     */
600
-    public function get_columns()
601
-    {
602
-        /**
603
-         * Dynamic hook allowing for adding additional columns in this list table.
604
-         * Note that $this->screen->id is in the format
605
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
606
-         * table it is: event-espresso_page_espresso_messages.
607
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
608
-         * hook prefix ("event-espresso") will be different.
609
-         *
610
-         * @var array
611
-         */
612
-        return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
613
-    }
614
-
615
-
616
-    /**
617
-     * Get an associative array ( id => link ) with the list
618
-     * of views available on this table.
619
-     *
620
-     * @return array
621
-     * @since  3.1.0
622
-     * @access protected
623
-     */
624
-    public function get_views()
625
-    {
626
-        return $this->_views;
627
-    }
628
-
629
-
630
-    /**
631
-     * Generate the views html.
632
-     */
633
-    public function display_views()
634
-    {
635
-        $views           = $this->get_views();
636
-        $assembled_views = [];
637
-
638
-        if (empty($views)) {
639
-            return;
640
-        }
641
-        echo "<ul class='subsubsub'>\n";
642
-        foreach ($views as $view) {
643
-            $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
644
-            if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
645
-                $filter = "<li";
646
-                $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
647
-                $filter .= ">";
648
-                $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
649
-                $filter .= '<span class="count">(' . $count . ')</span>';
650
-                $filter .= '</li>';
651
-                $assembled_views[ $view['slug'] ] = $filter;
652
-            }
653
-        }
654
-
655
-        echo ! empty($assembled_views)
656
-            ? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
657
-            : '';
658
-        echo "</ul>";
659
-    }
660
-
661
-
662
-    /**
663
-     * Generates content for a single row of the table
664
-     *
665
-     * @param EE_Base_Class $item The current item
666
-     * @since  4.1
667
-     * @access public
668
-     */
669
-    public function single_row($item)
670
-    {
671
-        $row_class = $this->_get_row_class($item);
672
-        echo '<tr class="' . esc_attr($row_class) . '">';
673
-        $this->single_row_columns($item); // already escaped
674
-        echo '</tr>';
675
-    }
676
-
677
-
678
-    /**
679
-     * This simply sets up the row class for the table rows.
680
-     * Allows for easier overriding of child methods for setting up sorting.
681
-     *
682
-     * @param EE_Base_Class $item the current item
683
-     * @return string
684
-     */
685
-    protected function _get_row_class($item)
686
-    {
687
-        static $row_class = '';
688
-        $row_class = ($row_class === '' ? 'alternate' : '');
689
-
690
-        $new_row_class = $row_class;
691
-
692
-        if (! empty($this->_ajax_sorting_callback)) {
693
-            $new_row_class .= ' rowsortable';
694
-        }
695
-
696
-        return $new_row_class;
697
-    }
698
-
699
-
700
-    /**
701
-     * @return array
702
-     */
703
-    public function get_sortable_columns()
704
-    {
705
-        return (array) $this->_sortable_columns;
706
-    }
707
-
708
-
709
-    /**
710
-     * @return string
711
-     */
712
-    public function get_ajax_sorting_callback()
713
-    {
714
-        return $this->_ajax_sorting_callback;
715
-    }
716
-
717
-
718
-    /**
719
-     * @return array
720
-     */
721
-    public function get_hidden_columns()
722
-    {
723
-        $user_id     = get_current_user_id();
724
-        $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
725
-        if (empty($has_default) && ! empty($this->_hidden_columns)) {
726
-            update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
727
-            update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
728
-        }
729
-        $ref = 'manage' . $this->screen->id . 'columnshidden';
730
-        return (array) get_user_option($ref, $user_id);
731
-    }
732
-
733
-
734
-    /**
735
-     * Generates the columns for a single row of the table.
736
-     * Overridden from wp_list_table so as to allow us to filter the column content for a given
737
-     * column.
738
-     *
739
-     * @param EE_Base_Class $item The current item
740
-     * @since 3.1.0
741
-     */
742
-    public function single_row_columns($item)
743
-    {
744
-        [$columns, $hidden, $sortable, $primary] = $this->get_column_info();
745
-
746
-        foreach ($columns as $column_name => $column_display_name) {
747
-
748
-            /**
749
-             * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
750
-             * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
751
-             */
752
-            $hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
753
-
754
-            $classes = $column_name . ' column-' . $column_name . $hidden_class;
755
-            if ($primary === $column_name) {
756
-                $classes .= ' has-row-actions column-primary';
757
-            }
758
-
759
-            $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
760
-
761
-            $class = 'class="' . esc_attr($classes) . '"';
762
-
763
-            $attributes = "{$class}{$data}";
764
-
765
-            if ($column_name === 'cb') {
766
-                echo '<th scope="row" class="check-column">';
767
-                echo apply_filters(
768
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
769
-                    $this->column_cb($item), // already escaped
770
-                    $item,
771
-                    $this
772
-                );
773
-                echo '</th>';
774
-            } elseif (method_exists($this, "column_$column_name")) {
775
-                echo "<td $attributes>"; // already escaped
776
-                echo apply_filters(
777
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
778
-                    call_user_func([$this, "column_$column_name"], $item),
779
-                    $item,
780
-                    $this
781
-                );
782
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
783
-                echo "</td>";
784
-            } else {
785
-                echo "<td $attributes>"; // already escaped
786
-                echo apply_filters(
787
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
788
-                    $this->column_default($item, $column_name),
789
-                    $item,
790
-                    $column_name,
791
-                    $this
792
-                );
793
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
794
-                echo "</td>";
795
-            }
796
-        }
797
-    }
798
-
799
-
800
-    /**
801
-     * Extra controls to be displayed between bulk actions and pagination
802
-     *
803
-     * @access public
804
-     * @param string $which
805
-     * @throws EE_Error
806
-     */
807
-    public function extra_tablenav($which)
808
-    {
809
-        if ($which === 'top') {
810
-            $this->_filters();
811
-            echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
812
-        } else {
813
-            echo '<div class="list-table-bottom-buttons alignleft actions">';
814
-            foreach ($this->_bottom_buttons as $type => $action) {
815
-                $route         = $action['route'] ?? '';
816
-                $extra_request = $action['extra_request'] ?? [];
817
-                $btn_class     = $action['btn_class'] ?? 'button button--secondary';
818
-                // already escaped
819
-                echo wp_kses($this->_admin_page->get_action_link_or_button(
820
-                    $route,
821
-                    $type,
822
-                    $extra_request,
823
-                    $btn_class
824
-                ), AllowedTags::getWithFormTags());
825
-            }
826
-            do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
827
-            echo '</div>';
828
-        }
829
-    }
830
-
831
-
832
-    /**
833
-     * Get an associative array ( option_name => option_title ) with the list
834
-     * of bulk actions available on this table.
835
-     *
836
-     * @return array
837
-     * @since  3.1.0
838
-     * @access protected
839
-     */
840
-    public function get_bulk_actions()
841
-    {
842
-        return (array) $this->_get_bulk_actions();
843
-    }
844
-
845
-
846
-    /**
847
-     * Processing bulk actions.
848
-     */
849
-    public function process_bulk_action()
850
-    {
851
-        // this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
852
-        // reference in case there is a case where it gets used.
853
-    }
854
-
855
-
856
-    /**
857
-     * returns the EE admin page this list table is associated with
858
-     *
859
-     * @return EE_Admin_Page
860
-     */
861
-    public function get_admin_page()
862
-    {
863
-        return $this->_admin_page;
864
-    }
865
-
866
-
867
-    /**
868
-     * A "helper" function for all children to provide an html string of
869
-     * actions to output in their content.  It is preferable for child classes
870
-     * to use this method for generating their actions content so that it's
871
-     * filterable by plugins
872
-     *
873
-     * @param string        $action_container           what are the html container
874
-     *                                                  elements for this actions string?
875
-     * @param string        $action_class               What class is for the container
876
-     *                                                  element.
877
-     * @param string        $action_items               The contents for the action items
878
-     *                                                  container.  This is filtered before
879
-     *                                                  returned.
880
-     * @param string        $action_id                  What id (optional) is used for the
881
-     *                                                  container element.
882
-     * @param EE_Base_Class $item                       The object for the column displaying
883
-     *                                                  the actions.
884
-     * @return string The assembled action elements container.
885
-     */
886
-    protected function _action_string(
887
-        $action_items,
888
-        $item,
889
-        $action_container = 'ul',
890
-        $action_class = '',
891
-        $action_id = ''
892
-    ) {
893
-        $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
894
-        $action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
895
-        $open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
896
-        $close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
897
-        try {
898
-            $content = apply_filters(
899
-                'FHEE__EE_Admin_List_Table___action_string__action_items',
900
-                $action_items,
901
-                $item,
902
-                $this
903
-            );
904
-        } catch (Exception $e) {
905
-            if (WP_DEBUG) {
906
-                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
907
-            }
908
-            $content = $action_items;
909
-        }
910
-        return "{$open_tag}{$content}{$close_tag}";
911
-    }
912
-
913
-
914
-    /**
915
-     * @return string
916
-     */
917
-    protected function getReturnUrl()
918
-    {
919
-        $host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
920
-        $uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
921
-        return urlencode(esc_url_raw("//{$host}{$uri}"));
922
-    }
923
-
924
-
925
-    /**
926
-     * @param string $id
927
-     * @param string $content
928
-     * @param string $align     start (default), center, end
929
-     * @return string
930
-     * @since   5.0.0.p
931
-     */
932
-    protected function columnContent($id, $content, $align = 'start')
933
-    {
934
-        if (! isset($this->_columns[ $id ])) {
935
-            throw new DomainException('missing column id');
936
-        }
937
-        $heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
938
-        $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
939
-        $align = "ee-responsive-table-cell--{$align}";
940
-
941
-        $html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>";
942
-        $html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>";
943
-        $html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>";
944
-        $html .= "</div>";
945
-        return $html;
946
-    }
947
-
948
-
949
-    protected function actionsModalMenu($actions): string
950
-    {
951
-        return '
486
+	}
487
+
488
+
489
+	/**
490
+	 * _filters
491
+	 * This receives the filters array from children _get_table_filters() and assembles the string including the filter
492
+	 * button.
493
+	 *
494
+	 * @access private
495
+	 * @return void  echos html showing filters
496
+	 */
497
+	private function _filters(): void
498
+	{
499
+		$classname = get_class($this);
500
+		$filters   = apply_filters(
501
+			"FHEE__{$classname}__filters",
502
+			$this->_get_table_filters(),
503
+			$this,
504
+			$this->_screen
505
+		);
506
+
507
+		if (empty($filters)) {
508
+			return;
509
+		}
510
+
511
+		$this->admin_list_table_filters->filters(
512
+			$filters,
513
+			$this->get_admin_page()->get_current_page_view_url()
514
+		);
515
+	}
516
+
517
+
518
+	/**
519
+	 * Callback for 'list_table_primary_column' WordPress filter
520
+	 * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
521
+	 * column when class is instantiated.
522
+	 *
523
+	 * @param string $column_name
524
+	 * @return string
525
+	 * @see WP_List_Table::get_primary_column_name
526
+	 */
527
+	public function set_primary_column($column_name)
528
+	{
529
+		return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
530
+	}
531
+
532
+
533
+	/**
534
+	 *
535
+	 */
536
+	public function prepare_items()
537
+	{
538
+		$this->_set_column_info();
539
+		$this->process_bulk_action();
540
+
541
+		$this->items = $this->_data;
542
+		$this->set_pagination_args(
543
+			[
544
+				'total_items' => $this->_all_data_count,
545
+				'per_page'    => $this->_per_page,
546
+				'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
547
+			]
548
+		);
549
+	}
550
+
551
+
552
+	/**
553
+	 * @param object|array $item
554
+	 * @return string html content for the column
555
+	 */
556
+	protected function column_cb($item)
557
+	{
558
+		return '';
559
+	}
560
+
561
+
562
+	/**
563
+	 * This column is the default for when there is no defined column method for a registered column.
564
+	 * This can be overridden by child classes, but allows for hooking in for custom columns.
565
+	 *
566
+	 * @param EE_Base_Class $item
567
+	 * @param string        $column_name The column being called.
568
+	 * @return string html content for the column
569
+	 */
570
+	public function column_default($item, $column_name)
571
+	{
572
+		/**
573
+		 * Dynamic hook allowing for adding additional column content in this list table.
574
+		 * Note that $this->screen->id is in the format
575
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
576
+		 * table it is: event-espresso_page_espresso_messages.
577
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
578
+		 * hook prefix ("event-espresso") will be different.
579
+		 */
580
+		ob_start();
581
+		do_action(
582
+			'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
583
+			$item,
584
+			$this->_screen
585
+		);
586
+		$content = ob_get_clean();
587
+		return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
588
+	}
589
+
590
+
591
+	/**
592
+	 * Get a list of columns. The format is:
593
+	 * 'internal-name' => 'Title'
594
+	 *
595
+	 * @return array
596
+	 * @since  3.1.0
597
+	 * @access public
598
+	 * @abstract
599
+	 */
600
+	public function get_columns()
601
+	{
602
+		/**
603
+		 * Dynamic hook allowing for adding additional columns in this list table.
604
+		 * Note that $this->screen->id is in the format
605
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
606
+		 * table it is: event-espresso_page_espresso_messages.
607
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
608
+		 * hook prefix ("event-espresso") will be different.
609
+		 *
610
+		 * @var array
611
+		 */
612
+		return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
613
+	}
614
+
615
+
616
+	/**
617
+	 * Get an associative array ( id => link ) with the list
618
+	 * of views available on this table.
619
+	 *
620
+	 * @return array
621
+	 * @since  3.1.0
622
+	 * @access protected
623
+	 */
624
+	public function get_views()
625
+	{
626
+		return $this->_views;
627
+	}
628
+
629
+
630
+	/**
631
+	 * Generate the views html.
632
+	 */
633
+	public function display_views()
634
+	{
635
+		$views           = $this->get_views();
636
+		$assembled_views = [];
637
+
638
+		if (empty($views)) {
639
+			return;
640
+		}
641
+		echo "<ul class='subsubsub'>\n";
642
+		foreach ($views as $view) {
643
+			$count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
644
+			if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
645
+				$filter = "<li";
646
+				$filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
647
+				$filter .= ">";
648
+				$filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
649
+				$filter .= '<span class="count">(' . $count . ')</span>';
650
+				$filter .= '</li>';
651
+				$assembled_views[ $view['slug'] ] = $filter;
652
+			}
653
+		}
654
+
655
+		echo ! empty($assembled_views)
656
+			? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
657
+			: '';
658
+		echo "</ul>";
659
+	}
660
+
661
+
662
+	/**
663
+	 * Generates content for a single row of the table
664
+	 *
665
+	 * @param EE_Base_Class $item The current item
666
+	 * @since  4.1
667
+	 * @access public
668
+	 */
669
+	public function single_row($item)
670
+	{
671
+		$row_class = $this->_get_row_class($item);
672
+		echo '<tr class="' . esc_attr($row_class) . '">';
673
+		$this->single_row_columns($item); // already escaped
674
+		echo '</tr>';
675
+	}
676
+
677
+
678
+	/**
679
+	 * This simply sets up the row class for the table rows.
680
+	 * Allows for easier overriding of child methods for setting up sorting.
681
+	 *
682
+	 * @param EE_Base_Class $item the current item
683
+	 * @return string
684
+	 */
685
+	protected function _get_row_class($item)
686
+	{
687
+		static $row_class = '';
688
+		$row_class = ($row_class === '' ? 'alternate' : '');
689
+
690
+		$new_row_class = $row_class;
691
+
692
+		if (! empty($this->_ajax_sorting_callback)) {
693
+			$new_row_class .= ' rowsortable';
694
+		}
695
+
696
+		return $new_row_class;
697
+	}
698
+
699
+
700
+	/**
701
+	 * @return array
702
+	 */
703
+	public function get_sortable_columns()
704
+	{
705
+		return (array) $this->_sortable_columns;
706
+	}
707
+
708
+
709
+	/**
710
+	 * @return string
711
+	 */
712
+	public function get_ajax_sorting_callback()
713
+	{
714
+		return $this->_ajax_sorting_callback;
715
+	}
716
+
717
+
718
+	/**
719
+	 * @return array
720
+	 */
721
+	public function get_hidden_columns()
722
+	{
723
+		$user_id     = get_current_user_id();
724
+		$has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
725
+		if (empty($has_default) && ! empty($this->_hidden_columns)) {
726
+			update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
727
+			update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
728
+		}
729
+		$ref = 'manage' . $this->screen->id . 'columnshidden';
730
+		return (array) get_user_option($ref, $user_id);
731
+	}
732
+
733
+
734
+	/**
735
+	 * Generates the columns for a single row of the table.
736
+	 * Overridden from wp_list_table so as to allow us to filter the column content for a given
737
+	 * column.
738
+	 *
739
+	 * @param EE_Base_Class $item The current item
740
+	 * @since 3.1.0
741
+	 */
742
+	public function single_row_columns($item)
743
+	{
744
+		[$columns, $hidden, $sortable, $primary] = $this->get_column_info();
745
+
746
+		foreach ($columns as $column_name => $column_display_name) {
747
+
748
+			/**
749
+			 * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
750
+			 * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
751
+			 */
752
+			$hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
753
+
754
+			$classes = $column_name . ' column-' . $column_name . $hidden_class;
755
+			if ($primary === $column_name) {
756
+				$classes .= ' has-row-actions column-primary';
757
+			}
758
+
759
+			$data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
760
+
761
+			$class = 'class="' . esc_attr($classes) . '"';
762
+
763
+			$attributes = "{$class}{$data}";
764
+
765
+			if ($column_name === 'cb') {
766
+				echo '<th scope="row" class="check-column">';
767
+				echo apply_filters(
768
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
769
+					$this->column_cb($item), // already escaped
770
+					$item,
771
+					$this
772
+				);
773
+				echo '</th>';
774
+			} elseif (method_exists($this, "column_$column_name")) {
775
+				echo "<td $attributes>"; // already escaped
776
+				echo apply_filters(
777
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
778
+					call_user_func([$this, "column_$column_name"], $item),
779
+					$item,
780
+					$this
781
+				);
782
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
783
+				echo "</td>";
784
+			} else {
785
+				echo "<td $attributes>"; // already escaped
786
+				echo apply_filters(
787
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
788
+					$this->column_default($item, $column_name),
789
+					$item,
790
+					$column_name,
791
+					$this
792
+				);
793
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
794
+				echo "</td>";
795
+			}
796
+		}
797
+	}
798
+
799
+
800
+	/**
801
+	 * Extra controls to be displayed between bulk actions and pagination
802
+	 *
803
+	 * @access public
804
+	 * @param string $which
805
+	 * @throws EE_Error
806
+	 */
807
+	public function extra_tablenav($which)
808
+	{
809
+		if ($which === 'top') {
810
+			$this->_filters();
811
+			echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
812
+		} else {
813
+			echo '<div class="list-table-bottom-buttons alignleft actions">';
814
+			foreach ($this->_bottom_buttons as $type => $action) {
815
+				$route         = $action['route'] ?? '';
816
+				$extra_request = $action['extra_request'] ?? [];
817
+				$btn_class     = $action['btn_class'] ?? 'button button--secondary';
818
+				// already escaped
819
+				echo wp_kses($this->_admin_page->get_action_link_or_button(
820
+					$route,
821
+					$type,
822
+					$extra_request,
823
+					$btn_class
824
+				), AllowedTags::getWithFormTags());
825
+			}
826
+			do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
827
+			echo '</div>';
828
+		}
829
+	}
830
+
831
+
832
+	/**
833
+	 * Get an associative array ( option_name => option_title ) with the list
834
+	 * of bulk actions available on this table.
835
+	 *
836
+	 * @return array
837
+	 * @since  3.1.0
838
+	 * @access protected
839
+	 */
840
+	public function get_bulk_actions()
841
+	{
842
+		return (array) $this->_get_bulk_actions();
843
+	}
844
+
845
+
846
+	/**
847
+	 * Processing bulk actions.
848
+	 */
849
+	public function process_bulk_action()
850
+	{
851
+		// this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
852
+		// reference in case there is a case where it gets used.
853
+	}
854
+
855
+
856
+	/**
857
+	 * returns the EE admin page this list table is associated with
858
+	 *
859
+	 * @return EE_Admin_Page
860
+	 */
861
+	public function get_admin_page()
862
+	{
863
+		return $this->_admin_page;
864
+	}
865
+
866
+
867
+	/**
868
+	 * A "helper" function for all children to provide an html string of
869
+	 * actions to output in their content.  It is preferable for child classes
870
+	 * to use this method for generating their actions content so that it's
871
+	 * filterable by plugins
872
+	 *
873
+	 * @param string        $action_container           what are the html container
874
+	 *                                                  elements for this actions string?
875
+	 * @param string        $action_class               What class is for the container
876
+	 *                                                  element.
877
+	 * @param string        $action_items               The contents for the action items
878
+	 *                                                  container.  This is filtered before
879
+	 *                                                  returned.
880
+	 * @param string        $action_id                  What id (optional) is used for the
881
+	 *                                                  container element.
882
+	 * @param EE_Base_Class $item                       The object for the column displaying
883
+	 *                                                  the actions.
884
+	 * @return string The assembled action elements container.
885
+	 */
886
+	protected function _action_string(
887
+		$action_items,
888
+		$item,
889
+		$action_container = 'ul',
890
+		$action_class = '',
891
+		$action_id = ''
892
+	) {
893
+		$action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
894
+		$action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
895
+		$open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
896
+		$close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
897
+		try {
898
+			$content = apply_filters(
899
+				'FHEE__EE_Admin_List_Table___action_string__action_items',
900
+				$action_items,
901
+				$item,
902
+				$this
903
+			);
904
+		} catch (Exception $e) {
905
+			if (WP_DEBUG) {
906
+				EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
907
+			}
908
+			$content = $action_items;
909
+		}
910
+		return "{$open_tag}{$content}{$close_tag}";
911
+	}
912
+
913
+
914
+	/**
915
+	 * @return string
916
+	 */
917
+	protected function getReturnUrl()
918
+	{
919
+		$host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
920
+		$uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
921
+		return urlencode(esc_url_raw("//{$host}{$uri}"));
922
+	}
923
+
924
+
925
+	/**
926
+	 * @param string $id
927
+	 * @param string $content
928
+	 * @param string $align     start (default), center, end
929
+	 * @return string
930
+	 * @since   5.0.0.p
931
+	 */
932
+	protected function columnContent($id, $content, $align = 'start')
933
+	{
934
+		if (! isset($this->_columns[ $id ])) {
935
+			throw new DomainException('missing column id');
936
+		}
937
+		$heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
938
+		$align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
939
+		$align = "ee-responsive-table-cell--{$align}";
940
+
941
+		$html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>";
942
+		$html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>";
943
+		$html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>";
944
+		$html .= "</div>";
945
+		return $html;
946
+	}
947
+
948
+
949
+	protected function actionsModalMenu($actions): string
950
+	{
951
+		return '
952 952
         <div class="ee-modal-menu">
953 953
             <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip"
954 954
                     aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '"
@@ -960,43 +960,43 @@  discard block
 block discarded – undo
960 960
                 ' . $actions . '
961 961
             </div>
962 962
         </div>';
963
-    }
963
+	}
964 964
 
965 965
 
966
-    public function actionsColumnHeader(): string
967
-    {
968
-        return '
966
+	public function actionsColumnHeader(): string
967
+	{
968
+		return '
969 969
             <span class="ee-actions-column-header-wrap">
970 970
                 <span class="dashicons dashicons-screenoptions"></span>
971 971
                 <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span>
972 972
             </span>';
973
-    }
974
-
975
-
976
-    protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
977
-    {
978
-        $class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
979
-        $class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
980
-        $label = ! empty($label) ? " aria-label='{$label}'" : '';
981
-        return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
982
-    }
983
-
984
-    /**
985
-     * Override the search box method of WP List Table to include a reset button
986
-     *
987
-     * @param string $text     The 'submit' button label.
988
-     * @param string $input_id ID attribute value for the search input field.
989
-     */
990
-    public function search_box($text, $input_id)
991
-    {
992
-        if (empty($_REQUEST['s']) && ! $this->has_items()) {
993
-            return;
994
-        }
995
-
996
-        $this->admin_list_table_filters->searchBox(
997
-            $text,
998
-            $input_id,
999
-            $this->get_admin_page()->get_current_page_view_url()
1000
-        );
1001
-    }
973
+	}
974
+
975
+
976
+	protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
977
+	{
978
+		$class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
979
+		$class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
980
+		$label = ! empty($label) ? " aria-label='{$label}'" : '';
981
+		return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
982
+	}
983
+
984
+	/**
985
+	 * Override the search box method of WP List Table to include a reset button
986
+	 *
987
+	 * @param string $text     The 'submit' button label.
988
+	 * @param string $input_id ID attribute value for the search input field.
989
+	 */
990
+	public function search_box($text, $input_id)
991
+	{
992
+		if (empty($_REQUEST['s']) && ! $this->has_items()) {
993
+			return;
994
+		}
995
+
996
+		$this->admin_list_table_filters->searchBox(
997
+			$text,
998
+			$input_id,
999
+			$this->get_admin_page()->get_current_page_view_url()
1000
+		);
1001
+	}
1002 1002
 }
Please login to merge, or discard this patch.
Spacing   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -5,8 +5,8 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\services\request\RequestInterface;
6 6
 use EventEspresso\core\services\request\sanitizers\AllowedTags;
7 7
 
8
-if (! class_exists('WP_List_Table')) {
9
-    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
8
+if ( ! class_exists('WP_List_Table')) {
9
+    require_once ABSPATH.'wp-admin/includes/class-wp-list-table.php';
10 10
 }
11 11
 
12 12
 
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
      */
221 221
     protected ?AdminListTableFilters $admin_list_table_filters = null;
222 222
 
223
-    protected ?RequestInterface    $request            = null;
223
+    protected ?RequestInterface    $request = null;
224 224
 
225 225
 
226 226
     /**
@@ -235,13 +235,13 @@  discard block
 block discarded – undo
235 235
         $this->_view         = $this->_admin_page->get_view();
236 236
         $this->_views        = $this->_admin_page->get_list_table_view_RLs();
237 237
         $this->_current_page = $this->get_pagenum();
238
-        $this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
238
+        $this->_screen       = $this->_admin_page->get_current_page().'_'.$this->_admin_page->get_current_view();
239 239
         $this->_yes_no       = [
240 240
             esc_html__('No', 'event_espresso'),
241 241
             esc_html__('Yes', 'event_espresso')
242 242
         ];
243 243
 
244
-        $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
244
+        $this->_per_page = $this->get_items_per_page($this->_screen.'_per_page');
245 245
 
246 246
         $this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247 247
             ? $filters
@@ -325,14 +325,14 @@  discard block
 block discarded – undo
325 325
         $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
326 326
         // if action is STILL empty, then we set it to default
327 327
         $action = empty($action) ? 'default' : $action;
328
-        $field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
329
-        $field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
330
-        $field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
328
+        $field  = '<input type="hidden" name="page" value="'.esc_attr($this->_req_data['page']).'" />'."\n";
329
+        $field  .= '<input type="hidden" name="route" value="'.esc_attr($action).'" />'."\n";
330
+        $field  .= '<input type="hidden" name="perpage" value="'.esc_attr($this->_per_page).'" />'."\n";
331 331
 
332 332
         $bulk_actions = $this->_get_bulk_actions();
333 333
         foreach ($bulk_actions as $bulk_action => $label) {
334
-            $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
335
-                      . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
334
+            $field .= '<input type="hidden" name="'.$bulk_action.'_nonce"'
335
+                      . ' value="'.wp_create_nonce($bulk_action.'_nonce').'" />'."\n";
336 336
         }
337 337
 
338 338
         return $field;
@@ -384,11 +384,11 @@  discard block
 block discarded – undo
384 384
 
385 385
             $data = (array) $data;
386 386
 
387
-            if (! isset($data[1])) {
387
+            if ( ! isset($data[1])) {
388 388
                 $_data[1] = false;
389 389
             }
390 390
 
391
-            $sortable[ $id ] = $_data;
391
+            $sortable[$id] = $_data;
392 392
         }
393 393
         $primary               = $this->get_primary_column_name();
394 394
         $this->_column_headers = [$columns, $hidden, $sortable, $primary];
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
                 // for that page route and skip adding the bulk action if no access for the current logged in user.
449 449
                 foreach ($args['bulk_action'] as $route => $label) {
450 450
                     if ($this->_admin_page->check_user_access($route, true)) {
451
-                        $actions[ $route ] = $label;
451
+                        $actions[$route] = $label;
452 452
                     }
453 453
                 }
454 454
             }
@@ -467,7 +467,7 @@  discard block
 block discarded – undo
467 467
     public function display_tablenav($which)
468 468
     {
469 469
         if ('top' === $which) {
470
-            wp_nonce_field('bulk-' . $this->_args['plural']);
470
+            wp_nonce_field('bulk-'.$this->_args['plural']);
471 471
         }
472 472
         ?>
473 473
         <div class="tablenav <?php echo esc_attr($which); ?>">
@@ -579,7 +579,7 @@  discard block
 block discarded – undo
579 579
          */
580 580
         ob_start();
581 581
         do_action(
582
-            'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
582
+            'AHEE__EE_Admin_List_Table__column_'.$column_name.'__'.$this->screen->id,
583 583
             $item,
584 584
             $this->_screen
585 585
         );
@@ -643,12 +643,12 @@  discard block
 block discarded – undo
643 643
             $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
644 644
             if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
645 645
                 $filter = "<li";
646
-                $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
646
+                $filter .= $view['class'] ? " class='".esc_attr($view['class'])."'" : '';
647 647
                 $filter .= ">";
648
-                $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
649
-                $filter .= '<span class="count">(' . $count . ')</span>';
648
+                $filter .= '<a href="'.esc_url_raw($view['url']).'">'.esc_html($view['label']).'</a>';
649
+                $filter .= '<span class="count">('.$count.')</span>';
650 650
                 $filter .= '</li>';
651
-                $assembled_views[ $view['slug'] ] = $filter;
651
+                $assembled_views[$view['slug']] = $filter;
652 652
             }
653 653
         }
654 654
 
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
     public function single_row($item)
670 670
     {
671 671
         $row_class = $this->_get_row_class($item);
672
-        echo '<tr class="' . esc_attr($row_class) . '">';
672
+        echo '<tr class="'.esc_attr($row_class).'">';
673 673
         $this->single_row_columns($item); // already escaped
674 674
         echo '</tr>';
675 675
     }
@@ -689,7 +689,7 @@  discard block
 block discarded – undo
689 689
 
690 690
         $new_row_class = $row_class;
691 691
 
692
-        if (! empty($this->_ajax_sorting_callback)) {
692
+        if ( ! empty($this->_ajax_sorting_callback)) {
693 693
             $new_row_class .= ' rowsortable';
694 694
         }
695 695
 
@@ -721,12 +721,12 @@  discard block
 block discarded – undo
721 721
     public function get_hidden_columns()
722 722
     {
723 723
         $user_id     = get_current_user_id();
724
-        $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
724
+        $has_default = get_user_option('default'.$this->screen->id.'columnshidden', $user_id);
725 725
         if (empty($has_default) && ! empty($this->_hidden_columns)) {
726
-            update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
727
-            update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
726
+            update_user_option($user_id, 'default'.$this->screen->id.'columnshidden', true);
727
+            update_user_option($user_id, 'manage'.$this->screen->id.'columnshidden', $this->_hidden_columns, true);
728 728
         }
729
-        $ref = 'manage' . $this->screen->id . 'columnshidden';
729
+        $ref = 'manage'.$this->screen->id.'columnshidden';
730 730
         return (array) get_user_option($ref, $user_id);
731 731
     }
732 732
 
@@ -751,14 +751,14 @@  discard block
 block discarded – undo
751 751
              */
752 752
             $hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
753 753
 
754
-            $classes = $column_name . ' column-' . $column_name . $hidden_class;
754
+            $classes = $column_name.' column-'.$column_name.$hidden_class;
755 755
             if ($primary === $column_name) {
756 756
                 $classes .= ' has-row-actions column-primary';
757 757
             }
758 758
 
759
-            $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
759
+            $data = ' data-colname="'.wp_strip_all_tags($column_display_name).'"';
760 760
 
761
-            $class = 'class="' . esc_attr($classes) . '"';
761
+            $class = 'class="'.esc_attr($classes).'"';
762 762
 
763 763
             $attributes = "{$class}{$data}";
764 764
 
@@ -774,7 +774,7 @@  discard block
 block discarded – undo
774 774
             } elseif (method_exists($this, "column_$column_name")) {
775 775
                 echo "<td $attributes>"; // already escaped
776 776
                 echo apply_filters(
777
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
777
+                    'FHEE__EE_Admin_List_Table__single_row_columns__column_'.$column_name.'__column_content',
778 778
                     call_user_func([$this, "column_$column_name"], $item),
779 779
                     $item,
780 780
                     $this
@@ -890,10 +890,10 @@  discard block
 block discarded – undo
890 890
         $action_class = '',
891 891
         $action_id = ''
892 892
     ) {
893
-        $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
894
-        $action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
895
-        $open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
896
-        $close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
893
+        $action_class = ! empty($action_class) ? ' class="'.esc_attr($action_class).'"' : '';
894
+        $action_id    = ! empty($action_id) ? ' id="'.esc_attr($action_id).'"' : '';
895
+        $open_tag     = ! empty($action_container) ? '<'.$action_container.$action_class.$action_id.'>' : '';
896
+        $close_tag    = ! empty($action_container) ? '</'.$action_container.'>' : '';
897 897
         try {
898 898
             $content = apply_filters(
899 899
                 'FHEE__EE_Admin_List_Table___action_string__action_items',
@@ -931,10 +931,10 @@  discard block
 block discarded – undo
931 931
      */
932 932
     protected function columnContent($id, $content, $align = 'start')
933 933
     {
934
-        if (! isset($this->_columns[ $id ])) {
934
+        if ( ! isset($this->_columns[$id])) {
935 935
             throw new DomainException('missing column id');
936 936
         }
937
-        $heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
937
+        $heading = $id !== 'cb' ? $this->_columns[$id] : '';
938 938
         $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
939 939
         $align = "ee-responsive-table-cell--{$align}";
940 940
 
@@ -951,13 +951,13 @@  discard block
 block discarded – undo
951 951
         return '
952 952
         <div class="ee-modal-menu">
953 953
             <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip"
954
-                    aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '"
954
+                    aria-label="' . esc_attr__('list table actions menu', 'event_espresso').'"
955 955
             >
956 956
                 <span class="dashicons dashicons-menu"></span>
957 957
             </button>
958 958
             <div class="ee-modal-menu__content ee-admin-container">
959 959
                 <span class="ee-modal-menu__close dashicons dashicons-no"></span>
960
-                ' . $actions . '
960
+                ' . $actions.'
961 961
             </div>
962 962
         </div>';
963 963
     }
@@ -968,7 +968,7 @@  discard block
 block discarded – undo
968 968
         return '
969 969
             <span class="ee-actions-column-header-wrap">
970 970
                 <span class="dashicons dashicons-screenoptions"></span>
971
-                <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span>
971
+                <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso').'</span>
972 972
             </span>';
973 973
     }
974 974
 
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Loader.core.php 2 patches
Indentation   +433 added lines, -433 removed lines patch added patch discarded remove patch
@@ -17,437 +17,437 @@
 block discarded – undo
17 17
  */
18 18
 class EE_Admin_Page_Loader
19 19
 {
20
-    /**
21
-     * @var AdminMenuManager $menu_manager
22
-     */
23
-    protected $menu_manager;
24
-
25
-    /**
26
-     * @var LoaderInterface $loader
27
-     */
28
-    protected $loader;
29
-
30
-    /**
31
-     * _installed_pages
32
-     * objects for page_init objects detected and loaded
33
-     *
34
-     * @access private
35
-     * @var EE_Admin_Page_Init[]
36
-     */
37
-    private $_installed_pages = [];
38
-
39
-
40
-    /**
41
-     * this is used to hold the registry of menu slugs for all the installed admin pages
42
-     *
43
-     * @var array
44
-     */
45
-    private $_menu_slugs = [];
46
-
47
-
48
-    /**
49
-     * _caffeinated_extends
50
-     * This array is the generated configuration array for which core EE_Admin pages are extended (and the bits and
51
-     * pieces needed to do so).  This property is defined in the _set_caffeinated method.
52
-     *
53
-     * @var array
54
-     */
55
-    private $_caffeinated_extends = [];
56
-
57
-
58
-    /**
59
-     * This property will hold the hook file for setting up the filter that does all the connections between admin
60
-     * pages.
61
-     *
62
-     * @var string
63
-     */
64
-    public $hook_file;
65
-
66
-    /**
67
-     * @var bool
68
-     * @since 5.0.0.p
69
-     */
70
-    private bool $full_site_maintenance = false;
71
-
72
-
73
-    /**
74
-     * @throws InvalidArgumentException
75
-     * @throws InvalidDataTypeException
76
-     * @throws InvalidInterfaceException
77
-     */
78
-    public function __construct(?LoaderInterface $loader)
79
-    {
80
-        $this->loader = $loader instanceof LoaderInterface ? $loader : LoaderFactory::getLoader();
81
-        $this->menu_manager = $this->loader->getShared(AdminMenuManager::class, [$this->loader]);
82
-    }
83
-
84
-
85
-    /**
86
-     * @throws EE_Error
87
-     * @throws ReflectionException
88
-     * @since 5.0.0.p
89
-     */
90
-    public function init()
91
-    {
92
-        $this->menu_manager->initialize();
93
-        $this->full_site_maintenance = MaintenanceStatus::isFullSite();
94
-        // let's do a scan and see what installed pages we have
95
-        $this->findAndLoadAdminPages();
96
-    }
97
-
98
-
99
-    /**
100
-     * When caffeinated system is detected, this method is called to setup the caffeinated directory constants used by
101
-     * files in the caffeinated folder.
102
-     *
103
-     * @access private
104
-     * @return void
105
-     */
106
-    private function defineCaffeinatedConstants()
107
-    {
108
-        if (! defined('EE_CORE_CAF_ADMIN')) {
109
-            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
110
-            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
111
-            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
112
-            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
113
-            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
114
-            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
115
-        }
116
-    }
117
-
118
-
119
-    /**
120
-     * This just gets the list of installed EE_Admin_pages.
121
-     *
122
-     * @access private
123
-     * @return void
124
-     * @throws EE_Error
125
-     * @throws InvalidArgumentException
126
-     * @throws InvalidDataTypeException
127
-     * @throws InvalidInterfaceException
128
-     * @throws ReflectionException
129
-     */
130
-    private function findAndLoadAdminPages()
131
-    {
132
-        $admin_pages = $this->findAdminPages();
133
-        // this just checks the caffeinated folder and takes care of setting up any caffeinated stuff.
134
-        $admin_pages = $this->findCaffeinatedAdminPages($admin_pages);
135
-        // then extensions and hooks, although they don't get added to the admin pages array
136
-        $this->findAdminPageExtensions();
137
-        $this->findAdminPageHooks();
138
-        // allow plugins to add in their own pages (note at this point they will need to have an autoloader defined for their class) OR hook into EEH_Autoloader::load_admin_page() to add their path.;
139
-        // loop through admin pages and setup the $_installed_pages array.
140
-        $hooks_ref = [];
141
-        $menu_pages = [];
142
-        foreach ($admin_pages as $page => $path) {
143
-            // don't load the page init class IF IT's ALREADY LOADED !!!
144
-            if (
145
-                isset($this->_installed_pages[ $page ])
146
-                && $this->_installed_pages[ $page ] instanceof EE_Admin_Page_Init
147
-            ) {
148
-                continue;
149
-            }
150
-            // build list of installed pages
151
-            $admin_page_init = $this->loadAdminPageInit($page);
152
-            $this->_installed_pages[ $page ] = $admin_page_init;
153
-            $admin_menu = $this->menu_manager->getAdminMenu($admin_page_init);
154
-            $admin_page_init->setCapability($admin_menu->capability(), $admin_menu->menuSlug());
155
-            // skip if in full maintenance mode and maintenance_mode_parent is NOT set
156
-            if ($this->full_site_maintenance && ! $admin_menu->maintenanceModeParent()) {
157
-                unset($admin_pages[ $page ]);
158
-                continue;
159
-            }
160
-            $menu_slug = $admin_menu->menuSlug();
161
-            $this->_menu_slugs[ $menu_slug ] = $page;
162
-            $menu_pages[ $menu_slug ] = $admin_page_init;
163
-            // now that we've got the admin_init objects...
164
-            // lets see if there are any caffeinated pages extending the originals.
165
-            // If there are then let's hook into the init admin filter and load our extend instead.
166
-            // Set flag for register hooks on extended pages b/c extended pages use the default INIT.
167
-            $extended_hooks = $admin_page_init->register_hooks(
168
-                $this->loadCaffeinatedExtensions($admin_page_init, $page, $menu_slug)
169
-            );
170
-            $hooks_ref      += $extended_hooks;
171
-        }
172
-        // the hooks_ref is all the pages where we have $extended _Hooks files
173
-        // that will extend a class in a different folder.
174
-        // So we want to make sure we load the file for the parent.
175
-        // first make sure we've got unique values
176
-        $hooks_ref = array_unique($hooks_ref);
177
-        // now let's loop and require!
178
-        foreach ($hooks_ref as $path) {
179
-            require_once($path);
180
-        }
181
-        // make sure we have menu slugs global setup. Used in EE_Admin_Page->page_setup() to ensure we don't do a full class load for an admin page that isn't requested.
182
-        global $ee_menu_slugs;
183
-        $ee_menu_slugs = $this->_menu_slugs;
184
-        // we need to loop again to run any early code
185
-        foreach ($this->_installed_pages as $page) {
186
-            $page->do_initial_loads();
187
-        }
188
-        $this->menu_manager->setInstalledPages($menu_pages);
189
-        do_action('AHEE__EE_Admin_Page_Loader___get_installed_pages_loaded', $this->_installed_pages);
190
-    }
191
-
192
-
193
-    /**
194
-     * @return array
195
-     * @throws EE_Error
196
-     * @since   5.0.0.p
197
-     */
198
-    private function findAdminPages(): array
199
-    {
200
-
201
-        // grab everything in the  admin core directory
202
-        $admin_page_folders = $this->findAdminPageFolders(EE_ADMIN_PAGES . '*');
203
-        $admin_page_folders = apply_filters(
204
-            'FHEE__EE_Admin_Page_Loader__findAdminPages__admin_page_folders',
205
-            $admin_page_folders
206
-        );
207
-        if (! empty($admin_page_folders)) {
208
-            return $admin_page_folders;
209
-        }
210
-        $error_msg = esc_html__(
211
-            'There are no EE_Admin pages detected, it looks like EE did not install properly',
212
-            'event_espresso'
213
-        );
214
-        $error_msg .= '||';
215
-        $error_msg .= sprintf(
216
-            esc_html__(
217
-                'Check that the %s folder exists and is writable. Maybe try deactivating, then reactivating Event Espresso again.',
218
-                'event_espresso'
219
-            ),
220
-            EE_ADMIN_PAGES
221
-        );
222
-        throw new RuntimeException($error_msg);
223
-    }
224
-
225
-
226
-    /**
227
-     * get_admin_page_object
228
-     *
229
-     * @param string $page_slug
230
-     * @return EE_Admin_Page
231
-     */
232
-    public function get_admin_page_object(string $page_slug = ''): ?EE_Admin_Page
233
-    {
234
-        return isset($this->_installed_pages[ $page_slug ])
235
-               && $this->_installed_pages[ $page_slug ] instanceof EE_Admin_Page_Init
236
-            ? $this->_installed_pages[ $page_slug ]->loaded_page_object()
237
-            : null;
238
-    }
239
-
240
-
241
-    /**
242
-     * generates an "Admin Page Init" class based on the directory  name
243
-     *
244
-     * @param string $dir_name
245
-     * @return string
246
-     */
247
-    private function getClassnameForAdminPageInit(string $dir_name = ''): string
248
-    {
249
-        $class_name = str_replace('_', ' ', strtolower($dir_name));
250
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
251
-    }
252
-
253
-
254
-    /**
255
-     * _load_admin_page
256
-     * Loads and instantiates page_init object for a single EE_admin page.
257
-     *
258
-     * @param string $page page_reference
259
-     * @return EE_Admin_Page_Init
260
-     * @throws EE_Error
261
-     */
262
-    private function loadAdminPageInit(string $page = ''): EE_Admin_Page_Init
263
-    {
264
-        $class_name = $this->getClassnameForAdminPageInit($page);
265
-        if (class_exists($class_name)) {
266
-            $admin_page_init = $this->loader->getShared($class_name);
267
-            // verify returned object
268
-            if ($admin_page_init instanceof EE_Admin_Page_Init) {
269
-                return $admin_page_init;
270
-            }
271
-        }
272
-        $error_msg = sprintf(
273
-            esc_html__('Something went wrong with loading the %s admin page.', 'event_espresso'),
274
-            $page
275
-        );
276
-        $error_msg .= '||'; // separates public from developer messages
277
-        $error_msg .= "\r\n";
278
-        $error_msg .= sprintf(
279
-            esc_html__('There is no Init class in place for the %s admin page.', 'event_espresso'),
280
-            $page
281
-        );
282
-        $error_msg .= '<br />';
283
-        $error_msg .= sprintf(
284
-            esc_html__(
285
-                'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
286
-                'event_espresso'
287
-            ),
288
-            '<strong>' . $class_name . '</strong>'
289
-        );
290
-        throw new EE_Error($error_msg);
291
-    }
292
-
293
-
294
-    /**
295
-     * This method is the "workhorse" for detecting and setting up caffeinated functionality.
296
-     * In this method there are three checks being done:
297
-     * 1. Do we have any NEW admin page sets.  If we do, lets add them into the menu setup (via the $admin_pages
298
-     * array) etc.  (new page sets are found in caffeinated/new/{page})
299
-     * 2. Do we have any EXTENDED page sets.  Basically an extended EE_Admin Page extends the core {child}_Admin_Page
300
-     * class.  eg. would be caffeinated/extend/events/Extend_Events_Admin_Page.core.php and in there would be a class:
301
-     * Extend_Events_Admin_Page extends Events_Admin_Page.
302
-     * 3. Do we have any files just for setting up hooks into other core pages.  The files can be any name in
303
-     * "caffeinated/hooks" EXCEPT they need a ".class.php" extension and the file name must correspond with the
304
-     * classname inside.  These classes are instantiated really early so that any hooks in them are run before the
305
-     * corresponding apply_filters/do_actions that are found in any future loaded EE_Admin pages (INCLUDING caffeinated
306
-     * admin_pages)
307
-     *
308
-     * @param array $admin_pages the original installed_refs array that may contain our NEW EE_Admin_Pages to be
309
-     *                              loaded.
310
-     * @return array
311
-     * @throws EE_Error
312
-     */
313
-    private function findCaffeinatedAdminPages(array $admin_pages): array
314
-    {
315
-        // first let's check if there IS a caffeinated folder. If there is not then lets get out.
316
-        if ((defined('EE_DECAF') && EE_DECAF) || ! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin')) {
317
-            return $admin_pages;
318
-        }
319
-        $this->defineCaffeinatedConstants();
320
-        // okay let's setup an "New" pages first (we'll return installed refs later)
321
-        $admin_pages += $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'new/*', ['tickets']);
322
-
323
-        return apply_filters(
324
-            'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
325
-            $admin_pages
326
-        );
327
-    }
328
-
329
-
330
-    /**
331
-     * @throws EE_Error
332
-     * @since   5.0.0.p
333
-     */
334
-    private function findAdminPageExtensions()
335
-    {
336
-        // let's see if there are any EXTENDS to setup in the $_caffeinated_extends array
337
-        // (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
338
-        $extensions = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'extend/*');
339
-        if ($extensions) {
340
-            foreach ($extensions as $folder => $extension) {
341
-                // convert lowercase_snake_case to Uppercase_Snake_Case
342
-                $filename = str_replace(' ', '_', ucwords(str_replace('_', ' ', $folder)));
343
-                $filename = "Extend_{$filename}_Admin_Page";
344
-                $filepath = EE_CORE_CAF_ADMIN . "extend/$folder/$filename.core.php";
345
-                // save filename and filepath for later
346
-                $this->_caffeinated_extends[ $folder ]['path']       = str_replace(['\\', '/'], '/', $filepath);
347
-                $this->_caffeinated_extends[ $folder ]['admin_page'] = $filename;
348
-            }
349
-        }
350
-        $this->_caffeinated_extends = apply_filters(
351
-            'FHEE__EE_Admin_Page_Loader___get_installed_pages__caffeinated_extends',
352
-            $this->_caffeinated_extends
353
-        );
354
-    }
355
-
356
-
357
-    private function loadCaffeinatedExtensions(
358
-        EE_Admin_Page_Init $admin_page_init,
359
-        string $page,
360
-        string $menu_slug
361
-    ): bool {
362
-        if (! isset($this->_caffeinated_extends[ $page ])) {
363
-            return false;
364
-        }
365
-        $admin_page_name = $admin_page_init->get_admin_page_name();
366
-        $caf_path        = $this->_caffeinated_extends[ $page ]['path'];
367
-        $caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
368
-        add_filter(
369
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_$admin_page_name",
370
-            static function ($path_to_file) use ($caf_path) {
371
-                return $caf_path;
372
-            }
373
-        );
374
-        add_filter(
375
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_$admin_page_name",
376
-            static function ($admin_page) use ($caf_admin_page) {
377
-                return $caf_admin_page;
378
-            }
379
-        );
380
-        return true;
381
-    }
382
-
383
-
384
-    /**
385
-     * @throws EE_Error
386
-     * @since   5.0.0.p
387
-     */
388
-    private function findAdminPageHooks()
389
-    {
390
-        // let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
391
-        $ee_admin_hooks   = [];
392
-        $admin_page_hooks = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'hooks/*.class.php', [], 0, false);
393
-        if ($admin_page_hooks) {
394
-            foreach ($admin_page_hooks as $hook) {
395
-                if (is_readable($hook)) {
396
-                    require_once $hook;
397
-                    $classname = str_replace([EE_CORE_CAF_ADMIN . 'hooks/', '.class.php'], '', $hook);
398
-                    if (class_exists($classname)) {
399
-                        $ee_admin_hooks[] = $this->loader->getShared($classname);
400
-                    }
401
-                }
402
-            }
403
-        }
404
-        apply_filters('FHEE__EE_Admin_Page_Loader__set_caffeinated__ee_admin_hooks', $ee_admin_hooks);
405
-    }
406
-
407
-
408
-    /**
409
-     * _default_header_link
410
-     * This is just a dummy method to use with header submenu items
411
-     *
412
-     * @return bool false
413
-     */
414
-    public function _default_header_link(): bool
415
-    {
416
-        return false;
417
-    }
418
-
419
-
420
-    /**
421
-     * @param string $path
422
-     * @param int    $flags
423
-     * @param array  $exclude
424
-     * @param bool   $register_autoloaders
425
-     * @return array
426
-     * @throws EE_Error
427
-     * @since 5.0.0.p
428
-     */
429
-    private function findAdminPageFolders(
430
-        string $path,
431
-        array $exclude = [],
432
-        int $flags = GLOB_ONLYDIR,
433
-        bool $register_autoloaders = true
434
-    ): array {
435
-        $folders = [];
436
-        $subfolders = glob($path, $flags);
437
-        if ($subfolders) {
438
-            foreach ($subfolders as $admin_screen) {
439
-                $admin_screen_name = basename($admin_screen);
440
-                // files and anything in the exclude array need not apply
441
-                if (! in_array($admin_screen_name, $exclude, true)) {
442
-                    // these folders represent the different EE admin pages
443
-                    $folders[ $admin_screen_name ] = $admin_screen;
444
-                    if ($register_autoloaders) {
445
-                        // set autoloaders for our admin page classes based on included path information
446
-                        EEH_Autoloader::register_autoloaders_for_each_file_in_folder($admin_screen);
447
-                    }
448
-                }
449
-            }
450
-        }
451
-        return $folders;
452
-    }
20
+	/**
21
+	 * @var AdminMenuManager $menu_manager
22
+	 */
23
+	protected $menu_manager;
24
+
25
+	/**
26
+	 * @var LoaderInterface $loader
27
+	 */
28
+	protected $loader;
29
+
30
+	/**
31
+	 * _installed_pages
32
+	 * objects for page_init objects detected and loaded
33
+	 *
34
+	 * @access private
35
+	 * @var EE_Admin_Page_Init[]
36
+	 */
37
+	private $_installed_pages = [];
38
+
39
+
40
+	/**
41
+	 * this is used to hold the registry of menu slugs for all the installed admin pages
42
+	 *
43
+	 * @var array
44
+	 */
45
+	private $_menu_slugs = [];
46
+
47
+
48
+	/**
49
+	 * _caffeinated_extends
50
+	 * This array is the generated configuration array for which core EE_Admin pages are extended (and the bits and
51
+	 * pieces needed to do so).  This property is defined in the _set_caffeinated method.
52
+	 *
53
+	 * @var array
54
+	 */
55
+	private $_caffeinated_extends = [];
56
+
57
+
58
+	/**
59
+	 * This property will hold the hook file for setting up the filter that does all the connections between admin
60
+	 * pages.
61
+	 *
62
+	 * @var string
63
+	 */
64
+	public $hook_file;
65
+
66
+	/**
67
+	 * @var bool
68
+	 * @since 5.0.0.p
69
+	 */
70
+	private bool $full_site_maintenance = false;
71
+
72
+
73
+	/**
74
+	 * @throws InvalidArgumentException
75
+	 * @throws InvalidDataTypeException
76
+	 * @throws InvalidInterfaceException
77
+	 */
78
+	public function __construct(?LoaderInterface $loader)
79
+	{
80
+		$this->loader = $loader instanceof LoaderInterface ? $loader : LoaderFactory::getLoader();
81
+		$this->menu_manager = $this->loader->getShared(AdminMenuManager::class, [$this->loader]);
82
+	}
83
+
84
+
85
+	/**
86
+	 * @throws EE_Error
87
+	 * @throws ReflectionException
88
+	 * @since 5.0.0.p
89
+	 */
90
+	public function init()
91
+	{
92
+		$this->menu_manager->initialize();
93
+		$this->full_site_maintenance = MaintenanceStatus::isFullSite();
94
+		// let's do a scan and see what installed pages we have
95
+		$this->findAndLoadAdminPages();
96
+	}
97
+
98
+
99
+	/**
100
+	 * When caffeinated system is detected, this method is called to setup the caffeinated directory constants used by
101
+	 * files in the caffeinated folder.
102
+	 *
103
+	 * @access private
104
+	 * @return void
105
+	 */
106
+	private function defineCaffeinatedConstants()
107
+	{
108
+		if (! defined('EE_CORE_CAF_ADMIN')) {
109
+			define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
110
+			define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
111
+			define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
112
+			define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
113
+			define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
114
+			define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
115
+		}
116
+	}
117
+
118
+
119
+	/**
120
+	 * This just gets the list of installed EE_Admin_pages.
121
+	 *
122
+	 * @access private
123
+	 * @return void
124
+	 * @throws EE_Error
125
+	 * @throws InvalidArgumentException
126
+	 * @throws InvalidDataTypeException
127
+	 * @throws InvalidInterfaceException
128
+	 * @throws ReflectionException
129
+	 */
130
+	private function findAndLoadAdminPages()
131
+	{
132
+		$admin_pages = $this->findAdminPages();
133
+		// this just checks the caffeinated folder and takes care of setting up any caffeinated stuff.
134
+		$admin_pages = $this->findCaffeinatedAdminPages($admin_pages);
135
+		// then extensions and hooks, although they don't get added to the admin pages array
136
+		$this->findAdminPageExtensions();
137
+		$this->findAdminPageHooks();
138
+		// allow plugins to add in their own pages (note at this point they will need to have an autoloader defined for their class) OR hook into EEH_Autoloader::load_admin_page() to add their path.;
139
+		// loop through admin pages and setup the $_installed_pages array.
140
+		$hooks_ref = [];
141
+		$menu_pages = [];
142
+		foreach ($admin_pages as $page => $path) {
143
+			// don't load the page init class IF IT's ALREADY LOADED !!!
144
+			if (
145
+				isset($this->_installed_pages[ $page ])
146
+				&& $this->_installed_pages[ $page ] instanceof EE_Admin_Page_Init
147
+			) {
148
+				continue;
149
+			}
150
+			// build list of installed pages
151
+			$admin_page_init = $this->loadAdminPageInit($page);
152
+			$this->_installed_pages[ $page ] = $admin_page_init;
153
+			$admin_menu = $this->menu_manager->getAdminMenu($admin_page_init);
154
+			$admin_page_init->setCapability($admin_menu->capability(), $admin_menu->menuSlug());
155
+			// skip if in full maintenance mode and maintenance_mode_parent is NOT set
156
+			if ($this->full_site_maintenance && ! $admin_menu->maintenanceModeParent()) {
157
+				unset($admin_pages[ $page ]);
158
+				continue;
159
+			}
160
+			$menu_slug = $admin_menu->menuSlug();
161
+			$this->_menu_slugs[ $menu_slug ] = $page;
162
+			$menu_pages[ $menu_slug ] = $admin_page_init;
163
+			// now that we've got the admin_init objects...
164
+			// lets see if there are any caffeinated pages extending the originals.
165
+			// If there are then let's hook into the init admin filter and load our extend instead.
166
+			// Set flag for register hooks on extended pages b/c extended pages use the default INIT.
167
+			$extended_hooks = $admin_page_init->register_hooks(
168
+				$this->loadCaffeinatedExtensions($admin_page_init, $page, $menu_slug)
169
+			);
170
+			$hooks_ref      += $extended_hooks;
171
+		}
172
+		// the hooks_ref is all the pages where we have $extended _Hooks files
173
+		// that will extend a class in a different folder.
174
+		// So we want to make sure we load the file for the parent.
175
+		// first make sure we've got unique values
176
+		$hooks_ref = array_unique($hooks_ref);
177
+		// now let's loop and require!
178
+		foreach ($hooks_ref as $path) {
179
+			require_once($path);
180
+		}
181
+		// make sure we have menu slugs global setup. Used in EE_Admin_Page->page_setup() to ensure we don't do a full class load for an admin page that isn't requested.
182
+		global $ee_menu_slugs;
183
+		$ee_menu_slugs = $this->_menu_slugs;
184
+		// we need to loop again to run any early code
185
+		foreach ($this->_installed_pages as $page) {
186
+			$page->do_initial_loads();
187
+		}
188
+		$this->menu_manager->setInstalledPages($menu_pages);
189
+		do_action('AHEE__EE_Admin_Page_Loader___get_installed_pages_loaded', $this->_installed_pages);
190
+	}
191
+
192
+
193
+	/**
194
+	 * @return array
195
+	 * @throws EE_Error
196
+	 * @since   5.0.0.p
197
+	 */
198
+	private function findAdminPages(): array
199
+	{
200
+
201
+		// grab everything in the  admin core directory
202
+		$admin_page_folders = $this->findAdminPageFolders(EE_ADMIN_PAGES . '*');
203
+		$admin_page_folders = apply_filters(
204
+			'FHEE__EE_Admin_Page_Loader__findAdminPages__admin_page_folders',
205
+			$admin_page_folders
206
+		);
207
+		if (! empty($admin_page_folders)) {
208
+			return $admin_page_folders;
209
+		}
210
+		$error_msg = esc_html__(
211
+			'There are no EE_Admin pages detected, it looks like EE did not install properly',
212
+			'event_espresso'
213
+		);
214
+		$error_msg .= '||';
215
+		$error_msg .= sprintf(
216
+			esc_html__(
217
+				'Check that the %s folder exists and is writable. Maybe try deactivating, then reactivating Event Espresso again.',
218
+				'event_espresso'
219
+			),
220
+			EE_ADMIN_PAGES
221
+		);
222
+		throw new RuntimeException($error_msg);
223
+	}
224
+
225
+
226
+	/**
227
+	 * get_admin_page_object
228
+	 *
229
+	 * @param string $page_slug
230
+	 * @return EE_Admin_Page
231
+	 */
232
+	public function get_admin_page_object(string $page_slug = ''): ?EE_Admin_Page
233
+	{
234
+		return isset($this->_installed_pages[ $page_slug ])
235
+			   && $this->_installed_pages[ $page_slug ] instanceof EE_Admin_Page_Init
236
+			? $this->_installed_pages[ $page_slug ]->loaded_page_object()
237
+			: null;
238
+	}
239
+
240
+
241
+	/**
242
+	 * generates an "Admin Page Init" class based on the directory  name
243
+	 *
244
+	 * @param string $dir_name
245
+	 * @return string
246
+	 */
247
+	private function getClassnameForAdminPageInit(string $dir_name = ''): string
248
+	{
249
+		$class_name = str_replace('_', ' ', strtolower($dir_name));
250
+		return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
251
+	}
252
+
253
+
254
+	/**
255
+	 * _load_admin_page
256
+	 * Loads and instantiates page_init object for a single EE_admin page.
257
+	 *
258
+	 * @param string $page page_reference
259
+	 * @return EE_Admin_Page_Init
260
+	 * @throws EE_Error
261
+	 */
262
+	private function loadAdminPageInit(string $page = ''): EE_Admin_Page_Init
263
+	{
264
+		$class_name = $this->getClassnameForAdminPageInit($page);
265
+		if (class_exists($class_name)) {
266
+			$admin_page_init = $this->loader->getShared($class_name);
267
+			// verify returned object
268
+			if ($admin_page_init instanceof EE_Admin_Page_Init) {
269
+				return $admin_page_init;
270
+			}
271
+		}
272
+		$error_msg = sprintf(
273
+			esc_html__('Something went wrong with loading the %s admin page.', 'event_espresso'),
274
+			$page
275
+		);
276
+		$error_msg .= '||'; // separates public from developer messages
277
+		$error_msg .= "\r\n";
278
+		$error_msg .= sprintf(
279
+			esc_html__('There is no Init class in place for the %s admin page.', 'event_espresso'),
280
+			$page
281
+		);
282
+		$error_msg .= '<br />';
283
+		$error_msg .= sprintf(
284
+			esc_html__(
285
+				'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
286
+				'event_espresso'
287
+			),
288
+			'<strong>' . $class_name . '</strong>'
289
+		);
290
+		throw new EE_Error($error_msg);
291
+	}
292
+
293
+
294
+	/**
295
+	 * This method is the "workhorse" for detecting and setting up caffeinated functionality.
296
+	 * In this method there are three checks being done:
297
+	 * 1. Do we have any NEW admin page sets.  If we do, lets add them into the menu setup (via the $admin_pages
298
+	 * array) etc.  (new page sets are found in caffeinated/new/{page})
299
+	 * 2. Do we have any EXTENDED page sets.  Basically an extended EE_Admin Page extends the core {child}_Admin_Page
300
+	 * class.  eg. would be caffeinated/extend/events/Extend_Events_Admin_Page.core.php and in there would be a class:
301
+	 * Extend_Events_Admin_Page extends Events_Admin_Page.
302
+	 * 3. Do we have any files just for setting up hooks into other core pages.  The files can be any name in
303
+	 * "caffeinated/hooks" EXCEPT they need a ".class.php" extension and the file name must correspond with the
304
+	 * classname inside.  These classes are instantiated really early so that any hooks in them are run before the
305
+	 * corresponding apply_filters/do_actions that are found in any future loaded EE_Admin pages (INCLUDING caffeinated
306
+	 * admin_pages)
307
+	 *
308
+	 * @param array $admin_pages the original installed_refs array that may contain our NEW EE_Admin_Pages to be
309
+	 *                              loaded.
310
+	 * @return array
311
+	 * @throws EE_Error
312
+	 */
313
+	private function findCaffeinatedAdminPages(array $admin_pages): array
314
+	{
315
+		// first let's check if there IS a caffeinated folder. If there is not then lets get out.
316
+		if ((defined('EE_DECAF') && EE_DECAF) || ! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin')) {
317
+			return $admin_pages;
318
+		}
319
+		$this->defineCaffeinatedConstants();
320
+		// okay let's setup an "New" pages first (we'll return installed refs later)
321
+		$admin_pages += $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'new/*', ['tickets']);
322
+
323
+		return apply_filters(
324
+			'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
325
+			$admin_pages
326
+		);
327
+	}
328
+
329
+
330
+	/**
331
+	 * @throws EE_Error
332
+	 * @since   5.0.0.p
333
+	 */
334
+	private function findAdminPageExtensions()
335
+	{
336
+		// let's see if there are any EXTENDS to setup in the $_caffeinated_extends array
337
+		// (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
338
+		$extensions = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'extend/*');
339
+		if ($extensions) {
340
+			foreach ($extensions as $folder => $extension) {
341
+				// convert lowercase_snake_case to Uppercase_Snake_Case
342
+				$filename = str_replace(' ', '_', ucwords(str_replace('_', ' ', $folder)));
343
+				$filename = "Extend_{$filename}_Admin_Page";
344
+				$filepath = EE_CORE_CAF_ADMIN . "extend/$folder/$filename.core.php";
345
+				// save filename and filepath for later
346
+				$this->_caffeinated_extends[ $folder ]['path']       = str_replace(['\\', '/'], '/', $filepath);
347
+				$this->_caffeinated_extends[ $folder ]['admin_page'] = $filename;
348
+			}
349
+		}
350
+		$this->_caffeinated_extends = apply_filters(
351
+			'FHEE__EE_Admin_Page_Loader___get_installed_pages__caffeinated_extends',
352
+			$this->_caffeinated_extends
353
+		);
354
+	}
355
+
356
+
357
+	private function loadCaffeinatedExtensions(
358
+		EE_Admin_Page_Init $admin_page_init,
359
+		string $page,
360
+		string $menu_slug
361
+	): bool {
362
+		if (! isset($this->_caffeinated_extends[ $page ])) {
363
+			return false;
364
+		}
365
+		$admin_page_name = $admin_page_init->get_admin_page_name();
366
+		$caf_path        = $this->_caffeinated_extends[ $page ]['path'];
367
+		$caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
368
+		add_filter(
369
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_$admin_page_name",
370
+			static function ($path_to_file) use ($caf_path) {
371
+				return $caf_path;
372
+			}
373
+		);
374
+		add_filter(
375
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_$admin_page_name",
376
+			static function ($admin_page) use ($caf_admin_page) {
377
+				return $caf_admin_page;
378
+			}
379
+		);
380
+		return true;
381
+	}
382
+
383
+
384
+	/**
385
+	 * @throws EE_Error
386
+	 * @since   5.0.0.p
387
+	 */
388
+	private function findAdminPageHooks()
389
+	{
390
+		// let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
391
+		$ee_admin_hooks   = [];
392
+		$admin_page_hooks = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'hooks/*.class.php', [], 0, false);
393
+		if ($admin_page_hooks) {
394
+			foreach ($admin_page_hooks as $hook) {
395
+				if (is_readable($hook)) {
396
+					require_once $hook;
397
+					$classname = str_replace([EE_CORE_CAF_ADMIN . 'hooks/', '.class.php'], '', $hook);
398
+					if (class_exists($classname)) {
399
+						$ee_admin_hooks[] = $this->loader->getShared($classname);
400
+					}
401
+				}
402
+			}
403
+		}
404
+		apply_filters('FHEE__EE_Admin_Page_Loader__set_caffeinated__ee_admin_hooks', $ee_admin_hooks);
405
+	}
406
+
407
+
408
+	/**
409
+	 * _default_header_link
410
+	 * This is just a dummy method to use with header submenu items
411
+	 *
412
+	 * @return bool false
413
+	 */
414
+	public function _default_header_link(): bool
415
+	{
416
+		return false;
417
+	}
418
+
419
+
420
+	/**
421
+	 * @param string $path
422
+	 * @param int    $flags
423
+	 * @param array  $exclude
424
+	 * @param bool   $register_autoloaders
425
+	 * @return array
426
+	 * @throws EE_Error
427
+	 * @since 5.0.0.p
428
+	 */
429
+	private function findAdminPageFolders(
430
+		string $path,
431
+		array $exclude = [],
432
+		int $flags = GLOB_ONLYDIR,
433
+		bool $register_autoloaders = true
434
+	): array {
435
+		$folders = [];
436
+		$subfolders = glob($path, $flags);
437
+		if ($subfolders) {
438
+			foreach ($subfolders as $admin_screen) {
439
+				$admin_screen_name = basename($admin_screen);
440
+				// files and anything in the exclude array need not apply
441
+				if (! in_array($admin_screen_name, $exclude, true)) {
442
+					// these folders represent the different EE admin pages
443
+					$folders[ $admin_screen_name ] = $admin_screen;
444
+					if ($register_autoloaders) {
445
+						// set autoloaders for our admin page classes based on included path information
446
+						EEH_Autoloader::register_autoloaders_for_each_file_in_folder($admin_screen);
447
+					}
448
+				}
449
+			}
450
+		}
451
+		return $folders;
452
+	}
453 453
 }
Please login to merge, or discard this patch.
Spacing   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -105,13 +105,13 @@  discard block
 block discarded – undo
105 105
      */
106 106
     private function defineCaffeinatedConstants()
107 107
     {
108
-        if (! defined('EE_CORE_CAF_ADMIN')) {
109
-            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH . 'caffeinated/admin/');
110
-            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL . 'caffeinated/admin/');
111
-            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN . 'new/');
112
-            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN . 'extend/');
113
-            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL . 'extend/');
114
-            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN . 'hooks/');
108
+        if ( ! defined('EE_CORE_CAF_ADMIN')) {
109
+            define('EE_CORE_CAF_ADMIN', EE_PLUGIN_DIR_PATH.'caffeinated/admin/');
110
+            define('EE_CORE_CAF_ADMIN_URL', EE_PLUGIN_DIR_URL.'caffeinated/admin/');
111
+            define('EE_CORE_CAF_ADMIN_NEW', EE_CORE_CAF_ADMIN.'new/');
112
+            define('EE_CORE_CAF_ADMIN_EXTEND', EE_CORE_CAF_ADMIN.'extend/');
113
+            define('EE_CORE_CAF_ADMIN_EXTEND_URL', EE_CORE_CAF_ADMIN_URL.'extend/');
114
+            define('EE_CORE_CAF_ADMIN_HOOKS', EE_CORE_CAF_ADMIN.'hooks/');
115 115
         }
116 116
     }
117 117
 
@@ -142,24 +142,24 @@  discard block
 block discarded – undo
142 142
         foreach ($admin_pages as $page => $path) {
143 143
             // don't load the page init class IF IT's ALREADY LOADED !!!
144 144
             if (
145
-                isset($this->_installed_pages[ $page ])
146
-                && $this->_installed_pages[ $page ] instanceof EE_Admin_Page_Init
145
+                isset($this->_installed_pages[$page])
146
+                && $this->_installed_pages[$page] instanceof EE_Admin_Page_Init
147 147
             ) {
148 148
                 continue;
149 149
             }
150 150
             // build list of installed pages
151 151
             $admin_page_init = $this->loadAdminPageInit($page);
152
-            $this->_installed_pages[ $page ] = $admin_page_init;
152
+            $this->_installed_pages[$page] = $admin_page_init;
153 153
             $admin_menu = $this->menu_manager->getAdminMenu($admin_page_init);
154 154
             $admin_page_init->setCapability($admin_menu->capability(), $admin_menu->menuSlug());
155 155
             // skip if in full maintenance mode and maintenance_mode_parent is NOT set
156 156
             if ($this->full_site_maintenance && ! $admin_menu->maintenanceModeParent()) {
157
-                unset($admin_pages[ $page ]);
157
+                unset($admin_pages[$page]);
158 158
                 continue;
159 159
             }
160 160
             $menu_slug = $admin_menu->menuSlug();
161
-            $this->_menu_slugs[ $menu_slug ] = $page;
162
-            $menu_pages[ $menu_slug ] = $admin_page_init;
161
+            $this->_menu_slugs[$menu_slug] = $page;
162
+            $menu_pages[$menu_slug] = $admin_page_init;
163 163
             // now that we've got the admin_init objects...
164 164
             // lets see if there are any caffeinated pages extending the originals.
165 165
             // If there are then let's hook into the init admin filter and load our extend instead.
@@ -167,7 +167,7 @@  discard block
 block discarded – undo
167 167
             $extended_hooks = $admin_page_init->register_hooks(
168 168
                 $this->loadCaffeinatedExtensions($admin_page_init, $page, $menu_slug)
169 169
             );
170
-            $hooks_ref      += $extended_hooks;
170
+            $hooks_ref += $extended_hooks;
171 171
         }
172 172
         // the hooks_ref is all the pages where we have $extended _Hooks files
173 173
         // that will extend a class in a different folder.
@@ -199,12 +199,12 @@  discard block
 block discarded – undo
199 199
     {
200 200
 
201 201
         // grab everything in the  admin core directory
202
-        $admin_page_folders = $this->findAdminPageFolders(EE_ADMIN_PAGES . '*');
202
+        $admin_page_folders = $this->findAdminPageFolders(EE_ADMIN_PAGES.'*');
203 203
         $admin_page_folders = apply_filters(
204 204
             'FHEE__EE_Admin_Page_Loader__findAdminPages__admin_page_folders',
205 205
             $admin_page_folders
206 206
         );
207
-        if (! empty($admin_page_folders)) {
207
+        if ( ! empty($admin_page_folders)) {
208 208
             return $admin_page_folders;
209 209
         }
210 210
         $error_msg = esc_html__(
@@ -231,9 +231,9 @@  discard block
 block discarded – undo
231 231
      */
232 232
     public function get_admin_page_object(string $page_slug = ''): ?EE_Admin_Page
233 233
     {
234
-        return isset($this->_installed_pages[ $page_slug ])
235
-               && $this->_installed_pages[ $page_slug ] instanceof EE_Admin_Page_Init
236
-            ? $this->_installed_pages[ $page_slug ]->loaded_page_object()
234
+        return isset($this->_installed_pages[$page_slug])
235
+               && $this->_installed_pages[$page_slug] instanceof EE_Admin_Page_Init
236
+            ? $this->_installed_pages[$page_slug]->loaded_page_object()
237 237
             : null;
238 238
     }
239 239
 
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
     private function getClassnameForAdminPageInit(string $dir_name = ''): string
248 248
     {
249 249
         $class_name = str_replace('_', ' ', strtolower($dir_name));
250
-        return str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page_Init';
250
+        return str_replace(' ', '_', ucwords($class_name)).'_Admin_Page_Init';
251 251
     }
252 252
 
253 253
 
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
                 'Make sure you have %1$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
286 286
                 'event_espresso'
287 287
             ),
288
-            '<strong>' . $class_name . '</strong>'
288
+            '<strong>'.$class_name.'</strong>'
289 289
         );
290 290
         throw new EE_Error($error_msg);
291 291
     }
@@ -313,12 +313,12 @@  discard block
 block discarded – undo
313 313
     private function findCaffeinatedAdminPages(array $admin_pages): array
314 314
     {
315 315
         // first let's check if there IS a caffeinated folder. If there is not then lets get out.
316
-        if ((defined('EE_DECAF') && EE_DECAF) || ! is_dir(EE_PLUGIN_DIR_PATH . 'caffeinated/admin')) {
316
+        if ((defined('EE_DECAF') && EE_DECAF) || ! is_dir(EE_PLUGIN_DIR_PATH.'caffeinated/admin')) {
317 317
             return $admin_pages;
318 318
         }
319 319
         $this->defineCaffeinatedConstants();
320 320
         // okay let's setup an "New" pages first (we'll return installed refs later)
321
-        $admin_pages += $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'new/*', ['tickets']);
321
+        $admin_pages += $this->findAdminPageFolders(EE_CORE_CAF_ADMIN.'new/*', ['tickets']);
322 322
 
323 323
         return apply_filters(
324 324
             'FHEE__EE_Admin_Page_Loader___get_installed_pages__installed_refs',
@@ -335,16 +335,16 @@  discard block
 block discarded – undo
335 335
     {
336 336
         // let's see if there are any EXTENDS to setup in the $_caffeinated_extends array
337 337
         // (that will be used later for hooking into the _initialize_admin_age in the related core_init admin page)
338
-        $extensions = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'extend/*');
338
+        $extensions = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN.'extend/*');
339 339
         if ($extensions) {
340 340
             foreach ($extensions as $folder => $extension) {
341 341
                 // convert lowercase_snake_case to Uppercase_Snake_Case
342 342
                 $filename = str_replace(' ', '_', ucwords(str_replace('_', ' ', $folder)));
343 343
                 $filename = "Extend_{$filename}_Admin_Page";
344
-                $filepath = EE_CORE_CAF_ADMIN . "extend/$folder/$filename.core.php";
344
+                $filepath = EE_CORE_CAF_ADMIN."extend/$folder/$filename.core.php";
345 345
                 // save filename and filepath for later
346
-                $this->_caffeinated_extends[ $folder ]['path']       = str_replace(['\\', '/'], '/', $filepath);
347
-                $this->_caffeinated_extends[ $folder ]['admin_page'] = $filename;
346
+                $this->_caffeinated_extends[$folder]['path']       = str_replace(['\\', '/'], '/', $filepath);
347
+                $this->_caffeinated_extends[$folder]['admin_page'] = $filename;
348 348
             }
349 349
         }
350 350
         $this->_caffeinated_extends = apply_filters(
@@ -359,21 +359,21 @@  discard block
 block discarded – undo
359 359
         string $page,
360 360
         string $menu_slug
361 361
     ): bool {
362
-        if (! isset($this->_caffeinated_extends[ $page ])) {
362
+        if ( ! isset($this->_caffeinated_extends[$page])) {
363 363
             return false;
364 364
         }
365 365
         $admin_page_name = $admin_page_init->get_admin_page_name();
366
-        $caf_path        = $this->_caffeinated_extends[ $page ]['path'];
367
-        $caf_admin_page  = $this->_caffeinated_extends[ $page ]['admin_page'];
366
+        $caf_path        = $this->_caffeinated_extends[$page]['path'];
367
+        $caf_admin_page  = $this->_caffeinated_extends[$page]['admin_page'];
368 368
         add_filter(
369 369
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$menu_slug}_$admin_page_name",
370
-            static function ($path_to_file) use ($caf_path) {
370
+            static function($path_to_file) use ($caf_path) {
371 371
                 return $caf_path;
372 372
             }
373 373
         );
374 374
         add_filter(
375 375
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$menu_slug}_$admin_page_name",
376
-            static function ($admin_page) use ($caf_admin_page) {
376
+            static function($admin_page) use ($caf_admin_page) {
377 377
                 return $caf_admin_page;
378 378
             }
379 379
         );
@@ -389,12 +389,12 @@  discard block
 block discarded – undo
389 389
     {
390 390
         // let's see if there are any HOOK files and instantiate them if there are (so that hooks are loaded early!).
391 391
         $ee_admin_hooks   = [];
392
-        $admin_page_hooks = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN . 'hooks/*.class.php', [], 0, false);
392
+        $admin_page_hooks = $this->findAdminPageFolders(EE_CORE_CAF_ADMIN.'hooks/*.class.php', [], 0, false);
393 393
         if ($admin_page_hooks) {
394 394
             foreach ($admin_page_hooks as $hook) {
395 395
                 if (is_readable($hook)) {
396 396
                     require_once $hook;
397
-                    $classname = str_replace([EE_CORE_CAF_ADMIN . 'hooks/', '.class.php'], '', $hook);
397
+                    $classname = str_replace([EE_CORE_CAF_ADMIN.'hooks/', '.class.php'], '', $hook);
398 398
                     if (class_exists($classname)) {
399 399
                         $ee_admin_hooks[] = $this->loader->getShared($classname);
400 400
                     }
@@ -438,9 +438,9 @@  discard block
 block discarded – undo
438 438
             foreach ($subfolders as $admin_screen) {
439 439
                 $admin_screen_name = basename($admin_screen);
440 440
                 // files and anything in the exclude array need not apply
441
-                if (! in_array($admin_screen_name, $exclude, true)) {
441
+                if ( ! in_array($admin_screen_name, $exclude, true)) {
442 442
                     // these folders represent the different EE admin pages
443
-                    $folders[ $admin_screen_name ] = $admin_screen;
443
+                    $folders[$admin_screen_name] = $admin_screen;
444 444
                     if ($register_autoloaders) {
445 445
                         // set autoloaders for our admin page classes based on included path information
446 446
                         EEH_Autoloader::register_autoloaders_for_each_file_in_folder($admin_screen);
Please login to merge, or discard this patch.
core/EE_Addon.core.php 2 patches
Indentation   +859 added lines, -859 removed lines patch added patch discarded remove patch
@@ -20,870 +20,870 @@
 block discarded – undo
20 20
  */
21 21
 abstract class EE_Addon extends EE_Configurable implements RequiresDependencyMapInterface, RequiresDomainInterface
22 22
 {
23
-    /**
24
-     * prefix to be added onto an addon's plugin slug to make a wp option name
25
-     * which will be used to store the plugin's activation history
26
-     */
27
-    const ee_addon_version_history_option_prefix = 'ee_version_history_';
28
-
29
-    /**
30
-     * @var $_version
31
-     * @type string
32
-     */
33
-    protected $_version = '';
34
-
35
-    /**
36
-     * @var $_min_core_version
37
-     * @type string
38
-     */
39
-    protected $_min_core_version = '';
40
-
41
-    /**
42
-     * derived from plugin 'main_file_path using plugin_basename()
43
-     *
44
-     * @type string $_plugin_basename
45
-     */
46
-    protected $_plugin_basename = '';
47
-
48
-    /**
49
-     * A non-internationalized name to identify this addon for use in URLs, etc
50
-     *
51
-     * @type string $_plugin_slug
52
-     */
53
-    protected $_plugin_slug = '';
54
-
55
-    /**
56
-     * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
57
-     *
58
-     * @type string _addon_name
59
-     */
60
-    protected $_addon_name = '';
61
-
62
-    /**
63
-     * one of the EE_System::req_type_* constants
64
-     *
65
-     * @type int $_req_type
66
-     */
67
-    protected $_req_type;
68
-
69
-    /**
70
-     * page slug to be used when generating the "Settings" link on the WP plugin page
71
-     *
72
-     * @type string $_plugin_action_slug
73
-     */
74
-    protected $_plugin_action_slug = '';
75
-
76
-    /**
77
-     * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
78
-     * that can be used for adding upgrading/marketing info
79
-     *
80
-     * @type array $_plugins_page_row
81
-     */
82
-    protected $_plugins_page_row = [];
83
-
84
-
85
-    /**
86
-     *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
87
-     *
88
-     * @type string
89
-     */
90
-    protected $_main_plugin_file;
91
-
92
-    /**
93
-     *    This is the slug used to identify this add-on within the plugin update engine.
94
-     *
95
-     * @type string
96
-     */
97
-    protected $pue_slug = '';
98
-
99
-
100
-    /**
101
-     * @var EE_Dependency_Map $dependency_map
102
-     */
103
-    private $dependency_map;
104
-
105
-
106
-    /**
107
-     * @var DomainInterface $domain
108
-     */
109
-    private $domain;
110
-
111
-
112
-    /**
113
-     * @param EE_Dependency_Map|null $dependency_map [optional]
114
-     * @param DomainInterface|null   $domain         [optional]
115
-     */
116
-    public function __construct(EE_Dependency_Map $dependency_map = null, DomainInterface $domain = null)
117
-    {
118
-        if ($dependency_map instanceof EE_Dependency_Map) {
119
-            $this->setDependencyMap($dependency_map);
120
-        }
121
-        if ($domain instanceof DomainInterface) {
122
-            $this->setDomain($domain);
123
-        }
124
-        add_action('AHEE__EE_System__load_controllers__load_admin_controllers', [$this, 'admin_init']);
125
-    }
126
-
127
-
128
-    /**
129
-     * @param EE_Dependency_Map $dependency_map
130
-     */
131
-    public function setDependencyMap($dependency_map)
132
-    {
133
-        $this->dependency_map = $dependency_map;
134
-    }
135
-
136
-
137
-    /**
138
-     * @return EE_Dependency_Map
139
-     */
140
-    public function dependencyMap(): ?EE_Dependency_Map
141
-    {
142
-        return $this->dependency_map;
143
-    }
144
-
145
-
146
-    /**
147
-     * @param DomainInterface $domain
148
-     */
149
-    public function setDomain(DomainInterface $domain)
150
-    {
151
-        $this->domain = $domain;
152
-    }
153
-
154
-
155
-    /**
156
-     * @return DomainInterface
157
-     */
158
-    public function domain(): ?DomainInterface
159
-    {
160
-        return $this->domain;
161
-    }
162
-
163
-
164
-    /**
165
-     * @param string $version
166
-     */
167
-    public function set_version(string $version = '')
168
-    {
169
-        $this->_version = $version;
170
-    }
171
-
172
-
173
-    /**
174
-     * get__version
175
-     *
176
-     * @return string
177
-     */
178
-    public function version(): string
179
-    {
180
-        return $this->_version;
181
-    }
182
-
183
-
184
-    /**
185
-     * @param mixed $min_core_version
186
-     */
187
-    public function set_min_core_version($min_core_version = null)
188
-    {
189
-        $this->_min_core_version = $min_core_version;
190
-    }
191
-
192
-
193
-    /**
194
-     * get__min_core_version
195
-     *
196
-     * @return string
197
-     */
198
-    public function min_core_version(): string
199
-    {
200
-        return $this->_min_core_version;
201
-    }
202
-
203
-
204
-    /**
205
-     * Sets addon_name
206
-     *
207
-     * @param string $addon_name
208
-     */
209
-    public function set_name(string $addon_name)
210
-    {
211
-        $this->_addon_name = $addon_name;
212
-    }
213
-
214
-
215
-    /**
216
-     * Gets addon_name
217
-     *
218
-     * @return string
219
-     */
220
-    public function name()
221
-    {
222
-        return $this->_addon_name;
223
-    }
224
-
225
-
226
-    /**
227
-     * @return string
228
-     */
229
-    public function plugin_basename(): string
230
-    {
231
-
232
-        return $this->_plugin_basename;
233
-    }
234
-
235
-
236
-    /**
237
-     * @param string $plugin_basename
238
-     */
239
-    public function set_plugin_basename(string $plugin_basename)
240
-    {
241
-
242
-        $this->_plugin_basename = $plugin_basename;
243
-    }
244
-
245
-
246
-    /**
247
-     * @return string
248
-     */
249
-    public function plugin_slug(): string
250
-    {
251
-
252
-        return $this->_plugin_slug;
253
-    }
254
-
255
-
256
-    /**
257
-     * @param string $plugin_slug
258
-     */
259
-    public function set_plugin_slug(string $plugin_slug)
260
-    {
261
-
262
-        $this->_plugin_slug = $plugin_slug;
263
-    }
264
-
265
-
266
-    /**
267
-     * @return string
268
-     */
269
-    public function plugin_action_slug(): string
270
-    {
271
-
272
-        return $this->_plugin_action_slug;
273
-    }
274
-
275
-
276
-    /**
277
-     * @param string $plugin_action_slug
278
-     */
279
-    public function set_plugin_action_slug(string $plugin_action_slug)
280
-    {
281
-
282
-        $this->_plugin_action_slug = $plugin_action_slug;
283
-    }
284
-
285
-
286
-    /**
287
-     * @return array
288
-     */
289
-    public function get_plugins_page_row(): array
290
-    {
291
-
292
-        return $this->_plugins_page_row;
293
-    }
294
-
295
-
296
-    /**
297
-     * @param array|string $plugins_page_row
298
-     */
299
-    public function set_plugins_page_row(array $plugins_page_row = [])
300
-    {
301
-        // sigh.... check for example content that I stupidly merged to master and remove it if found
302
-        if (
303
-            ! is_array($plugins_page_row)
304
-            && strpos($plugins_page_row, '<h3>Promotions Addon Upsell Info</h3>') !== false
305
-        ) {
306
-            $plugins_page_row = [];
307
-        }
308
-        $this->_plugins_page_row = (array) $plugins_page_row;
309
-    }
310
-
311
-
312
-    /**
313
-     * Called when EE core detects this addon has been activated for the first time.
314
-     * If the site isn't in maintenance mode, should setup the addon's database
315
-     *
316
-     * @return void
317
-     * @throws EE_Error
318
-     */
319
-    public function new_install()
320
-    {
321
-        $classname = get_class($this);
322
-        do_action("AHEE__{$classname}__new_install");
323
-        do_action('AHEE__EE_Addon__new_install', $this);
324
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
325
-        add_action(
326
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
327
-            [$this, 'initialize_db_if_no_migrations_required']
328
-        );
329
-    }
330
-
331
-
332
-    /**
333
-     * Called when EE core detects this addon has been reactivated. When this happens,
334
-     * it's good to just check that your data is still intact
335
-     *
336
-     * @return void
337
-     * @throws EE_Error
338
-     */
339
-    public function reactivation()
340
-    {
341
-        $classname = get_class($this);
342
-        do_action("AHEE__{$classname}__reactivation");
343
-        do_action('AHEE__EE_Addon__reactivation', $this);
344
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
345
-        add_action(
346
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
347
-            [$this, 'initialize_db_if_no_migrations_required']
348
-        );
349
-    }
350
-
351
-
352
-    /**
353
-     * Called when the registered deactivation hook for this addon fires.
354
-     *
355
-     * @throws EE_Error
356
-     */
357
-    public function deactivation()
358
-    {
359
-        $classname = get_class($this);
360
-        do_action("AHEE__{$classname}__deactivation");
361
-        do_action('AHEE__EE_Addon__deactivation', $this);
362
-        // check if the site no longer needs to be in maintenance mode
363
-        EE_Register_Addon::deregister($this->name());
364
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
365
-    }
366
-
367
-
368
-    /**
369
-     * Takes care of double-checking that we're not in maintenance mode, and then
370
-     * initializing this addon's necessary initial data. This is called by default on new activations
371
-     * and reactivations.
372
-     *
373
-     * @param bool $verify_schema whether to verify the database's schema for this addon, or just its data.
374
-     *                               This is a resource-intensive job so we prefer to only do it when necessary
375
-     * @return void
376
-     * @throws EE_Error
377
-     * @throws InvalidInterfaceException
378
-     * @throws InvalidDataTypeException
379
-     * @throws InvalidArgumentException
380
-     * @throws ReflectionException
381
-     */
382
-    public function initialize_db_if_no_migrations_required($verify_schema = true)
383
-    {
384
-        if ($verify_schema === '') {
385
-            // wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
386
-            // (ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
387
-            // calls them with an argument of an empty string (ie ""), which evaluates to false
388
-            // so we need to treat the empty string as if nothing had been passed, and should instead use the default
389
-            $verify_schema = true;
390
-        }
391
-        if (DbStatus::isOnline()) {
392
-            if ($verify_schema) {
393
-                $this->initialize_db();
394
-            }
395
-            $this->initialize_default_data();
396
-            // @todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
397
-            EE_Data_Migration_Manager::instance()->update_current_database_state_to(
398
-                [
399
-                    'slug'    => $this->name(),
400
-                    'version' => $this->version(),
401
-                ]
402
-            );
403
-            /* make sure core's data is a-ok
23
+	/**
24
+	 * prefix to be added onto an addon's plugin slug to make a wp option name
25
+	 * which will be used to store the plugin's activation history
26
+	 */
27
+	const ee_addon_version_history_option_prefix = 'ee_version_history_';
28
+
29
+	/**
30
+	 * @var $_version
31
+	 * @type string
32
+	 */
33
+	protected $_version = '';
34
+
35
+	/**
36
+	 * @var $_min_core_version
37
+	 * @type string
38
+	 */
39
+	protected $_min_core_version = '';
40
+
41
+	/**
42
+	 * derived from plugin 'main_file_path using plugin_basename()
43
+	 *
44
+	 * @type string $_plugin_basename
45
+	 */
46
+	protected $_plugin_basename = '';
47
+
48
+	/**
49
+	 * A non-internationalized name to identify this addon for use in URLs, etc
50
+	 *
51
+	 * @type string $_plugin_slug
52
+	 */
53
+	protected $_plugin_slug = '';
54
+
55
+	/**
56
+	 * A non-internationalized name to identify this addon. Eg 'Calendar','MailChimp',etc/
57
+	 *
58
+	 * @type string _addon_name
59
+	 */
60
+	protected $_addon_name = '';
61
+
62
+	/**
63
+	 * one of the EE_System::req_type_* constants
64
+	 *
65
+	 * @type int $_req_type
66
+	 */
67
+	protected $_req_type;
68
+
69
+	/**
70
+	 * page slug to be used when generating the "Settings" link on the WP plugin page
71
+	 *
72
+	 * @type string $_plugin_action_slug
73
+	 */
74
+	protected $_plugin_action_slug = '';
75
+
76
+	/**
77
+	 * if not empty, inserts a new table row after this plugin's row on the WP Plugins page
78
+	 * that can be used for adding upgrading/marketing info
79
+	 *
80
+	 * @type array $_plugins_page_row
81
+	 */
82
+	protected $_plugins_page_row = [];
83
+
84
+
85
+	/**
86
+	 *    filepath to the main file, which can be used for register_activation_hook, register_deactivation_hook, etc.
87
+	 *
88
+	 * @type string
89
+	 */
90
+	protected $_main_plugin_file;
91
+
92
+	/**
93
+	 *    This is the slug used to identify this add-on within the plugin update engine.
94
+	 *
95
+	 * @type string
96
+	 */
97
+	protected $pue_slug = '';
98
+
99
+
100
+	/**
101
+	 * @var EE_Dependency_Map $dependency_map
102
+	 */
103
+	private $dependency_map;
104
+
105
+
106
+	/**
107
+	 * @var DomainInterface $domain
108
+	 */
109
+	private $domain;
110
+
111
+
112
+	/**
113
+	 * @param EE_Dependency_Map|null $dependency_map [optional]
114
+	 * @param DomainInterface|null   $domain         [optional]
115
+	 */
116
+	public function __construct(EE_Dependency_Map $dependency_map = null, DomainInterface $domain = null)
117
+	{
118
+		if ($dependency_map instanceof EE_Dependency_Map) {
119
+			$this->setDependencyMap($dependency_map);
120
+		}
121
+		if ($domain instanceof DomainInterface) {
122
+			$this->setDomain($domain);
123
+		}
124
+		add_action('AHEE__EE_System__load_controllers__load_admin_controllers', [$this, 'admin_init']);
125
+	}
126
+
127
+
128
+	/**
129
+	 * @param EE_Dependency_Map $dependency_map
130
+	 */
131
+	public function setDependencyMap($dependency_map)
132
+	{
133
+		$this->dependency_map = $dependency_map;
134
+	}
135
+
136
+
137
+	/**
138
+	 * @return EE_Dependency_Map
139
+	 */
140
+	public function dependencyMap(): ?EE_Dependency_Map
141
+	{
142
+		return $this->dependency_map;
143
+	}
144
+
145
+
146
+	/**
147
+	 * @param DomainInterface $domain
148
+	 */
149
+	public function setDomain(DomainInterface $domain)
150
+	{
151
+		$this->domain = $domain;
152
+	}
153
+
154
+
155
+	/**
156
+	 * @return DomainInterface
157
+	 */
158
+	public function domain(): ?DomainInterface
159
+	{
160
+		return $this->domain;
161
+	}
162
+
163
+
164
+	/**
165
+	 * @param string $version
166
+	 */
167
+	public function set_version(string $version = '')
168
+	{
169
+		$this->_version = $version;
170
+	}
171
+
172
+
173
+	/**
174
+	 * get__version
175
+	 *
176
+	 * @return string
177
+	 */
178
+	public function version(): string
179
+	{
180
+		return $this->_version;
181
+	}
182
+
183
+
184
+	/**
185
+	 * @param mixed $min_core_version
186
+	 */
187
+	public function set_min_core_version($min_core_version = null)
188
+	{
189
+		$this->_min_core_version = $min_core_version;
190
+	}
191
+
192
+
193
+	/**
194
+	 * get__min_core_version
195
+	 *
196
+	 * @return string
197
+	 */
198
+	public function min_core_version(): string
199
+	{
200
+		return $this->_min_core_version;
201
+	}
202
+
203
+
204
+	/**
205
+	 * Sets addon_name
206
+	 *
207
+	 * @param string $addon_name
208
+	 */
209
+	public function set_name(string $addon_name)
210
+	{
211
+		$this->_addon_name = $addon_name;
212
+	}
213
+
214
+
215
+	/**
216
+	 * Gets addon_name
217
+	 *
218
+	 * @return string
219
+	 */
220
+	public function name()
221
+	{
222
+		return $this->_addon_name;
223
+	}
224
+
225
+
226
+	/**
227
+	 * @return string
228
+	 */
229
+	public function plugin_basename(): string
230
+	{
231
+
232
+		return $this->_plugin_basename;
233
+	}
234
+
235
+
236
+	/**
237
+	 * @param string $plugin_basename
238
+	 */
239
+	public function set_plugin_basename(string $plugin_basename)
240
+	{
241
+
242
+		$this->_plugin_basename = $plugin_basename;
243
+	}
244
+
245
+
246
+	/**
247
+	 * @return string
248
+	 */
249
+	public function plugin_slug(): string
250
+	{
251
+
252
+		return $this->_plugin_slug;
253
+	}
254
+
255
+
256
+	/**
257
+	 * @param string $plugin_slug
258
+	 */
259
+	public function set_plugin_slug(string $plugin_slug)
260
+	{
261
+
262
+		$this->_plugin_slug = $plugin_slug;
263
+	}
264
+
265
+
266
+	/**
267
+	 * @return string
268
+	 */
269
+	public function plugin_action_slug(): string
270
+	{
271
+
272
+		return $this->_plugin_action_slug;
273
+	}
274
+
275
+
276
+	/**
277
+	 * @param string $plugin_action_slug
278
+	 */
279
+	public function set_plugin_action_slug(string $plugin_action_slug)
280
+	{
281
+
282
+		$this->_plugin_action_slug = $plugin_action_slug;
283
+	}
284
+
285
+
286
+	/**
287
+	 * @return array
288
+	 */
289
+	public function get_plugins_page_row(): array
290
+	{
291
+
292
+		return $this->_plugins_page_row;
293
+	}
294
+
295
+
296
+	/**
297
+	 * @param array|string $plugins_page_row
298
+	 */
299
+	public function set_plugins_page_row(array $plugins_page_row = [])
300
+	{
301
+		// sigh.... check for example content that I stupidly merged to master and remove it if found
302
+		if (
303
+			! is_array($plugins_page_row)
304
+			&& strpos($plugins_page_row, '<h3>Promotions Addon Upsell Info</h3>') !== false
305
+		) {
306
+			$plugins_page_row = [];
307
+		}
308
+		$this->_plugins_page_row = (array) $plugins_page_row;
309
+	}
310
+
311
+
312
+	/**
313
+	 * Called when EE core detects this addon has been activated for the first time.
314
+	 * If the site isn't in maintenance mode, should setup the addon's database
315
+	 *
316
+	 * @return void
317
+	 * @throws EE_Error
318
+	 */
319
+	public function new_install()
320
+	{
321
+		$classname = get_class($this);
322
+		do_action("AHEE__{$classname}__new_install");
323
+		do_action('AHEE__EE_Addon__new_install', $this);
324
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
325
+		add_action(
326
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
327
+			[$this, 'initialize_db_if_no_migrations_required']
328
+		);
329
+	}
330
+
331
+
332
+	/**
333
+	 * Called when EE core detects this addon has been reactivated. When this happens,
334
+	 * it's good to just check that your data is still intact
335
+	 *
336
+	 * @return void
337
+	 * @throws EE_Error
338
+	 */
339
+	public function reactivation()
340
+	{
341
+		$classname = get_class($this);
342
+		do_action("AHEE__{$classname}__reactivation");
343
+		do_action('AHEE__EE_Addon__reactivation', $this);
344
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
345
+		add_action(
346
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
347
+			[$this, 'initialize_db_if_no_migrations_required']
348
+		);
349
+	}
350
+
351
+
352
+	/**
353
+	 * Called when the registered deactivation hook for this addon fires.
354
+	 *
355
+	 * @throws EE_Error
356
+	 */
357
+	public function deactivation()
358
+	{
359
+		$classname = get_class($this);
360
+		do_action("AHEE__{$classname}__deactivation");
361
+		do_action('AHEE__EE_Addon__deactivation', $this);
362
+		// check if the site no longer needs to be in maintenance mode
363
+		EE_Register_Addon::deregister($this->name());
364
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
365
+	}
366
+
367
+
368
+	/**
369
+	 * Takes care of double-checking that we're not in maintenance mode, and then
370
+	 * initializing this addon's necessary initial data. This is called by default on new activations
371
+	 * and reactivations.
372
+	 *
373
+	 * @param bool $verify_schema whether to verify the database's schema for this addon, or just its data.
374
+	 *                               This is a resource-intensive job so we prefer to only do it when necessary
375
+	 * @return void
376
+	 * @throws EE_Error
377
+	 * @throws InvalidInterfaceException
378
+	 * @throws InvalidDataTypeException
379
+	 * @throws InvalidArgumentException
380
+	 * @throws ReflectionException
381
+	 */
382
+	public function initialize_db_if_no_migrations_required($verify_schema = true)
383
+	{
384
+		if ($verify_schema === '') {
385
+			// wp core bug imo: if no args are passed to `do_action('some_hook_name')` besides the hook's name
386
+			// (ie, no 2nd or 3rd arguments), instead of calling the registered callbacks with no arguments, it
387
+			// calls them with an argument of an empty string (ie ""), which evaluates to false
388
+			// so we need to treat the empty string as if nothing had been passed, and should instead use the default
389
+			$verify_schema = true;
390
+		}
391
+		if (DbStatus::isOnline()) {
392
+			if ($verify_schema) {
393
+				$this->initialize_db();
394
+			}
395
+			$this->initialize_default_data();
396
+			// @todo: this will probably need to be adjusted in 4.4 as the array changed formats I believe
397
+			EE_Data_Migration_Manager::instance()->update_current_database_state_to(
398
+				[
399
+					'slug'    => $this->name(),
400
+					'version' => $this->version(),
401
+				]
402
+			);
403
+			/* make sure core's data is a-ok
404 404
              * (at the time of writing, we especially want to verify all the caps are present
405 405
              * because payment method type capabilities are added dynamically, and it's
406 406
              * possible this addon added a payment method. But it's also possible
407 407
              * other data needs to be verified)
408 408
              */
409
-            EEH_Activation::initialize_db_content();
410
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
411
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
412
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
413
-            );
414
-            $rewrite_rules->flushRewriteRules();
415
-            // in case there are lots of addons being activated at once, let's force garbage collection
416
-            // to help avoid memory limit errors
417
-            // EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
418
-            gc_collect_cycles();
419
-        } else {
420
-            // ask the data migration manager to init this addon's data
421
-            // when migrations are finished because we can't do it now
422
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
423
-        }
424
-    }
425
-
426
-
427
-    /**
428
-     * Used to setup this addon's database tables, but not necessarily any default
429
-     * data in them. The default is to actually use the most up-to-date data migration script
430
-     * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
431
-     * methods to setup the db.
432
-     *
433
-     * @throws EE_Error
434
-     * @throws ReflectionException
435
-     */
436
-    public function initialize_db()
437
-    {
438
-        // find the migration script that sets the database to be compatible with the code
439
-        $current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
440
-        if ($current_dms_name) {
441
-            $current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
442
-            $current_data_migration_script->set_migrating(false);
443
-            $current_data_migration_script->schema_changes_before_migration();
444
-            $current_data_migration_script->schema_changes_after_migration();
445
-            if ($current_data_migration_script->get_errors()) {
446
-                foreach ($current_data_migration_script->get_errors() as $error) {
447
-                    EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
448
-                }
449
-            }
450
-        }
451
-        // if not DMS was found that should be ok. This addon just doesn't require any database changes
452
-        EE_Data_Migration_Manager::instance()->update_current_database_state_to(
453
-            [
454
-                'slug'    => $this->name(),
455
-                'version' => $this->version(),
456
-            ]
457
-        );
458
-    }
459
-
460
-
461
-    /**
462
-     * If you want to setup default data for the addon, override this method, and call
463
-     * parent::initialize_default_data() from within it. This is normally called
464
-     * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
465
-     * and should verify default data is present (but this is also called
466
-     * on reactivations and just after migrations, so please verify you actually want
467
-     * to ADD default data, because it may already be present).
468
-     * However, please call this parent (currently it just fires a hook which other
469
-     * addons may be depending on)
470
-     */
471
-    public function initialize_default_data()
472
-    {
473
-        /**
474
-         * Called when an addon is ensuring its default data is set (possibly called
475
-         * on a reactivation, so first check for the absence of other data before setting
476
-         * default data)
477
-         *
478
-         * @param EE_Addon $addon the addon that called this
479
-         */
480
-        do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
481
-        // override to insert default data. It is safe to use the models here
482
-        // because the site should not be in maintenance mode
483
-    }
484
-
485
-
486
-    /**
487
-     * EE Core detected that this addon has been upgraded. We should check if there
488
-     * are any new migration scripts, and if so put the site into maintenance mode until
489
-     * they're ran
490
-     *
491
-     * @return void
492
-     * @throws EE_Error
493
-     */
494
-    public function upgrade()
495
-    {
496
-        $classname = get_class($this);
497
-        do_action("AHEE__{$classname}__upgrade");
498
-        do_action('AHEE__EE_Addon__upgrade', $this);
499
-        EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
500
-        // also it's possible there is new default data that needs to be added
501
-        add_action(
502
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
503
-            [$this, 'initialize_db_if_no_migrations_required']
504
-        );
505
-    }
506
-
507
-
508
-    /**
509
-     * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
510
-     */
511
-    public function downgrade()
512
-    {
513
-        $classname = get_class($this);
514
-        do_action("AHEE__{$classname}__downgrade");
515
-        do_action('AHEE__EE_Addon__downgrade', $this);
516
-        // it's possible there's old default data that needs to be double-checked
517
-        add_action(
518
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
519
-            [$this, 'initialize_db_if_no_migrations_required']
520
-        );
521
-    }
522
-
523
-
524
-    /**
525
-     * set_db_update_option_name
526
-     * Until we do something better, we'll just check for migration scripts upon
527
-     * plugin activation only. In the future, we'll want to do it on plugin updates too
528
-     *
529
-     * @return bool
530
-     */
531
-    public function set_db_update_option_name(): bool
532
-    {
533
-        EE_Error::doing_it_wrong(
534
-            __FUNCTION__,
535
-            esc_html__(
536
-                'EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
537
-                'event_espresso'
538
-            ),
539
-            '4.3.0.alpha.016'
540
-        );
541
-        // let's just handle this on the next request, ok? right now we're just not really ready
542
-        return $this->set_activation_indicator_option();
543
-    }
544
-
545
-
546
-    /**
547
-     * Returns the name of the activation indicator option
548
-     * (an option which is set temporarily to indicate that this addon was just activated)
549
-     *
550
-     * @return string
551
-     * @deprecated since version 4.3.0.alpha.016
552
-     */
553
-    public function get_db_update_option_name(): string
554
-    {
555
-        EE_Error::doing_it_wrong(
556
-            __FUNCTION__,
557
-            esc_html__(
558
-                'EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
559
-                'event_espresso'
560
-            ),
561
-            '4.3.0.alpha.016'
562
-        );
563
-        return $this->get_activation_indicator_option_name();
564
-    }
565
-
566
-
567
-    /**
568
-     * When the addon is activated, this should be called to set a wordpress option that
569
-     * indicates it was activated. This is especially useful for detecting reactivations.
570
-     *
571
-     * @return bool
572
-     */
573
-    public function set_activation_indicator_option(): bool
574
-    {
575
-        // let's just handle this on the next request, ok? right now we're just not really ready
576
-        return update_option($this->get_activation_indicator_option_name(), true);
577
-    }
578
-
579
-
580
-    /**
581
-     * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
582
-     *
583
-     * @return string
584
-     */
585
-    public function get_activation_indicator_option_name(): string
586
-    {
587
-        return 'ee_activation_' . $this->name();
588
-    }
589
-
590
-
591
-    /**
592
-     * Used by EE_System to set the request type of this addon. Should not be used by addon developers
593
-     *
594
-     * @param int $req_type
595
-     */
596
-    public function set_req_type(int $req_type)
597
-    {
598
-        $this->_req_type = $req_type;
599
-    }
600
-
601
-
602
-    /**
603
-     * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
604
-     * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
605
-     * EE_System when it is checking for new install or upgrades of addons
606
-     */
607
-    public function detect_req_type($redetect = false): int
608
-    {
609
-        if ($this->_req_type === null || $redetect) {
610
-            $this->detect_activation_or_upgrade();
611
-        }
612
-        return $this->_req_type;
613
-    }
614
-
615
-
616
-    /**
617
-     * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
618
-     * Should only be called once per request
619
-     *
620
-     * @return void
621
-     * @throws EE_Error
622
-     */
623
-    public function detect_activation_or_upgrade()
624
-    {
625
-        $activation_history_for_addon = $this->get_activation_history();
626
-        $request_type                 = EE_System::detect_req_type_given_activation_history(
627
-            $activation_history_for_addon,
628
-            $this->get_activation_indicator_option_name(),
629
-            $this->version()
630
-        );
631
-        $this->set_req_type($request_type);
632
-        $classname = get_class($this);
633
-        switch ($request_type) {
634
-            case EE_System::req_type_new_activation:
635
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
636
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
637
-                $this->new_install();
638
-                $this->update_list_of_installed_versions($activation_history_for_addon);
639
-                break;
640
-            case EE_System::req_type_reactivation:
641
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
642
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
643
-                $this->reactivation();
644
-                $this->update_list_of_installed_versions($activation_history_for_addon);
645
-                break;
646
-            case EE_System::req_type_upgrade:
647
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
648
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
649
-                $this->upgrade();
650
-                $this->update_list_of_installed_versions($activation_history_for_addon);
651
-                break;
652
-            case EE_System::req_type_downgrade:
653
-                do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
654
-                do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
655
-                $this->downgrade();
656
-                $this->update_list_of_installed_versions($activation_history_for_addon);
657
-                break;
658
-            case EE_System::req_type_normal:
659
-            default:
660
-                break;
661
-        }
662
-
663
-        do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
664
-    }
665
-
666
-
667
-    /**
668
-     * Updates the version history for this addon
669
-     *
670
-     * @param array  $version_history
671
-     * @param string $current_version_to_add
672
-     * @return bool success
673
-     */
674
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
675
-    {
676
-        if (! $version_history) {
677
-            $version_history = $this->get_activation_history();
678
-        }
679
-        if ($current_version_to_add === null) {
680
-            $current_version_to_add = $this->version();
681
-        }
682
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
683
-        return update_option($this->get_activation_history_option_name(), $version_history);
684
-    }
685
-
686
-
687
-    /**
688
-     * Gets the name of the wp option that stores the activation history
689
-     * of this addon
690
-     *
691
-     * @return string
692
-     */
693
-    public function get_activation_history_option_name(): string
694
-    {
695
-        return self::ee_addon_version_history_option_prefix . $this->name();
696
-    }
697
-
698
-
699
-    /**
700
-     * Gets the wp option which stores the activation history for this addon
701
-     *
702
-     * @return array
703
-     */
704
-    public function get_activation_history(): array
705
-    {
706
-        return get_option($this->get_activation_history_option_name(), []);
707
-    }
708
-
709
-
710
-    /**
711
-     * @param string $config_section
712
-     */
713
-    public function set_config_section($config_section = '')
714
-    {
715
-        $this->_config_section = ! empty($config_section) ? $config_section : 'addons';
716
-    }
717
-
718
-
719
-    /**
720
-     * Sets the filepath to the main plugin file
721
-     *
722
-     * @param string $filepath
723
-     */
724
-    public function set_main_plugin_file(string $filepath)
725
-    {
726
-        $this->_main_plugin_file = $filepath;
727
-    }
728
-
729
-
730
-    /**
731
-     * gets the filepath to teh main file
732
-     *
733
-     * @return string
734
-     */
735
-    public function get_main_plugin_file(): string
736
-    {
737
-        return $this->_main_plugin_file;
738
-    }
739
-
740
-
741
-    /**
742
-     * Gets the filename (no path) of the main file (the main file loaded
743
-     * by WP)
744
-     *
745
-     * @return string
746
-     */
747
-    public function get_main_plugin_file_basename(): string
748
-    {
749
-        return plugin_basename($this->get_main_plugin_file());
750
-    }
751
-
752
-
753
-    /**
754
-     * Gets the folder name which contains the main plugin file
755
-     *
756
-     * @return string
757
-     */
758
-    public function get_main_plugin_file_dirname(): string
759
-    {
760
-        return dirname($this->get_main_plugin_file());
761
-    }
762
-
763
-
764
-    /**
765
-     * sets hooks used in the admin
766
-     *
767
-     * @return void
768
-     */
769
-    public function admin_init()
770
-    {
771
-        // is admin and not in M-Mode ?
772
-        if (is_admin() && MaintenanceStatus::isDisabled()) {
773
-            add_filter('plugin_action_links', [$this, 'plugin_action_links'], 10, 2);
774
-            add_filter('after_plugin_row_' . $this->_plugin_basename, [$this, 'after_plugin_row'], 10, 3);
775
-        }
776
-    }
777
-
778
-
779
-    /**
780
-     * plugin_actions
781
-     * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
782
-     *
783
-     * @param array  $links
784
-     * @param string $file
785
-     * @return array
786
-     */
787
-    public function plugin_action_links(array $links, string $file): array
788
-    {
789
-        if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
790
-            // before other links
791
-            array_unshift(
792
-                $links,
793
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
794
-                . esc_html__('Settings', 'event_espresso')
795
-                . '</a>'
796
-            );
797
-        }
798
-        return $links;
799
-    }
800
-
801
-
802
-    /**
803
-     * after_plugin_row
804
-     * Add additional content to the plugins page plugin row
805
-     * Inserts another row
806
-     *
807
-     * @param string $plugin_file
808
-     * @param array  $plugin_data
809
-     * @param string $status
810
-     * @return void
811
-     */
812
-    public function after_plugin_row(string $plugin_file, array $plugin_data, string $status)
813
-    {
814
-        $after_plugin_row = '';
815
-        $plugins_page_row = $this->get_plugins_page_row();
816
-        if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
817
-            $class       = $status ? 'active' : 'inactive';
818
-            $link_text   = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
819
-            $link_url    = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
820
-            $description = isset($plugins_page_row['description'])
821
-                ? $plugins_page_row['description']
822
-                : '';
823
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
824
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
825
-                $after_plugin_row .= '<th class="check-column" scope="row"></th>';
826
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
827
-                $after_plugin_row .= '<p class="ee-addon-upsell-info-dv">
409
+			EEH_Activation::initialize_db_content();
410
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
411
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
412
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
413
+			);
414
+			$rewrite_rules->flushRewriteRules();
415
+			// in case there are lots of addons being activated at once, let's force garbage collection
416
+			// to help avoid memory limit errors
417
+			// EEH_Debug_Tools::instance()->measure_memory( 'db content initialized for ' . get_class( $this), true );
418
+			gc_collect_cycles();
419
+		} else {
420
+			// ask the data migration manager to init this addon's data
421
+			// when migrations are finished because we can't do it now
422
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for($this->name());
423
+		}
424
+	}
425
+
426
+
427
+	/**
428
+	 * Used to setup this addon's database tables, but not necessarily any default
429
+	 * data in them. The default is to actually use the most up-to-date data migration script
430
+	 * for this addon, and just use its schema_changes_before_migration() and schema_changes_after_migration()
431
+	 * methods to setup the db.
432
+	 *
433
+	 * @throws EE_Error
434
+	 * @throws ReflectionException
435
+	 */
436
+	public function initialize_db()
437
+	{
438
+		// find the migration script that sets the database to be compatible with the code
439
+		$current_dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms($this->name());
440
+		if ($current_dms_name) {
441
+			$current_data_migration_script = EE_Registry::instance()->load_dms($current_dms_name);
442
+			$current_data_migration_script->set_migrating(false);
443
+			$current_data_migration_script->schema_changes_before_migration();
444
+			$current_data_migration_script->schema_changes_after_migration();
445
+			if ($current_data_migration_script->get_errors()) {
446
+				foreach ($current_data_migration_script->get_errors() as $error) {
447
+					EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
448
+				}
449
+			}
450
+		}
451
+		// if not DMS was found that should be ok. This addon just doesn't require any database changes
452
+		EE_Data_Migration_Manager::instance()->update_current_database_state_to(
453
+			[
454
+				'slug'    => $this->name(),
455
+				'version' => $this->version(),
456
+			]
457
+		);
458
+	}
459
+
460
+
461
+	/**
462
+	 * If you want to setup default data for the addon, override this method, and call
463
+	 * parent::initialize_default_data() from within it. This is normally called
464
+	 * from EE_Addon::initialize_db_if_no_migrations_required(), just after EE_Addon::initialize_db()
465
+	 * and should verify default data is present (but this is also called
466
+	 * on reactivations and just after migrations, so please verify you actually want
467
+	 * to ADD default data, because it may already be present).
468
+	 * However, please call this parent (currently it just fires a hook which other
469
+	 * addons may be depending on)
470
+	 */
471
+	public function initialize_default_data()
472
+	{
473
+		/**
474
+		 * Called when an addon is ensuring its default data is set (possibly called
475
+		 * on a reactivation, so first check for the absence of other data before setting
476
+		 * default data)
477
+		 *
478
+		 * @param EE_Addon $addon the addon that called this
479
+		 */
480
+		do_action('AHEE__EE_Addon__initialize_default_data__begin', $this);
481
+		// override to insert default data. It is safe to use the models here
482
+		// because the site should not be in maintenance mode
483
+	}
484
+
485
+
486
+	/**
487
+	 * EE Core detected that this addon has been upgraded. We should check if there
488
+	 * are any new migration scripts, and if so put the site into maintenance mode until
489
+	 * they're ran
490
+	 *
491
+	 * @return void
492
+	 * @throws EE_Error
493
+	 */
494
+	public function upgrade()
495
+	{
496
+		$classname = get_class($this);
497
+		do_action("AHEE__{$classname}__upgrade");
498
+		do_action('AHEE__EE_Addon__upgrade', $this);
499
+		EE_Maintenance_Mode::instance()->set_maintenance_mode_if_db_old();
500
+		// also it's possible there is new default data that needs to be added
501
+		add_action(
502
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
503
+			[$this, 'initialize_db_if_no_migrations_required']
504
+		);
505
+	}
506
+
507
+
508
+	/**
509
+	 * If Core detects this addon has been downgraded, you may want to invoke some special logic here.
510
+	 */
511
+	public function downgrade()
512
+	{
513
+		$classname = get_class($this);
514
+		do_action("AHEE__{$classname}__downgrade");
515
+		do_action('AHEE__EE_Addon__downgrade', $this);
516
+		// it's possible there's old default data that needs to be double-checked
517
+		add_action(
518
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
519
+			[$this, 'initialize_db_if_no_migrations_required']
520
+		);
521
+	}
522
+
523
+
524
+	/**
525
+	 * set_db_update_option_name
526
+	 * Until we do something better, we'll just check for migration scripts upon
527
+	 * plugin activation only. In the future, we'll want to do it on plugin updates too
528
+	 *
529
+	 * @return bool
530
+	 */
531
+	public function set_db_update_option_name(): bool
532
+	{
533
+		EE_Error::doing_it_wrong(
534
+			__FUNCTION__,
535
+			esc_html__(
536
+				'EE_Addon::set_db_update_option_name was renamed to EE_Addon::set_activation_indicator_option',
537
+				'event_espresso'
538
+			),
539
+			'4.3.0.alpha.016'
540
+		);
541
+		// let's just handle this on the next request, ok? right now we're just not really ready
542
+		return $this->set_activation_indicator_option();
543
+	}
544
+
545
+
546
+	/**
547
+	 * Returns the name of the activation indicator option
548
+	 * (an option which is set temporarily to indicate that this addon was just activated)
549
+	 *
550
+	 * @return string
551
+	 * @deprecated since version 4.3.0.alpha.016
552
+	 */
553
+	public function get_db_update_option_name(): string
554
+	{
555
+		EE_Error::doing_it_wrong(
556
+			__FUNCTION__,
557
+			esc_html__(
558
+				'EE_Addon::get_db_update_option was renamed to EE_Addon::get_activation_indicator_option_name',
559
+				'event_espresso'
560
+			),
561
+			'4.3.0.alpha.016'
562
+		);
563
+		return $this->get_activation_indicator_option_name();
564
+	}
565
+
566
+
567
+	/**
568
+	 * When the addon is activated, this should be called to set a wordpress option that
569
+	 * indicates it was activated. This is especially useful for detecting reactivations.
570
+	 *
571
+	 * @return bool
572
+	 */
573
+	public function set_activation_indicator_option(): bool
574
+	{
575
+		// let's just handle this on the next request, ok? right now we're just not really ready
576
+		return update_option($this->get_activation_indicator_option_name(), true);
577
+	}
578
+
579
+
580
+	/**
581
+	 * Gets the name of the wp option which is used to temporarily indicate that this addon was activated
582
+	 *
583
+	 * @return string
584
+	 */
585
+	public function get_activation_indicator_option_name(): string
586
+	{
587
+		return 'ee_activation_' . $this->name();
588
+	}
589
+
590
+
591
+	/**
592
+	 * Used by EE_System to set the request type of this addon. Should not be used by addon developers
593
+	 *
594
+	 * @param int $req_type
595
+	 */
596
+	public function set_req_type(int $req_type)
597
+	{
598
+		$this->_req_type = $req_type;
599
+	}
600
+
601
+
602
+	/**
603
+	 * Returns the request type of this addon (ie, EE_System::req_type_normal, EE_System::req_type_new_activation,
604
+	 * EE_System::req_type_reactivation, EE_System::req_type_upgrade, or EE_System::req_type_downgrade). This is set by
605
+	 * EE_System when it is checking for new install or upgrades of addons
606
+	 */
607
+	public function detect_req_type($redetect = false): int
608
+	{
609
+		if ($this->_req_type === null || $redetect) {
610
+			$this->detect_activation_or_upgrade();
611
+		}
612
+		return $this->_req_type;
613
+	}
614
+
615
+
616
+	/**
617
+	 * Detects the request type for this addon (whether it was just activated, upgrades, a normal request, etc.)
618
+	 * Should only be called once per request
619
+	 *
620
+	 * @return void
621
+	 * @throws EE_Error
622
+	 */
623
+	public function detect_activation_or_upgrade()
624
+	{
625
+		$activation_history_for_addon = $this->get_activation_history();
626
+		$request_type                 = EE_System::detect_req_type_given_activation_history(
627
+			$activation_history_for_addon,
628
+			$this->get_activation_indicator_option_name(),
629
+			$this->version()
630
+		);
631
+		$this->set_req_type($request_type);
632
+		$classname = get_class($this);
633
+		switch ($request_type) {
634
+			case EE_System::req_type_new_activation:
635
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__new_activation");
636
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__new_activation', $this);
637
+				$this->new_install();
638
+				$this->update_list_of_installed_versions($activation_history_for_addon);
639
+				break;
640
+			case EE_System::req_type_reactivation:
641
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__reactivation");
642
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__reactivation', $this);
643
+				$this->reactivation();
644
+				$this->update_list_of_installed_versions($activation_history_for_addon);
645
+				break;
646
+			case EE_System::req_type_upgrade:
647
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__upgrade");
648
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__upgrade', $this);
649
+				$this->upgrade();
650
+				$this->update_list_of_installed_versions($activation_history_for_addon);
651
+				break;
652
+			case EE_System::req_type_downgrade:
653
+				do_action("AHEE__{$classname}__detect_activations_or_upgrades__downgrade");
654
+				do_action('AHEE__EE_Addon__detect_activations_or_upgrades__downgrade', $this);
655
+				$this->downgrade();
656
+				$this->update_list_of_installed_versions($activation_history_for_addon);
657
+				break;
658
+			case EE_System::req_type_normal:
659
+			default:
660
+				break;
661
+		}
662
+
663
+		do_action("AHEE__{$classname}__detect_if_activation_or_upgrade__complete");
664
+	}
665
+
666
+
667
+	/**
668
+	 * Updates the version history for this addon
669
+	 *
670
+	 * @param array  $version_history
671
+	 * @param string $current_version_to_add
672
+	 * @return bool success
673
+	 */
674
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
675
+	{
676
+		if (! $version_history) {
677
+			$version_history = $this->get_activation_history();
678
+		}
679
+		if ($current_version_to_add === null) {
680
+			$current_version_to_add = $this->version();
681
+		}
682
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
683
+		return update_option($this->get_activation_history_option_name(), $version_history);
684
+	}
685
+
686
+
687
+	/**
688
+	 * Gets the name of the wp option that stores the activation history
689
+	 * of this addon
690
+	 *
691
+	 * @return string
692
+	 */
693
+	public function get_activation_history_option_name(): string
694
+	{
695
+		return self::ee_addon_version_history_option_prefix . $this->name();
696
+	}
697
+
698
+
699
+	/**
700
+	 * Gets the wp option which stores the activation history for this addon
701
+	 *
702
+	 * @return array
703
+	 */
704
+	public function get_activation_history(): array
705
+	{
706
+		return get_option($this->get_activation_history_option_name(), []);
707
+	}
708
+
709
+
710
+	/**
711
+	 * @param string $config_section
712
+	 */
713
+	public function set_config_section($config_section = '')
714
+	{
715
+		$this->_config_section = ! empty($config_section) ? $config_section : 'addons';
716
+	}
717
+
718
+
719
+	/**
720
+	 * Sets the filepath to the main plugin file
721
+	 *
722
+	 * @param string $filepath
723
+	 */
724
+	public function set_main_plugin_file(string $filepath)
725
+	{
726
+		$this->_main_plugin_file = $filepath;
727
+	}
728
+
729
+
730
+	/**
731
+	 * gets the filepath to teh main file
732
+	 *
733
+	 * @return string
734
+	 */
735
+	public function get_main_plugin_file(): string
736
+	{
737
+		return $this->_main_plugin_file;
738
+	}
739
+
740
+
741
+	/**
742
+	 * Gets the filename (no path) of the main file (the main file loaded
743
+	 * by WP)
744
+	 *
745
+	 * @return string
746
+	 */
747
+	public function get_main_plugin_file_basename(): string
748
+	{
749
+		return plugin_basename($this->get_main_plugin_file());
750
+	}
751
+
752
+
753
+	/**
754
+	 * Gets the folder name which contains the main plugin file
755
+	 *
756
+	 * @return string
757
+	 */
758
+	public function get_main_plugin_file_dirname(): string
759
+	{
760
+		return dirname($this->get_main_plugin_file());
761
+	}
762
+
763
+
764
+	/**
765
+	 * sets hooks used in the admin
766
+	 *
767
+	 * @return void
768
+	 */
769
+	public function admin_init()
770
+	{
771
+		// is admin and not in M-Mode ?
772
+		if (is_admin() && MaintenanceStatus::isDisabled()) {
773
+			add_filter('plugin_action_links', [$this, 'plugin_action_links'], 10, 2);
774
+			add_filter('after_plugin_row_' . $this->_plugin_basename, [$this, 'after_plugin_row'], 10, 3);
775
+		}
776
+	}
777
+
778
+
779
+	/**
780
+	 * plugin_actions
781
+	 * Add a settings link to the Plugins page, so people can go straight from the plugin page to the settings page.
782
+	 *
783
+	 * @param array  $links
784
+	 * @param string $file
785
+	 * @return array
786
+	 */
787
+	public function plugin_action_links(array $links, string $file): array
788
+	{
789
+		if ($file === $this->plugin_basename() && $this->plugin_action_slug() !== '') {
790
+			// before other links
791
+			array_unshift(
792
+				$links,
793
+				'<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
794
+				. esc_html__('Settings', 'event_espresso')
795
+				. '</a>'
796
+			);
797
+		}
798
+		return $links;
799
+	}
800
+
801
+
802
+	/**
803
+	 * after_plugin_row
804
+	 * Add additional content to the plugins page plugin row
805
+	 * Inserts another row
806
+	 *
807
+	 * @param string $plugin_file
808
+	 * @param array  $plugin_data
809
+	 * @param string $status
810
+	 * @return void
811
+	 */
812
+	public function after_plugin_row(string $plugin_file, array $plugin_data, string $status)
813
+	{
814
+		$after_plugin_row = '';
815
+		$plugins_page_row = $this->get_plugins_page_row();
816
+		if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
817
+			$class       = $status ? 'active' : 'inactive';
818
+			$link_text   = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
819
+			$link_url    = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
820
+			$description = isset($plugins_page_row['description'])
821
+				? $plugins_page_row['description']
822
+				: '';
823
+			if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
824
+				$after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
825
+				$after_plugin_row .= '<th class="check-column" scope="row"></th>';
826
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
827
+				$after_plugin_row .= '<p class="ee-addon-upsell-info-dv">
828 828
 	                <a class="button button--primary" href="' . esc_url_raw($link_url) . '">'
829
-                    . $link_text
830
-                    . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
831
-                    . '</a>
829
+					. $link_text
830
+					. ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
831
+					. '</a>
832 832
                 </p>';
833
-                $after_plugin_row .= '</td>';
834
-                $after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
835
-                $after_plugin_row .= $description;
836
-                $after_plugin_row .= '</td>';
837
-                $after_plugin_row .= '</tr>';
838
-            } else {
839
-                $after_plugin_row .= $description;
840
-            }
841
-        }
842
-
843
-        echo wp_kses($after_plugin_row, AllowedTags::getAllowedTags());
844
-    }
845
-
846
-
847
-    /**
848
-     * A safe space for addons to add additional logic like setting hooks that need to be set early in the request.
849
-     * Child classes that have logic like that to run can override this method declaration.  This was not made abstract
850
-     * for back compat reasons.
851
-     *
852
-     * This will fire on the `AHEE__EE_System__load_espresso_addons__complete` hook at priority 999.
853
-     *
854
-     * It is recommended, if client code is `de-registering` an add-on, then do it on the
855
-     * `AHEE__EE_System__load_espresso_addons__complete` hook before priority 999 so as to ensure any code logic in this
856
-     * callback does not get run/set in that request.
857
-     *
858
-     * Also, keep in mind that if a registered add-on happens to be deactivated via
859
-     * EE_System::_deactivate_incompatible_addons() because its incompatible, any code executed in this method
860
-     * (including setting hooks etc) will have executed before the plugin was deactivated.  If you use
861
-     * `after_registration` to set any filter and/or action hooks and want to ensure they are removed on this add-on's
862
-     * deactivation, you can override `EE_Addon::deactivation` and unset your hooks and filters there.  Just remember
863
-     * to call `parent::deactivation`.
864
-     *
865
-     * @since 4.9.26
866
-     */
867
-    public function after_registration()
868
-    {
869
-        // cricket chirp... cricket chirp...
870
-    }
871
-
872
-
873
-    /**
874
-     * @return string
875
-     */
876
-    public function getPueSlug(): string
877
-    {
878
-        return $this->pue_slug;
879
-    }
880
-
881
-
882
-    /**
883
-     * @param string $pue_slug
884
-     */
885
-    public function setPueSlug(string $pue_slug)
886
-    {
887
-        $this->pue_slug = $pue_slug;
888
-    }
833
+				$after_plugin_row .= '</td>';
834
+				$after_plugin_row .= '<td class="ee-addon-upsell-info-desc-td column-description desc">';
835
+				$after_plugin_row .= $description;
836
+				$after_plugin_row .= '</td>';
837
+				$after_plugin_row .= '</tr>';
838
+			} else {
839
+				$after_plugin_row .= $description;
840
+			}
841
+		}
842
+
843
+		echo wp_kses($after_plugin_row, AllowedTags::getAllowedTags());
844
+	}
845
+
846
+
847
+	/**
848
+	 * A safe space for addons to add additional logic like setting hooks that need to be set early in the request.
849
+	 * Child classes that have logic like that to run can override this method declaration.  This was not made abstract
850
+	 * for back compat reasons.
851
+	 *
852
+	 * This will fire on the `AHEE__EE_System__load_espresso_addons__complete` hook at priority 999.
853
+	 *
854
+	 * It is recommended, if client code is `de-registering` an add-on, then do it on the
855
+	 * `AHEE__EE_System__load_espresso_addons__complete` hook before priority 999 so as to ensure any code logic in this
856
+	 * callback does not get run/set in that request.
857
+	 *
858
+	 * Also, keep in mind that if a registered add-on happens to be deactivated via
859
+	 * EE_System::_deactivate_incompatible_addons() because its incompatible, any code executed in this method
860
+	 * (including setting hooks etc) will have executed before the plugin was deactivated.  If you use
861
+	 * `after_registration` to set any filter and/or action hooks and want to ensure they are removed on this add-on's
862
+	 * deactivation, you can override `EE_Addon::deactivation` and unset your hooks and filters there.  Just remember
863
+	 * to call `parent::deactivation`.
864
+	 *
865
+	 * @since 4.9.26
866
+	 */
867
+	public function after_registration()
868
+	{
869
+		// cricket chirp... cricket chirp...
870
+	}
871
+
872
+
873
+	/**
874
+	 * @return string
875
+	 */
876
+	public function getPueSlug(): string
877
+	{
878
+		return $this->pue_slug;
879
+	}
880
+
881
+
882
+	/**
883
+	 * @param string $pue_slug
884
+	 */
885
+	public function setPueSlug(string $pue_slug)
886
+	{
887
+		$this->pue_slug = $pue_slug;
888
+	}
889 889
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
      */
585 585
     public function get_activation_indicator_option_name(): string
586 586
     {
587
-        return 'ee_activation_' . $this->name();
587
+        return 'ee_activation_'.$this->name();
588 588
     }
589 589
 
590 590
 
@@ -673,13 +673,13 @@  discard block
 block discarded – undo
673 673
      */
674 674
     public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null): bool
675 675
     {
676
-        if (! $version_history) {
676
+        if ( ! $version_history) {
677 677
             $version_history = $this->get_activation_history();
678 678
         }
679 679
         if ($current_version_to_add === null) {
680 680
             $current_version_to_add = $this->version();
681 681
         }
682
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
682
+        $version_history[$current_version_to_add][] = date('Y-m-d H:i:s', time());
683 683
         return update_option($this->get_activation_history_option_name(), $version_history);
684 684
     }
685 685
 
@@ -692,7 +692,7 @@  discard block
 block discarded – undo
692 692
      */
693 693
     public function get_activation_history_option_name(): string
694 694
     {
695
-        return self::ee_addon_version_history_option_prefix . $this->name();
695
+        return self::ee_addon_version_history_option_prefix.$this->name();
696 696
     }
697 697
 
698 698
 
@@ -771,7 +771,7 @@  discard block
 block discarded – undo
771 771
         // is admin and not in M-Mode ?
772 772
         if (is_admin() && MaintenanceStatus::isDisabled()) {
773 773
             add_filter('plugin_action_links', [$this, 'plugin_action_links'], 10, 2);
774
-            add_filter('after_plugin_row_' . $this->_plugin_basename, [$this, 'after_plugin_row'], 10, 3);
774
+            add_filter('after_plugin_row_'.$this->_plugin_basename, [$this, 'after_plugin_row'], 10, 3);
775 775
         }
776 776
     }
777 777
 
@@ -790,7 +790,7 @@  discard block
 block discarded – undo
790 790
             // before other links
791 791
             array_unshift(
792 792
                 $links,
793
-                '<a href="admin.php?page=' . $this->plugin_action_slug() . '">'
793
+                '<a href="admin.php?page='.$this->plugin_action_slug().'">'
794 794
                 . esc_html__('Settings', 'event_espresso')
795 795
                 . '</a>'
796 796
             );
@@ -813,19 +813,19 @@  discard block
 block discarded – undo
813 813
     {
814 814
         $after_plugin_row = '';
815 815
         $plugins_page_row = $this->get_plugins_page_row();
816
-        if (! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
816
+        if ( ! empty($plugins_page_row) && $plugin_file === $this->plugin_basename()) {
817 817
             $class       = $status ? 'active' : 'inactive';
818 818
             $link_text   = isset($plugins_page_row['link_text']) ? $plugins_page_row['link_text'] : '';
819 819
             $link_url    = isset($plugins_page_row['link_url']) ? $plugins_page_row['link_url'] : '';
820 820
             $description = isset($plugins_page_row['description'])
821 821
                 ? $plugins_page_row['description']
822 822
                 : '';
823
-            if (! empty($link_text) && ! empty($link_url) && ! empty($description)) {
824
-                $after_plugin_row .= '<tr id="' . sanitize_title($plugin_file) . '-ee-addon" class="' . $class . '">';
823
+            if ( ! empty($link_text) && ! empty($link_url) && ! empty($description)) {
824
+                $after_plugin_row .= '<tr id="'.sanitize_title($plugin_file).'-ee-addon" class="'.$class.'">';
825 825
                 $after_plugin_row .= '<th class="check-column" scope="row"></th>';
826 826
                 $after_plugin_row .= '<td class="ee-addon-upsell-info-title-td plugin-title column-primary">';
827 827
                 $after_plugin_row .= '<p class="ee-addon-upsell-info-dv">
828
-	                <a class="button button--primary" href="' . esc_url_raw($link_url) . '">'
828
+	                <a class="button button--primary" href="' . esc_url_raw($link_url).'">'
829 829
                     . $link_text
830 830
                     . ' &nbsp;<span class="dashicons dashicons-arrow-right-alt2" style="margin:0;"></span>'
831 831
                     . '</a>
Please login to merge, or discard this patch.
core/EE_Maintenance_Mode.core.php 2 patches
Indentation   +502 added lines, -502 removed lines patch added patch discarded remove patch
@@ -19,514 +19,514 @@
 block discarded – undo
19 19
  */
20 20
 class EE_Maintenance_Mode implements ResettableInterface
21 21
 {
22
-    /**
23
-     * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
24
-     * STATUS_OFF means the site is NOT in maintenance mode (so everything's normal)
25
-     */
26
-    public const STATUS_OFF = 0;
27
-
28
-
29
-    /**
30
-     * STATUS_PUBLIC_ONLY means that the site's frontend EE code should be completely disabled
31
-     * but the admin backend should be running as normal. Maybe an admin can view the frontend though
32
-     */
33
-    public const STATUS_PUBLIC_ONLY = 1;
34
-
35
-    /**
36
-     * STATUS_FULL_SITE means the frontend AND EE backend code are disabled. The only system running
37
-     * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
38
-     * migration scripts before taking the site out of maintenance mode
39
-     */
40
-    public const STATUS_FULL_SITE = 2;
41
-
42
-    /**
43
-     * the name of the option which stores the current level of maintenance mode
44
-     */
45
-    private const OPTION_NAME = 'ee_maintenance_mode';
46
-
47
-
48
-    protected LoaderInterface $loader;
49
-
50
-    private RequestInterface $request;
51
-
52
-    private static ?EE_Maintenance_Mode $_instance = null;
53
-
54
-    /**
55
-     * @var int
56
-     * @since 5.0.12.p
57
-     */
58
-    private int $status;
59
-
60
-    /**
61
-     * @var int
62
-     * @since 5.0.12.p
63
-     */
64
-    private int $admin_status;
65
-
66
-    /**
67
-     * true if current_user_can('administrator')
68
-     *
69
-     * @var bool
70
-     * @since 5.0.12.p
71
-     */
72
-    private bool $current_user_is_admin;
73
-
74
-    /**
75
-     * used to control updates to the WP options setting in the database
76
-     *
77
-     * @var bool
78
-     * @since 5.0.12.p
79
-     */
80
-    private bool $update_db;
81
-
82
-
83
-    /**
84
-     * @singleton method used to instantiate class object
85
-     * @param LoaderInterface|null  $loader
86
-     * @param RequestInterface|null $request
87
-     * @return EE_Maintenance_Mode|null
88
-     */
89
-    public static function instance(
90
-        ?LoaderInterface $loader = null,
91
-        ?RequestInterface $request = null
92
-    ): ?EE_Maintenance_Mode {
93
-        // check if class object is instantiated
94
-        if (! self::$_instance instanceof EE_Maintenance_Mode) {
95
-            self::$_instance = new EE_Maintenance_Mode($loader, $request);
96
-        }
97
-        return self::$_instance;
98
-    }
99
-
100
-
101
-    /**
102
-     * Resets maintenance mode (mostly just re-checks whether we should be in maintenance mode)
103
-     *
104
-     * @return EE_Maintenance_Mode|null
105
-     * @throws EE_Error
106
-     */
107
-    public static function reset(): ?EE_Maintenance_Mode
108
-    {
109
-        self::instance()->set_maintenance_mode_if_db_old();
110
-        return self::instance();
111
-    }
112
-
113
-
114
-    /**
115
-     *private constructor to prevent direct creation
116
-     */
117
-    private function __construct(LoaderInterface $loader, RequestInterface $request)
118
-    {
119
-        $this->loader                = $loader;
120
-        $this->request               = $request;
121
-        $this->current_user_is_admin = current_user_can('administrator');
122
-        $this->status                = $this->loadStatusFromDatabase();
123
-        $this->admin_status          = $this->setAdminStatus($this->status);
124
-        // now make sure the status is set correctly everywhere
125
-        $this->update_db = false;
126
-        $this->set_maintenance_level($this->status);
127
-        $this->update_db = true;
128
-
129
-        // if M-Mode level 2 is engaged, we still need basic assets loaded
130
-        add_action('wp_enqueue_scripts', [$this, 'load_assets_required_for_m_mode']);
131
-        // shut 'er down for maintenance ?
132
-        add_filter('the_content', [$this, 'the_content'], 2);
133
-        // redirect ee menus to maintenance page
134
-        add_action('admin_page_access_denied', [$this, 'redirect_to_maintenance']);
135
-        // add powered by EE msg
136
-        add_action('shutdown', [$this, 'display_maintenance_mode_notice']);
137
-    }
138
-
139
-
140
-    private function loadStatusFromDatabase(): int
141
-    {
142
-        return (int) get_option(EE_Maintenance_Mode::OPTION_NAME, EE_Maintenance_Mode::STATUS_OFF);
143
-    }
144
-
145
-
146
-    /**
147
-     * changes the maintenance mode level to reflect whether the current user is an admin or not.
148
-     * Determines whether we're in maintenance mode and what level. However, while the site
149
-     * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
150
-     * to them as if the site isn't in maintenance mode.
151
-     *      EE_Maintenance_Mode::STATUS_OFF => not in maintenance mode (in normal mode)
152
-     *      EE_Maintenance_Mode::STATUS_PUBLIC_ONLY=> frontend-only maintenance mode
153
-     *      EE_Maintenance_Mode::STATUS_FULL_SITE => frontend and backend maintenance mode
154
-     *
155
-     * @param int $status
156
-     * @return int
157
-     * @since 5.0.12.p
158
-     */
159
-    private function setAdminStatus(int $status): int
160
-    {
161
-        if (
162
-            $status === EE_Maintenance_Mode::STATUS_PUBLIC_ONLY
163
-            && $this->current_user_is_admin
164
-            && ($this->request->isAjax() || ! $this->request->isAdmin())
165
-        ) {
166
-            return EE_Maintenance_Mode::STATUS_OFF;
167
-        }
168
-        return $status;
169
-    }
170
-
171
-
172
-    public function real_level(): int
173
-    {
174
-        return $this->status;
175
-    }
176
-
177
-
178
-    /**
179
-     * @return int
180
-     */
181
-    public function level(): int
182
-    {
183
-        return $this->admin_status;
184
-    }
185
-
186
-
187
-    /**
188
-     * Determines if we need to put EE in maintenance mode because the database needs updating
189
-     *
190
-     * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
191
-     * @throws EE_Error
192
-     */
193
-    public function set_maintenance_mode_if_db_old(): bool
194
-    {
195
-        $this->loader->getShared('Data_Migration_Manager');
196
-        if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
197
-            $this->activateFullSiteMaintenanceMode();
198
-            return true;
199
-        }
200
-        if ($this->status === EE_Maintenance_Mode::STATUS_FULL_SITE) {
201
-            // we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
202
-            // then we shouldn't be in mm2. (Maybe an addon got deactivated?)
203
-            $this->deactivateMaintenanceMode();
204
-        }
205
-        return false;
206
-    }
207
-
208
-
209
-    /**
210
-     * Updates the maintenance level on the site
211
-     *
212
-     * @param int $level
213
-     * @return void
214
-     */
215
-    public function set_maintenance_level(int $level): void
216
-    {
217
-        switch ($level) {
218
-            case EE_Maintenance_Mode::STATUS_OFF:
219
-                $this->deactivateMaintenanceMode();
220
-                return;
221
-            case EE_Maintenance_Mode::STATUS_PUBLIC_ONLY:
222
-                $this->activatePublicOnlyMaintenanceMode();
223
-                return;
224
-            case EE_Maintenance_Mode::STATUS_FULL_SITE:
225
-                $this->activateFullSiteMaintenanceMode();
226
-                return;
227
-        }
228
-        throw new DomainException(
229
-            sprintf(
230
-                esc_html__(
231
-                    '"%1$s" is not valid a EE maintenance mode level. Please choose from one of the following: %2$s',
232
-                    'event_espresso'
233
-                ),
234
-                $level,
235
-                'EE_Maintenance_Mode::STATUS_OFF, EE_Maintenance_Mode::STATUS_PUBLIC_ONLY, EE_Maintenance_Mode::STATUS_FULL_SITE',
236
-            )
237
-        );
238
-    }
239
-
240
-
241
-    /**
242
-     * sets database status to online
243
-     * sets maintenance mode status to public only, unless current user is an admin, then maintenance mode is disabled
244
-     *
245
-     * @return void
246
-     * @since 5.0.12.p
247
-     */
248
-    public function activatePublicOnlyMaintenanceMode()
249
-    {
250
-        DbStatus::setOnline();
251
-        // disable maintenance mode for admins, otherwise enable public only maintenance mode
252
-        if ($this->admin_status === EE_Maintenance_Mode::STATUS_OFF) {
253
-            MaintenanceStatus::disableMaintenanceMode();
254
-        } else {
255
-            MaintenanceStatus::setPublicOnlyMaintenanceMode();
256
-        }
257
-        $this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_PUBLIC_ONLY);
258
-    }
259
-
260
-
261
-    /**
262
-     * sets database status to offline
263
-     * sets maintenance mode status to full site
264
-     *
265
-     * @return void
266
-     * @since 5.0.12.p
267
-     */
268
-    public function activateFullSiteMaintenanceMode()
269
-    {
270
-        DbStatus::setOffline();
271
-        MaintenanceStatus::setFullSiteMaintenanceMode();
272
-        $this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_FULL_SITE);
273
-    }
274
-
275
-
276
-    /**
277
-     * sets database status to online
278
-     * turns maintenance mode off
279
-     *
280
-     * @return void
281
-     * @since 5.0.12.p
282
-     */
283
-    public function deactivateMaintenanceMode()
284
-    {
285
-        DbStatus::setOnline();
286
-        MaintenanceStatus::disableMaintenanceMode();
287
-        $this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_OFF);
288
-    }
289
-
290
-
291
-    private function updateMaintenaceModeStatus(int $status)
292
-    {
293
-        if (! $this->update_db) {
294
-            return;
295
-        }
296
-        do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $status);
297
-        update_option(EE_Maintenance_Mode::OPTION_NAME, $status);
298
-    }
299
-
300
-
301
-    /**
302
-     * returns TRUE if M-Mode is engaged and the current request is not for the admin
303
-     *
304
-     * @return bool
305
-     */
306
-    public static function disable_frontend_for_maintenance(): bool
307
-    {
308
-        return ! is_admin() && MaintenanceStatus::isNotDisabled();
309
-    }
310
-
311
-
312
-    /**
313
-     * @return void
314
-     */
315
-    public function load_assets_required_for_m_mode(): void
316
-    {
317
-        if (
318
-            $this->status === EE_Maintenance_Mode::STATUS_FULL_SITE
319
-            && ! wp_script_is('espresso_core')
320
-        ) {
321
-            wp_register_style(
322
-                'espresso_default',
323
-                EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
324
-                ['dashicons'],
325
-                EVENT_ESPRESSO_VERSION
326
-            );
327
-            wp_enqueue_style('espresso_default');
328
-            wp_register_script(
329
-                'espresso_core',
330
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
331
-                ['jquery'],
332
-                EVENT_ESPRESSO_VERSION,
333
-                true
334
-            );
335
-            wp_enqueue_script('espresso_core');
336
-        }
337
-    }
338
-
339
-
340
-    /**
341
-     * replacement EE CPT template that displays message notifying site visitors
342
-     * that EE has been temporarily placed into maintenance mode
343
-     * does NOT get called on non-EE-CPT requests
344
-     *
345
-     * @return    string
346
-     */
347
-    public static function template_include(): string
348
-    {
349
-        // shut 'er down for maintenance ? then don't use any of our templates for our endpoints
350
-        return get_template_directory() . '/index.php';
351
-    }
352
-
353
-
354
-    /**
355
-     * displays message notifying site visitors that EE has been temporarily
356
-     * placed into maintenance mode when post_type != EE CPT
357
-     *
358
-     * @param string $the_content
359
-     * @return string
360
-     */
361
-    public function the_content(string $the_content): string
362
-    {
363
-        // check if M-mode is engaged and for EE shortcode
364
-        if ($this->admin_status && strpos($the_content, '[ESPRESSO_') !== false) {
365
-            // this can eventually be moved to a template, or edited via admin. But for now...
366
-            $the_content = sprintf(
367
-                esc_html__(
368
-                    '%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
369
-                    'event_espresso'
370
-                ),
371
-                '<h3>',
372
-                '</h3><p>',
373
-                '</p>'
374
-            );
375
-        }
376
-        return $the_content;
377
-    }
378
-
379
-
380
-    /**
381
-     * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
382
-     */
383
-    public function display_maintenance_mode_notice()
384
-    {
385
-        if (
386
-            ! $this->current_user_is_admin
387
-            || $this->status === EE_Maintenance_Mode::STATUS_OFF
388
-            || $this->request->isAdmin()
389
-            || $this->request->isAjax()
390
-            || ! did_action('AHEE__EE_System__load_core_configuration__complete')
391
-        ) {
392
-            return;
393
-        }
394
-        /** @var CurrentPage $current_page */
395
-        $current_page = $this->loader->getShared(CurrentPage::class);
396
-        if ($current_page->isEspressoPage()) {
397
-            printf(
398
-                esc_html__(
399
-                    '%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
400
-                    'event_espresso'
401
-                ),
402
-                '<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
403
-                '"><span class="dashicons dashicons-no"></span></a><p>',
404
-                ' &raquo; <a href="' . add_query_arg(
405
-                    ['page' => 'espresso_maintenance_settings'],
406
-                    admin_url('admin.php')
407
-                ) . '">',
408
-                '</a></p></div>'
409
-            );
410
-        }
411
-    }
412
-    // espresso-notices important-notice ee-attention
413
-
414
-
415
-    /**
416
-     * Redirects EE admin menu requests to the maintenance page
417
-     */
418
-    public function redirect_to_maintenance()
419
-    {
420
-        global $pagenow;
421
-        $page = $this->request->getRequestParam('page', '', DataType::STRING);
422
-        if (
423
-            $pagenow == 'admin.php'
424
-            && $page !== 'espresso_maintenance_settings'
425
-            && strpos($page, 'espresso_') !== false
426
-            && $this->status == EE_Maintenance_Mode::STATUS_FULL_SITE
427
-        ) {
428
-            EEH_URL::safeRedirectAndExit('admin.php?page=espresso_maintenance_settings');
429
-        }
430
-    }
431
-
432
-
433
-    /**
434
-     * override magic methods
435
-     */
436
-    final public function __destruct()
437
-    {
438
-    }
439
-
440
-
441
-    final public function __call($a, $b)
442
-    {
443
-    }
444
-
445
-
446
-    final public function __get($a)
447
-    {
448
-    }
449
-
450
-
451
-    final public function __set($a, $b)
452
-    {
453
-    }
454
-
455
-
456
-    final public function __isset($a)
457
-    {
458
-    }
459
-
460
-
461
-    final public function __unset($a)
462
-    {
463
-    }
464
-
465
-
466
-    final public function __sleep()
467
-    {
468
-        return [];
469
-    }
470
-
471
-
472
-    final public function __wakeup()
473
-    {
474
-    }
475
-
476
-
477
-    final public function __invoke()
478
-    {
479
-    }
480
-
481
-
482
-    final public static function __set_state($a = null)
483
-    {
484
-        return EE_Maintenance_Mode::instance();
485
-    }
486
-
487
-
488
-    final public function __clone()
489
-    {
490
-    }
491
-
492
-
493
-    final public static function __callStatic($a, $b)
494
-    {
495
-    }
22
+	/**
23
+	 * constants available to client code for interpreting the values of EE_Maintenance_Mode::level().
24
+	 * STATUS_OFF means the site is NOT in maintenance mode (so everything's normal)
25
+	 */
26
+	public const STATUS_OFF = 0;
27
+
28
+
29
+	/**
30
+	 * STATUS_PUBLIC_ONLY means that the site's frontend EE code should be completely disabled
31
+	 * but the admin backend should be running as normal. Maybe an admin can view the frontend though
32
+	 */
33
+	public const STATUS_PUBLIC_ONLY = 1;
34
+
35
+	/**
36
+	 * STATUS_FULL_SITE means the frontend AND EE backend code are disabled. The only system running
37
+	 * is the maintenance mode stuff, which will require users to update all addons, and then finish running all
38
+	 * migration scripts before taking the site out of maintenance mode
39
+	 */
40
+	public const STATUS_FULL_SITE = 2;
41
+
42
+	/**
43
+	 * the name of the option which stores the current level of maintenance mode
44
+	 */
45
+	private const OPTION_NAME = 'ee_maintenance_mode';
46
+
47
+
48
+	protected LoaderInterface $loader;
49
+
50
+	private RequestInterface $request;
51
+
52
+	private static ?EE_Maintenance_Mode $_instance = null;
53
+
54
+	/**
55
+	 * @var int
56
+	 * @since 5.0.12.p
57
+	 */
58
+	private int $status;
59
+
60
+	/**
61
+	 * @var int
62
+	 * @since 5.0.12.p
63
+	 */
64
+	private int $admin_status;
65
+
66
+	/**
67
+	 * true if current_user_can('administrator')
68
+	 *
69
+	 * @var bool
70
+	 * @since 5.0.12.p
71
+	 */
72
+	private bool $current_user_is_admin;
73
+
74
+	/**
75
+	 * used to control updates to the WP options setting in the database
76
+	 *
77
+	 * @var bool
78
+	 * @since 5.0.12.p
79
+	 */
80
+	private bool $update_db;
81
+
82
+
83
+	/**
84
+	 * @singleton method used to instantiate class object
85
+	 * @param LoaderInterface|null  $loader
86
+	 * @param RequestInterface|null $request
87
+	 * @return EE_Maintenance_Mode|null
88
+	 */
89
+	public static function instance(
90
+		?LoaderInterface $loader = null,
91
+		?RequestInterface $request = null
92
+	): ?EE_Maintenance_Mode {
93
+		// check if class object is instantiated
94
+		if (! self::$_instance instanceof EE_Maintenance_Mode) {
95
+			self::$_instance = new EE_Maintenance_Mode($loader, $request);
96
+		}
97
+		return self::$_instance;
98
+	}
99
+
100
+
101
+	/**
102
+	 * Resets maintenance mode (mostly just re-checks whether we should be in maintenance mode)
103
+	 *
104
+	 * @return EE_Maintenance_Mode|null
105
+	 * @throws EE_Error
106
+	 */
107
+	public static function reset(): ?EE_Maintenance_Mode
108
+	{
109
+		self::instance()->set_maintenance_mode_if_db_old();
110
+		return self::instance();
111
+	}
112
+
113
+
114
+	/**
115
+	 *private constructor to prevent direct creation
116
+	 */
117
+	private function __construct(LoaderInterface $loader, RequestInterface $request)
118
+	{
119
+		$this->loader                = $loader;
120
+		$this->request               = $request;
121
+		$this->current_user_is_admin = current_user_can('administrator');
122
+		$this->status                = $this->loadStatusFromDatabase();
123
+		$this->admin_status          = $this->setAdminStatus($this->status);
124
+		// now make sure the status is set correctly everywhere
125
+		$this->update_db = false;
126
+		$this->set_maintenance_level($this->status);
127
+		$this->update_db = true;
128
+
129
+		// if M-Mode level 2 is engaged, we still need basic assets loaded
130
+		add_action('wp_enqueue_scripts', [$this, 'load_assets_required_for_m_mode']);
131
+		// shut 'er down for maintenance ?
132
+		add_filter('the_content', [$this, 'the_content'], 2);
133
+		// redirect ee menus to maintenance page
134
+		add_action('admin_page_access_denied', [$this, 'redirect_to_maintenance']);
135
+		// add powered by EE msg
136
+		add_action('shutdown', [$this, 'display_maintenance_mode_notice']);
137
+	}
138
+
139
+
140
+	private function loadStatusFromDatabase(): int
141
+	{
142
+		return (int) get_option(EE_Maintenance_Mode::OPTION_NAME, EE_Maintenance_Mode::STATUS_OFF);
143
+	}
144
+
145
+
146
+	/**
147
+	 * changes the maintenance mode level to reflect whether the current user is an admin or not.
148
+	 * Determines whether we're in maintenance mode and what level. However, while the site
149
+	 * is in level 1 maintenance, and an admin visits the frontend, this function makes it appear
150
+	 * to them as if the site isn't in maintenance mode.
151
+	 *      EE_Maintenance_Mode::STATUS_OFF => not in maintenance mode (in normal mode)
152
+	 *      EE_Maintenance_Mode::STATUS_PUBLIC_ONLY=> frontend-only maintenance mode
153
+	 *      EE_Maintenance_Mode::STATUS_FULL_SITE => frontend and backend maintenance mode
154
+	 *
155
+	 * @param int $status
156
+	 * @return int
157
+	 * @since 5.0.12.p
158
+	 */
159
+	private function setAdminStatus(int $status): int
160
+	{
161
+		if (
162
+			$status === EE_Maintenance_Mode::STATUS_PUBLIC_ONLY
163
+			&& $this->current_user_is_admin
164
+			&& ($this->request->isAjax() || ! $this->request->isAdmin())
165
+		) {
166
+			return EE_Maintenance_Mode::STATUS_OFF;
167
+		}
168
+		return $status;
169
+	}
170
+
171
+
172
+	public function real_level(): int
173
+	{
174
+		return $this->status;
175
+	}
176
+
177
+
178
+	/**
179
+	 * @return int
180
+	 */
181
+	public function level(): int
182
+	{
183
+		return $this->admin_status;
184
+	}
185
+
186
+
187
+	/**
188
+	 * Determines if we need to put EE in maintenance mode because the database needs updating
189
+	 *
190
+	 * @return boolean true if DB is old and maintenance mode was triggered; false otherwise
191
+	 * @throws EE_Error
192
+	 */
193
+	public function set_maintenance_mode_if_db_old(): bool
194
+	{
195
+		$this->loader->getShared('Data_Migration_Manager');
196
+		if (EE_Data_Migration_Manager::instance()->check_for_applicable_data_migration_scripts()) {
197
+			$this->activateFullSiteMaintenanceMode();
198
+			return true;
199
+		}
200
+		if ($this->status === EE_Maintenance_Mode::STATUS_FULL_SITE) {
201
+			// we also want to handle the opposite: if the site is mm2, but there aren't any migrations to run
202
+			// then we shouldn't be in mm2. (Maybe an addon got deactivated?)
203
+			$this->deactivateMaintenanceMode();
204
+		}
205
+		return false;
206
+	}
207
+
208
+
209
+	/**
210
+	 * Updates the maintenance level on the site
211
+	 *
212
+	 * @param int $level
213
+	 * @return void
214
+	 */
215
+	public function set_maintenance_level(int $level): void
216
+	{
217
+		switch ($level) {
218
+			case EE_Maintenance_Mode::STATUS_OFF:
219
+				$this->deactivateMaintenanceMode();
220
+				return;
221
+			case EE_Maintenance_Mode::STATUS_PUBLIC_ONLY:
222
+				$this->activatePublicOnlyMaintenanceMode();
223
+				return;
224
+			case EE_Maintenance_Mode::STATUS_FULL_SITE:
225
+				$this->activateFullSiteMaintenanceMode();
226
+				return;
227
+		}
228
+		throw new DomainException(
229
+			sprintf(
230
+				esc_html__(
231
+					'"%1$s" is not valid a EE maintenance mode level. Please choose from one of the following: %2$s',
232
+					'event_espresso'
233
+				),
234
+				$level,
235
+				'EE_Maintenance_Mode::STATUS_OFF, EE_Maintenance_Mode::STATUS_PUBLIC_ONLY, EE_Maintenance_Mode::STATUS_FULL_SITE',
236
+			)
237
+		);
238
+	}
239
+
240
+
241
+	/**
242
+	 * sets database status to online
243
+	 * sets maintenance mode status to public only, unless current user is an admin, then maintenance mode is disabled
244
+	 *
245
+	 * @return void
246
+	 * @since 5.0.12.p
247
+	 */
248
+	public function activatePublicOnlyMaintenanceMode()
249
+	{
250
+		DbStatus::setOnline();
251
+		// disable maintenance mode for admins, otherwise enable public only maintenance mode
252
+		if ($this->admin_status === EE_Maintenance_Mode::STATUS_OFF) {
253
+			MaintenanceStatus::disableMaintenanceMode();
254
+		} else {
255
+			MaintenanceStatus::setPublicOnlyMaintenanceMode();
256
+		}
257
+		$this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_PUBLIC_ONLY);
258
+	}
259
+
260
+
261
+	/**
262
+	 * sets database status to offline
263
+	 * sets maintenance mode status to full site
264
+	 *
265
+	 * @return void
266
+	 * @since 5.0.12.p
267
+	 */
268
+	public function activateFullSiteMaintenanceMode()
269
+	{
270
+		DbStatus::setOffline();
271
+		MaintenanceStatus::setFullSiteMaintenanceMode();
272
+		$this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_FULL_SITE);
273
+	}
274
+
275
+
276
+	/**
277
+	 * sets database status to online
278
+	 * turns maintenance mode off
279
+	 *
280
+	 * @return void
281
+	 * @since 5.0.12.p
282
+	 */
283
+	public function deactivateMaintenanceMode()
284
+	{
285
+		DbStatus::setOnline();
286
+		MaintenanceStatus::disableMaintenanceMode();
287
+		$this->updateMaintenaceModeStatus(EE_Maintenance_Mode::STATUS_OFF);
288
+	}
289
+
290
+
291
+	private function updateMaintenaceModeStatus(int $status)
292
+	{
293
+		if (! $this->update_db) {
294
+			return;
295
+		}
296
+		do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $status);
297
+		update_option(EE_Maintenance_Mode::OPTION_NAME, $status);
298
+	}
299
+
300
+
301
+	/**
302
+	 * returns TRUE if M-Mode is engaged and the current request is not for the admin
303
+	 *
304
+	 * @return bool
305
+	 */
306
+	public static function disable_frontend_for_maintenance(): bool
307
+	{
308
+		return ! is_admin() && MaintenanceStatus::isNotDisabled();
309
+	}
310
+
311
+
312
+	/**
313
+	 * @return void
314
+	 */
315
+	public function load_assets_required_for_m_mode(): void
316
+	{
317
+		if (
318
+			$this->status === EE_Maintenance_Mode::STATUS_FULL_SITE
319
+			&& ! wp_script_is('espresso_core')
320
+		) {
321
+			wp_register_style(
322
+				'espresso_default',
323
+				EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
324
+				['dashicons'],
325
+				EVENT_ESPRESSO_VERSION
326
+			);
327
+			wp_enqueue_style('espresso_default');
328
+			wp_register_script(
329
+				'espresso_core',
330
+				EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
331
+				['jquery'],
332
+				EVENT_ESPRESSO_VERSION,
333
+				true
334
+			);
335
+			wp_enqueue_script('espresso_core');
336
+		}
337
+	}
338
+
339
+
340
+	/**
341
+	 * replacement EE CPT template that displays message notifying site visitors
342
+	 * that EE has been temporarily placed into maintenance mode
343
+	 * does NOT get called on non-EE-CPT requests
344
+	 *
345
+	 * @return    string
346
+	 */
347
+	public static function template_include(): string
348
+	{
349
+		// shut 'er down for maintenance ? then don't use any of our templates for our endpoints
350
+		return get_template_directory() . '/index.php';
351
+	}
352
+
353
+
354
+	/**
355
+	 * displays message notifying site visitors that EE has been temporarily
356
+	 * placed into maintenance mode when post_type != EE CPT
357
+	 *
358
+	 * @param string $the_content
359
+	 * @return string
360
+	 */
361
+	public function the_content(string $the_content): string
362
+	{
363
+		// check if M-mode is engaged and for EE shortcode
364
+		if ($this->admin_status && strpos($the_content, '[ESPRESSO_') !== false) {
365
+			// this can eventually be moved to a template, or edited via admin. But for now...
366
+			$the_content = sprintf(
367
+				esc_html__(
368
+					'%sMaintenance Mode%sEvent Registration has been temporarily closed while system maintenance is being performed. We\'re sorry for any inconveniences this may have caused. Please try back again later.%s',
369
+					'event_espresso'
370
+				),
371
+				'<h3>',
372
+				'</h3><p>',
373
+				'</p>'
374
+			);
375
+		}
376
+		return $the_content;
377
+	}
378
+
379
+
380
+	/**
381
+	 * displays message on frontend of site notifying admin that EE has been temporarily placed into maintenance mode
382
+	 */
383
+	public function display_maintenance_mode_notice()
384
+	{
385
+		if (
386
+			! $this->current_user_is_admin
387
+			|| $this->status === EE_Maintenance_Mode::STATUS_OFF
388
+			|| $this->request->isAdmin()
389
+			|| $this->request->isAjax()
390
+			|| ! did_action('AHEE__EE_System__load_core_configuration__complete')
391
+		) {
392
+			return;
393
+		}
394
+		/** @var CurrentPage $current_page */
395
+		$current_page = $this->loader->getShared(CurrentPage::class);
396
+		if ($current_page->isEspressoPage()) {
397
+			printf(
398
+				esc_html__(
399
+					'%sclose%sEvent Registration is currently disabled because Event Espresso has been placed into Maintenance Mode. To change Maintenance Mode settings, click here %sEE Maintenance Mode Admin Page%s',
400
+					'event_espresso'
401
+				),
402
+				'<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
403
+				'"><span class="dashicons dashicons-no"></span></a><p>',
404
+				' &raquo; <a href="' . add_query_arg(
405
+					['page' => 'espresso_maintenance_settings'],
406
+					admin_url('admin.php')
407
+				) . '">',
408
+				'</a></p></div>'
409
+			);
410
+		}
411
+	}
412
+	// espresso-notices important-notice ee-attention
413
+
414
+
415
+	/**
416
+	 * Redirects EE admin menu requests to the maintenance page
417
+	 */
418
+	public function redirect_to_maintenance()
419
+	{
420
+		global $pagenow;
421
+		$page = $this->request->getRequestParam('page', '', DataType::STRING);
422
+		if (
423
+			$pagenow == 'admin.php'
424
+			&& $page !== 'espresso_maintenance_settings'
425
+			&& strpos($page, 'espresso_') !== false
426
+			&& $this->status == EE_Maintenance_Mode::STATUS_FULL_SITE
427
+		) {
428
+			EEH_URL::safeRedirectAndExit('admin.php?page=espresso_maintenance_settings');
429
+		}
430
+	}
431
+
432
+
433
+	/**
434
+	 * override magic methods
435
+	 */
436
+	final public function __destruct()
437
+	{
438
+	}
439
+
440
+
441
+	final public function __call($a, $b)
442
+	{
443
+	}
444
+
445
+
446
+	final public function __get($a)
447
+	{
448
+	}
449
+
450
+
451
+	final public function __set($a, $b)
452
+	{
453
+	}
454
+
455
+
456
+	final public function __isset($a)
457
+	{
458
+	}
459
+
460
+
461
+	final public function __unset($a)
462
+	{
463
+	}
464
+
465
+
466
+	final public function __sleep()
467
+	{
468
+		return [];
469
+	}
470
+
471
+
472
+	final public function __wakeup()
473
+	{
474
+	}
475
+
476
+
477
+	final public function __invoke()
478
+	{
479
+	}
480
+
481
+
482
+	final public static function __set_state($a = null)
483
+	{
484
+		return EE_Maintenance_Mode::instance();
485
+	}
486
+
487
+
488
+	final public function __clone()
489
+	{
490
+	}
491
+
492
+
493
+	final public static function __callStatic($a, $b)
494
+	{
495
+	}
496 496
 
497 497
 
498
-    /************************ @DEPRECATED ********************** */
498
+	/************************ @DEPRECATED ********************** */
499 499
 
500
-    /**
501
-     * @depecated 5.0.12.p
502
-     */
503
-    const level_0_not_in_maintenance = 0;
500
+	/**
501
+	 * @depecated 5.0.12.p
502
+	 */
503
+	const level_0_not_in_maintenance = 0;
504 504
 
505
-    /**
506
-     * @depecated 5.0.12.p
507
-     */
508
-    const level_1_frontend_only_maintenance = 1;
505
+	/**
506
+	 * @depecated 5.0.12.p
507
+	 */
508
+	const level_1_frontend_only_maintenance = 1;
509 509
 
510
-    /**
511
-     * @depecated 5.0.12.p
512
-     */
513
-    const level_2_complete_maintenance = 2;
510
+	/**
511
+	 * @depecated 5.0.12.p
512
+	 */
513
+	const level_2_complete_maintenance = 2;
514 514
 
515
-    /**
516
-     * @depecated 5.0.12.p
517
-     */
518
-    const option_name_maintenance_mode = 'ee_maintenance_mode';
515
+	/**
516
+	 * @depecated 5.0.12.p
517
+	 */
518
+	const option_name_maintenance_mode = 'ee_maintenance_mode';
519 519
 
520 520
 
521
-    /**
522
-     * Returns whether the models reportedly are able to run queries or not
523
-     * (ie, if the system thinks their tables are present and up-to-date).
524
-     *
525
-     * @return boolean
526
-     * @depecated 5.0.12.p
527
-     */
528
-    public function models_can_query(): bool
529
-    {
530
-        return DbStatus::isOnline();
531
-    }
521
+	/**
522
+	 * Returns whether the models reportedly are able to run queries or not
523
+	 * (ie, if the system thinks their tables are present and up-to-date).
524
+	 *
525
+	 * @return boolean
526
+	 * @depecated 5.0.12.p
527
+	 */
528
+	public function models_can_query(): bool
529
+	{
530
+		return DbStatus::isOnline();
531
+	}
532 532
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -91,7 +91,7 @@  discard block
 block discarded – undo
91 91
         ?RequestInterface $request = null
92 92
     ): ?EE_Maintenance_Mode {
93 93
         // check if class object is instantiated
94
-        if (! self::$_instance instanceof EE_Maintenance_Mode) {
94
+        if ( ! self::$_instance instanceof EE_Maintenance_Mode) {
95 95
             self::$_instance = new EE_Maintenance_Mode($loader, $request);
96 96
         }
97 97
         return self::$_instance;
@@ -290,7 +290,7 @@  discard block
 block discarded – undo
290 290
 
291 291
     private function updateMaintenaceModeStatus(int $status)
292 292
     {
293
-        if (! $this->update_db) {
293
+        if ( ! $this->update_db) {
294 294
             return;
295 295
         }
296 296
         do_action('AHEE__EE_Maintenance_Mode__set_maintenance_level', $status);
@@ -320,14 +320,14 @@  discard block
 block discarded – undo
320 320
         ) {
321 321
             wp_register_style(
322 322
                 'espresso_default',
323
-                EE_GLOBAL_ASSETS_URL . 'css/espresso_default.css',
323
+                EE_GLOBAL_ASSETS_URL.'css/espresso_default.css',
324 324
                 ['dashicons'],
325 325
                 EVENT_ESPRESSO_VERSION
326 326
             );
327 327
             wp_enqueue_style('espresso_default');
328 328
             wp_register_script(
329 329
                 'espresso_core',
330
-                EE_GLOBAL_ASSETS_URL . 'scripts/espresso_core.js',
330
+                EE_GLOBAL_ASSETS_URL.'scripts/espresso_core.js',
331 331
                 ['jquery'],
332 332
                 EVENT_ESPRESSO_VERSION,
333 333
                 true
@@ -347,7 +347,7 @@  discard block
 block discarded – undo
347 347
     public static function template_include(): string
348 348
     {
349 349
         // shut 'er down for maintenance ? then don't use any of our templates for our endpoints
350
-        return get_template_directory() . '/index.php';
350
+        return get_template_directory().'/index.php';
351 351
     }
352 352
 
353 353
 
@@ -401,10 +401,10 @@  discard block
 block discarded – undo
401 401
                 ),
402 402
                 '<div id="ee-m-mode-admin-notice-dv" class="ee-really-important-notice-dv"><a class="close-espresso-notice" title="',
403 403
                 '"><span class="dashicons dashicons-no"></span></a><p>',
404
-                ' &raquo; <a href="' . add_query_arg(
404
+                ' &raquo; <a href="'.add_query_arg(
405 405
                     ['page' => 'espresso_maintenance_settings'],
406 406
                     admin_url('admin.php')
407
-                ) . '">',
407
+                ).'">',
408 408
                 '</a></p></div>'
409 409
             );
410 410
         }
Please login to merge, or discard this patch.
core/EES_Shortcode.shortcode.php 2 patches
Indentation   +168 added lines, -168 removed lines patch added patch discarded remove patch
@@ -15,172 +15,172 @@
 block discarded – undo
15 15
  */
16 16
 abstract class EES_Shortcode extends EE_Base
17 17
 {
18
-    /**
19
-     * @protected   public
20
-     * @var     array $_attributes
21
-     */
22
-    protected $_attributes = [];
23
-
24
-
25
-    /**
26
-     * class constructor - should ONLY be instantiated by EE_Front_Controller
27
-     */
28
-    final public function __construct()
29
-    {
30
-        $shortcode = LegacyShortcodesManager::generateShortcodeTagFromClassName(get_class($this));
31
-        // assign shortcode to the preferred callback, which overwrites the "fallback shortcode processor" assigned earlier
32
-        add_shortcode($shortcode, [$this, 'process_shortcode']);
33
-        // make sure system knows this is an EE page
34
-        /** @var CurrentPage $current_page */
35
-        $current_page = LoaderFactory::getLoader()->getShared(CurrentPage::class);
36
-        $current_page->setEspressoPage(true);
37
-    }
38
-
39
-
40
-    /**
41
-     * run - initial shortcode module setup called during "parse_request" hook by
42
-     * \EE_Front_Controller::_initialize_shortcodes() IF this shortcode is going to execute during this request !
43
-     * It may also get called by \EES_Shortcode::fallback_shortcode_processor() if the shortcode is being implemented
44
-     * by a theme or plugin in a non-standard way.
45
-     * Basically this method is primarily used for loading resources and assets like CSS or JS
46
-     * that will be required by the shortcode when it is actually processed.
47
-     * Please note that assets may not load if the fallback_shortcode_processor() is being used.
48
-     *
49
-     * @param WP $WP
50
-     * @return void
51
-     */
52
-    abstract public function run(WP $WP);
53
-
54
-
55
-    /**
56
-     *  process_shortcode
57
-     *  this method is the callback function for the actual shortcode, and is what runs when WP encounters the
58
-     *  shortcode within the_content
59
-     *
60
-     * @param array|string $attributes
61
-     * @return mixed
62
-     */
63
-    abstract public function process_shortcode($attributes = []);
64
-
65
-
66
-    /**
67
-     *    instance - returns instance of child class object
68
-     *
69
-     * @param string|null $shortcode_class
70
-     * @return EES_Shortcode
71
-     */
72
-    final public static function instance(string $shortcode_class = ''): ?EES_Shortcode
73
-    {
74
-        $shortcode_class = ! empty($shortcode_class) ? $shortcode_class : get_called_class();
75
-        if ($shortcode_class === 'EES_Shortcode' || empty($shortcode_class)) {
76
-            return null;
77
-        }
78
-        $shortcode     = LegacyShortcodesManager::generateShortcodeTagFromClassName($shortcode_class);
79
-        $shortcode_obj = isset(EE_Registry::instance()->shortcodes->{$shortcode})
80
-            ? EE_Registry::instance()->shortcodes->{$shortcode}
81
-            : null;
82
-        return $shortcode_obj instanceof $shortcode_class || $shortcode_class === 'self'
83
-            ? $shortcode_obj
84
-            : new $shortcode_class();
85
-    }
86
-
87
-
88
-    /**
89
-     *    fallback_shortcode_processor - create instance and call process_shortcode
90
-     *    NOTE: shortcode may not function perfectly dues to missing assets, but it's better than not having things
91
-     *    work at all
92
-     *
93
-     * @param array|string $attributes
94
-     * @return mixed
95
-     */
96
-    final public static function fallback_shortcode_processor($attributes = null)
97
-    {
98
-        if (! is_admin() && MaintenanceStatus::isNotDisabled()) {
99
-            return null;
100
-        }
101
-        // what shortcode was actually parsed ?
102
-        $shortcode_class = get_called_class();
103
-        // notify rest of system that fallback processor was triggered
104
-        add_filter('FHEE__fallback_shortcode_processor__' . $shortcode_class, '__return_true');
105
-        // get instance of actual shortcode
106
-        $shortcode_obj = self::instance($shortcode_class);
107
-        // verify class
108
-        if ($shortcode_obj instanceof EES_Shortcode) {
109
-            global $wp;
110
-            $shortcode_obj->run($wp);
111
-            // set attributes and run the shortcode
112
-            $shortcode_obj->_attributes = (array) $attributes;
113
-            return $shortcode_obj->process_shortcode($shortcode_obj->_attributes);
114
-        }
115
-        return null;
116
-    }
117
-
118
-
119
-    /**
120
-     *    invalid_shortcode_processor -  used in cases where we know the shortcode is invalid, most likely due to a
121
-     *    deactivated addon, and simply returns an empty string
122
-     *
123
-     * @param $attributes
124
-     * @return string
125
-     */
126
-    final public static function invalid_shortcode_processor($attributes): string
127
-    {
128
-        return '';
129
-    }
130
-
131
-
132
-    /**
133
-     * Performs basic sanitization on shortcode attributes
134
-     * Since incoming attributes from the shortcode usage in the WP editor will all be strings,
135
-     * most attributes will by default be sanitized using the sanitize_text_field() function.
136
-     * This can be overridden by supplying an array for the $custom_sanitization param,
137
-     * where keys match keys in your attributes array,
138
-     * and values represent the sanitization function you wish to be applied to that attribute.
139
-     * So for example, if you had an integer attribute named "event_id"
140
-     * that you wanted to be sanitized using absint(),
141
-     * then you would pass the following for your $custom_sanitization array:
142
-     *      array('event_id' => 'absint')
143
-     * all other attributes would be sanitized using the defaults in the switch statement below
144
-     *
145
-     * @param array $attributes
146
-     * @param array $custom_sanitization
147
-     * @return array
148
-     */
149
-    public static function sanitize_attributes(array $attributes, array $custom_sanitization = []): array
150
-    {
151
-        foreach ($attributes as $key => $value) {
152
-            // is a custom sanitization callback specified ?
153
-            if (isset($custom_sanitization[ $key ])) {
154
-                $callback = $custom_sanitization[ $key ];
155
-                if ($callback === 'skip_sanitization') {
156
-                    $attributes[ $key ] = $value;
157
-                    continue;
158
-                } elseif (function_exists($callback)) {
159
-                    $attributes[ $key ] = $callback($value);
160
-                    continue;
161
-                }
162
-            }
163
-            switch (true) {
164
-                case $value === null:
165
-                case is_int($value):
166
-                case is_float($value):
167
-                    // typical booleans
168
-                case in_array($value, [true, 'true', '1', 'on', 'yes', false, 'false', '0', 'off', 'no'], true):
169
-                    $attributes[ $key ] = $value;
170
-                    break;
171
-                case is_string($value):
172
-                    $attributes[ $key ] = sanitize_text_field($value);
173
-                    break;
174
-                case is_array($value):
175
-                    $attributes[ $key ] = EES_Shortcode::sanitize_attributes($value);
176
-                    break;
177
-                default:
178
-                    // only remaining data types are Object and Resource
179
-                    // which are not allowed as shortcode attributes
180
-                    $attributes[ $key ] = null;
181
-                    break;
182
-            }
183
-        }
184
-        return $attributes;
185
-    }
18
+	/**
19
+	 * @protected   public
20
+	 * @var     array $_attributes
21
+	 */
22
+	protected $_attributes = [];
23
+
24
+
25
+	/**
26
+	 * class constructor - should ONLY be instantiated by EE_Front_Controller
27
+	 */
28
+	final public function __construct()
29
+	{
30
+		$shortcode = LegacyShortcodesManager::generateShortcodeTagFromClassName(get_class($this));
31
+		// assign shortcode to the preferred callback, which overwrites the "fallback shortcode processor" assigned earlier
32
+		add_shortcode($shortcode, [$this, 'process_shortcode']);
33
+		// make sure system knows this is an EE page
34
+		/** @var CurrentPage $current_page */
35
+		$current_page = LoaderFactory::getLoader()->getShared(CurrentPage::class);
36
+		$current_page->setEspressoPage(true);
37
+	}
38
+
39
+
40
+	/**
41
+	 * run - initial shortcode module setup called during "parse_request" hook by
42
+	 * \EE_Front_Controller::_initialize_shortcodes() IF this shortcode is going to execute during this request !
43
+	 * It may also get called by \EES_Shortcode::fallback_shortcode_processor() if the shortcode is being implemented
44
+	 * by a theme or plugin in a non-standard way.
45
+	 * Basically this method is primarily used for loading resources and assets like CSS or JS
46
+	 * that will be required by the shortcode when it is actually processed.
47
+	 * Please note that assets may not load if the fallback_shortcode_processor() is being used.
48
+	 *
49
+	 * @param WP $WP
50
+	 * @return void
51
+	 */
52
+	abstract public function run(WP $WP);
53
+
54
+
55
+	/**
56
+	 *  process_shortcode
57
+	 *  this method is the callback function for the actual shortcode, and is what runs when WP encounters the
58
+	 *  shortcode within the_content
59
+	 *
60
+	 * @param array|string $attributes
61
+	 * @return mixed
62
+	 */
63
+	abstract public function process_shortcode($attributes = []);
64
+
65
+
66
+	/**
67
+	 *    instance - returns instance of child class object
68
+	 *
69
+	 * @param string|null $shortcode_class
70
+	 * @return EES_Shortcode
71
+	 */
72
+	final public static function instance(string $shortcode_class = ''): ?EES_Shortcode
73
+	{
74
+		$shortcode_class = ! empty($shortcode_class) ? $shortcode_class : get_called_class();
75
+		if ($shortcode_class === 'EES_Shortcode' || empty($shortcode_class)) {
76
+			return null;
77
+		}
78
+		$shortcode     = LegacyShortcodesManager::generateShortcodeTagFromClassName($shortcode_class);
79
+		$shortcode_obj = isset(EE_Registry::instance()->shortcodes->{$shortcode})
80
+			? EE_Registry::instance()->shortcodes->{$shortcode}
81
+			: null;
82
+		return $shortcode_obj instanceof $shortcode_class || $shortcode_class === 'self'
83
+			? $shortcode_obj
84
+			: new $shortcode_class();
85
+	}
86
+
87
+
88
+	/**
89
+	 *    fallback_shortcode_processor - create instance and call process_shortcode
90
+	 *    NOTE: shortcode may not function perfectly dues to missing assets, but it's better than not having things
91
+	 *    work at all
92
+	 *
93
+	 * @param array|string $attributes
94
+	 * @return mixed
95
+	 */
96
+	final public static function fallback_shortcode_processor($attributes = null)
97
+	{
98
+		if (! is_admin() && MaintenanceStatus::isNotDisabled()) {
99
+			return null;
100
+		}
101
+		// what shortcode was actually parsed ?
102
+		$shortcode_class = get_called_class();
103
+		// notify rest of system that fallback processor was triggered
104
+		add_filter('FHEE__fallback_shortcode_processor__' . $shortcode_class, '__return_true');
105
+		// get instance of actual shortcode
106
+		$shortcode_obj = self::instance($shortcode_class);
107
+		// verify class
108
+		if ($shortcode_obj instanceof EES_Shortcode) {
109
+			global $wp;
110
+			$shortcode_obj->run($wp);
111
+			// set attributes and run the shortcode
112
+			$shortcode_obj->_attributes = (array) $attributes;
113
+			return $shortcode_obj->process_shortcode($shortcode_obj->_attributes);
114
+		}
115
+		return null;
116
+	}
117
+
118
+
119
+	/**
120
+	 *    invalid_shortcode_processor -  used in cases where we know the shortcode is invalid, most likely due to a
121
+	 *    deactivated addon, and simply returns an empty string
122
+	 *
123
+	 * @param $attributes
124
+	 * @return string
125
+	 */
126
+	final public static function invalid_shortcode_processor($attributes): string
127
+	{
128
+		return '';
129
+	}
130
+
131
+
132
+	/**
133
+	 * Performs basic sanitization on shortcode attributes
134
+	 * Since incoming attributes from the shortcode usage in the WP editor will all be strings,
135
+	 * most attributes will by default be sanitized using the sanitize_text_field() function.
136
+	 * This can be overridden by supplying an array for the $custom_sanitization param,
137
+	 * where keys match keys in your attributes array,
138
+	 * and values represent the sanitization function you wish to be applied to that attribute.
139
+	 * So for example, if you had an integer attribute named "event_id"
140
+	 * that you wanted to be sanitized using absint(),
141
+	 * then you would pass the following for your $custom_sanitization array:
142
+	 *      array('event_id' => 'absint')
143
+	 * all other attributes would be sanitized using the defaults in the switch statement below
144
+	 *
145
+	 * @param array $attributes
146
+	 * @param array $custom_sanitization
147
+	 * @return array
148
+	 */
149
+	public static function sanitize_attributes(array $attributes, array $custom_sanitization = []): array
150
+	{
151
+		foreach ($attributes as $key => $value) {
152
+			// is a custom sanitization callback specified ?
153
+			if (isset($custom_sanitization[ $key ])) {
154
+				$callback = $custom_sanitization[ $key ];
155
+				if ($callback === 'skip_sanitization') {
156
+					$attributes[ $key ] = $value;
157
+					continue;
158
+				} elseif (function_exists($callback)) {
159
+					$attributes[ $key ] = $callback($value);
160
+					continue;
161
+				}
162
+			}
163
+			switch (true) {
164
+				case $value === null:
165
+				case is_int($value):
166
+				case is_float($value):
167
+					// typical booleans
168
+				case in_array($value, [true, 'true', '1', 'on', 'yes', false, 'false', '0', 'off', 'no'], true):
169
+					$attributes[ $key ] = $value;
170
+					break;
171
+				case is_string($value):
172
+					$attributes[ $key ] = sanitize_text_field($value);
173
+					break;
174
+				case is_array($value):
175
+					$attributes[ $key ] = EES_Shortcode::sanitize_attributes($value);
176
+					break;
177
+				default:
178
+					// only remaining data types are Object and Resource
179
+					// which are not allowed as shortcode attributes
180
+					$attributes[ $key ] = null;
181
+					break;
182
+			}
183
+		}
184
+		return $attributes;
185
+	}
186 186
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -95,13 +95,13 @@  discard block
 block discarded – undo
95 95
      */
96 96
     final public static function fallback_shortcode_processor($attributes = null)
97 97
     {
98
-        if (! is_admin() && MaintenanceStatus::isNotDisabled()) {
98
+        if ( ! is_admin() && MaintenanceStatus::isNotDisabled()) {
99 99
             return null;
100 100
         }
101 101
         // what shortcode was actually parsed ?
102 102
         $shortcode_class = get_called_class();
103 103
         // notify rest of system that fallback processor was triggered
104
-        add_filter('FHEE__fallback_shortcode_processor__' . $shortcode_class, '__return_true');
104
+        add_filter('FHEE__fallback_shortcode_processor__'.$shortcode_class, '__return_true');
105 105
         // get instance of actual shortcode
106 106
         $shortcode_obj = self::instance($shortcode_class);
107 107
         // verify class
@@ -150,13 +150,13 @@  discard block
 block discarded – undo
150 150
     {
151 151
         foreach ($attributes as $key => $value) {
152 152
             // is a custom sanitization callback specified ?
153
-            if (isset($custom_sanitization[ $key ])) {
154
-                $callback = $custom_sanitization[ $key ];
153
+            if (isset($custom_sanitization[$key])) {
154
+                $callback = $custom_sanitization[$key];
155 155
                 if ($callback === 'skip_sanitization') {
156
-                    $attributes[ $key ] = $value;
156
+                    $attributes[$key] = $value;
157 157
                     continue;
158 158
                 } elseif (function_exists($callback)) {
159
-                    $attributes[ $key ] = $callback($value);
159
+                    $attributes[$key] = $callback($value);
160 160
                     continue;
161 161
                 }
162 162
             }
@@ -166,18 +166,18 @@  discard block
 block discarded – undo
166 166
                 case is_float($value):
167 167
                     // typical booleans
168 168
                 case in_array($value, [true, 'true', '1', 'on', 'yes', false, 'false', '0', 'off', 'no'], true):
169
-                    $attributes[ $key ] = $value;
169
+                    $attributes[$key] = $value;
170 170
                     break;
171 171
                 case is_string($value):
172
-                    $attributes[ $key ] = sanitize_text_field($value);
172
+                    $attributes[$key] = sanitize_text_field($value);
173 173
                     break;
174 174
                 case is_array($value):
175
-                    $attributes[ $key ] = EES_Shortcode::sanitize_attributes($value);
175
+                    $attributes[$key] = EES_Shortcode::sanitize_attributes($value);
176 176
                     break;
177 177
                 default:
178 178
                     // only remaining data types are Object and Resource
179 179
                     // which are not allowed as shortcode attributes
180
-                    $attributes[ $key ] = null;
180
+                    $attributes[$key] = null;
181 181
                     break;
182 182
             }
183 183
         }
Please login to merge, or discard this patch.
core/services/container/RegistryContainer.php 2 patches
Indentation   +162 added lines, -162 removed lines patch added patch discarded remove patch
@@ -16,166 +16,166 @@
 block discarded – undo
16 16
  */
17 17
 class RegistryContainer implements ArrayAccess, CountableTraversableAggregate
18 18
 {
19
-    private array $container = [];
20
-
21
-
22
-    /**
23
-     * RegistryContainer constructor.
24
-     * Container data can be seeded by passing parameters to constructor.
25
-     * Each parameter will become its own element in the container
26
-     */
27
-    public function __construct()
28
-    {
29
-    }
30
-
31
-
32
-    /**
33
-     * @param mixed $offset
34
-     * @param mixed $value
35
-     */
36
-    public function offsetSet($offset, $value): void
37
-    {
38
-        $this->container[ $offset ] = $value;
39
-    }
40
-
41
-
42
-    /**
43
-     * @param mixed $offset
44
-     * @return bool
45
-     */
46
-    public function offsetExists($offset): bool
47
-    {
48
-        return isset($this->container[ $offset ]);
49
-    }
50
-
51
-
52
-    /**
53
-     * @param mixed $offset
54
-     */
55
-    public function offsetUnset($offset): void
56
-    {
57
-        unset($this->container[ $offset ]);
58
-    }
59
-
60
-
61
-    /**
62
-     * @param mixed $offset
63
-     * @return mixed|null
64
-     */
65
-    #[\ReturnTypeWillChange]
66
-    public function offsetGet($offset)
67
-    {
68
-        return $this->offsetExists($offset) ? $this->container[ $offset ] : null;
69
-    }
70
-
71
-
72
-    /**
73
-     * @return int
74
-     */
75
-    public function count(): int
76
-    {
77
-        return count($this->container);
78
-    }
79
-
80
-
81
-    /**
82
-     * @return ArrayIterator
83
-     */
84
-    public function getIterator(): ArrayIterator
85
-    {
86
-        return new ArrayIterator($this->container);
87
-    }
88
-
89
-
90
-    /**
91
-     * @param $offset
92
-     * @param $value
93
-     */
94
-    public function __set($offset, $value): void
95
-    {
96
-        $this->offsetSet($offset, $value);
97
-    }
98
-
99
-
100
-    /**
101
-     * @param $offset
102
-     * @return mixed
103
-     * @throws OutOfBoundsException
104
-     */
105
-    #[\ReturnTypeWillChange]
106
-    public function __get($offset)
107
-    {
108
-        if (! array_key_exists($offset, $this->container)) {
109
-            $trace = debug_backtrace();
110
-            throw new OutOfBoundsException(
111
-                sprintf(
112
-                    esc_html__('Invalid offset: %1$s %2$sCalled from %3$s on line %4$d', 'event_espresso'),
113
-                    $offset,
114
-                    '<br  />',
115
-                    $trace[0]['file'],
116
-                    $trace[0]['line']
117
-                )
118
-            );
119
-        }
120
-        return $this->offsetGet($offset);
121
-    }
122
-
123
-
124
-    /**
125
-     * @param $offset
126
-     * @return bool
127
-     */
128
-    public function __isset($offset): bool
129
-    {
130
-        return $this->offsetExists($offset);
131
-    }
132
-
133
-
134
-    /**
135
-     * @param $offset
136
-     */
137
-    public function __unset($offset): void
138
-    {
139
-        $this->offsetUnset($offset);
140
-    }
141
-
142
-
143
-    /**
144
-     * @param $offset
145
-     * @param $value
146
-     */
147
-    public function add($offset, $value): void
148
-    {
149
-        $this->offsetSet($offset, $value);
150
-    }
151
-
152
-
153
-    /**
154
-     * @param $offset
155
-     */
156
-    public function remove($offset): void
157
-    {
158
-        $this->offsetUnset($offset);
159
-    }
160
-
161
-
162
-    /**
163
-     * @param $offset
164
-     * @return bool
165
-     */
166
-    public function has($offset): bool
167
-    {
168
-        return $this->offsetExists($offset);
169
-    }
170
-
171
-
172
-    /**
173
-     * @param $offset
174
-     * @return mixed|null
175
-     */
176
-    #[\ReturnTypeWillChange]
177
-    public function get($offset)
178
-    {
179
-        return $this->offsetGet($offset);
180
-    }
19
+	private array $container = [];
20
+
21
+
22
+	/**
23
+	 * RegistryContainer constructor.
24
+	 * Container data can be seeded by passing parameters to constructor.
25
+	 * Each parameter will become its own element in the container
26
+	 */
27
+	public function __construct()
28
+	{
29
+	}
30
+
31
+
32
+	/**
33
+	 * @param mixed $offset
34
+	 * @param mixed $value
35
+	 */
36
+	public function offsetSet($offset, $value): void
37
+	{
38
+		$this->container[ $offset ] = $value;
39
+	}
40
+
41
+
42
+	/**
43
+	 * @param mixed $offset
44
+	 * @return bool
45
+	 */
46
+	public function offsetExists($offset): bool
47
+	{
48
+		return isset($this->container[ $offset ]);
49
+	}
50
+
51
+
52
+	/**
53
+	 * @param mixed $offset
54
+	 */
55
+	public function offsetUnset($offset): void
56
+	{
57
+		unset($this->container[ $offset ]);
58
+	}
59
+
60
+
61
+	/**
62
+	 * @param mixed $offset
63
+	 * @return mixed|null
64
+	 */
65
+	#[\ReturnTypeWillChange]
66
+	public function offsetGet($offset)
67
+	{
68
+		return $this->offsetExists($offset) ? $this->container[ $offset ] : null;
69
+	}
70
+
71
+
72
+	/**
73
+	 * @return int
74
+	 */
75
+	public function count(): int
76
+	{
77
+		return count($this->container);
78
+	}
79
+
80
+
81
+	/**
82
+	 * @return ArrayIterator
83
+	 */
84
+	public function getIterator(): ArrayIterator
85
+	{
86
+		return new ArrayIterator($this->container);
87
+	}
88
+
89
+
90
+	/**
91
+	 * @param $offset
92
+	 * @param $value
93
+	 */
94
+	public function __set($offset, $value): void
95
+	{
96
+		$this->offsetSet($offset, $value);
97
+	}
98
+
99
+
100
+	/**
101
+	 * @param $offset
102
+	 * @return mixed
103
+	 * @throws OutOfBoundsException
104
+	 */
105
+	#[\ReturnTypeWillChange]
106
+	public function __get($offset)
107
+	{
108
+		if (! array_key_exists($offset, $this->container)) {
109
+			$trace = debug_backtrace();
110
+			throw new OutOfBoundsException(
111
+				sprintf(
112
+					esc_html__('Invalid offset: %1$s %2$sCalled from %3$s on line %4$d', 'event_espresso'),
113
+					$offset,
114
+					'<br  />',
115
+					$trace[0]['file'],
116
+					$trace[0]['line']
117
+				)
118
+			);
119
+		}
120
+		return $this->offsetGet($offset);
121
+	}
122
+
123
+
124
+	/**
125
+	 * @param $offset
126
+	 * @return bool
127
+	 */
128
+	public function __isset($offset): bool
129
+	{
130
+		return $this->offsetExists($offset);
131
+	}
132
+
133
+
134
+	/**
135
+	 * @param $offset
136
+	 */
137
+	public function __unset($offset): void
138
+	{
139
+		$this->offsetUnset($offset);
140
+	}
141
+
142
+
143
+	/**
144
+	 * @param $offset
145
+	 * @param $value
146
+	 */
147
+	public function add($offset, $value): void
148
+	{
149
+		$this->offsetSet($offset, $value);
150
+	}
151
+
152
+
153
+	/**
154
+	 * @param $offset
155
+	 */
156
+	public function remove($offset): void
157
+	{
158
+		$this->offsetUnset($offset);
159
+	}
160
+
161
+
162
+	/**
163
+	 * @param $offset
164
+	 * @return bool
165
+	 */
166
+	public function has($offset): bool
167
+	{
168
+		return $this->offsetExists($offset);
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param $offset
174
+	 * @return mixed|null
175
+	 */
176
+	#[\ReturnTypeWillChange]
177
+	public function get($offset)
178
+	{
179
+		return $this->offsetGet($offset);
180
+	}
181 181
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -35,7 +35,7 @@  discard block
 block discarded – undo
35 35
      */
36 36
     public function offsetSet($offset, $value): void
37 37
     {
38
-        $this->container[ $offset ] = $value;
38
+        $this->container[$offset] = $value;
39 39
     }
40 40
 
41 41
 
@@ -45,7 +45,7 @@  discard block
 block discarded – undo
45 45
      */
46 46
     public function offsetExists($offset): bool
47 47
     {
48
-        return isset($this->container[ $offset ]);
48
+        return isset($this->container[$offset]);
49 49
     }
50 50
 
51 51
 
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
      */
55 55
     public function offsetUnset($offset): void
56 56
     {
57
-        unset($this->container[ $offset ]);
57
+        unset($this->container[$offset]);
58 58
     }
59 59
 
60 60
 
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
     #[\ReturnTypeWillChange]
66 66
     public function offsetGet($offset)
67 67
     {
68
-        return $this->offsetExists($offset) ? $this->container[ $offset ] : null;
68
+        return $this->offsetExists($offset) ? $this->container[$offset] : null;
69 69
     }
70 70
 
71 71
 
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
     #[\ReturnTypeWillChange]
106 106
     public function __get($offset)
107 107
     {
108
-        if (! array_key_exists($offset, $this->container)) {
108
+        if ( ! array_key_exists($offset, $this->container)) {
109 109
             $trace = debug_backtrace();
110 110
             throw new OutOfBoundsException(
111 111
                 sprintf(
Please login to merge, or discard this patch.
core/services/calculators/LineItemCalculator.php 2 patches
Indentation   +920 added lines, -920 removed lines patch added patch discarded remove patch
@@ -21,924 +21,924 @@
 block discarded – undo
21 21
  */
22 22
 class LineItemCalculator
23 23
 {
24
-    use DebugDisplay;
25
-
26
-    protected DecimalValues $decimal_values;
27
-
28
-    protected array $default_query_params = [
29
-        ['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]],
30
-    ];
31
-
32
-
33
-    /**
34
-     * @param DecimalValues $decimal_values
35
-     */
36
-    public function __construct(DecimalValues $decimal_values)
37
-    {
38
-        $this->decimal_values = $decimal_values;
39
-        $this->initializeDebugDisplay();
40
-    }
41
-
42
-
43
-    /**
44
-     * Gets the final total on this item, taking taxes into account.
45
-     * Has the side effect of setting the sub-total as it was just calculated.
46
-     * If this is used on a grand-total line item, also updates the transaction's
47
-     * TXN_total (provided this line item is allowed to persist, otherwise we don't
48
-     * want to change a persistable transaction with info from a non-persistent line item)
49
-     *
50
-     * @param EE_Line_Item $line_item
51
-     * @param bool         $update_txn_status
52
-     * @return float
53
-     * @throws EE_Error
54
-     * @throws ReflectionException
55
-     */
56
-    public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float
57
-    {
58
-        $this->debugLog('', 2);
59
-        $this->debugLog(__METHOD__);
60
-        $this->debugLog(str_repeat('*', strlen(__METHOD__)), 2);
61
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
62
-        $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item);
63
-        if (empty($ticket_line_items)) {
64
-            // no tickets? ensure totals are zero
65
-            $this->updatePreTaxTotal($line_item, 0);
66
-            $this->updateTotal($line_item, 0);
67
-            $this->updateTransaction($line_item, 0, $update_txn_status);
68
-            return 0;
69
-        }
70
-        [, $pretax_total] = $this->recalculateLineItemTotals($line_item);
71
-        // EEH_Line_Item::visualize($line_item);
72
-        $total_tax = $this->recalculateTaxesAndTaxTotal($line_item);
73
-        // no negative totals plz
74
-        $grand_total = max($pretax_total + $total_tax, 0);
75
-        $this->updatePreTaxTotal($line_item, $pretax_total, true);
76
-        $grand_total = $this->updateTotal($line_item, $grand_total, true);
77
-        $this->updateTransaction($line_item, $grand_total, $update_txn_status);
78
-        return $grand_total;
79
-    }
80
-
81
-
82
-    /**
83
-     * Recursively goes through all the children and recalculates sub-totals EXCEPT for
84
-     * tax-sub-totals (they're an odd beast). Updates the 'total' on each line item according to either its
85
-     * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
86
-     * when this is called on the grand total
87
-     *
88
-     * @param EE_Line_Item $line_item
89
-     * @param float        $total
90
-     * @param float        $pretax_total
91
-     * @param bool         $is_taxable
92
-     * @return array
93
-     * @throws EE_Error
94
-     * @throws ReflectionException
95
-     */
96
-    public function recalculateLineItemTotals(
97
-        EE_Line_Item $line_item,
98
-        float $total = 0,
99
-        float $pretax_total = 0,
100
-        bool $is_taxable = false
101
-    ): array {
102
-        $this->debugLog(__FUNCTION__);
103
-        $OBJ = $line_item->OBJ_type();
104
-        $OBJ .= $OBJ ? ': ' : '';
105
-        $this->debugLog(
106
-            ' * ' . $OBJ . $line_item->name() . ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
107
-            2
108
-        );
109
-        $this->debugLog(" * total: $total", 3);
110
-        $this->debugLog(" * pretax: $pretax_total", 3);
111
-        switch ($line_item->type()) {
112
-            case EEM_Line_Item::type_total:
113
-            case EEM_Line_Item::type_sub_total:
114
-                [$total, $pretax_total] = $this->recalculateSubTotal($line_item);
115
-                break;
116
-
117
-            case EEM_Line_Item::type_line_item:
118
-                [$total, $pretax_total] = $this->recalculateLineItem($line_item, $total, $pretax_total);
119
-                break;
120
-
121
-            case EEM_Line_Item::type_sub_line_item:
122
-                // sub-line-items operate on the total and update both the total AND the pre-tax total
123
-                [$total, $pretax_total] = $this->recalculateSubLineItem($line_item, $total, $pretax_total, $is_taxable);
124
-                break;
125
-
126
-            case EEM_Line_Item::type_sub_tax:
127
-                // sub-line-items taxes ONLY operate on the pre-tax total and ONLY update the total
128
-                [$total, $pretax_total] = $this->recalculateSubTax($line_item, $pretax_total);
129
-                break;
130
-
131
-            case EEM_Line_Item::type_tax_sub_total:
132
-            case EEM_Line_Item::type_tax:
133
-            case EEM_Line_Item::type_cancellation:
134
-                // completely ignore tax totals, tax sub-totals, and cancelled line items
135
-                // when calculating the pre-tax-total
136
-                $total = $pretax_total = 0;
137
-                break;
138
-        }
139
-        return [$total, $pretax_total];
140
-    }
141
-
142
-
143
-    /**
144
-     * @param EE_Line_Item $line_item
145
-     * @return array
146
-     * @throws EE_Error
147
-     * @throws ReflectionException
148
-     */
149
-    private function recalculateSubTotal(EE_Line_Item $line_item): array
150
-    {
151
-        $this->debugLog(__FUNCTION__);
152
-        // reset the total and pretax total to zero since we are recalculating them
153
-        $total = $pretax_total = 0;
154
-        if ($line_item->is_total()) {
155
-            // if this is the grand total line item
156
-            // then first update ALL the line item quantities (if need be)
157
-            $this->updateLineItemQuantities($line_item);
158
-        }
159
-        // recursively loop through children and recalculate their totals
160
-        $children = $line_item->children($this->default_query_params);
161
-        if (empty($children)) {
162
-            $this->debugLog(' - ' . __FUNCTION__, 3);
163
-            $this->debugLog(" - - total : $total ", 3);
164
-            $this->debugLog(" - - pretax: $pretax_total ", 3);
165
-            return [$total, $pretax_total];
166
-        }
167
-        foreach ($children as $child_line_item) {
168
-            [$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
169
-                $child_line_item,
170
-                $total,
171
-                $pretax_total
172
-            );
173
-            $total        += $child_total;
174
-            $pretax_total += $child_pretax_total;
175
-        }
176
-        // update the unit price and pretax total
177
-        $this->updateUnitPrice($line_item, $pretax_total, false);
178
-        $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true, false);
179
-        $this->debugLog(' - ' . __FUNCTION__, 3);
180
-        $this->debugLog(" - - line_item->name() : " . $line_item->name(), 3);
181
-        $this->debugLog(" - - line_item->code() : " . $line_item->code(), 3);
182
-        // for the actual pre-tax sub-total line item, we want to save the pretax value for everything
183
-        if ($line_item->is_sub_total() && $line_item->code() === 'pre-tax-subtotal') {
184
-            $this->updateTotal($line_item, $pretax_total, true);
185
-        } elseif (! $line_item->is_total()) {
186
-            // we don't update the total for the total line item, because that will need to include taxes
187
-            $total = $this->updateTotal($line_item, $total, true);
188
-        }
189
-        $this->debugLog(' - ' . __FUNCTION__, 3);
190
-        $this->debugLog(" - - total : $total ", 3);
191
-        $this->debugLog(" - - pretax: $pretax_total ", 3);
192
-        return [$total, $pretax_total];
193
-    }
194
-
195
-
196
-    /**
197
-     * @param EE_Line_Item $line_item
198
-     * @param float        $total
199
-     * @param float        $pretax_total
200
-     * @return array
201
-     * @throws EE_Error
202
-     * @throws ReflectionException
203
-     */
204
-    private function recalculateLineItem(
205
-        EE_Line_Item $line_item,
206
-        float $total = 0,
207
-        float $pretax_total = 0
208
-    ): array {
209
-        $this->debugLog(__FUNCTION__);
210
-        $this->reorderSubLineItems($line_item);
211
-        [$total, $pretax_total] = $line_item->is_percent()
212
-            ? $this->recalculatePercentageLineItem($line_item, $total, $pretax_total)
213
-            : $this->recalculateNonPercentageLineItem($line_item);
214
-
215
-        $total        = $this->updateTotal($line_item, $total, true);
216
-        $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
217
-
218
-        // need to also adjust unit price too if the pretax total or quantity has been updated
219
-        $this->updateUnitPrice($line_item, $pretax_total);
220
-        $this->debugLog(' - ' . __FUNCTION__, 3);
221
-        $this->debugLog(" - - total : $total", 3);
222
-        $this->debugLog(" - - pretax: $pretax_total", 3);
223
-        return [$total, $pretax_total];
224
-    }
225
-
226
-
227
-    /**
228
-     * @param EE_Line_Item $line_item
229
-     * @param float        $total
230
-     * @param float        $pretax_total
231
-     * @return float[]
232
-     * @throws EE_Error
233
-     * @throws ReflectionException
234
-     * @since 5.0.12.p
235
-     */
236
-    private function recalculatePercentageLineItem(
237
-        EE_Line_Item $line_item,
238
-        float $total = 0,
239
-        float $pretax_total = 0
240
-    ): array {
241
-        $this->debugLog(' % ' . __FUNCTION__, 2);
242
-        $pretax_total = $this->calculatePercentage($pretax_total, $line_item->percent());
243
-        // if the line item is taxable, then we need to calculate the total,
244
-        // otherwise we can just use the pretax total
245
-        $total = $line_item->is_taxable()
246
-            ? $this->calculatePercentage($total, $line_item->percent())
247
-            : $pretax_total;
248
-        $this->debugLog(' % ' . __FUNCTION__, 3);
249
-        $this->debugLog(" % % total : $total ", 3);
250
-        $this->debugLog(" % % pretax: $pretax_total ", 3);
251
-        return [$total, $pretax_total];
252
-    }
253
-
254
-
255
-    /**
256
-     * @param EE_Line_Item $line_item
257
-     * @return float[]
258
-     * @throws EE_Error
259
-     * @throws ReflectionException
260
-     * @since 5.0.12.p
261
-     */
262
-    private function recalculateNonPercentageLineItem(
263
-        EE_Line_Item $line_item
264
-    ): array {
265
-        $this->debugLog(' $ ' . __FUNCTION__, 2);
266
-        // recursively loop through children and recalculate their totals
267
-        $children = $line_item->children($this->default_query_params);
268
-        if (! empty($children)) {
269
-            // reset the total and pretax total to zero since we are recalculating them
270
-            $total = $pretax_total = 0;
271
-            foreach ($children as $child_line_item) {
272
-                [$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
273
-                    $child_line_item,
274
-                    $total,
275
-                    $pretax_total,
276
-                    $line_item->is_taxable()
277
-                );
278
-                $this->debugLog(' $ $ ' . __FUNCTION__, 3);
279
-                $this->debugLog(
280
-                    ' $ $ $ ' . $child_line_item->name() . ' '
281
-                    . $child_line_item->type() . ' ' . $child_line_item->code(),
282
-                    3
283
-                );
284
-                $this->debugLog(" $ $ $ $ child total: $child_total", 3);
285
-                $this->debugLog(" $ $ $ $ child pretax: $child_pretax_total", 3);
286
-                $total        += $child_total;
287
-                $pretax_total += $child_pretax_total;
288
-            }
289
-        } else {
290
-            // no child line items, so recalculate the total from the unit price and quantity
291
-            // and set the pretax total to match since there are obviously no sub-taxes
292
-            $pretax_total = $total = $this->calculateTotalForQuantity($line_item);
293
-        }
294
-        $this->debugLog(' $ ' . __FUNCTION__, 3);
295
-        $this->debugLog(' $ $ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
296
-        $this->debugLog(" $ $ $ total: $total", 3);
297
-        $this->debugLog(" $ $ $ pretax: $pretax_total", 3);
298
-        return [$total, $pretax_total];
299
-    }
300
-
301
-
302
-    /**
303
-     * @param EE_Line_Item $sub_line_item
304
-     * @param float|int    $total
305
-     * @param float|int    $pretax_total
306
-     * @param bool         $is_taxable
307
-     * @return float[]
308
-     * @throws EE_Error
309
-     * @throws ReflectionException
310
-     */
311
-    private function recalculateSubLineItem(
312
-        EE_Line_Item $sub_line_item,
313
-        float $total = 0,
314
-        float $pretax_total = 0,
315
-        bool $is_taxable = false
316
-    ): array {
317
-        $this->debugLog(__FUNCTION__);
318
-        $total = $is_taxable ? $total : $pretax_total;
319
-        if ($sub_line_item->is_percent()) {
320
-            $new_total        = $this->calculatePercentage($total, $sub_line_item->percent());
321
-            $new_pretax_total = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
322
-        } else {
323
-            $new_total = $new_pretax_total = $this->calculateTotalForQuantity($sub_line_item);
324
-        }
325
-        $total        = $this->updateTotal($sub_line_item, $new_total, false, false);
326
-        $pretax_total = $this->updatePreTaxTotal($sub_line_item, $new_pretax_total, false, false);
327
-        // need to also adjust unit price too if the pretax total or quantity has been updated
328
-        $this->updateUnitPrice($sub_line_item, $pretax_total);
329
-        $this->debugLog(" - - total : $total ", 3);
330
-        $this->debugLog(" - - pretax: $pretax_total ", 3);
331
-        return [$total, $pretax_total];
332
-    }
333
-
334
-
335
-    /**
336
-     * @param EE_Line_Item $sub_line_item
337
-     * @param float|int    $pretax_total
338
-     * @return float[]
339
-     * @throws EE_Error
340
-     * @throws ReflectionException
341
-     */
342
-    private function recalculateSubTax(EE_Line_Item $sub_line_item, float $pretax_total = 0): array
343
-    {
344
-        $this->debugLog(__FUNCTION__);
345
-        $total_tax = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
346
-        $total_tax = $this->updateTotal($sub_line_item, $total_tax);
347
-        $this->debugLog(" - total_tax : $total_tax ", 3);
348
-        return [$total_tax, 0];
349
-    }
350
-
351
-
352
-    /**
353
-     * recursively loops through the entire line item tree updating line item quantities accordingly.
354
-     * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p
355
-     *
356
-     * @param EE_Line_Item $line_item
357
-     * @param int          $quantity
358
-     * @return int
359
-     * @throws EE_Error
360
-     * @throws ReflectionException
361
-     */
362
-    private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int
363
-    {
364
-        switch ($line_item->type()) {
365
-            case EEM_Line_Item::type_total:
366
-            case EEM_Line_Item::type_sub_total:
367
-            case EEM_Line_Item::type_tax_sub_total:
368
-                // first, loop through children and set their quantities
369
-                $count    = 0;
370
-                $children = $line_item->children($this->default_query_params);
371
-                foreach ($children as $child_line_item) {
372
-                    $count += $this->updateLineItemQuantities($child_line_item);
373
-                }
374
-                // totals and subtotals should have a quantity of 1
375
-                // unless their children have all been removed, in which case we can set them to 0
376
-                $quantity = $count > 0 ? 1 : 0;
377
-                $this->updateQuantity($line_item, $quantity);
378
-                return $quantity;
379
-
380
-            case EEM_Line_Item::type_line_item:
381
-                // line items should ALREADY have accurate quantities set, if not, then somebody done goofed!
382
-                // but if this is a percentage based line item, then ensure its quantity is 1
383
-                if ($line_item->is_percent()) {
384
-                    $this->updateQuantity($line_item, 1);
385
-                }
386
-                // and we also need to loop through all the sub items and ensure those quantities match this parent.
387
-                $children = $line_item->children($this->default_query_params);
388
-                $quantity = $line_item->quantity();
389
-                foreach ($children as $child_line_item) {
390
-                    $this->updateLineItemQuantities($child_line_item, $quantity);
391
-                }
392
-                // percentage line items should not increment their parent's count, so they return 0
393
-                return ! $line_item->is_percent() ? $quantity : 0;
394
-
395
-            case EEM_Line_Item::type_sub_line_item:
396
-                // percentage based items need their quantity set to 1,
397
-                // all others use the incoming value from the parent line item
398
-                $quantity = $line_item->is_percent() ? 1 : $quantity;
399
-                $this->updateQuantity($line_item, $quantity);
400
-                // percentage line items should not increment their parent's count, so they return 0
401
-                return ! $line_item->is_percent() ? $quantity : 0;
402
-
403
-            case EEM_Line_Item::type_tax:
404
-            case EEM_Line_Item::type_sub_tax:
405
-                // taxes should have a quantity of 1
406
-                $this->updateQuantity($line_item, 1);
407
-                return 1;
408
-
409
-            case EEM_Line_Item::type_cancellation:
410
-                // cancellations will be ignored for all calculations
411
-                // because their parent quantities should have already been adjusted when they were added
412
-                // so assume that things are already set correctly
413
-                return 0;
414
-        }
415
-        return 0;
416
-    }
417
-
418
-
419
-    /**
420
-     * @param float $total
421
-     * @param float $percent
422
-     * @param bool  $round
423
-     * @return float
424
-     */
425
-    private function calculatePercentage(float $total, float $percent, bool $round = false): float
426
-    {
427
-        $amount = $total * $percent / 100;
428
-        $amount = $this->decimal_values->roundDecimalValue($amount, $round);
429
-        $this->debugLog(' % ' . __FUNCTION__, 2);
430
-        $this->debugLog(" % % total: $total", 3);
431
-        $this->debugLog(" % % percent: $percent", 3);
432
-        $this->debugLog(" % % amount: $amount", 3);
433
-        return $amount;
434
-    }
435
-
436
-
437
-    /**
438
-     * @param EE_Line_Item $line_item
439
-     * @return float
440
-     * @throws EE_Error
441
-     * @throws ReflectionException
442
-     */
443
-    private function calculateTotalForQuantity(EE_Line_Item $line_item): float
444
-    {
445
-        $this->debugLog(' # ' . __FUNCTION__, 2);
446
-        $this->debugLog(' # # ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
447
-        $this->debugLog(" # # # unit_price: " . $line_item->unit_price(), 3);
448
-        $this->debugLog(" # # # quantity: " . $line_item->quantity(), 3);
449
-        $total = $line_item->unit_price() * $line_item->quantity();
450
-        return $this->decimal_values->roundDecimalValue($total);
451
-    }
452
-
453
-
454
-    /**
455
-     * @param EE_Line_Item $line_item
456
-     * @param float        $percent
457
-     * @throws EE_Error
458
-     * @throws ReflectionException
459
-     */
460
-    private function updatePercent(EE_Line_Item $line_item, float $percent)
461
-    {
462
-        // update and save new percent only if incoming value does not match existing value
463
-        if ($line_item->percent() !== $percent) {
464
-            $line_item->set_percent($percent);
465
-            $line_item->maybe_save();
466
-        }
467
-    }
468
-
469
-
470
-    /**
471
-     * @param EE_Line_Item $line_item
472
-     * @param float        $pretax_total
473
-     * @param bool         $round
474
-     * @param bool         $save
475
-     * @return float
476
-     * @throws EE_Error
477
-     * @throws ReflectionException
478
-     */
479
-    private function updatePreTaxTotal(
480
-        EE_Line_Item $line_item,
481
-        float $pretax_total,
482
-        bool $round = false,
483
-        bool $save = true
484
-    ): float {
485
-        $pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round);
486
-        // update and save new total only if incoming value does not match existing value
487
-        if ($line_item->preTaxTotal() !== $pretax_total) {
488
-            $line_item->setPreTaxTotal($pretax_total);
489
-            if ($save) {
490
-                $line_item->maybe_save();
491
-            }
492
-        }
493
-        return $pretax_total;
494
-    }
495
-
496
-
497
-    /**
498
-     * @param EE_Line_Item $line_item
499
-     * @param int          $quantity
500
-     * @throws EE_Error
501
-     * @throws ReflectionException
502
-     */
503
-    private function updateQuantity(EE_Line_Item $line_item, int $quantity)
504
-    {
505
-        // update and save new quantity only if incoming value does not match existing value
506
-        if ($line_item->quantity() !== $quantity) {
507
-            $line_item->set_quantity($quantity);
508
-            $line_item->maybe_save();
509
-        }
510
-    }
511
-
512
-
513
-    /**
514
-     * @param EE_Line_Item $line_item
515
-     * @param float        $total
516
-     * @param bool         $round
517
-     * @param bool         $save
518
-     * @return float
519
-     * @throws EE_Error
520
-     * @throws ReflectionException
521
-     */
522
-    private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false, bool $save = true): float
523
-    {
524
-        $total = $this->decimal_values->roundDecimalValue($total, $round);
525
-        // update and save new total only if incoming value does not match existing value
526
-        if ($line_item->total() !== $total) {
527
-            $line_item->set_total($total);
528
-            if ($save) {
529
-                $line_item->maybe_save();
530
-            }
531
-        }
532
-        return (float) $total;
533
-    }
534
-
535
-
536
-    /**
537
-     * @param EE_Line_Item $line_item
538
-     * @param float        $total
539
-     * @param bool         $update_status
540
-     * @return void
541
-     * @throws EE_Error
542
-     * @throws ReflectionException
543
-     */
544
-    private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status)
545
-    {
546
-        // only update the related transaction's total
547
-        // if we intend to save this line item and it's a grand total
548
-        if ($line_item->allow_persist()) {
549
-            $transaction = $line_item->transaction();
550
-            if ($transaction instanceof EE_Transaction) {
551
-                $transaction->set_total($total);
552
-                if ($update_status) {
553
-                    // don't save the TXN because that will be done below
554
-                    // and the following method only saves if the status changes
555
-                    $transaction->update_status_based_on_total_paid(false);
556
-                }
557
-                if ($transaction->ID()) {
558
-                    $transaction->save();
559
-                }
560
-            }
561
-        }
562
-    }
563
-
564
-
565
-    /**
566
-     * @param EE_Line_Item $line_item
567
-     * @param float        $pretax_total
568
-     * @param bool         $save
569
-     * @return void
570
-     * @throws EE_Error
571
-     * @throws ReflectionException
572
-     */
573
-    private function updateUnitPrice(EE_Line_Item $line_item, float $pretax_total, bool $save = true)
574
-    {
575
-        $quantity = $line_item->quantity();
576
-        // don't divide by zero else you'll create a singularity and implode the interweb
577
-        // we also don't set unit prices for percentage based line items
578
-        if ($quantity === 0 || $line_item->is_percent()) {
579
-            return;
580
-        }
581
-        $new_unit_price = $pretax_total / $quantity;
582
-        $new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price);
583
-        // update and save new total only if incoming value does not match existing value
584
-        if ($line_item->unit_price() !== $new_unit_price) {
585
-            $this->debugLog(' @ ' . __FUNCTION__, 3);
586
-            $this->debugLog(' @ @ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
587
-            $this->debugLog(" @ @ @ pretax: $pretax_total", 3);
588
-            $this->debugLog(" @ @ @ quantity: $quantity", 3);
589
-            $this->debugLog(" @ @ @ old unit price: " . $line_item->unit_price(), 3);
590
-            $this->debugLog(" @ @ @ new unit price: $new_unit_price", 3);
591
-            $line_item->set_unit_price($new_unit_price);
592
-            if ($save) {
593
-                $line_item->maybe_save();
594
-            }
595
-        }
596
-    }
597
-
598
-
599
-    /**
600
-     * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
601
-     * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
602
-     * and tax sub-total if already in the DB
603
-     *
604
-     * @param EE_Line_Item $total_line_item
605
-     * @return float
606
-     * @throws EE_Error
607
-     * @throws ReflectionException
608
-     */
609
-    public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float
610
-    {
611
-        $this->debugLog(__FUNCTION__, 3);
612
-        $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
613
-        // calculate the total taxable amount for globally applied taxes
614
-        $taxable_total    = $this->taxableAmountForGlobalTaxes($total_line_item);
615
-        [$total_tax, $global_taxes ]    = $this->applyGlobalTaxes($total_line_item, $taxable_total);
616
-        $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
617
-        $all_tax_total    = $this->applyNonGlobalTaxes($total_line_item, $total_tax, $global_taxes, $non_global_taxes);
618
-        $this->recalculateTaxSubTotal($total_line_item);
619
-        $this->debugLog(" - taxable_total : $taxable_total", 4);
620
-        $this->debugLog(" - total_tax : $total_tax", 4);
621
-        $this->debugLog(" - all_tax_total : $all_tax_total", 4);
622
-        return $all_tax_total;
623
-    }
624
-
625
-
626
-    /**
627
-     * @param EE_Line_Item $total_line_item
628
-     * @param float        $taxable_total
629
-     * @return array
630
-     * @throws EE_Error
631
-     * @throws ReflectionException
632
-     */
633
-    private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): array
634
-    {
635
-        $this->debugLog(__FUNCTION__, 4);
636
-        $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
637
-        $total_tax = 0;
638
-        if ($taxable_total === 0.0) {
639
-            return [0, []];
640
-        }
641
-        // loop through all global taxes all taxes
642
-        $global_taxes = $total_line_item->tax_descendants();
643
-        foreach ($global_taxes as $tax) {
644
-            $tax_total = $this->calculatePercentage($taxable_total, $tax->percent());
645
-            if ($tax_total === 0.0) {
646
-                $tax->delete();
647
-                continue;
648
-            }
649
-            $tax_total = $this->updateTotal($tax, $tax_total, true);
650
-            $total_tax += $tax_total;
651
-        }
652
-        return [$this->decimal_values->roundDecimalValue($total_tax, true), $global_taxes];
653
-    }
654
-
655
-
656
-    /**
657
-     * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
658
-     *
659
-     * @param EE_Line_Item $line_item
660
-     * @return void
661
-     * @throws EE_Error
662
-     * @throws ReflectionException
663
-     */
664
-    private function recalculateTaxSubTotal(EE_Line_Item $line_item)
665
-    {
666
-        $this->debugLog(__FUNCTION__, 4);
667
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
668
-        foreach ($line_item->children() as $maybe_tax_subtotal) {
669
-            if (
670
-                $this->validateLineItemAndType($maybe_tax_subtotal)
671
-                && $maybe_tax_subtotal->is_tax_sub_total()
672
-            ) {
673
-                $total         = 0;
674
-                $total_percent = 0;
675
-                // simply loop through all its children (which should be taxes) and sum their total
676
-                foreach ($maybe_tax_subtotal->children() as $child_tax) {
677
-                    if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) {
678
-                        $total         += $child_tax->total();
679
-                        $total_percent += $child_tax->percent();
680
-                    }
681
-                }
682
-                $this->updateTotal($maybe_tax_subtotal, $total, true);
683
-                $this->updatePercent($maybe_tax_subtotal, $total_percent);
684
-            }
685
-        }
686
-    }
687
-
688
-
689
-    /**
690
-     * returns an array of tax details like:
691
-     *  [
692
-     *      'GST_7' => [
693
-     *          'name'  => 'GST',
694
-     *          'rate'  => float(7),
695
-     *          'total' => float(4.9),
696
-     *      ]
697
-     *  ]
698
-     *
699
-     * @param EE_Line_Item $total_line_item
700
-     * @param array        $non_global_taxes
701
-     * @param float        $line_item_total
702
-     * @return array
703
-     * @throws EE_Error
704
-     * @throws ReflectionException
705
-     */
706
-    private function calculateNonGlobalTaxes(
707
-        EE_Line_Item $total_line_item,
708
-        array $non_global_taxes = [],
709
-        float $line_item_total = 0
710
-    ): array {
711
-        $this->debugLog(__FUNCTION__, 4);
712
-        foreach ($total_line_item->children() as $line_item) {
713
-            if ($this->validateLineItemAndType($line_item)) {
714
-                if ($line_item->is_sub_total()) {
715
-                    $non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes);
716
-                } elseif ($line_item->is_line_item()) {
717
-                    $non_global_taxes = $this->calculateNonGlobalTaxes(
718
-                        $line_item,
719
-                        $non_global_taxes,
720
-                        $line_item->pretaxTotal()
721
-                    );
722
-                } elseif ($line_item->isSubTax()) {
723
-                    $tax_ID = $line_item->name() . '_' . $line_item->percent();
724
-                    if (! isset($non_global_taxes[ $tax_ID ])) {
725
-                        $non_global_taxes[ $tax_ID ] = [
726
-                            'name'  => $line_item->name(),
727
-                            'rate'  => $line_item->percent(),
728
-                            'total' => 0,
729
-                            'obj'   => $line_item->OBJ_type(),
730
-                            'objID' => $line_item->OBJ_ID(),
731
-                        ];
732
-                    }
733
-                    $tax = $this->calculatePercentage($line_item_total, $line_item->percent());
734
-
735
-                    $non_global_taxes[ $tax_ID ]['total'] += $tax;
736
-                }
737
-            }
738
-        }
739
-        return $non_global_taxes;
740
-    }
741
-
742
-
743
-    /**
744
-     * @param EE_Line_Item   $total_line_item
745
-     * @param float          $tax_total
746
-     * @param EE_Line_Item[] $global_taxes array of tax line items returned from applyGlobalTaxes()
747
-     * @param array          $non_global_taxes array of tax details generated by calculateNonGlobalTaxes()
748
-     * @return float
749
-     * @throws EE_Error
750
-     * @throws ReflectionException
751
-     */
752
-    private function applyNonGlobalTaxes(
753
-        EE_Line_Item $total_line_item,
754
-        float $tax_total,
755
-        array $global_taxes,
756
-        array $non_global_taxes
757
-    ): float {
758
-        $this->debugLog(__FUNCTION__, 4);
759
-        $taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item);
760
-        foreach ($non_global_taxes as $non_global_tax) {
761
-            $found = false;
762
-            foreach ($global_taxes as $global_tax) {
763
-                if (
764
-                    $this->validateLineItemAndType($global_tax)
765
-                    && $non_global_tax['obj'] === $global_tax->OBJ_type()
766
-                    && $non_global_tax['objID'] === $global_tax->OBJ_ID()
767
-                ) {
768
-                    $found     = true;
769
-                    $new_total = $global_tax->total() + $non_global_tax['total'];
770
-                    // add non-global tax to matching global tax AND the tax total
771
-                    $global_tax->set_total($new_total);
772
-                    $global_tax->maybe_save();
773
-                    $tax_total += $non_global_tax['total'];
774
-                }
775
-            }
776
-            if (! $found) {
777
-                // add a new line item for this non-global tax
778
-                $taxes_subtotal->add_child_line_item(
779
-                    EE_Line_Item::new_instance(
780
-                        [
781
-                            'LIN_name'       => $non_global_tax['name'],
782
-                            'LIN_percent'    => $non_global_tax['rate'],
783
-                            'LIN_is_taxable' => false,
784
-                            'LIN_total'      => $non_global_tax['total'],
785
-                            'LIN_type'       => EEM_Line_Item::type_tax,
786
-                            'OBJ_type'       => $non_global_tax['obj'],
787
-                            'OBJ_ID'         => $non_global_tax['objID'],
788
-                        ]
789
-                    )
790
-                );
791
-                $tax_total += $non_global_tax['total'];
792
-            }
793
-        }
794
-        return $this->decimal_values->roundDecimalValue($tax_total, true);
795
-    }
796
-
797
-
798
-    /**
799
-     * Gets the total tax on this line item. Assumes taxes have already been calculated using
800
-     * recalculate_taxes_and_total
801
-     *
802
-     * @param EE_Line_Item $line_item
803
-     * @return float
804
-     * @throws EE_Error
805
-     * @throws ReflectionException
806
-     */
807
-    public function getTotalTax(EE_Line_Item $line_item): float
808
-    {
809
-        $this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
810
-        $this->recalculateTaxSubTotal($line_item);
811
-        $total = 0;
812
-        foreach ($line_item->tax_descendants() as $tax_line_item) {
813
-            if ($this->validateLineItemAndType($tax_line_item)) {
814
-                $total += $tax_line_item->total();
815
-            }
816
-        }
817
-        return $this->decimal_values->roundDecimalValue($total, true);
818
-    }
819
-
820
-
821
-    /**
822
-     * Returns the amount taxable among this line item's children (or if it has no children,
823
-     * how much of it is taxable). Does not recalculate totals or subtotals.
824
-     * If the taxable total is negative, (eg, if none of the tickets were taxable,
825
-     * but there is a "Taxable" discount), returns 0.
826
-     *
827
-     * @param EE_Line_Item|null $line_item
828
-     * @return float
829
-     * @throws EE_Error
830
-     * @throws ReflectionException
831
-     */
832
-    public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float
833
-    {
834
-        $this->debugLog(__FUNCTION__, 4);
835
-        $total            = 0;
836
-        $child_line_items = $line_item->children($this->default_query_params);
837
-        foreach ($child_line_items as $child_line_item) {
838
-            $this->validateLineItemAndType($child_line_item);
839
-            if ($child_line_item->is_sub_total()) {
840
-                $total += $this->taxableAmountForGlobalTaxes($child_line_item);
841
-            } elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) {
842
-                // if it's a percent item, only take into account
843
-                // the percentage that's taxable (the taxable total so far)
844
-                if ($child_line_item->is_percent()) {
845
-                    $total += $this->calculatePercentage($total, $child_line_item->percent(), true);
846
-                } else {
847
-                    // pretax total will be equal to the total for line items with globally applied taxes
848
-                    $pretax_total = $this->calculateTotalForQuantity($child_line_item);
849
-                    $total        += $this->updatePreTaxTotal($child_line_item, $pretax_total);
850
-                }
851
-            }
852
-        }
853
-        return max($total, 0);
854
-    }
855
-
856
-
857
-    /**
858
-     * @param EE_Line_Item|null $line_item
859
-     * @param string|null       $type
860
-     * @return bool
861
-     * @throws EE_Error
862
-     * @throws ReflectionException
863
-     */
864
-    private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
865
-    {
866
-        if (! $line_item instanceof EE_Line_Item) {
867
-            throw new DomainException(
868
-                esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
869
-            );
870
-        }
871
-        if ($type && $line_item->type() !== $type) {
872
-            throw new DomainException(
873
-                sprintf(
874
-                    esc_html__(
875
-                        'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".',
876
-                        'event_espresso'
877
-                    ),
878
-                    $line_item->type(),
879
-                    $type
880
-                )
881
-            );
882
-        }
883
-        return true;
884
-    }
885
-
886
-
887
-    /**
888
-     * loops through all sub-line-items for the supplied line item and reorders them as follows:
889
-     * 1. sub items
890
-     * 2. other??? (not a sub-item or sub-tax)
891
-     * 3. sub taxes
892
-     *
893
-     * @param EE_Line_Item $line_item
894
-     * @return void
895
-     * @throws EE_Error
896
-     * @throws ReflectionException
897
-     * @since 5.0.12.p
898
-     */
899
-    public function reorderSubLineItems(EE_Line_Item $line_item)
900
-    {
901
-        if ($line_item->type() !== EEM_Line_Item::type_line_item) {
902
-            return;
903
-        }
904
-        $this->debugLog(' + LineItemCalculator::reorderSubLineItems', 3);
905
-        $this->debugLog(
906
-            ' + + ' . $line_item->OBJ_type() . ' ' . $line_item->name()
907
-            . ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
908
-            3
909
-        );
910
-        $sub_line_items = $line_item->children();
911
-        $items          = [];
912
-        $other          = [];
913
-        $taxes          = [];
914
-        foreach ($sub_line_items as $sub_line_item) {
915
-            switch ($sub_line_item->type()) {
916
-                case EEM_Line_Item::type_sub_line_item:
917
-                    $items[ $sub_line_item->ID() ] = $sub_line_item;
918
-                    break;
919
-                case EEM_Line_Item::type_sub_tax:
920
-                    $taxes[ $sub_line_item->ID() ] = $sub_line_item;
921
-                    break;
922
-                default:
923
-                    $other[ $sub_line_item->ID() ] = $sub_line_item;
924
-            }
925
-        }
926
-        $order      = 0;
927
-        $line_items = apply_filters(
928
-            'FHEE__EventEspresso_core_services_calculators_LineItemCalculator__reorderSubLineItems__line_items',
929
-            ['items' => $items, 'other' => $other, 'taxes' => $taxes]
930
-        );
931
-        foreach ($line_items as $sub_items) {
932
-            foreach ($sub_items as $sub_item) {
933
-                $order++;
934
-                $sub_item->set_order($order);
935
-                $sub_item->save();
936
-                $this->debugLog(
937
-                    ' + + + ' . $order . '. ' . $sub_item->OBJ_type() . ' ' . $sub_item->name()
938
-                    . ' - ' . $sub_item->type() . ' (' . $sub_item->code() . ')',
939
-                    3
940
-                );
941
-            }
942
-        }
943
-    }
24
+	use DebugDisplay;
25
+
26
+	protected DecimalValues $decimal_values;
27
+
28
+	protected array $default_query_params = [
29
+		['LIN_type' => ['!=', EEM_Line_Item::type_cancellation]],
30
+	];
31
+
32
+
33
+	/**
34
+	 * @param DecimalValues $decimal_values
35
+	 */
36
+	public function __construct(DecimalValues $decimal_values)
37
+	{
38
+		$this->decimal_values = $decimal_values;
39
+		$this->initializeDebugDisplay();
40
+	}
41
+
42
+
43
+	/**
44
+	 * Gets the final total on this item, taking taxes into account.
45
+	 * Has the side effect of setting the sub-total as it was just calculated.
46
+	 * If this is used on a grand-total line item, also updates the transaction's
47
+	 * TXN_total (provided this line item is allowed to persist, otherwise we don't
48
+	 * want to change a persistable transaction with info from a non-persistent line item)
49
+	 *
50
+	 * @param EE_Line_Item $line_item
51
+	 * @param bool         $update_txn_status
52
+	 * @return float
53
+	 * @throws EE_Error
54
+	 * @throws ReflectionException
55
+	 */
56
+	public function recalculateTotalIncludingTaxes(EE_Line_Item $line_item, bool $update_txn_status = false): float
57
+	{
58
+		$this->debugLog('', 2);
59
+		$this->debugLog(__METHOD__);
60
+		$this->debugLog(str_repeat('*', strlen(__METHOD__)), 2);
61
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
62
+		$ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item);
63
+		if (empty($ticket_line_items)) {
64
+			// no tickets? ensure totals are zero
65
+			$this->updatePreTaxTotal($line_item, 0);
66
+			$this->updateTotal($line_item, 0);
67
+			$this->updateTransaction($line_item, 0, $update_txn_status);
68
+			return 0;
69
+		}
70
+		[, $pretax_total] = $this->recalculateLineItemTotals($line_item);
71
+		// EEH_Line_Item::visualize($line_item);
72
+		$total_tax = $this->recalculateTaxesAndTaxTotal($line_item);
73
+		// no negative totals plz
74
+		$grand_total = max($pretax_total + $total_tax, 0);
75
+		$this->updatePreTaxTotal($line_item, $pretax_total, true);
76
+		$grand_total = $this->updateTotal($line_item, $grand_total, true);
77
+		$this->updateTransaction($line_item, $grand_total, $update_txn_status);
78
+		return $grand_total;
79
+	}
80
+
81
+
82
+	/**
83
+	 * Recursively goes through all the children and recalculates sub-totals EXCEPT for
84
+	 * tax-sub-totals (they're an odd beast). Updates the 'total' on each line item according to either its
85
+	 * unit price * quantity or the total of all its children EXCEPT when we're only calculating the taxable total and
86
+	 * when this is called on the grand total
87
+	 *
88
+	 * @param EE_Line_Item $line_item
89
+	 * @param float        $total
90
+	 * @param float        $pretax_total
91
+	 * @param bool         $is_taxable
92
+	 * @return array
93
+	 * @throws EE_Error
94
+	 * @throws ReflectionException
95
+	 */
96
+	public function recalculateLineItemTotals(
97
+		EE_Line_Item $line_item,
98
+		float $total = 0,
99
+		float $pretax_total = 0,
100
+		bool $is_taxable = false
101
+	): array {
102
+		$this->debugLog(__FUNCTION__);
103
+		$OBJ = $line_item->OBJ_type();
104
+		$OBJ .= $OBJ ? ': ' : '';
105
+		$this->debugLog(
106
+			' * ' . $OBJ . $line_item->name() . ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
107
+			2
108
+		);
109
+		$this->debugLog(" * total: $total", 3);
110
+		$this->debugLog(" * pretax: $pretax_total", 3);
111
+		switch ($line_item->type()) {
112
+			case EEM_Line_Item::type_total:
113
+			case EEM_Line_Item::type_sub_total:
114
+				[$total, $pretax_total] = $this->recalculateSubTotal($line_item);
115
+				break;
116
+
117
+			case EEM_Line_Item::type_line_item:
118
+				[$total, $pretax_total] = $this->recalculateLineItem($line_item, $total, $pretax_total);
119
+				break;
120
+
121
+			case EEM_Line_Item::type_sub_line_item:
122
+				// sub-line-items operate on the total and update both the total AND the pre-tax total
123
+				[$total, $pretax_total] = $this->recalculateSubLineItem($line_item, $total, $pretax_total, $is_taxable);
124
+				break;
125
+
126
+			case EEM_Line_Item::type_sub_tax:
127
+				// sub-line-items taxes ONLY operate on the pre-tax total and ONLY update the total
128
+				[$total, $pretax_total] = $this->recalculateSubTax($line_item, $pretax_total);
129
+				break;
130
+
131
+			case EEM_Line_Item::type_tax_sub_total:
132
+			case EEM_Line_Item::type_tax:
133
+			case EEM_Line_Item::type_cancellation:
134
+				// completely ignore tax totals, tax sub-totals, and cancelled line items
135
+				// when calculating the pre-tax-total
136
+				$total = $pretax_total = 0;
137
+				break;
138
+		}
139
+		return [$total, $pretax_total];
140
+	}
141
+
142
+
143
+	/**
144
+	 * @param EE_Line_Item $line_item
145
+	 * @return array
146
+	 * @throws EE_Error
147
+	 * @throws ReflectionException
148
+	 */
149
+	private function recalculateSubTotal(EE_Line_Item $line_item): array
150
+	{
151
+		$this->debugLog(__FUNCTION__);
152
+		// reset the total and pretax total to zero since we are recalculating them
153
+		$total = $pretax_total = 0;
154
+		if ($line_item->is_total()) {
155
+			// if this is the grand total line item
156
+			// then first update ALL the line item quantities (if need be)
157
+			$this->updateLineItemQuantities($line_item);
158
+		}
159
+		// recursively loop through children and recalculate their totals
160
+		$children = $line_item->children($this->default_query_params);
161
+		if (empty($children)) {
162
+			$this->debugLog(' - ' . __FUNCTION__, 3);
163
+			$this->debugLog(" - - total : $total ", 3);
164
+			$this->debugLog(" - - pretax: $pretax_total ", 3);
165
+			return [$total, $pretax_total];
166
+		}
167
+		foreach ($children as $child_line_item) {
168
+			[$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
169
+				$child_line_item,
170
+				$total,
171
+				$pretax_total
172
+			);
173
+			$total        += $child_total;
174
+			$pretax_total += $child_pretax_total;
175
+		}
176
+		// update the unit price and pretax total
177
+		$this->updateUnitPrice($line_item, $pretax_total, false);
178
+		$pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true, false);
179
+		$this->debugLog(' - ' . __FUNCTION__, 3);
180
+		$this->debugLog(" - - line_item->name() : " . $line_item->name(), 3);
181
+		$this->debugLog(" - - line_item->code() : " . $line_item->code(), 3);
182
+		// for the actual pre-tax sub-total line item, we want to save the pretax value for everything
183
+		if ($line_item->is_sub_total() && $line_item->code() === 'pre-tax-subtotal') {
184
+			$this->updateTotal($line_item, $pretax_total, true);
185
+		} elseif (! $line_item->is_total()) {
186
+			// we don't update the total for the total line item, because that will need to include taxes
187
+			$total = $this->updateTotal($line_item, $total, true);
188
+		}
189
+		$this->debugLog(' - ' . __FUNCTION__, 3);
190
+		$this->debugLog(" - - total : $total ", 3);
191
+		$this->debugLog(" - - pretax: $pretax_total ", 3);
192
+		return [$total, $pretax_total];
193
+	}
194
+
195
+
196
+	/**
197
+	 * @param EE_Line_Item $line_item
198
+	 * @param float        $total
199
+	 * @param float        $pretax_total
200
+	 * @return array
201
+	 * @throws EE_Error
202
+	 * @throws ReflectionException
203
+	 */
204
+	private function recalculateLineItem(
205
+		EE_Line_Item $line_item,
206
+		float $total = 0,
207
+		float $pretax_total = 0
208
+	): array {
209
+		$this->debugLog(__FUNCTION__);
210
+		$this->reorderSubLineItems($line_item);
211
+		[$total, $pretax_total] = $line_item->is_percent()
212
+			? $this->recalculatePercentageLineItem($line_item, $total, $pretax_total)
213
+			: $this->recalculateNonPercentageLineItem($line_item);
214
+
215
+		$total        = $this->updateTotal($line_item, $total, true);
216
+		$pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true);
217
+
218
+		// need to also adjust unit price too if the pretax total or quantity has been updated
219
+		$this->updateUnitPrice($line_item, $pretax_total);
220
+		$this->debugLog(' - ' . __FUNCTION__, 3);
221
+		$this->debugLog(" - - total : $total", 3);
222
+		$this->debugLog(" - - pretax: $pretax_total", 3);
223
+		return [$total, $pretax_total];
224
+	}
225
+
226
+
227
+	/**
228
+	 * @param EE_Line_Item $line_item
229
+	 * @param float        $total
230
+	 * @param float        $pretax_total
231
+	 * @return float[]
232
+	 * @throws EE_Error
233
+	 * @throws ReflectionException
234
+	 * @since 5.0.12.p
235
+	 */
236
+	private function recalculatePercentageLineItem(
237
+		EE_Line_Item $line_item,
238
+		float $total = 0,
239
+		float $pretax_total = 0
240
+	): array {
241
+		$this->debugLog(' % ' . __FUNCTION__, 2);
242
+		$pretax_total = $this->calculatePercentage($pretax_total, $line_item->percent());
243
+		// if the line item is taxable, then we need to calculate the total,
244
+		// otherwise we can just use the pretax total
245
+		$total = $line_item->is_taxable()
246
+			? $this->calculatePercentage($total, $line_item->percent())
247
+			: $pretax_total;
248
+		$this->debugLog(' % ' . __FUNCTION__, 3);
249
+		$this->debugLog(" % % total : $total ", 3);
250
+		$this->debugLog(" % % pretax: $pretax_total ", 3);
251
+		return [$total, $pretax_total];
252
+	}
253
+
254
+
255
+	/**
256
+	 * @param EE_Line_Item $line_item
257
+	 * @return float[]
258
+	 * @throws EE_Error
259
+	 * @throws ReflectionException
260
+	 * @since 5.0.12.p
261
+	 */
262
+	private function recalculateNonPercentageLineItem(
263
+		EE_Line_Item $line_item
264
+	): array {
265
+		$this->debugLog(' $ ' . __FUNCTION__, 2);
266
+		// recursively loop through children and recalculate their totals
267
+		$children = $line_item->children($this->default_query_params);
268
+		if (! empty($children)) {
269
+			// reset the total and pretax total to zero since we are recalculating them
270
+			$total = $pretax_total = 0;
271
+			foreach ($children as $child_line_item) {
272
+				[$child_total, $child_pretax_total] = $this->recalculateLineItemTotals(
273
+					$child_line_item,
274
+					$total,
275
+					$pretax_total,
276
+					$line_item->is_taxable()
277
+				);
278
+				$this->debugLog(' $ $ ' . __FUNCTION__, 3);
279
+				$this->debugLog(
280
+					' $ $ $ ' . $child_line_item->name() . ' '
281
+					. $child_line_item->type() . ' ' . $child_line_item->code(),
282
+					3
283
+				);
284
+				$this->debugLog(" $ $ $ $ child total: $child_total", 3);
285
+				$this->debugLog(" $ $ $ $ child pretax: $child_pretax_total", 3);
286
+				$total        += $child_total;
287
+				$pretax_total += $child_pretax_total;
288
+			}
289
+		} else {
290
+			// no child line items, so recalculate the total from the unit price and quantity
291
+			// and set the pretax total to match since there are obviously no sub-taxes
292
+			$pretax_total = $total = $this->calculateTotalForQuantity($line_item);
293
+		}
294
+		$this->debugLog(' $ ' . __FUNCTION__, 3);
295
+		$this->debugLog(' $ $ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
296
+		$this->debugLog(" $ $ $ total: $total", 3);
297
+		$this->debugLog(" $ $ $ pretax: $pretax_total", 3);
298
+		return [$total, $pretax_total];
299
+	}
300
+
301
+
302
+	/**
303
+	 * @param EE_Line_Item $sub_line_item
304
+	 * @param float|int    $total
305
+	 * @param float|int    $pretax_total
306
+	 * @param bool         $is_taxable
307
+	 * @return float[]
308
+	 * @throws EE_Error
309
+	 * @throws ReflectionException
310
+	 */
311
+	private function recalculateSubLineItem(
312
+		EE_Line_Item $sub_line_item,
313
+		float $total = 0,
314
+		float $pretax_total = 0,
315
+		bool $is_taxable = false
316
+	): array {
317
+		$this->debugLog(__FUNCTION__);
318
+		$total = $is_taxable ? $total : $pretax_total;
319
+		if ($sub_line_item->is_percent()) {
320
+			$new_total        = $this->calculatePercentage($total, $sub_line_item->percent());
321
+			$new_pretax_total = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
322
+		} else {
323
+			$new_total = $new_pretax_total = $this->calculateTotalForQuantity($sub_line_item);
324
+		}
325
+		$total        = $this->updateTotal($sub_line_item, $new_total, false, false);
326
+		$pretax_total = $this->updatePreTaxTotal($sub_line_item, $new_pretax_total, false, false);
327
+		// need to also adjust unit price too if the pretax total or quantity has been updated
328
+		$this->updateUnitPrice($sub_line_item, $pretax_total);
329
+		$this->debugLog(" - - total : $total ", 3);
330
+		$this->debugLog(" - - pretax: $pretax_total ", 3);
331
+		return [$total, $pretax_total];
332
+	}
333
+
334
+
335
+	/**
336
+	 * @param EE_Line_Item $sub_line_item
337
+	 * @param float|int    $pretax_total
338
+	 * @return float[]
339
+	 * @throws EE_Error
340
+	 * @throws ReflectionException
341
+	 */
342
+	private function recalculateSubTax(EE_Line_Item $sub_line_item, float $pretax_total = 0): array
343
+	{
344
+		$this->debugLog(__FUNCTION__);
345
+		$total_tax = $this->calculatePercentage($pretax_total, $sub_line_item->percent());
346
+		$total_tax = $this->updateTotal($sub_line_item, $total_tax);
347
+		$this->debugLog(" - total_tax : $total_tax ", 3);
348
+		return [$total_tax, 0];
349
+	}
350
+
351
+
352
+	/**
353
+	 * recursively loops through the entire line item tree updating line item quantities accordingly.
354
+	 * this needs to be done prior to running any other calculations for reasons that are hopefully obvious :p
355
+	 *
356
+	 * @param EE_Line_Item $line_item
357
+	 * @param int          $quantity
358
+	 * @return int
359
+	 * @throws EE_Error
360
+	 * @throws ReflectionException
361
+	 */
362
+	private function updateLineItemQuantities(EE_Line_Item $line_item, int $quantity = 1): int
363
+	{
364
+		switch ($line_item->type()) {
365
+			case EEM_Line_Item::type_total:
366
+			case EEM_Line_Item::type_sub_total:
367
+			case EEM_Line_Item::type_tax_sub_total:
368
+				// first, loop through children and set their quantities
369
+				$count    = 0;
370
+				$children = $line_item->children($this->default_query_params);
371
+				foreach ($children as $child_line_item) {
372
+					$count += $this->updateLineItemQuantities($child_line_item);
373
+				}
374
+				// totals and subtotals should have a quantity of 1
375
+				// unless their children have all been removed, in which case we can set them to 0
376
+				$quantity = $count > 0 ? 1 : 0;
377
+				$this->updateQuantity($line_item, $quantity);
378
+				return $quantity;
379
+
380
+			case EEM_Line_Item::type_line_item:
381
+				// line items should ALREADY have accurate quantities set, if not, then somebody done goofed!
382
+				// but if this is a percentage based line item, then ensure its quantity is 1
383
+				if ($line_item->is_percent()) {
384
+					$this->updateQuantity($line_item, 1);
385
+				}
386
+				// and we also need to loop through all the sub items and ensure those quantities match this parent.
387
+				$children = $line_item->children($this->default_query_params);
388
+				$quantity = $line_item->quantity();
389
+				foreach ($children as $child_line_item) {
390
+					$this->updateLineItemQuantities($child_line_item, $quantity);
391
+				}
392
+				// percentage line items should not increment their parent's count, so they return 0
393
+				return ! $line_item->is_percent() ? $quantity : 0;
394
+
395
+			case EEM_Line_Item::type_sub_line_item:
396
+				// percentage based items need their quantity set to 1,
397
+				// all others use the incoming value from the parent line item
398
+				$quantity = $line_item->is_percent() ? 1 : $quantity;
399
+				$this->updateQuantity($line_item, $quantity);
400
+				// percentage line items should not increment their parent's count, so they return 0
401
+				return ! $line_item->is_percent() ? $quantity : 0;
402
+
403
+			case EEM_Line_Item::type_tax:
404
+			case EEM_Line_Item::type_sub_tax:
405
+				// taxes should have a quantity of 1
406
+				$this->updateQuantity($line_item, 1);
407
+				return 1;
408
+
409
+			case EEM_Line_Item::type_cancellation:
410
+				// cancellations will be ignored for all calculations
411
+				// because their parent quantities should have already been adjusted when they were added
412
+				// so assume that things are already set correctly
413
+				return 0;
414
+		}
415
+		return 0;
416
+	}
417
+
418
+
419
+	/**
420
+	 * @param float $total
421
+	 * @param float $percent
422
+	 * @param bool  $round
423
+	 * @return float
424
+	 */
425
+	private function calculatePercentage(float $total, float $percent, bool $round = false): float
426
+	{
427
+		$amount = $total * $percent / 100;
428
+		$amount = $this->decimal_values->roundDecimalValue($amount, $round);
429
+		$this->debugLog(' % ' . __FUNCTION__, 2);
430
+		$this->debugLog(" % % total: $total", 3);
431
+		$this->debugLog(" % % percent: $percent", 3);
432
+		$this->debugLog(" % % amount: $amount", 3);
433
+		return $amount;
434
+	}
435
+
436
+
437
+	/**
438
+	 * @param EE_Line_Item $line_item
439
+	 * @return float
440
+	 * @throws EE_Error
441
+	 * @throws ReflectionException
442
+	 */
443
+	private function calculateTotalForQuantity(EE_Line_Item $line_item): float
444
+	{
445
+		$this->debugLog(' # ' . __FUNCTION__, 2);
446
+		$this->debugLog(' # # ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
447
+		$this->debugLog(" # # # unit_price: " . $line_item->unit_price(), 3);
448
+		$this->debugLog(" # # # quantity: " . $line_item->quantity(), 3);
449
+		$total = $line_item->unit_price() * $line_item->quantity();
450
+		return $this->decimal_values->roundDecimalValue($total);
451
+	}
452
+
453
+
454
+	/**
455
+	 * @param EE_Line_Item $line_item
456
+	 * @param float        $percent
457
+	 * @throws EE_Error
458
+	 * @throws ReflectionException
459
+	 */
460
+	private function updatePercent(EE_Line_Item $line_item, float $percent)
461
+	{
462
+		// update and save new percent only if incoming value does not match existing value
463
+		if ($line_item->percent() !== $percent) {
464
+			$line_item->set_percent($percent);
465
+			$line_item->maybe_save();
466
+		}
467
+	}
468
+
469
+
470
+	/**
471
+	 * @param EE_Line_Item $line_item
472
+	 * @param float        $pretax_total
473
+	 * @param bool         $round
474
+	 * @param bool         $save
475
+	 * @return float
476
+	 * @throws EE_Error
477
+	 * @throws ReflectionException
478
+	 */
479
+	private function updatePreTaxTotal(
480
+		EE_Line_Item $line_item,
481
+		float $pretax_total,
482
+		bool $round = false,
483
+		bool $save = true
484
+	): float {
485
+		$pretax_total = $this->decimal_values->roundDecimalValue($pretax_total, $round);
486
+		// update and save new total only if incoming value does not match existing value
487
+		if ($line_item->preTaxTotal() !== $pretax_total) {
488
+			$line_item->setPreTaxTotal($pretax_total);
489
+			if ($save) {
490
+				$line_item->maybe_save();
491
+			}
492
+		}
493
+		return $pretax_total;
494
+	}
495
+
496
+
497
+	/**
498
+	 * @param EE_Line_Item $line_item
499
+	 * @param int          $quantity
500
+	 * @throws EE_Error
501
+	 * @throws ReflectionException
502
+	 */
503
+	private function updateQuantity(EE_Line_Item $line_item, int $quantity)
504
+	{
505
+		// update and save new quantity only if incoming value does not match existing value
506
+		if ($line_item->quantity() !== $quantity) {
507
+			$line_item->set_quantity($quantity);
508
+			$line_item->maybe_save();
509
+		}
510
+	}
511
+
512
+
513
+	/**
514
+	 * @param EE_Line_Item $line_item
515
+	 * @param float        $total
516
+	 * @param bool         $round
517
+	 * @param bool         $save
518
+	 * @return float
519
+	 * @throws EE_Error
520
+	 * @throws ReflectionException
521
+	 */
522
+	private function updateTotal(EE_Line_Item $line_item, float $total, bool $round = false, bool $save = true): float
523
+	{
524
+		$total = $this->decimal_values->roundDecimalValue($total, $round);
525
+		// update and save new total only if incoming value does not match existing value
526
+		if ($line_item->total() !== $total) {
527
+			$line_item->set_total($total);
528
+			if ($save) {
529
+				$line_item->maybe_save();
530
+			}
531
+		}
532
+		return (float) $total;
533
+	}
534
+
535
+
536
+	/**
537
+	 * @param EE_Line_Item $line_item
538
+	 * @param float        $total
539
+	 * @param bool         $update_status
540
+	 * @return void
541
+	 * @throws EE_Error
542
+	 * @throws ReflectionException
543
+	 */
544
+	private function updateTransaction(EE_Line_Item $line_item, float $total, bool $update_status)
545
+	{
546
+		// only update the related transaction's total
547
+		// if we intend to save this line item and it's a grand total
548
+		if ($line_item->allow_persist()) {
549
+			$transaction = $line_item->transaction();
550
+			if ($transaction instanceof EE_Transaction) {
551
+				$transaction->set_total($total);
552
+				if ($update_status) {
553
+					// don't save the TXN because that will be done below
554
+					// and the following method only saves if the status changes
555
+					$transaction->update_status_based_on_total_paid(false);
556
+				}
557
+				if ($transaction->ID()) {
558
+					$transaction->save();
559
+				}
560
+			}
561
+		}
562
+	}
563
+
564
+
565
+	/**
566
+	 * @param EE_Line_Item $line_item
567
+	 * @param float        $pretax_total
568
+	 * @param bool         $save
569
+	 * @return void
570
+	 * @throws EE_Error
571
+	 * @throws ReflectionException
572
+	 */
573
+	private function updateUnitPrice(EE_Line_Item $line_item, float $pretax_total, bool $save = true)
574
+	{
575
+		$quantity = $line_item->quantity();
576
+		// don't divide by zero else you'll create a singularity and implode the interweb
577
+		// we also don't set unit prices for percentage based line items
578
+		if ($quantity === 0 || $line_item->is_percent()) {
579
+			return;
580
+		}
581
+		$new_unit_price = $pretax_total / $quantity;
582
+		$new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price);
583
+		// update and save new total only if incoming value does not match existing value
584
+		if ($line_item->unit_price() !== $new_unit_price) {
585
+			$this->debugLog(' @ ' . __FUNCTION__, 3);
586
+			$this->debugLog(' @ @ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
587
+			$this->debugLog(" @ @ @ pretax: $pretax_total", 3);
588
+			$this->debugLog(" @ @ @ quantity: $quantity", 3);
589
+			$this->debugLog(" @ @ @ old unit price: " . $line_item->unit_price(), 3);
590
+			$this->debugLog(" @ @ @ new unit price: $new_unit_price", 3);
591
+			$line_item->set_unit_price($new_unit_price);
592
+			if ($save) {
593
+				$line_item->maybe_save();
594
+			}
595
+		}
596
+	}
597
+
598
+
599
+	/**
600
+	 * Recalculates the total on each individual tax (based on a recalculation of the pre-tax total), sets
601
+	 * the totals on each tax calculated, and returns the final tax total. Re-saves tax line items
602
+	 * and tax sub-total if already in the DB
603
+	 *
604
+	 * @param EE_Line_Item $total_line_item
605
+	 * @return float
606
+	 * @throws EE_Error
607
+	 * @throws ReflectionException
608
+	 */
609
+	public function recalculateTaxesAndTaxTotal(EE_Line_Item $total_line_item): float
610
+	{
611
+		$this->debugLog(__FUNCTION__, 3);
612
+		$this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
613
+		// calculate the total taxable amount for globally applied taxes
614
+		$taxable_total    = $this->taxableAmountForGlobalTaxes($total_line_item);
615
+		[$total_tax, $global_taxes ]    = $this->applyGlobalTaxes($total_line_item, $taxable_total);
616
+		$non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
617
+		$all_tax_total    = $this->applyNonGlobalTaxes($total_line_item, $total_tax, $global_taxes, $non_global_taxes);
618
+		$this->recalculateTaxSubTotal($total_line_item);
619
+		$this->debugLog(" - taxable_total : $taxable_total", 4);
620
+		$this->debugLog(" - total_tax : $total_tax", 4);
621
+		$this->debugLog(" - all_tax_total : $all_tax_total", 4);
622
+		return $all_tax_total;
623
+	}
624
+
625
+
626
+	/**
627
+	 * @param EE_Line_Item $total_line_item
628
+	 * @param float        $taxable_total
629
+	 * @return array
630
+	 * @throws EE_Error
631
+	 * @throws ReflectionException
632
+	 */
633
+	private function applyGlobalTaxes(EE_Line_Item $total_line_item, float $taxable_total): array
634
+	{
635
+		$this->debugLog(__FUNCTION__, 4);
636
+		$this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
637
+		$total_tax = 0;
638
+		if ($taxable_total === 0.0) {
639
+			return [0, []];
640
+		}
641
+		// loop through all global taxes all taxes
642
+		$global_taxes = $total_line_item->tax_descendants();
643
+		foreach ($global_taxes as $tax) {
644
+			$tax_total = $this->calculatePercentage($taxable_total, $tax->percent());
645
+			if ($tax_total === 0.0) {
646
+				$tax->delete();
647
+				continue;
648
+			}
649
+			$tax_total = $this->updateTotal($tax, $tax_total, true);
650
+			$total_tax += $tax_total;
651
+		}
652
+		return [$this->decimal_values->roundDecimalValue($total_tax, true), $global_taxes];
653
+	}
654
+
655
+
656
+	/**
657
+	 * Simply forces all the tax-sub-totals to recalculate. Assumes the taxes have been calculated
658
+	 *
659
+	 * @param EE_Line_Item $line_item
660
+	 * @return void
661
+	 * @throws EE_Error
662
+	 * @throws ReflectionException
663
+	 */
664
+	private function recalculateTaxSubTotal(EE_Line_Item $line_item)
665
+	{
666
+		$this->debugLog(__FUNCTION__, 4);
667
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
668
+		foreach ($line_item->children() as $maybe_tax_subtotal) {
669
+			if (
670
+				$this->validateLineItemAndType($maybe_tax_subtotal)
671
+				&& $maybe_tax_subtotal->is_tax_sub_total()
672
+			) {
673
+				$total         = 0;
674
+				$total_percent = 0;
675
+				// simply loop through all its children (which should be taxes) and sum their total
676
+				foreach ($maybe_tax_subtotal->children() as $child_tax) {
677
+					if ($this->validateLineItemAndType($child_tax) && $child_tax->isGlobalTax()) {
678
+						$total         += $child_tax->total();
679
+						$total_percent += $child_tax->percent();
680
+					}
681
+				}
682
+				$this->updateTotal($maybe_tax_subtotal, $total, true);
683
+				$this->updatePercent($maybe_tax_subtotal, $total_percent);
684
+			}
685
+		}
686
+	}
687
+
688
+
689
+	/**
690
+	 * returns an array of tax details like:
691
+	 *  [
692
+	 *      'GST_7' => [
693
+	 *          'name'  => 'GST',
694
+	 *          'rate'  => float(7),
695
+	 *          'total' => float(4.9),
696
+	 *      ]
697
+	 *  ]
698
+	 *
699
+	 * @param EE_Line_Item $total_line_item
700
+	 * @param array        $non_global_taxes
701
+	 * @param float        $line_item_total
702
+	 * @return array
703
+	 * @throws EE_Error
704
+	 * @throws ReflectionException
705
+	 */
706
+	private function calculateNonGlobalTaxes(
707
+		EE_Line_Item $total_line_item,
708
+		array $non_global_taxes = [],
709
+		float $line_item_total = 0
710
+	): array {
711
+		$this->debugLog(__FUNCTION__, 4);
712
+		foreach ($total_line_item->children() as $line_item) {
713
+			if ($this->validateLineItemAndType($line_item)) {
714
+				if ($line_item->is_sub_total()) {
715
+					$non_global_taxes = $this->calculateNonGlobalTaxes($line_item, $non_global_taxes);
716
+				} elseif ($line_item->is_line_item()) {
717
+					$non_global_taxes = $this->calculateNonGlobalTaxes(
718
+						$line_item,
719
+						$non_global_taxes,
720
+						$line_item->pretaxTotal()
721
+					);
722
+				} elseif ($line_item->isSubTax()) {
723
+					$tax_ID = $line_item->name() . '_' . $line_item->percent();
724
+					if (! isset($non_global_taxes[ $tax_ID ])) {
725
+						$non_global_taxes[ $tax_ID ] = [
726
+							'name'  => $line_item->name(),
727
+							'rate'  => $line_item->percent(),
728
+							'total' => 0,
729
+							'obj'   => $line_item->OBJ_type(),
730
+							'objID' => $line_item->OBJ_ID(),
731
+						];
732
+					}
733
+					$tax = $this->calculatePercentage($line_item_total, $line_item->percent());
734
+
735
+					$non_global_taxes[ $tax_ID ]['total'] += $tax;
736
+				}
737
+			}
738
+		}
739
+		return $non_global_taxes;
740
+	}
741
+
742
+
743
+	/**
744
+	 * @param EE_Line_Item   $total_line_item
745
+	 * @param float          $tax_total
746
+	 * @param EE_Line_Item[] $global_taxes array of tax line items returned from applyGlobalTaxes()
747
+	 * @param array          $non_global_taxes array of tax details generated by calculateNonGlobalTaxes()
748
+	 * @return float
749
+	 * @throws EE_Error
750
+	 * @throws ReflectionException
751
+	 */
752
+	private function applyNonGlobalTaxes(
753
+		EE_Line_Item $total_line_item,
754
+		float $tax_total,
755
+		array $global_taxes,
756
+		array $non_global_taxes
757
+	): float {
758
+		$this->debugLog(__FUNCTION__, 4);
759
+		$taxes_subtotal = EEH_Line_Item::get_taxes_subtotal($total_line_item);
760
+		foreach ($non_global_taxes as $non_global_tax) {
761
+			$found = false;
762
+			foreach ($global_taxes as $global_tax) {
763
+				if (
764
+					$this->validateLineItemAndType($global_tax)
765
+					&& $non_global_tax['obj'] === $global_tax->OBJ_type()
766
+					&& $non_global_tax['objID'] === $global_tax->OBJ_ID()
767
+				) {
768
+					$found     = true;
769
+					$new_total = $global_tax->total() + $non_global_tax['total'];
770
+					// add non-global tax to matching global tax AND the tax total
771
+					$global_tax->set_total($new_total);
772
+					$global_tax->maybe_save();
773
+					$tax_total += $non_global_tax['total'];
774
+				}
775
+			}
776
+			if (! $found) {
777
+				// add a new line item for this non-global tax
778
+				$taxes_subtotal->add_child_line_item(
779
+					EE_Line_Item::new_instance(
780
+						[
781
+							'LIN_name'       => $non_global_tax['name'],
782
+							'LIN_percent'    => $non_global_tax['rate'],
783
+							'LIN_is_taxable' => false,
784
+							'LIN_total'      => $non_global_tax['total'],
785
+							'LIN_type'       => EEM_Line_Item::type_tax,
786
+							'OBJ_type'       => $non_global_tax['obj'],
787
+							'OBJ_ID'         => $non_global_tax['objID'],
788
+						]
789
+					)
790
+				);
791
+				$tax_total += $non_global_tax['total'];
792
+			}
793
+		}
794
+		return $this->decimal_values->roundDecimalValue($tax_total, true);
795
+	}
796
+
797
+
798
+	/**
799
+	 * Gets the total tax on this line item. Assumes taxes have already been calculated using
800
+	 * recalculate_taxes_and_total
801
+	 *
802
+	 * @param EE_Line_Item $line_item
803
+	 * @return float
804
+	 * @throws EE_Error
805
+	 * @throws ReflectionException
806
+	 */
807
+	public function getTotalTax(EE_Line_Item $line_item): float
808
+	{
809
+		$this->validateLineItemAndType($line_item, EEM_Line_Item::type_total);
810
+		$this->recalculateTaxSubTotal($line_item);
811
+		$total = 0;
812
+		foreach ($line_item->tax_descendants() as $tax_line_item) {
813
+			if ($this->validateLineItemAndType($tax_line_item)) {
814
+				$total += $tax_line_item->total();
815
+			}
816
+		}
817
+		return $this->decimal_values->roundDecimalValue($total, true);
818
+	}
819
+
820
+
821
+	/**
822
+	 * Returns the amount taxable among this line item's children (or if it has no children,
823
+	 * how much of it is taxable). Does not recalculate totals or subtotals.
824
+	 * If the taxable total is negative, (eg, if none of the tickets were taxable,
825
+	 * but there is a "Taxable" discount), returns 0.
826
+	 *
827
+	 * @param EE_Line_Item|null $line_item
828
+	 * @return float
829
+	 * @throws EE_Error
830
+	 * @throws ReflectionException
831
+	 */
832
+	public function taxableAmountForGlobalTaxes(?EE_Line_Item $line_item): float
833
+	{
834
+		$this->debugLog(__FUNCTION__, 4);
835
+		$total            = 0;
836
+		$child_line_items = $line_item->children($this->default_query_params);
837
+		foreach ($child_line_items as $child_line_item) {
838
+			$this->validateLineItemAndType($child_line_item);
839
+			if ($child_line_item->is_sub_total()) {
840
+				$total += $this->taxableAmountForGlobalTaxes($child_line_item);
841
+			} elseif ($child_line_item->is_line_item() && $child_line_item->is_taxable()) {
842
+				// if it's a percent item, only take into account
843
+				// the percentage that's taxable (the taxable total so far)
844
+				if ($child_line_item->is_percent()) {
845
+					$total += $this->calculatePercentage($total, $child_line_item->percent(), true);
846
+				} else {
847
+					// pretax total will be equal to the total for line items with globally applied taxes
848
+					$pretax_total = $this->calculateTotalForQuantity($child_line_item);
849
+					$total        += $this->updatePreTaxTotal($child_line_item, $pretax_total);
850
+				}
851
+			}
852
+		}
853
+		return max($total, 0);
854
+	}
855
+
856
+
857
+	/**
858
+	 * @param EE_Line_Item|null $line_item
859
+	 * @param string|null       $type
860
+	 * @return bool
861
+	 * @throws EE_Error
862
+	 * @throws ReflectionException
863
+	 */
864
+	private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
865
+	{
866
+		if (! $line_item instanceof EE_Line_Item) {
867
+			throw new DomainException(
868
+				esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
869
+			);
870
+		}
871
+		if ($type && $line_item->type() !== $type) {
872
+			throw new DomainException(
873
+				sprintf(
874
+					esc_html__(
875
+						'Invalid Line Item type supplied. Received "%1$s" but expected "%2$s".',
876
+						'event_espresso'
877
+					),
878
+					$line_item->type(),
879
+					$type
880
+				)
881
+			);
882
+		}
883
+		return true;
884
+	}
885
+
886
+
887
+	/**
888
+	 * loops through all sub-line-items for the supplied line item and reorders them as follows:
889
+	 * 1. sub items
890
+	 * 2. other??? (not a sub-item or sub-tax)
891
+	 * 3. sub taxes
892
+	 *
893
+	 * @param EE_Line_Item $line_item
894
+	 * @return void
895
+	 * @throws EE_Error
896
+	 * @throws ReflectionException
897
+	 * @since 5.0.12.p
898
+	 */
899
+	public function reorderSubLineItems(EE_Line_Item $line_item)
900
+	{
901
+		if ($line_item->type() !== EEM_Line_Item::type_line_item) {
902
+			return;
903
+		}
904
+		$this->debugLog(' + LineItemCalculator::reorderSubLineItems', 3);
905
+		$this->debugLog(
906
+			' + + ' . $line_item->OBJ_type() . ' ' . $line_item->name()
907
+			. ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
908
+			3
909
+		);
910
+		$sub_line_items = $line_item->children();
911
+		$items          = [];
912
+		$other          = [];
913
+		$taxes          = [];
914
+		foreach ($sub_line_items as $sub_line_item) {
915
+			switch ($sub_line_item->type()) {
916
+				case EEM_Line_Item::type_sub_line_item:
917
+					$items[ $sub_line_item->ID() ] = $sub_line_item;
918
+					break;
919
+				case EEM_Line_Item::type_sub_tax:
920
+					$taxes[ $sub_line_item->ID() ] = $sub_line_item;
921
+					break;
922
+				default:
923
+					$other[ $sub_line_item->ID() ] = $sub_line_item;
924
+			}
925
+		}
926
+		$order      = 0;
927
+		$line_items = apply_filters(
928
+			'FHEE__EventEspresso_core_services_calculators_LineItemCalculator__reorderSubLineItems__line_items',
929
+			['items' => $items, 'other' => $other, 'taxes' => $taxes]
930
+		);
931
+		foreach ($line_items as $sub_items) {
932
+			foreach ($sub_items as $sub_item) {
933
+				$order++;
934
+				$sub_item->set_order($order);
935
+				$sub_item->save();
936
+				$this->debugLog(
937
+					' + + + ' . $order . '. ' . $sub_item->OBJ_type() . ' ' . $sub_item->name()
938
+					. ' - ' . $sub_item->type() . ' (' . $sub_item->code() . ')',
939
+					3
940
+				);
941
+			}
942
+		}
943
+	}
944 944
 }
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -103,7 +103,7 @@  discard block
 block discarded – undo
103 103
         $OBJ = $line_item->OBJ_type();
104 104
         $OBJ .= $OBJ ? ': ' : '';
105 105
         $this->debugLog(
106
-            ' * ' . $OBJ . $line_item->name() . ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
106
+            ' * '.$OBJ.$line_item->name().' - '.$line_item->type().' ('.$line_item->code().')',
107 107
             2
108 108
         );
109 109
         $this->debugLog(" * total: $total", 3);
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
         // recursively loop through children and recalculate their totals
160 160
         $children = $line_item->children($this->default_query_params);
161 161
         if (empty($children)) {
162
-            $this->debugLog(' - ' . __FUNCTION__, 3);
162
+            $this->debugLog(' - '.__FUNCTION__, 3);
163 163
             $this->debugLog(" - - total : $total ", 3);
164 164
             $this->debugLog(" - - pretax: $pretax_total ", 3);
165 165
             return [$total, $pretax_total];
@@ -176,17 +176,17 @@  discard block
 block discarded – undo
176 176
         // update the unit price and pretax total
177 177
         $this->updateUnitPrice($line_item, $pretax_total, false);
178 178
         $pretax_total = $this->updatePreTaxTotal($line_item, $pretax_total, true, false);
179
-        $this->debugLog(' - ' . __FUNCTION__, 3);
180
-        $this->debugLog(" - - line_item->name() : " . $line_item->name(), 3);
181
-        $this->debugLog(" - - line_item->code() : " . $line_item->code(), 3);
179
+        $this->debugLog(' - '.__FUNCTION__, 3);
180
+        $this->debugLog(" - - line_item->name() : ".$line_item->name(), 3);
181
+        $this->debugLog(" - - line_item->code() : ".$line_item->code(), 3);
182 182
         // for the actual pre-tax sub-total line item, we want to save the pretax value for everything
183 183
         if ($line_item->is_sub_total() && $line_item->code() === 'pre-tax-subtotal') {
184 184
             $this->updateTotal($line_item, $pretax_total, true);
185
-        } elseif (! $line_item->is_total()) {
185
+        } elseif ( ! $line_item->is_total()) {
186 186
             // we don't update the total for the total line item, because that will need to include taxes
187 187
             $total = $this->updateTotal($line_item, $total, true);
188 188
         }
189
-        $this->debugLog(' - ' . __FUNCTION__, 3);
189
+        $this->debugLog(' - '.__FUNCTION__, 3);
190 190
         $this->debugLog(" - - total : $total ", 3);
191 191
         $this->debugLog(" - - pretax: $pretax_total ", 3);
192 192
         return [$total, $pretax_total];
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
 
218 218
         // need to also adjust unit price too if the pretax total or quantity has been updated
219 219
         $this->updateUnitPrice($line_item, $pretax_total);
220
-        $this->debugLog(' - ' . __FUNCTION__, 3);
220
+        $this->debugLog(' - '.__FUNCTION__, 3);
221 221
         $this->debugLog(" - - total : $total", 3);
222 222
         $this->debugLog(" - - pretax: $pretax_total", 3);
223 223
         return [$total, $pretax_total];
@@ -238,14 +238,14 @@  discard block
 block discarded – undo
238 238
         float $total = 0,
239 239
         float $pretax_total = 0
240 240
     ): array {
241
-        $this->debugLog(' % ' . __FUNCTION__, 2);
241
+        $this->debugLog(' % '.__FUNCTION__, 2);
242 242
         $pretax_total = $this->calculatePercentage($pretax_total, $line_item->percent());
243 243
         // if the line item is taxable, then we need to calculate the total,
244 244
         // otherwise we can just use the pretax total
245 245
         $total = $line_item->is_taxable()
246 246
             ? $this->calculatePercentage($total, $line_item->percent())
247 247
             : $pretax_total;
248
-        $this->debugLog(' % ' . __FUNCTION__, 3);
248
+        $this->debugLog(' % '.__FUNCTION__, 3);
249 249
         $this->debugLog(" % % total : $total ", 3);
250 250
         $this->debugLog(" % % pretax: $pretax_total ", 3);
251 251
         return [$total, $pretax_total];
@@ -262,10 +262,10 @@  discard block
 block discarded – undo
262 262
     private function recalculateNonPercentageLineItem(
263 263
         EE_Line_Item $line_item
264 264
     ): array {
265
-        $this->debugLog(' $ ' . __FUNCTION__, 2);
265
+        $this->debugLog(' $ '.__FUNCTION__, 2);
266 266
         // recursively loop through children and recalculate their totals
267 267
         $children = $line_item->children($this->default_query_params);
268
-        if (! empty($children)) {
268
+        if ( ! empty($children)) {
269 269
             // reset the total and pretax total to zero since we are recalculating them
270 270
             $total = $pretax_total = 0;
271 271
             foreach ($children as $child_line_item) {
@@ -275,10 +275,10 @@  discard block
 block discarded – undo
275 275
                     $pretax_total,
276 276
                     $line_item->is_taxable()
277 277
                 );
278
-                $this->debugLog(' $ $ ' . __FUNCTION__, 3);
278
+                $this->debugLog(' $ $ '.__FUNCTION__, 3);
279 279
                 $this->debugLog(
280
-                    ' $ $ $ ' . $child_line_item->name() . ' '
281
-                    . $child_line_item->type() . ' ' . $child_line_item->code(),
280
+                    ' $ $ $ '.$child_line_item->name().' '
281
+                    . $child_line_item->type().' '.$child_line_item->code(),
282 282
                     3
283 283
                 );
284 284
                 $this->debugLog(" $ $ $ $ child total: $child_total", 3);
@@ -291,8 +291,8 @@  discard block
 block discarded – undo
291 291
             // and set the pretax total to match since there are obviously no sub-taxes
292 292
             $pretax_total = $total = $this->calculateTotalForQuantity($line_item);
293 293
         }
294
-        $this->debugLog(' $ ' . __FUNCTION__, 3);
295
-        $this->debugLog(' $ $ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
294
+        $this->debugLog(' $ '.__FUNCTION__, 3);
295
+        $this->debugLog(' $ $ '.$line_item->name().' '.$line_item->type().' '.$line_item->code(), 3);
296 296
         $this->debugLog(" $ $ $ total: $total", 3);
297 297
         $this->debugLog(" $ $ $ pretax: $pretax_total", 3);
298 298
         return [$total, $pretax_total];
@@ -426,7 +426,7 @@  discard block
 block discarded – undo
426 426
     {
427 427
         $amount = $total * $percent / 100;
428 428
         $amount = $this->decimal_values->roundDecimalValue($amount, $round);
429
-        $this->debugLog(' % ' . __FUNCTION__, 2);
429
+        $this->debugLog(' % '.__FUNCTION__, 2);
430 430
         $this->debugLog(" % % total: $total", 3);
431 431
         $this->debugLog(" % % percent: $percent", 3);
432 432
         $this->debugLog(" % % amount: $amount", 3);
@@ -442,10 +442,10 @@  discard block
 block discarded – undo
442 442
      */
443 443
     private function calculateTotalForQuantity(EE_Line_Item $line_item): float
444 444
     {
445
-        $this->debugLog(' # ' . __FUNCTION__, 2);
446
-        $this->debugLog(' # # ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
447
-        $this->debugLog(" # # # unit_price: " . $line_item->unit_price(), 3);
448
-        $this->debugLog(" # # # quantity: " . $line_item->quantity(), 3);
445
+        $this->debugLog(' # '.__FUNCTION__, 2);
446
+        $this->debugLog(' # # '.$line_item->name().' '.$line_item->type().' '.$line_item->code(), 3);
447
+        $this->debugLog(" # # # unit_price: ".$line_item->unit_price(), 3);
448
+        $this->debugLog(" # # # quantity: ".$line_item->quantity(), 3);
449 449
         $total = $line_item->unit_price() * $line_item->quantity();
450 450
         return $this->decimal_values->roundDecimalValue($total);
451 451
     }
@@ -582,11 +582,11 @@  discard block
 block discarded – undo
582 582
         $new_unit_price = $this->decimal_values->roundDecimalValue($new_unit_price);
583 583
         // update and save new total only if incoming value does not match existing value
584 584
         if ($line_item->unit_price() !== $new_unit_price) {
585
-            $this->debugLog(' @ ' . __FUNCTION__, 3);
586
-            $this->debugLog(' @ @ ' . $line_item->name() . ' ' . $line_item->type() . ' ' . $line_item->code(), 3);
585
+            $this->debugLog(' @ '.__FUNCTION__, 3);
586
+            $this->debugLog(' @ @ '.$line_item->name().' '.$line_item->type().' '.$line_item->code(), 3);
587 587
             $this->debugLog(" @ @ @ pretax: $pretax_total", 3);
588 588
             $this->debugLog(" @ @ @ quantity: $quantity", 3);
589
-            $this->debugLog(" @ @ @ old unit price: " . $line_item->unit_price(), 3);
589
+            $this->debugLog(" @ @ @ old unit price: ".$line_item->unit_price(), 3);
590 590
             $this->debugLog(" @ @ @ new unit price: $new_unit_price", 3);
591 591
             $line_item->set_unit_price($new_unit_price);
592 592
             if ($save) {
@@ -612,7 +612,7 @@  discard block
 block discarded – undo
612 612
         $this->validateLineItemAndType($total_line_item, EEM_Line_Item::type_total);
613 613
         // calculate the total taxable amount for globally applied taxes
614 614
         $taxable_total    = $this->taxableAmountForGlobalTaxes($total_line_item);
615
-        [$total_tax, $global_taxes ]    = $this->applyGlobalTaxes($total_line_item, $taxable_total);
615
+        [$total_tax, $global_taxes] = $this->applyGlobalTaxes($total_line_item, $taxable_total);
616 616
         $non_global_taxes = $this->calculateNonGlobalTaxes($total_line_item);
617 617
         $all_tax_total    = $this->applyNonGlobalTaxes($total_line_item, $total_tax, $global_taxes, $non_global_taxes);
618 618
         $this->recalculateTaxSubTotal($total_line_item);
@@ -720,9 +720,9 @@  discard block
 block discarded – undo
720 720
                         $line_item->pretaxTotal()
721 721
                     );
722 722
                 } elseif ($line_item->isSubTax()) {
723
-                    $tax_ID = $line_item->name() . '_' . $line_item->percent();
724
-                    if (! isset($non_global_taxes[ $tax_ID ])) {
725
-                        $non_global_taxes[ $tax_ID ] = [
723
+                    $tax_ID = $line_item->name().'_'.$line_item->percent();
724
+                    if ( ! isset($non_global_taxes[$tax_ID])) {
725
+                        $non_global_taxes[$tax_ID] = [
726 726
                             'name'  => $line_item->name(),
727 727
                             'rate'  => $line_item->percent(),
728 728
                             'total' => 0,
@@ -732,7 +732,7 @@  discard block
 block discarded – undo
732 732
                     }
733 733
                     $tax = $this->calculatePercentage($line_item_total, $line_item->percent());
734 734
 
735
-                    $non_global_taxes[ $tax_ID ]['total'] += $tax;
735
+                    $non_global_taxes[$tax_ID]['total'] += $tax;
736 736
                 }
737 737
             }
738 738
         }
@@ -773,7 +773,7 @@  discard block
 block discarded – undo
773 773
                     $tax_total += $non_global_tax['total'];
774 774
                 }
775 775
             }
776
-            if (! $found) {
776
+            if ( ! $found) {
777 777
                 // add a new line item for this non-global tax
778 778
                 $taxes_subtotal->add_child_line_item(
779 779
                     EE_Line_Item::new_instance(
@@ -846,7 +846,7 @@  discard block
 block discarded – undo
846 846
                 } else {
847 847
                     // pretax total will be equal to the total for line items with globally applied taxes
848 848
                     $pretax_total = $this->calculateTotalForQuantity($child_line_item);
849
-                    $total        += $this->updatePreTaxTotal($child_line_item, $pretax_total);
849
+                    $total += $this->updatePreTaxTotal($child_line_item, $pretax_total);
850 850
                 }
851 851
             }
852 852
         }
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
      */
864 864
     private function validateLineItemAndType(?EE_Line_Item $line_item, ?string $type = null): bool
865 865
     {
866
-        if (! $line_item instanceof EE_Line_Item) {
866
+        if ( ! $line_item instanceof EE_Line_Item) {
867 867
             throw new DomainException(
868 868
                 esc_html__('Invalid or missing Line Item supplied .', 'event_espresso')
869 869
             );
@@ -903,8 +903,8 @@  discard block
 block discarded – undo
903 903
         }
904 904
         $this->debugLog(' + LineItemCalculator::reorderSubLineItems', 3);
905 905
         $this->debugLog(
906
-            ' + + ' . $line_item->OBJ_type() . ' ' . $line_item->name()
907
-            . ' - ' . $line_item->type() . ' (' . $line_item->code() . ')',
906
+            ' + + '.$line_item->OBJ_type().' '.$line_item->name()
907
+            . ' - '.$line_item->type().' ('.$line_item->code().')',
908 908
             3
909 909
         );
910 910
         $sub_line_items = $line_item->children();
@@ -914,13 +914,13 @@  discard block
 block discarded – undo
914 914
         foreach ($sub_line_items as $sub_line_item) {
915 915
             switch ($sub_line_item->type()) {
916 916
                 case EEM_Line_Item::type_sub_line_item:
917
-                    $items[ $sub_line_item->ID() ] = $sub_line_item;
917
+                    $items[$sub_line_item->ID()] = $sub_line_item;
918 918
                     break;
919 919
                 case EEM_Line_Item::type_sub_tax:
920
-                    $taxes[ $sub_line_item->ID() ] = $sub_line_item;
920
+                    $taxes[$sub_line_item->ID()] = $sub_line_item;
921 921
                     break;
922 922
                 default:
923
-                    $other[ $sub_line_item->ID() ] = $sub_line_item;
923
+                    $other[$sub_line_item->ID()] = $sub_line_item;
924 924
             }
925 925
         }
926 926
         $order      = 0;
@@ -934,8 +934,8 @@  discard block
 block discarded – undo
934 934
                 $sub_item->set_order($order);
935 935
                 $sub_item->save();
936 936
                 $this->debugLog(
937
-                    ' + + + ' . $order . '. ' . $sub_item->OBJ_type() . ' ' . $sub_item->name()
938
-                    . ' - ' . $sub_item->type() . ' (' . $sub_item->code() . ')',
937
+                    ' + + + '.$order.'. '.$sub_item->OBJ_type().' '.$sub_item->name()
938
+                    . ' - '.$sub_item->type().' ('.$sub_item->code().')',
939 939
                     3
940 940
                 );
941 941
             }
Please login to merge, or discard this patch.