Completed
Branch CAFEREL (9bc155)
by
unknown
07:16 queued 03:43
created
core/admin/EE_Admin_Page.core.php 2 patches
Indentation   +4262 added lines, -4262 removed lines patch added patch discarded remove patch
@@ -24,4350 +24,4350 @@
 block discarded – undo
24 24
  */
25 25
 abstract class EE_Admin_Page extends EE_Base implements InterminableInterface
26 26
 {
27
-    /**
28
-     * @var EE_Admin_Config
29
-     */
30
-    protected $admin_config;
27
+	/**
28
+	 * @var EE_Admin_Config
29
+	 */
30
+	protected $admin_config;
31 31
 
32
-    /**
33
-     * @var LoaderInterface
34
-     */
35
-    protected $loader;
32
+	/**
33
+	 * @var LoaderInterface
34
+	 */
35
+	protected $loader;
36 36
 
37
-    /**
38
-     * @var RequestInterface
39
-     */
40
-    protected $request;
37
+	/**
38
+	 * @var RequestInterface
39
+	 */
40
+	protected $request;
41 41
 
42
-    // set in _init_page_props()
43
-    public $page_slug;
42
+	// set in _init_page_props()
43
+	public $page_slug;
44 44
 
45
-    public $page_label;
45
+	public $page_label;
46 46
 
47
-    public $page_folder;
47
+	public $page_folder;
48 48
 
49
-    // set in define_page_props()
50
-    protected $_admin_base_url;
49
+	// set in define_page_props()
50
+	protected $_admin_base_url;
51 51
 
52
-    protected $_admin_base_path;
52
+	protected $_admin_base_path;
53 53
 
54
-    protected $_admin_page_title;
54
+	protected $_admin_page_title;
55 55
 
56
-    protected $_labels;
56
+	protected $_labels;
57 57
 
58 58
 
59
-    // set early within EE_Admin_Init
60
-    protected $_wp_page_slug;
59
+	// set early within EE_Admin_Init
60
+	protected $_wp_page_slug;
61 61
 
62
-    // nav tabs
63
-    protected $_nav_tabs;
62
+	// nav tabs
63
+	protected $_nav_tabs;
64 64
 
65
-    protected $_default_nav_tab_name;
65
+	protected $_default_nav_tab_name;
66 66
 
67 67
 
68
-    // template variables (used by templates)
69
-    protected $_template_path;
68
+	// template variables (used by templates)
69
+	protected $_template_path;
70 70
 
71
-    protected $_column_template_path;
71
+	protected $_column_template_path;
72 72
 
73
-    /**
74
-     * @var array $_template_args
75
-     */
76
-    protected $_template_args = [];
73
+	/**
74
+	 * @var array $_template_args
75
+	 */
76
+	protected $_template_args = [];
77 77
 
78
-    /**
79
-     * this will hold the list table object for a given view.
80
-     *
81
-     * @var EE_Admin_List_Table $_list_table_object
82
-     */
83
-    protected $_list_table_object;
78
+	/**
79
+	 * this will hold the list table object for a given view.
80
+	 *
81
+	 * @var EE_Admin_List_Table $_list_table_object
82
+	 */
83
+	protected $_list_table_object;
84 84
 
85
-    // boolean
86
-    protected $_is_UI_request; // this starts at null so we can have no header routes progress through two states.
85
+	// boolean
86
+	protected $_is_UI_request; // this starts at null so we can have no header routes progress through two states.
87 87
 
88
-    protected $_routing;
88
+	protected $_routing;
89 89
 
90
-    // list table args
91
-    protected $_view;
90
+	// list table args
91
+	protected $_view;
92 92
 
93
-    protected $_views;
93
+	protected $_views;
94 94
 
95 95
 
96
-    // action => method pairs used for routing incoming requests
97
-    protected $_page_routes;
96
+	// action => method pairs used for routing incoming requests
97
+	protected $_page_routes;
98 98
 
99
-    /**
100
-     * @var array $_page_config
101
-     */
102
-    protected $_page_config;
99
+	/**
100
+	 * @var array $_page_config
101
+	 */
102
+	protected $_page_config;
103 103
 
104
-    /**
105
-     * the current page route and route config
106
-     *
107
-     * @var array|string|null $_route
108
-     */
109
-    protected $_route;
104
+	/**
105
+	 * the current page route and route config
106
+	 *
107
+	 * @var array|string|null $_route
108
+	 */
109
+	protected $_route;
110 110
 
111
-    /**
112
-     * @var string $_cpt_route
113
-     */
114
-    protected $_cpt_route;
111
+	/**
112
+	 * @var string $_cpt_route
113
+	 */
114
+	protected $_cpt_route;
115 115
 
116
-    /**
117
-     * @var array $_route_config
118
-     */
119
-    protected $_route_config;
116
+	/**
117
+	 * @var array $_route_config
118
+	 */
119
+	protected $_route_config;
120 120
 
121
-    /**
122
-     * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
123
-     * actions.
124
-     *
125
-     * @since 4.6.x
126
-     * @var array.
127
-     */
128
-    protected $_default_route_query_args;
121
+	/**
122
+	 * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
123
+	 * actions.
124
+	 *
125
+	 * @since 4.6.x
126
+	 * @var array.
127
+	 */
128
+	protected $_default_route_query_args;
129 129
 
130
-    // set via request page and action args.
131
-    protected $_current_page;
130
+	// set via request page and action args.
131
+	protected $_current_page;
132 132
 
133
-    protected $_current_view;
133
+	protected $_current_view;
134 134
 
135
-    protected $_current_page_view_url;
135
+	protected $_current_page_view_url;
136 136
 
137
-    /**
138
-     * unprocessed value for the 'action' request param (default '')
139
-     *
140
-     * @var string
141
-     */
142
-    protected $raw_req_action = '';
137
+	/**
138
+	 * unprocessed value for the 'action' request param (default '')
139
+	 *
140
+	 * @var string
141
+	 */
142
+	protected $raw_req_action = '';
143 143
 
144
-    /**
145
-     * unprocessed value for the 'page' request param (default '')
146
-     *
147
-     * @var string
148
-     */
149
-    protected $raw_req_page = '';
150
-
151
-    /**
152
-     * sanitized request action (and nonce)
153
-     *
154
-     * @var string
155
-     */
156
-    protected $_req_action = '';
157
-
158
-    /**
159
-     * sanitized request action nonce
160
-     *
161
-     * @var string
162
-     */
163
-    protected $_req_nonce = '';
164
-
165
-    /**
166
-     * @var string
167
-     */
168
-    protected $_search_btn_label = '';
169
-
170
-    /**
171
-     * @var string
172
-     */
173
-    protected $_search_box_callback = '';
174
-
175
-    /**
176
-     * @var WP_Screen
177
-     */
178
-    protected $_current_screen;
179
-
180
-    // for holding EE_Admin_Hooks object when needed (set via set_hook_object())
181
-    protected $_hook_obj;
182
-
183
-    // for holding incoming request data
184
-    protected $_req_data = [];
185
-
186
-    // yes / no array for admin form fields
187
-    protected $_yes_no_values = [];
188
-
189
-    // some default things shared by all child classes
190
-    protected $_default_espresso_metaboxes = [
191
-        '_espresso_news_post_box',
192
-        '_espresso_links_post_box',
193
-        '_espresso_ratings_request',
194
-        '_espresso_sponsors_post_box',
195
-    ];
196
-
197
-    /**
198
-     * @var EE_Registry
199
-     */
200
-    protected $EE;
201
-
202
-
203
-    /**
204
-     * This is just a property that flags whether the given route is a caffeinated route or not.
205
-     *
206
-     * @var boolean
207
-     */
208
-    protected $_is_caf = false;
209
-
210
-    /**
211
-     * whether or not initializePage() has run
212
-     *
213
-     * @var boolean
214
-     */
215
-    protected $initialized = false;
216
-
217
-    /**
218
-     * @var FeatureFlags
219
-     */
220
-    protected $feature;
221
-
222
-
223
-    /**
224
-     * @var string
225
-     */
226
-    protected $class_name;
227
-
228
-    /**
229
-     * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
230
-     * then this would be the parent classname: Events_Admin_Page
231
-     *
232
-     * @var string
233
-     */
234
-    protected $base_class_name;
235
-
236
-    /**
237
-     * @var array
238
-     * @since $VID:$
239
-     */
240
-    private $publish_post_meta_box_hidden_fields = [];
241
-
242
-
243
-    /**
244
-     * @Constructor
245
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
246
-     * @throws InvalidArgumentException
247
-     * @throws InvalidDataTypeException
248
-     * @throws InvalidInterfaceException
249
-     * @throws ReflectionException
250
-     */
251
-    public function __construct($routing = true)
252
-    {
253
-        $this->loader       = LoaderFactory::getLoader();
254
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
255
-        $this->feature      = $this->loader->getShared(FeatureFlags::class);
256
-        $this->request      = $this->loader->getShared(RequestInterface::class);
257
-        // routing enabled?
258
-        $this->_routing = $routing;
259
-
260
-        $this->class_name      = get_class($this);
261
-        $this->base_class_name = strpos($this->class_name, 'Extend_') === 0
262
-            ? str_replace('Extend_', '', $this->class_name)
263
-            : '';
264
-
265
-        if (strpos($this->_get_dir(), 'caffeinated') !== false) {
266
-            $this->_is_caf = true;
267
-        }
268
-        $this->_yes_no_values = [
269
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
270
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
271
-        ];
272
-        // set the _req_data property.
273
-        $this->_req_data = $this->request->requestParams();
274
-    }
275
-
276
-
277
-    /**
278
-     * @return EE_Admin_Config
279
-     */
280
-    public function adminConfig(): EE_Admin_Config
281
-    {
282
-        return $this->admin_config;
283
-    }
284
-
285
-
286
-    /**
287
-     * @return FeatureFlags
288
-     */
289
-    public function feature(): FeatureFlags
290
-    {
291
-        return $this->feature;
292
-    }
293
-
294
-
295
-    /**
296
-     * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
297
-     * for child classes that needed to set properties prior to these methods getting called,
298
-     * but also needed the parent class to have its construction completed as well.
299
-     * Bottom line is that constructors should ONLY be used for setting initial properties
300
-     * and any complex initialization logic should only run after instantiation is complete.
301
-     *
302
-     * This method gets called immediately after construction from within
303
-     *      EE_Admin_Page_Init::_initialize_admin_page()
304
-     *
305
-     * @throws EE_Error
306
-     * @throws InvalidArgumentException
307
-     * @throws InvalidDataTypeException
308
-     * @throws InvalidInterfaceException
309
-     * @throws ReflectionException
310
-     * @since $VID:$
311
-     */
312
-    public function initializePage()
313
-    {
314
-        if ($this->initialized) {
315
-            return;
316
-        }
317
-        // set initial page props (child method)
318
-        $this->_init_page_props();
319
-        // set global defaults
320
-        $this->_set_defaults();
321
-        // set early because incoming requests could be ajax related and we need to register those hooks.
322
-        $this->_global_ajax_hooks();
323
-        $this->_ajax_hooks();
324
-        // other_page_hooks have to be early too.
325
-        $this->_do_other_page_hooks();
326
-        // set up page dependencies
327
-        $this->_before_page_setup();
328
-        $this->_page_setup();
329
-        $this->initialized = true;
330
-    }
331
-
332
-
333
-    /**
334
-     * _init_page_props
335
-     * Child classes use to set at least the following properties:
336
-     * $page_slug.
337
-     * $page_label.
338
-     *
339
-     * @abstract
340
-     * @return void
341
-     */
342
-    abstract protected function _init_page_props();
343
-
344
-
345
-    /**
346
-     * _ajax_hooks
347
-     * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
348
-     * Note: within the ajax callback methods.
349
-     *
350
-     * @abstract
351
-     * @return void
352
-     */
353
-    abstract protected function _ajax_hooks();
354
-
355
-
356
-    /**
357
-     * _define_page_props
358
-     * child classes define page properties in here.  Must include at least:
359
-     * $_admin_base_url = base_url for all admin pages
360
-     * $_admin_page_title = default admin_page_title for admin pages
361
-     * $_labels = array of default labels for various automatically generated elements:
362
-     *    array(
363
-     *        'buttons' => array(
364
-     *            'add' => esc_html__('label for add new button'),
365
-     *            'edit' => esc_html__('label for edit button'),
366
-     *            'delete' => esc_html__('label for delete button')
367
-     *            )
368
-     *        )
369
-     *
370
-     * @abstract
371
-     * @return void
372
-     */
373
-    abstract protected function _define_page_props();
374
-
375
-
376
-    /**
377
-     * _set_page_routes
378
-     * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
379
-     * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
380
-     * have a 'default' route. Here's the format
381
-     * $this->_page_routes = array(
382
-     *        'default' => array(
383
-     *            'func' => '_default_method_handling_route',
384
-     *            'args' => array('array','of','args'),
385
-     *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
386
-     *            ajax request, backend processing)
387
-     *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
388
-     *            headers route after.  The string you enter here should match the defined route reference for a
389
-     *            headers sent route.
390
-     *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
391
-     *            this route.
392
-     *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
393
-     *            checks).
394
-     *        ),
395
-     *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
396
-     *        handling method.
397
-     *        )
398
-     * )
399
-     *
400
-     * @abstract
401
-     * @return void
402
-     */
403
-    abstract protected function _set_page_routes();
404
-
405
-
406
-    /**
407
-     * _set_page_config
408
-     * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
409
-     * array corresponds to the page_route for the loaded page. Format:
410
-     * $this->_page_config = array(
411
-     *        'default' => array(
412
-     *            'labels' => array(
413
-     *                'buttons' => array(
414
-     *                    'add' => esc_html__('label for adding item'),
415
-     *                    'edit' => esc_html__('label for editing item'),
416
-     *                    'delete' => esc_html__('label for deleting item')
417
-     *                ),
418
-     *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
419
-     *            ), //optional an array of custom labels for various automatically generated elements to use on the
420
-     *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
421
-     *            _define_page_props() method
422
-     *            'nav' => array(
423
-     *                'label' => esc_html__('Label for Tab', 'event_espresso').
424
-     *                'url' => 'http://someurl', //automatically generated UNLESS you define
425
-     *                'css_class' => 'css-class', //automatically generated UNLESS you define
426
-     *                'order' => 10, //required to indicate tab position.
427
-     *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
428
-     *                displayed then add this parameter.
429
-     *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
430
-     *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
431
-     *            metaboxes set for eventespresso admin pages.
432
-     *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
433
-     *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
434
-     *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
435
-     *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
436
-     *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
437
-     *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
438
-     *            array indicates the max number of columns (4) and the default number of columns on page load (2).
439
-     *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
440
-     *            want to display.
441
-     *            'help_tabs' => array( //this is used for adding help tabs to a page
442
-     *                'tab_id' => array(
443
-     *                    'title' => 'tab_title',
444
-     *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
445
-     *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
446
-     *                    should match a file in the admin folder's "help_tabs" dir (ie..
447
-     *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
448
-     *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
449
-     *                    attempt to use the callback which should match the name of a method in the class
450
-     *                    ),
451
-     *                'tab2_id' => array(
452
-     *                    'title' => 'tab2 title',
453
-     *                    'filename' => 'file_name_2'
454
-     *                    'callback' => 'callback_method_for_content',
455
-     *                 ),
456
-     *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
457
-     *            help tab area on an admin page. @return void
458
-     *
459
-     * @abstract
460
-     */
461
-    abstract protected function _set_page_config();
462
-
463
-
464
-    /**
465
-     * _add_screen_options
466
-     * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
467
-     * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
468
-     * to a particular view.
469
-     *
470
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
471
-     *         see also WP_Screen object documents...
472
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
473
-     * @abstract
474
-     * @return void
475
-     */
476
-    abstract protected function _add_screen_options();
477
-
478
-
479
-    /**
480
-     * _add_feature_pointers
481
-     * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
482
-     * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
483
-     * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
484
-     * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
485
-     * extended) also see:
486
-     *
487
-     * @link   http://eamann.com/tech/wordpress-portland/
488
-     * @abstract
489
-     * @return void
490
-     */
491
-    abstract protected function _add_feature_pointers();
492
-
493
-
494
-    /**
495
-     * load_scripts_styles
496
-     * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
497
-     * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
498
-     * scripts/styles per view by putting them in a dynamic function in this format
499
-     * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
500
-     *
501
-     * @abstract
502
-     * @return void
503
-     */
504
-    abstract public function load_scripts_styles();
505
-
506
-
507
-    /**
508
-     * admin_init
509
-     * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
510
-     * all pages/views loaded by child class.
511
-     *
512
-     * @abstract
513
-     * @return void
514
-     */
515
-    abstract public function admin_init();
516
-
517
-
518
-    /**
519
-     * admin_notices
520
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
521
-     * all pages/views loaded by child class.
522
-     *
523
-     * @abstract
524
-     * @return void
525
-     */
526
-    abstract public function admin_notices();
527
-
528
-
529
-    /**
530
-     * admin_footer_scripts
531
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
532
-     * will apply to all pages/views loaded by child class.
533
-     *
534
-     * @return void
535
-     */
536
-    abstract public function admin_footer_scripts();
537
-
538
-
539
-    /**
540
-     * admin_footer
541
-     * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
542
-     * apply to all pages/views loaded by child class.
543
-     *
544
-     * @return void
545
-     */
546
-    public function admin_footer()
547
-    {
548
-    }
549
-
550
-
551
-    /**
552
-     * _global_ajax_hooks
553
-     * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
554
-     * Note: within the ajax callback methods.
555
-     *
556
-     * @abstract
557
-     * @return void
558
-     */
559
-    protected function _global_ajax_hooks()
560
-    {
561
-        // for lazy loading of metabox content
562
-        add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content'], 10);
563
-
564
-        add_action(
565
-            'wp_ajax_espresso_hide_status_change_notice',
566
-            [$this, 'hideStatusChangeNotice']
567
-        );
568
-        add_action(
569
-            'wp_ajax_nopriv_espresso_hide_status_change_notice',
570
-            [$this, 'hideStatusChangeNotice']
571
-        );
572
-    }
573
-
574
-
575
-    public function ajax_metabox_content()
576
-    {
577
-        $content_id  = $this->request->getRequestParam('contentid', '');
578
-        $content_url = $this->request->getRequestParam('contenturl', '', 'url');
579
-        EE_Admin_Page::cached_rss_display($content_id, $content_url);
580
-        wp_die();
581
-    }
582
-
583
-
584
-    public function hideStatusChangeNotice()
585
-    {
586
-        $response = [];
587
-        try {
588
-            /** @var StatusChangeNotice $status_change_notice */
589
-            $status_change_notice = $this->loader->getShared(
590
-                'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
591
-            );
592
-            $response['success']  = $status_change_notice->dismiss() > -1;
593
-        } catch (Exception $exception) {
594
-            $response['errors'] = $exception->getMessage();
595
-        }
596
-        echo wp_json_encode($response);
597
-        exit();
598
-    }
599
-
600
-
601
-    /**
602
-     * allows extending classes do something specific before the parent constructor runs _page_setup().
603
-     *
604
-     * @return void
605
-     */
606
-    protected function _before_page_setup()
607
-    {
608
-        // default is to do nothing
609
-    }
610
-
611
-
612
-    /**
613
-     * Makes sure any things that need to be loaded early get handled.
614
-     * We also escape early here if the page requested doesn't match the object.
615
-     *
616
-     * @final
617
-     * @return void
618
-     * @throws EE_Error
619
-     * @throws InvalidArgumentException
620
-     * @throws ReflectionException
621
-     * @throws InvalidDataTypeException
622
-     * @throws InvalidInterfaceException
623
-     */
624
-    final protected function _page_setup()
625
-    {
626
-        // requires?
627
-        // admin_init stuff - global - we're setting this REALLY early
628
-        // so if EE_Admin pages have to hook into other WP pages they can.
629
-        // But keep in mind, not everything is available from the EE_Admin Page object at this point.
630
-        add_action('admin_init', [$this, 'admin_init_global'], 5);
631
-        // next verify if we need to load anything...
632
-        $this->_current_page = $this->request->getRequestParam('page', '', 'key');
633
-        $this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, 'key');
634
-        $this->page_folder   = strtolower(
635
-            str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
636
-        );
637
-        global $ee_menu_slugs;
638
-        $ee_menu_slugs = (array) $ee_menu_slugs;
639
-        if (
640
-            ! $this->request->isAjax()
641
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
642
-        ) {
643
-            return;
644
-        }
645
-        // because WP List tables have two duplicate select inputs for choosing bulk actions,
646
-        // we need to copy the action from the second to the first
647
-        $action     = $this->request->getRequestParam('action', '-1', 'key');
648
-        $action2    = $this->request->getRequestParam('action2', '-1', 'key');
649
-        $action     = $action !== '-1' ? $action : $action2;
650
-        $req_action = $action !== '-1' ? $action : 'default';
651
-
652
-        // if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
653
-        // then let's use the route as the action.
654
-        // This covers cases where we're coming in from a list table that isn't on the default route.
655
-        $route             = $this->request->getRequestParam('route');
656
-        $this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
657
-            ? $route
658
-            : $req_action;
659
-
660
-        $this->_current_view = $this->_req_action;
661
-        $this->_req_nonce    = $this->_req_action . '_nonce';
662
-        $this->_define_page_props();
663
-        $this->_current_page_view_url = add_query_arg(
664
-            ['page' => $this->_current_page, 'action' => $this->_current_view],
665
-            $this->_admin_base_url
666
-        );
667
-        // set page configs
668
-        $this->_set_page_routes();
669
-        $this->_set_page_config();
670
-        // let's include any referrer data in our default_query_args for this route for "stickiness".
671
-        if ($this->request->requestParamIsSet('wp_referer')) {
672
-            $wp_referer = $this->request->getRequestParam('wp_referer');
673
-            if ($wp_referer) {
674
-                $this->_default_route_query_args['wp_referer'] = $wp_referer;
675
-            }
676
-        }
677
-        // for CPT and other extended functionality.
678
-        // If there is an _extend_page_config_for_cpt
679
-        // then let's run that to modify all the various page configuration arrays.
680
-        if (method_exists($this, '_extend_page_config_for_cpt')) {
681
-            $this->_extend_page_config_for_cpt();
682
-        }
683
-        // filter routes and page_config so addons can add their stuff. Filtering done per class
684
-        $this->_page_routes = apply_filters(
685
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
686
-            $this->_page_routes,
687
-            $this
688
-        );
689
-        $this->_page_config = apply_filters(
690
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
691
-            $this->_page_config,
692
-            $this
693
-        );
694
-        if ($this->base_class_name !== '') {
695
-            $this->_page_routes = apply_filters(
696
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
697
-                $this->_page_routes,
698
-                $this
699
-            );
700
-            $this->_page_config = apply_filters(
701
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
702
-                $this->_page_config,
703
-                $this
704
-            );
705
-        }
706
-        // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
707
-        // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
708
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
709
-            add_action(
710
-                'AHEE__EE_Admin_Page__route_admin_request',
711
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
712
-                10,
713
-                2
714
-            );
715
-        }
716
-        // next route only if routing enabled
717
-        if ($this->_routing && ! $this->request->isAjax()) {
718
-            $this->_verify_routes();
719
-            // next let's just check user_access and kill if no access
720
-            $this->check_user_access();
721
-            if ($this->_is_UI_request) {
722
-                // admin_init stuff - global, all views for this page class, specific view
723
-                add_action('admin_init', [$this, 'admin_init'], 10);
724
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
725
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
726
-                }
727
-            } else {
728
-                // hijack regular WP loading and route admin request immediately
729
-                @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
730
-                $this->route_admin_request();
731
-            }
732
-        }
733
-    }
734
-
735
-
736
-    /**
737
-     * Provides a way for related child admin pages to load stuff on the loaded admin page.
738
-     *
739
-     * @return void
740
-     * @throws EE_Error
741
-     */
742
-    private function _do_other_page_hooks()
743
-    {
744
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
745
-        foreach ($registered_pages as $page) {
746
-            // now let's setup the file name and class that should be present
747
-            $classname = str_replace('.class.php', '', $page);
748
-            // autoloaders should take care of loading file
749
-            if (! class_exists($classname)) {
750
-                $error_msg[] = sprintf(
751
-                    esc_html__(
752
-                        'Something went wrong with loading the %s admin hooks page.',
753
-                        'event_espresso'
754
-                    ),
755
-                    $page
756
-                );
757
-                $error_msg[] = $error_msg[0]
758
-                               . "\r\n"
759
-                               . sprintf(
760
-                                   esc_html__(
761
-                                       'There is no class in place for the %1$s admin hooks page.%2$sMake sure you have %3$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
762
-                                       'event_espresso'
763
-                                   ),
764
-                                   $page,
765
-                                   '<br />',
766
-                                   '<strong>' . $classname . '</strong>'
767
-                               );
768
-                throw new EE_Error(implode('||', $error_msg));
769
-            }
770
-            // notice we are passing the instance of this class to the hook object.
771
-            $this->loader->getShared($classname, [$this]);
772
-        }
773
-    }
774
-
775
-
776
-    /**
777
-     * @throws ReflectionException
778
-     * @throws EE_Error
779
-     */
780
-    public function load_page_dependencies()
781
-    {
782
-        try {
783
-            $this->_load_page_dependencies();
784
-        } catch (EE_Error $e) {
785
-            $e->get_error();
786
-        }
787
-    }
788
-
789
-
790
-    /**
791
-     * load_page_dependencies
792
-     * loads things specific to this page class when its loaded.  Really helps with efficiency.
793
-     *
794
-     * @return void
795
-     * @throws DomainException
796
-     * @throws EE_Error
797
-     * @throws InvalidArgumentException
798
-     * @throws InvalidDataTypeException
799
-     * @throws InvalidInterfaceException
800
-     * @throws ReflectionException
801
-     */
802
-    protected function _load_page_dependencies()
803
-    {
804
-        // let's set the current_screen and screen options to override what WP set
805
-        $this->_current_screen = get_current_screen();
806
-        // load admin_notices - global, page class, and view specific
807
-        add_action('admin_notices', [$this, 'admin_notices_global'], 5);
808
-        add_action('admin_notices', [$this, 'admin_notices'], 10);
809
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
810
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
811
-        }
812
-        // load network admin_notices - global, page class, and view specific
813
-        add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
814
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
815
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
816
-        }
817
-        // this will save any per_page screen options if they are present
818
-        $this->_set_per_page_screen_options();
819
-        // setup list table properties
820
-        $this->_set_list_table();
821
-        // child classes can "register" a metabox to be automatically handled via the _page_config array property.
822
-        // However in some cases the metaboxes will need to be added within a route handling callback.
823
-        add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
824
-        // hack because promos admin was loading the edited promotion object in the metaboxes callback
825
-        // which should NOT be generated on non-UI requests like POST updates/inserts
826
-        if (
827
-            $this->class_name === 'Promotions_Admin_Page'
828
-            && ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
829
-        ) {
830
-            $this->addRegisteredMetaBoxes();
831
-        }
832
-        $this->_add_screen_columns();
833
-        // add screen options - global, page child class, and view specific
834
-        $this->_add_global_screen_options();
835
-        $this->_add_screen_options();
836
-        $add_screen_options = "_add_screen_options_{$this->_current_view}";
837
-        if (method_exists($this, $add_screen_options)) {
838
-            $this->{$add_screen_options}();
839
-        }
840
-        // add help tab(s) - set via page_config and qtips.
841
-        $this->_add_help_tabs();
842
-        $this->_add_qtips();
843
-        // add feature_pointers - global, page child class, and view specific
844
-        $this->_add_feature_pointers();
845
-        $this->_add_global_feature_pointers();
846
-        $add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
847
-        if (method_exists($this, $add_feature_pointer)) {
848
-            $this->{$add_feature_pointer}();
849
-        }
850
-        // enqueue scripts/styles - global, page class, and view specific
851
-        add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
852
-        add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles'], 10);
853
-        if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
854
-            add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_{$this->_current_view}"], 15);
855
-        }
856
-        add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 100);
857
-        // admin_print_footer_scripts - global, page child class, and view specific.
858
-        // NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
859
-        // In most cases that's doing_it_wrong().  But adding hidden container elements etc.
860
-        // is a good use case. Notice the late priority we're giving these
861
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
862
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
863
-        if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
864
-            add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_{$this->_current_view}"], 101);
865
-        }
866
-        // admin footer scripts
867
-        add_action('admin_footer', [$this, 'admin_footer_global'], 99);
868
-        add_action('admin_footer', [$this, 'admin_footer'], 100);
869
-        if (method_exists($this, "admin_footer_{$this->_current_view}")) {
870
-            add_action('admin_footer', [$this, "admin_footer_{$this->_current_view}"], 101);
871
-        }
872
-        do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
873
-        // targeted hook
874
-        do_action(
875
-            "FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
876
-        );
877
-    }
878
-
879
-
880
-    /**
881
-     * _set_defaults
882
-     * This sets some global defaults for class properties.
883
-     */
884
-    private function _set_defaults()
885
-    {
886
-        $this->_current_screen       = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
887
-        $this->_event                = $this->_template_path = $this->_column_template_path = null;
888
-        $this->_nav_tabs             = $this->_views = $this->_page_routes = [];
889
-        $this->_page_config          = $this->_default_route_query_args = [];
890
-        $this->_default_nav_tab_name = 'overview';
891
-        // init template args
892
-        $this->set_template_args(
893
-            [
894
-                'admin_page_header'  => '',
895
-                'admin_page_content' => '',
896
-                'post_body_content'  => '',
897
-                'before_list_table'  => '',
898
-                'after_list_table'   => '',
899
-            ]
900
-        );
901
-    }
902
-
903
-
904
-    /**
905
-     * route_admin_request
906
-     *
907
-     * @return void
908
-     * @throws InvalidArgumentException
909
-     * @throws InvalidInterfaceException
910
-     * @throws InvalidDataTypeException
911
-     * @throws EE_Error
912
-     * @throws ReflectionException
913
-     * @see    _route_admin_request()
914
-     */
915
-    public function route_admin_request()
916
-    {
917
-        try {
918
-            $this->_route_admin_request();
919
-        } catch (EE_Error $e) {
920
-            $e->get_error();
921
-        }
922
-    }
923
-
924
-
925
-    public function set_wp_page_slug($wp_page_slug)
926
-    {
927
-        $this->_wp_page_slug = $wp_page_slug;
928
-        // if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
929
-        if (is_network_admin()) {
930
-            $this->_wp_page_slug .= '-network';
931
-        }
932
-    }
933
-
934
-
935
-    /**
936
-     * _verify_routes
937
-     * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
938
-     * we know if we need to drop out.
939
-     *
940
-     * @return bool
941
-     * @throws EE_Error
942
-     */
943
-    protected function _verify_routes()
944
-    {
945
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
946
-        if (! $this->_current_page && ! $this->request->isAjax()) {
947
-            return false;
948
-        }
949
-        $this->_route = false;
950
-        // check that the page_routes array is not empty
951
-        if (empty($this->_page_routes)) {
952
-            // user error msg
953
-            $error_msg = sprintf(
954
-                esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
955
-                $this->_admin_page_title
956
-            );
957
-            // developer error msg
958
-            $error_msg .= '||' . $error_msg
959
-                          . esc_html__(
960
-                              ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
961
-                              'event_espresso'
962
-                          );
963
-            throw new EE_Error($error_msg);
964
-        }
965
-        // and that the requested page route exists
966
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
967
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
968
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
969
-        } else {
970
-            // user error msg
971
-            $error_msg = sprintf(
972
-                esc_html__(
973
-                    'The requested page route does not exist for the %s admin page.',
974
-                    'event_espresso'
975
-                ),
976
-                $this->_admin_page_title
977
-            );
978
-            // developer error msg
979
-            $error_msg .= '||' . $error_msg
980
-                          . sprintf(
981
-                              esc_html__(
982
-                                  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
983
-                                  'event_espresso'
984
-                              ),
985
-                              $this->_req_action
986
-                          );
987
-            throw new EE_Error($error_msg);
988
-        }
989
-        // and that a default route exists
990
-        if (! array_key_exists('default', $this->_page_routes)) {
991
-            // user error msg
992
-            $error_msg = sprintf(
993
-                esc_html__(
994
-                    'A default page route has not been set for the % admin page.',
995
-                    'event_espresso'
996
-                ),
997
-                $this->_admin_page_title
998
-            );
999
-            // developer error msg
1000
-            $error_msg .= '||' . $error_msg
1001
-                          . esc_html__(
1002
-                              ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
1003
-                              'event_espresso'
1004
-                          );
1005
-            throw new EE_Error($error_msg);
1006
-        }
1007
-
1008
-        // first lets' catch if the UI request has EVER been set.
1009
-        if ($this->_is_UI_request === null) {
1010
-            // lets set if this is a UI request or not.
1011
-            $this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, 'bool');
1012
-            // wait a minute... we might have a noheader in the route array
1013
-            $this->_is_UI_request = ! (
1014
-                is_array($this->_route) && isset($this->_route['noheader']) && $this->_route['noheader']
1015
-            )
1016
-                ? $this->_is_UI_request
1017
-                : false;
1018
-        }
1019
-        $this->_set_current_labels();
1020
-        return true;
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     * this method simply verifies a given route and makes sure its an actual route available for the loaded page
1026
-     *
1027
-     * @param string $route the route name we're verifying
1028
-     * @return bool we'll throw an exception if this isn't a valid route.
1029
-     * @throws EE_Error
1030
-     */
1031
-    protected function _verify_route($route)
1032
-    {
1033
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
1034
-            return true;
1035
-        }
1036
-        // user error msg
1037
-        $error_msg = sprintf(
1038
-            esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1039
-            $this->_admin_page_title
1040
-        );
1041
-        // developer error msg
1042
-        $error_msg .= '||' . $error_msg
1043
-                      . sprintf(
1044
-                          esc_html__(
1045
-                              ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1046
-                              'event_espresso'
1047
-                          ),
1048
-                          $route
1049
-                      );
1050
-        throw new EE_Error($error_msg);
1051
-    }
1052
-
1053
-
1054
-    /**
1055
-     * perform nonce verification
1056
-     * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1057
-     * using this method (and save retyping!)
1058
-     *
1059
-     * @param string $nonce     The nonce sent
1060
-     * @param string $nonce_ref The nonce reference string (name0)
1061
-     * @return void
1062
-     * @throws EE_Error
1063
-     * @throws InvalidArgumentException
1064
-     * @throws InvalidDataTypeException
1065
-     * @throws InvalidInterfaceException
1066
-     */
1067
-    protected function _verify_nonce($nonce, $nonce_ref)
1068
-    {
1069
-        // verify nonce against expected value
1070
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1071
-            // these are not the droids you are looking for !!!
1072
-            $msg = sprintf(
1073
-                esc_html__('%sNonce Fail.%s', 'event_espresso'),
1074
-                '<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1075
-                '</a>'
1076
-            );
1077
-            if (WP_DEBUG) {
1078
-                $msg .= "\n  ";
1079
-                $msg .= sprintf(
1080
-                    esc_html__(
1081
-                        'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1082
-                        'event_espresso'
1083
-                    ),
1084
-                    __CLASS__
1085
-                );
1086
-            }
1087
-            if (! $this->request->isAjax()) {
1088
-                wp_die($msg);
1089
-            }
1090
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1091
-            $this->_return_json();
1092
-        }
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     * _route_admin_request()
1098
-     * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1099
-     * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1100
-     * in the page routes and then will try to load the corresponding method.
1101
-     *
1102
-     * @return void
1103
-     * @throws EE_Error
1104
-     * @throws InvalidArgumentException
1105
-     * @throws InvalidDataTypeException
1106
-     * @throws InvalidInterfaceException
1107
-     * @throws ReflectionException
1108
-     */
1109
-    protected function _route_admin_request()
1110
-    {
1111
-        if (! $this->_is_UI_request) {
1112
-            $this->_verify_routes();
1113
-        }
1114
-        $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1115
-        if ($this->_req_action !== 'default' && $nonce_check) {
1116
-            // set nonce from post data
1117
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
1118
-            $this->_verify_nonce($nonce, $this->_req_nonce);
1119
-        }
1120
-        // set the nav_tabs array but ONLY if this is  UI_request
1121
-        if ($this->_is_UI_request) {
1122
-            $this->_set_nav_tabs();
1123
-        }
1124
-        // grab callback function
1125
-        $func = is_array($this->_route) && isset($this->_route['func'])
1126
-            ? $this->_route['func']
1127
-            : $this->_route;
1128
-        // check if callback has args
1129
-        $args = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : [];
1130
-        // action right before calling route
1131
-        // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1132
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1133
-            do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1134
-        }
1135
-        // strip _wp_http_referer from the server REQUEST_URI
1136
-        // else it grows in length on every submission due to recursion,
1137
-        // ultimately causing a "Request-URI Too Large" error
1138
-        $this->request->unSetRequestParam('_wp_http_referer');
1139
-        $this->request->unSetServerParam('_wp_http_referer');
1140
-        $cleaner_request_uri = remove_query_arg(
1141
-            '_wp_http_referer',
1142
-            wp_unslash($this->request->getServerParam('REQUEST_URI'))
1143
-        );
1144
-        $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1145
-        $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1146
-        $route_callback = [];
1147
-        if (! empty($func)) {
1148
-            if (is_array($func)) {
1149
-                $route_callback = $func;
1150
-            } elseif (is_string($func)) {
1151
-                if (strpos($func, '::') !== false) {
1152
-                    $route_callback = explode('::', $func);
1153
-                } elseif (method_exists($this, $func)) {
1154
-                    $route_callback = [$this, $func];
1155
-                } else {
1156
-                    $route_callback = $func;
1157
-                }
1158
-            }
1159
-            [$class, $method] = $route_callback;
1160
-            // is it neither a class method NOR a standalone function?
1161
-            if (! is_callable($route_callback)) {
1162
-                // user error msg
1163
-                $error_msg = esc_html__(
1164
-                    'An error occurred. The  requested page route could not be found.',
1165
-                    'event_espresso'
1166
-                );
1167
-                // developer error msg
1168
-                $error_msg .= '||';
1169
-                $error_msg .= sprintf(
1170
-                    esc_html__(
1171
-                        'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1172
-                        'event_espresso'
1173
-                    ),
1174
-                    $method
1175
-                );
1176
-                throw new DomainException($error_msg);
1177
-            }
1178
-            if ($class !== $this && ! in_array($this, $args)) {
1179
-                // send along this admin page object for access by addons.
1180
-                $args['admin_page'] = $this;
1181
-            }
1182
-
1183
-            try {
1184
-                call_user_func_array($route_callback, $args);
1185
-            } catch (Throwable $throwable) {
1186
-                $arg_keys = array_keys($args);
1187
-                $nice_args = [];
1188
-                foreach ($args as $key => $arg) {
1189
-                    $nice_args[ $key ] = is_object($arg) ? get_class($arg) : $arg_keys[ $key ];
1190
-                }
1191
-                new ExceptionStackTraceDisplay(
1192
-                        new RuntimeException(
1193
-                            sprintf(
1194
-                                esc_html__(
1195
-                                    'Page route "%1$s" with the supplied arguments (%2$s) threw the following exception: %3$s',
1196
-                                    'event_espresso'
1197
-                                ),
1198
-                                $method,
1199
-                                implode(', ', $nice_args),
1200
-                                $throwable->getMessage()
1201
-                            ),
1202
-                            $throwable->getCode(),
1203
-                            $throwable
1204
-                        )
1205
-                );
1206
-            }
1207
-        }
1208
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1209
-        // then we need to reset the routing properties to the new route.
1210
-        // now if UI request is FALSE and noheader is true AND we have a headers_sent_route in the route array then let's set UI_request to true because the no header route has a second func after headers have been sent.
1211
-        if (
1212
-            $this->_is_UI_request === false
1213
-            && is_array($this->_route)
1214
-            && ! empty($this->_route['headers_sent_route'])
1215
-        ) {
1216
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1217
-        }
1218
-    }
1219
-
1220
-
1221
-    /**
1222
-     * This method just allows the resetting of page properties in the case where a no headers
1223
-     * route redirects to a headers route in its route config.
1224
-     *
1225
-     * @param string $new_route New (non header) route to redirect to.
1226
-     * @return   void
1227
-     * @throws ReflectionException
1228
-     * @throws InvalidArgumentException
1229
-     * @throws InvalidInterfaceException
1230
-     * @throws InvalidDataTypeException
1231
-     * @throws EE_Error
1232
-     * @since   4.3.0
1233
-     */
1234
-    protected function _reset_routing_properties($new_route)
1235
-    {
1236
-        $this->_is_UI_request = true;
1237
-        // now we set the current route to whatever the headers_sent_route is set at
1238
-        $this->request->setRequestParam('action', $new_route);
1239
-        // rerun page setup
1240
-        $this->_page_setup();
1241
-    }
1242
-
1243
-
1244
-    /**
1245
-     * _add_query_arg
1246
-     * adds nonce to array of arguments then calls WP add_query_arg function
1247
-     *(internally just uses EEH_URL's function with the same name)
1248
-     *
1249
-     * @param array  $args
1250
-     * @param string $url
1251
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1252
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1253
-     *                                        Example usage: If the current page is:
1254
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1255
-     *                                        &action=default&event_id=20&month_range=March%202015
1256
-     *                                        &_wpnonce=5467821
1257
-     *                                        and you call:
1258
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1259
-     *                                        array(
1260
-     *                                        'action' => 'resend_something',
1261
-     *                                        'page=>espresso_registrations'
1262
-     *                                        ),
1263
-     *                                        $some_url,
1264
-     *                                        true
1265
-     *                                        );
1266
-     *                                        It will produce a url in this structure:
1267
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1268
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1269
-     *                                        month_range]=March%202015
1270
-     * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1271
-     * @param int    $context
1272
-     * @return string
1273
-     */
1274
-    public static function add_query_args_and_nonce(
1275
-        $args = [],
1276
-        $url = '',
1277
-        $sticky = false,
1278
-        $exclude_nonce = false,
1279
-        int $context = EEH_URL::CONTEXT_NONE
1280
-    ) {
1281
-        // if there is a _wp_http_referer include the values from the request but only if sticky = true
1282
-        if ($sticky) {
1283
-            /** @var RequestInterface $request */
1284
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1285
-            $request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1286
-            $request->unSetServerParam('_wp_http_referer', true);
1287
-            foreach ($request->requestParams() as $key => $value) {
1288
-                // do not add nonces
1289
-                if (strpos($key, 'nonce') !== false) {
1290
-                    continue;
1291
-                }
1292
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1293
-            }
1294
-        }
1295
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1296
-    }
1297
-
1298
-
1299
-    /**
1300
-     * This returns a generated link that will load the related help tab.
1301
-     *
1302
-     * @param string $help_tab_id the id for the connected help tab
1303
-     * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1304
-     * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1305
-     * @return string              generated link
1306
-     * @uses EEH_Template::get_help_tab_link()
1307
-     */
1308
-    protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1309
-    {
1310
-        return EEH_Template::get_help_tab_link(
1311
-            $help_tab_id,
1312
-            $this->page_slug,
1313
-            $this->_req_action,
1314
-            $icon_style,
1315
-            $help_text
1316
-        );
1317
-    }
1318
-
1319
-
1320
-    /**
1321
-     * _add_help_tabs
1322
-     * Note child classes define their help tabs within the page_config array.
1323
-     *
1324
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1325
-     * @return void
1326
-     * @throws DomainException
1327
-     * @throws EE_Error
1328
-     * @throws ReflectionException
1329
-     */
1330
-    protected function _add_help_tabs()
1331
-    {
1332
-        if (isset($this->_page_config[ $this->_req_action ])) {
1333
-            $config = $this->_page_config[ $this->_req_action ];
1334
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1335
-            if (is_array($config) && isset($config['help_sidebar'])) {
1336
-                // check that the callback given is valid
1337
-                if (! method_exists($this, $config['help_sidebar'])) {
1338
-                    throw new EE_Error(
1339
-                        sprintf(
1340
-                            esc_html__(
1341
-                                'The _page_config array has a callback set for the "help_sidebar" option.  However the callback given (%s) is not a valid callback.  Doublecheck the spelling and make sure this method exists for the class %s',
1342
-                                'event_espresso'
1343
-                            ),
1344
-                            $config['help_sidebar'],
1345
-                            $this->class_name
1346
-                        )
1347
-                    );
1348
-                }
1349
-                $content = apply_filters(
1350
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1351
-                    $this->{$config['help_sidebar']}()
1352
-                );
1353
-                $this->_current_screen->set_help_sidebar($content);
1354
-            }
1355
-            if (! isset($config['help_tabs'])) {
1356
-                return;
1357
-            } //no help tabs for this route
1358
-            foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1359
-                // we're here so there ARE help tabs!
1360
-                // make sure we've got what we need
1361
-                if (! isset($cfg['title'])) {
1362
-                    throw new EE_Error(
1363
-                        esc_html__(
1364
-                            'The _page_config array is not set up properly for help tabs.  It is missing a title',
1365
-                            'event_espresso'
1366
-                        )
1367
-                    );
1368
-                }
1369
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1370
-                    throw new EE_Error(
1371
-                        esc_html__(
1372
-                            'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
1373
-                            'event_espresso'
1374
-                        )
1375
-                    );
1376
-                }
1377
-                // first priority goes to content.
1378
-                if (! empty($cfg['content'])) {
1379
-                    $content = ! empty($cfg['content']) ? $cfg['content'] : null;
1380
-                    // second priority goes to filename
1381
-                } elseif (! empty($cfg['filename'])) {
1382
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1383
-                    // it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1384
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1385
-                                                             . basename($this->_get_dir())
1386
-                                                             . '/help_tabs/'
1387
-                                                             . $cfg['filename']
1388
-                                                             . '.help_tab.php' : $file_path;
1389
-                    // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1390
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1391
-                        EE_Error::add_error(
1392
-                            sprintf(
1393
-                                esc_html__(
1394
-                                    'The filename given for the help tab %s is not a valid file and there is no other configuration for the tab content.  Please check that the string you set for the help tab on this route (%s) is the correct spelling.  The file should be in %s',
1395
-                                    'event_espresso'
1396
-                                ),
1397
-                                $tab_id,
1398
-                                key($config),
1399
-                                $file_path
1400
-                            ),
1401
-                            __FILE__,
1402
-                            __FUNCTION__,
1403
-                            __LINE__
1404
-                        );
1405
-                        return;
1406
-                    }
1407
-                    $template_args['admin_page_obj'] = $this;
1408
-                    $content                         = EEH_Template::display_template(
1409
-                        $file_path,
1410
-                        $template_args,
1411
-                        true
1412
-                    );
1413
-                } else {
1414
-                    $content = '';
1415
-                }
1416
-                // check if callback is valid
1417
-                if (
1418
-                    empty($content)
1419
-                    && (
1420
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1421
-                    )
1422
-                ) {
1423
-                    EE_Error::add_error(
1424
-                        sprintf(
1425
-                            esc_html__(
1426
-                                'The callback given for a %s help tab on this page does not content OR a corresponding method for generating the content.  Check the spelling or make sure the method is present.',
1427
-                                'event_espresso'
1428
-                            ),
1429
-                            $cfg['title']
1430
-                        ),
1431
-                        __FILE__,
1432
-                        __FUNCTION__,
1433
-                        __LINE__
1434
-                    );
1435
-                    return;
1436
-                }
1437
-                // setup config array for help tab method
1438
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1439
-                $_ht = [
1440
-                    'id'       => $id,
1441
-                    'title'    => $cfg['title'],
1442
-                    'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1443
-                    'content'  => $content,
1444
-                ];
1445
-                $this->_current_screen->add_help_tab($_ht);
1446
-            }
1447
-        }
1448
-    }
1449
-
1450
-
1451
-    /**
1452
-     * This simply sets up any qtips that have been defined in the page config
1453
-     *
1454
-     * @return void
1455
-     * @throws ReflectionException
1456
-     * @throws EE_Error
1457
-     */
1458
-    protected function _add_qtips()
1459
-    {
1460
-        if (isset($this->_route_config['qtips'])) {
1461
-            $qtips = (array) $this->_route_config['qtips'];
1462
-            // load qtip loader
1463
-            $path = [
1464
-                $this->_get_dir() . '/qtips/',
1465
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1466
-            ];
1467
-            EEH_Qtip_Loader::instance()->register($qtips, $path);
1468
-        }
1469
-    }
1470
-
1471
-
1472
-    /**
1473
-     * _set_nav_tabs
1474
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1475
-     * wish to add additional tabs or modify accordingly.
1476
-     *
1477
-     * @return void
1478
-     * @throws InvalidArgumentException
1479
-     * @throws InvalidInterfaceException
1480
-     * @throws InvalidDataTypeException
1481
-     */
1482
-    protected function _set_nav_tabs()
1483
-    {
1484
-        $i        = 0;
1485
-        $only_tab = count($this->_page_config) < 2;
1486
-        foreach ($this->_page_config as $slug => $config) {
1487
-            if (! is_array($config) || empty($config['nav'])) {
1488
-                continue;
1489
-            }
1490
-            // no nav tab for this config
1491
-            // check for persistent flag
1492
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1493
-                // nav tab is only to appear when route requested.
1494
-                continue;
1495
-            }
1496
-            if (! $this->check_user_access($slug, true)) {
1497
-                // no nav tab because current user does not have access.
1498
-                continue;
1499
-            }
1500
-            $css_class = $config['css_class'] ?? '';
1501
-            $css_class .= $only_tab ? ' ee-only-tab' : '';
1502
-            $css_class .= " ee-nav-tab__$slug";
1503
-
1504
-            $this->_nav_tabs[ $slug ] = [
1505
-                'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1506
-                        ['action' => $slug],
1507
-                        $this->_admin_base_url
1508
-                    ),
1509
-                'link_text' => $this->navTabLabel($config['nav'], $slug),
1510
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1511
-                'order'     => $config['nav']['order'] ?? $i,
1512
-            ];
1513
-            $i++;
1514
-        }
1515
-        // if $this->_nav_tabs is empty then lets set the default
1516
-        if (empty($this->_nav_tabs)) {
1517
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1518
-                'url'       => $this->_admin_base_url,
1519
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1520
-                'css_class' => 'nav-tab-active',
1521
-                'order'     => 10,
1522
-            ];
1523
-        }
1524
-        // now let's sort the tabs according to order
1525
-        usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1526
-    }
1527
-
1528
-
1529
-    private function navTabLabel(array $nav_tab, string $slug): string
1530
-    {
1531
-        $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1532
-        $icon  = $nav_tab['icon'] ?? null;
1533
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1534
-        return '
144
+	/**
145
+	 * unprocessed value for the 'page' request param (default '')
146
+	 *
147
+	 * @var string
148
+	 */
149
+	protected $raw_req_page = '';
150
+
151
+	/**
152
+	 * sanitized request action (and nonce)
153
+	 *
154
+	 * @var string
155
+	 */
156
+	protected $_req_action = '';
157
+
158
+	/**
159
+	 * sanitized request action nonce
160
+	 *
161
+	 * @var string
162
+	 */
163
+	protected $_req_nonce = '';
164
+
165
+	/**
166
+	 * @var string
167
+	 */
168
+	protected $_search_btn_label = '';
169
+
170
+	/**
171
+	 * @var string
172
+	 */
173
+	protected $_search_box_callback = '';
174
+
175
+	/**
176
+	 * @var WP_Screen
177
+	 */
178
+	protected $_current_screen;
179
+
180
+	// for holding EE_Admin_Hooks object when needed (set via set_hook_object())
181
+	protected $_hook_obj;
182
+
183
+	// for holding incoming request data
184
+	protected $_req_data = [];
185
+
186
+	// yes / no array for admin form fields
187
+	protected $_yes_no_values = [];
188
+
189
+	// some default things shared by all child classes
190
+	protected $_default_espresso_metaboxes = [
191
+		'_espresso_news_post_box',
192
+		'_espresso_links_post_box',
193
+		'_espresso_ratings_request',
194
+		'_espresso_sponsors_post_box',
195
+	];
196
+
197
+	/**
198
+	 * @var EE_Registry
199
+	 */
200
+	protected $EE;
201
+
202
+
203
+	/**
204
+	 * This is just a property that flags whether the given route is a caffeinated route or not.
205
+	 *
206
+	 * @var boolean
207
+	 */
208
+	protected $_is_caf = false;
209
+
210
+	/**
211
+	 * whether or not initializePage() has run
212
+	 *
213
+	 * @var boolean
214
+	 */
215
+	protected $initialized = false;
216
+
217
+	/**
218
+	 * @var FeatureFlags
219
+	 */
220
+	protected $feature;
221
+
222
+
223
+	/**
224
+	 * @var string
225
+	 */
226
+	protected $class_name;
227
+
228
+	/**
229
+	 * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
230
+	 * then this would be the parent classname: Events_Admin_Page
231
+	 *
232
+	 * @var string
233
+	 */
234
+	protected $base_class_name;
235
+
236
+	/**
237
+	 * @var array
238
+	 * @since $VID:$
239
+	 */
240
+	private $publish_post_meta_box_hidden_fields = [];
241
+
242
+
243
+	/**
244
+	 * @Constructor
245
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
246
+	 * @throws InvalidArgumentException
247
+	 * @throws InvalidDataTypeException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws ReflectionException
250
+	 */
251
+	public function __construct($routing = true)
252
+	{
253
+		$this->loader       = LoaderFactory::getLoader();
254
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
255
+		$this->feature      = $this->loader->getShared(FeatureFlags::class);
256
+		$this->request      = $this->loader->getShared(RequestInterface::class);
257
+		// routing enabled?
258
+		$this->_routing = $routing;
259
+
260
+		$this->class_name      = get_class($this);
261
+		$this->base_class_name = strpos($this->class_name, 'Extend_') === 0
262
+			? str_replace('Extend_', '', $this->class_name)
263
+			: '';
264
+
265
+		if (strpos($this->_get_dir(), 'caffeinated') !== false) {
266
+			$this->_is_caf = true;
267
+		}
268
+		$this->_yes_no_values = [
269
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
270
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
271
+		];
272
+		// set the _req_data property.
273
+		$this->_req_data = $this->request->requestParams();
274
+	}
275
+
276
+
277
+	/**
278
+	 * @return EE_Admin_Config
279
+	 */
280
+	public function adminConfig(): EE_Admin_Config
281
+	{
282
+		return $this->admin_config;
283
+	}
284
+
285
+
286
+	/**
287
+	 * @return FeatureFlags
288
+	 */
289
+	public function feature(): FeatureFlags
290
+	{
291
+		return $this->feature;
292
+	}
293
+
294
+
295
+	/**
296
+	 * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
297
+	 * for child classes that needed to set properties prior to these methods getting called,
298
+	 * but also needed the parent class to have its construction completed as well.
299
+	 * Bottom line is that constructors should ONLY be used for setting initial properties
300
+	 * and any complex initialization logic should only run after instantiation is complete.
301
+	 *
302
+	 * This method gets called immediately after construction from within
303
+	 *      EE_Admin_Page_Init::_initialize_admin_page()
304
+	 *
305
+	 * @throws EE_Error
306
+	 * @throws InvalidArgumentException
307
+	 * @throws InvalidDataTypeException
308
+	 * @throws InvalidInterfaceException
309
+	 * @throws ReflectionException
310
+	 * @since $VID:$
311
+	 */
312
+	public function initializePage()
313
+	{
314
+		if ($this->initialized) {
315
+			return;
316
+		}
317
+		// set initial page props (child method)
318
+		$this->_init_page_props();
319
+		// set global defaults
320
+		$this->_set_defaults();
321
+		// set early because incoming requests could be ajax related and we need to register those hooks.
322
+		$this->_global_ajax_hooks();
323
+		$this->_ajax_hooks();
324
+		// other_page_hooks have to be early too.
325
+		$this->_do_other_page_hooks();
326
+		// set up page dependencies
327
+		$this->_before_page_setup();
328
+		$this->_page_setup();
329
+		$this->initialized = true;
330
+	}
331
+
332
+
333
+	/**
334
+	 * _init_page_props
335
+	 * Child classes use to set at least the following properties:
336
+	 * $page_slug.
337
+	 * $page_label.
338
+	 *
339
+	 * @abstract
340
+	 * @return void
341
+	 */
342
+	abstract protected function _init_page_props();
343
+
344
+
345
+	/**
346
+	 * _ajax_hooks
347
+	 * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
348
+	 * Note: within the ajax callback methods.
349
+	 *
350
+	 * @abstract
351
+	 * @return void
352
+	 */
353
+	abstract protected function _ajax_hooks();
354
+
355
+
356
+	/**
357
+	 * _define_page_props
358
+	 * child classes define page properties in here.  Must include at least:
359
+	 * $_admin_base_url = base_url for all admin pages
360
+	 * $_admin_page_title = default admin_page_title for admin pages
361
+	 * $_labels = array of default labels for various automatically generated elements:
362
+	 *    array(
363
+	 *        'buttons' => array(
364
+	 *            'add' => esc_html__('label for add new button'),
365
+	 *            'edit' => esc_html__('label for edit button'),
366
+	 *            'delete' => esc_html__('label for delete button')
367
+	 *            )
368
+	 *        )
369
+	 *
370
+	 * @abstract
371
+	 * @return void
372
+	 */
373
+	abstract protected function _define_page_props();
374
+
375
+
376
+	/**
377
+	 * _set_page_routes
378
+	 * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
379
+	 * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
380
+	 * have a 'default' route. Here's the format
381
+	 * $this->_page_routes = array(
382
+	 *        'default' => array(
383
+	 *            'func' => '_default_method_handling_route',
384
+	 *            'args' => array('array','of','args'),
385
+	 *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
386
+	 *            ajax request, backend processing)
387
+	 *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
388
+	 *            headers route after.  The string you enter here should match the defined route reference for a
389
+	 *            headers sent route.
390
+	 *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
391
+	 *            this route.
392
+	 *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
393
+	 *            checks).
394
+	 *        ),
395
+	 *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
396
+	 *        handling method.
397
+	 *        )
398
+	 * )
399
+	 *
400
+	 * @abstract
401
+	 * @return void
402
+	 */
403
+	abstract protected function _set_page_routes();
404
+
405
+
406
+	/**
407
+	 * _set_page_config
408
+	 * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
409
+	 * array corresponds to the page_route for the loaded page. Format:
410
+	 * $this->_page_config = array(
411
+	 *        'default' => array(
412
+	 *            'labels' => array(
413
+	 *                'buttons' => array(
414
+	 *                    'add' => esc_html__('label for adding item'),
415
+	 *                    'edit' => esc_html__('label for editing item'),
416
+	 *                    'delete' => esc_html__('label for deleting item')
417
+	 *                ),
418
+	 *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
419
+	 *            ), //optional an array of custom labels for various automatically generated elements to use on the
420
+	 *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
421
+	 *            _define_page_props() method
422
+	 *            'nav' => array(
423
+	 *                'label' => esc_html__('Label for Tab', 'event_espresso').
424
+	 *                'url' => 'http://someurl', //automatically generated UNLESS you define
425
+	 *                'css_class' => 'css-class', //automatically generated UNLESS you define
426
+	 *                'order' => 10, //required to indicate tab position.
427
+	 *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
428
+	 *                displayed then add this parameter.
429
+	 *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
430
+	 *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
431
+	 *            metaboxes set for eventespresso admin pages.
432
+	 *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
433
+	 *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
434
+	 *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
435
+	 *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
436
+	 *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
437
+	 *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
438
+	 *            array indicates the max number of columns (4) and the default number of columns on page load (2).
439
+	 *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
440
+	 *            want to display.
441
+	 *            'help_tabs' => array( //this is used for adding help tabs to a page
442
+	 *                'tab_id' => array(
443
+	 *                    'title' => 'tab_title',
444
+	 *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
445
+	 *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
446
+	 *                    should match a file in the admin folder's "help_tabs" dir (ie..
447
+	 *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
448
+	 *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
449
+	 *                    attempt to use the callback which should match the name of a method in the class
450
+	 *                    ),
451
+	 *                'tab2_id' => array(
452
+	 *                    'title' => 'tab2 title',
453
+	 *                    'filename' => 'file_name_2'
454
+	 *                    'callback' => 'callback_method_for_content',
455
+	 *                 ),
456
+	 *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
457
+	 *            help tab area on an admin page. @return void
458
+	 *
459
+	 * @abstract
460
+	 */
461
+	abstract protected function _set_page_config();
462
+
463
+
464
+	/**
465
+	 * _add_screen_options
466
+	 * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
467
+	 * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
468
+	 * to a particular view.
469
+	 *
470
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
471
+	 *         see also WP_Screen object documents...
472
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
473
+	 * @abstract
474
+	 * @return void
475
+	 */
476
+	abstract protected function _add_screen_options();
477
+
478
+
479
+	/**
480
+	 * _add_feature_pointers
481
+	 * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
482
+	 * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
483
+	 * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
484
+	 * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
485
+	 * extended) also see:
486
+	 *
487
+	 * @link   http://eamann.com/tech/wordpress-portland/
488
+	 * @abstract
489
+	 * @return void
490
+	 */
491
+	abstract protected function _add_feature_pointers();
492
+
493
+
494
+	/**
495
+	 * load_scripts_styles
496
+	 * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
497
+	 * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
498
+	 * scripts/styles per view by putting them in a dynamic function in this format
499
+	 * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
500
+	 *
501
+	 * @abstract
502
+	 * @return void
503
+	 */
504
+	abstract public function load_scripts_styles();
505
+
506
+
507
+	/**
508
+	 * admin_init
509
+	 * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
510
+	 * all pages/views loaded by child class.
511
+	 *
512
+	 * @abstract
513
+	 * @return void
514
+	 */
515
+	abstract public function admin_init();
516
+
517
+
518
+	/**
519
+	 * admin_notices
520
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
521
+	 * all pages/views loaded by child class.
522
+	 *
523
+	 * @abstract
524
+	 * @return void
525
+	 */
526
+	abstract public function admin_notices();
527
+
528
+
529
+	/**
530
+	 * admin_footer_scripts
531
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
532
+	 * will apply to all pages/views loaded by child class.
533
+	 *
534
+	 * @return void
535
+	 */
536
+	abstract public function admin_footer_scripts();
537
+
538
+
539
+	/**
540
+	 * admin_footer
541
+	 * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
542
+	 * apply to all pages/views loaded by child class.
543
+	 *
544
+	 * @return void
545
+	 */
546
+	public function admin_footer()
547
+	{
548
+	}
549
+
550
+
551
+	/**
552
+	 * _global_ajax_hooks
553
+	 * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
554
+	 * Note: within the ajax callback methods.
555
+	 *
556
+	 * @abstract
557
+	 * @return void
558
+	 */
559
+	protected function _global_ajax_hooks()
560
+	{
561
+		// for lazy loading of metabox content
562
+		add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content'], 10);
563
+
564
+		add_action(
565
+			'wp_ajax_espresso_hide_status_change_notice',
566
+			[$this, 'hideStatusChangeNotice']
567
+		);
568
+		add_action(
569
+			'wp_ajax_nopriv_espresso_hide_status_change_notice',
570
+			[$this, 'hideStatusChangeNotice']
571
+		);
572
+	}
573
+
574
+
575
+	public function ajax_metabox_content()
576
+	{
577
+		$content_id  = $this->request->getRequestParam('contentid', '');
578
+		$content_url = $this->request->getRequestParam('contenturl', '', 'url');
579
+		EE_Admin_Page::cached_rss_display($content_id, $content_url);
580
+		wp_die();
581
+	}
582
+
583
+
584
+	public function hideStatusChangeNotice()
585
+	{
586
+		$response = [];
587
+		try {
588
+			/** @var StatusChangeNotice $status_change_notice */
589
+			$status_change_notice = $this->loader->getShared(
590
+				'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
591
+			);
592
+			$response['success']  = $status_change_notice->dismiss() > -1;
593
+		} catch (Exception $exception) {
594
+			$response['errors'] = $exception->getMessage();
595
+		}
596
+		echo wp_json_encode($response);
597
+		exit();
598
+	}
599
+
600
+
601
+	/**
602
+	 * allows extending classes do something specific before the parent constructor runs _page_setup().
603
+	 *
604
+	 * @return void
605
+	 */
606
+	protected function _before_page_setup()
607
+	{
608
+		// default is to do nothing
609
+	}
610
+
611
+
612
+	/**
613
+	 * Makes sure any things that need to be loaded early get handled.
614
+	 * We also escape early here if the page requested doesn't match the object.
615
+	 *
616
+	 * @final
617
+	 * @return void
618
+	 * @throws EE_Error
619
+	 * @throws InvalidArgumentException
620
+	 * @throws ReflectionException
621
+	 * @throws InvalidDataTypeException
622
+	 * @throws InvalidInterfaceException
623
+	 */
624
+	final protected function _page_setup()
625
+	{
626
+		// requires?
627
+		// admin_init stuff - global - we're setting this REALLY early
628
+		// so if EE_Admin pages have to hook into other WP pages they can.
629
+		// But keep in mind, not everything is available from the EE_Admin Page object at this point.
630
+		add_action('admin_init', [$this, 'admin_init_global'], 5);
631
+		// next verify if we need to load anything...
632
+		$this->_current_page = $this->request->getRequestParam('page', '', 'key');
633
+		$this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, 'key');
634
+		$this->page_folder   = strtolower(
635
+			str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
636
+		);
637
+		global $ee_menu_slugs;
638
+		$ee_menu_slugs = (array) $ee_menu_slugs;
639
+		if (
640
+			! $this->request->isAjax()
641
+			&& (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
642
+		) {
643
+			return;
644
+		}
645
+		// because WP List tables have two duplicate select inputs for choosing bulk actions,
646
+		// we need to copy the action from the second to the first
647
+		$action     = $this->request->getRequestParam('action', '-1', 'key');
648
+		$action2    = $this->request->getRequestParam('action2', '-1', 'key');
649
+		$action     = $action !== '-1' ? $action : $action2;
650
+		$req_action = $action !== '-1' ? $action : 'default';
651
+
652
+		// if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
653
+		// then let's use the route as the action.
654
+		// This covers cases where we're coming in from a list table that isn't on the default route.
655
+		$route             = $this->request->getRequestParam('route');
656
+		$this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
657
+			? $route
658
+			: $req_action;
659
+
660
+		$this->_current_view = $this->_req_action;
661
+		$this->_req_nonce    = $this->_req_action . '_nonce';
662
+		$this->_define_page_props();
663
+		$this->_current_page_view_url = add_query_arg(
664
+			['page' => $this->_current_page, 'action' => $this->_current_view],
665
+			$this->_admin_base_url
666
+		);
667
+		// set page configs
668
+		$this->_set_page_routes();
669
+		$this->_set_page_config();
670
+		// let's include any referrer data in our default_query_args for this route for "stickiness".
671
+		if ($this->request->requestParamIsSet('wp_referer')) {
672
+			$wp_referer = $this->request->getRequestParam('wp_referer');
673
+			if ($wp_referer) {
674
+				$this->_default_route_query_args['wp_referer'] = $wp_referer;
675
+			}
676
+		}
677
+		// for CPT and other extended functionality.
678
+		// If there is an _extend_page_config_for_cpt
679
+		// then let's run that to modify all the various page configuration arrays.
680
+		if (method_exists($this, '_extend_page_config_for_cpt')) {
681
+			$this->_extend_page_config_for_cpt();
682
+		}
683
+		// filter routes and page_config so addons can add their stuff. Filtering done per class
684
+		$this->_page_routes = apply_filters(
685
+			'FHEE__' . $this->class_name . '__page_setup__page_routes',
686
+			$this->_page_routes,
687
+			$this
688
+		);
689
+		$this->_page_config = apply_filters(
690
+			'FHEE__' . $this->class_name . '__page_setup__page_config',
691
+			$this->_page_config,
692
+			$this
693
+		);
694
+		if ($this->base_class_name !== '') {
695
+			$this->_page_routes = apply_filters(
696
+				'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
697
+				$this->_page_routes,
698
+				$this
699
+			);
700
+			$this->_page_config = apply_filters(
701
+				'FHEE__' . $this->base_class_name . '__page_setup__page_config',
702
+				$this->_page_config,
703
+				$this
704
+			);
705
+		}
706
+		// if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
707
+		// then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
708
+		if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
709
+			add_action(
710
+				'AHEE__EE_Admin_Page__route_admin_request',
711
+				[$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
712
+				10,
713
+				2
714
+			);
715
+		}
716
+		// next route only if routing enabled
717
+		if ($this->_routing && ! $this->request->isAjax()) {
718
+			$this->_verify_routes();
719
+			// next let's just check user_access and kill if no access
720
+			$this->check_user_access();
721
+			if ($this->_is_UI_request) {
722
+				// admin_init stuff - global, all views for this page class, specific view
723
+				add_action('admin_init', [$this, 'admin_init'], 10);
724
+				if (method_exists($this, 'admin_init_' . $this->_current_view)) {
725
+					add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
726
+				}
727
+			} else {
728
+				// hijack regular WP loading and route admin request immediately
729
+				@ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
730
+				$this->route_admin_request();
731
+			}
732
+		}
733
+	}
734
+
735
+
736
+	/**
737
+	 * Provides a way for related child admin pages to load stuff on the loaded admin page.
738
+	 *
739
+	 * @return void
740
+	 * @throws EE_Error
741
+	 */
742
+	private function _do_other_page_hooks()
743
+	{
744
+		$registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
745
+		foreach ($registered_pages as $page) {
746
+			// now let's setup the file name and class that should be present
747
+			$classname = str_replace('.class.php', '', $page);
748
+			// autoloaders should take care of loading file
749
+			if (! class_exists($classname)) {
750
+				$error_msg[] = sprintf(
751
+					esc_html__(
752
+						'Something went wrong with loading the %s admin hooks page.',
753
+						'event_espresso'
754
+					),
755
+					$page
756
+				);
757
+				$error_msg[] = $error_msg[0]
758
+							   . "\r\n"
759
+							   . sprintf(
760
+								   esc_html__(
761
+									   'There is no class in place for the %1$s admin hooks page.%2$sMake sure you have %3$s defined. If this is a non-EE-core admin page then you also must have an autoloader in place for your class',
762
+									   'event_espresso'
763
+								   ),
764
+								   $page,
765
+								   '<br />',
766
+								   '<strong>' . $classname . '</strong>'
767
+							   );
768
+				throw new EE_Error(implode('||', $error_msg));
769
+			}
770
+			// notice we are passing the instance of this class to the hook object.
771
+			$this->loader->getShared($classname, [$this]);
772
+		}
773
+	}
774
+
775
+
776
+	/**
777
+	 * @throws ReflectionException
778
+	 * @throws EE_Error
779
+	 */
780
+	public function load_page_dependencies()
781
+	{
782
+		try {
783
+			$this->_load_page_dependencies();
784
+		} catch (EE_Error $e) {
785
+			$e->get_error();
786
+		}
787
+	}
788
+
789
+
790
+	/**
791
+	 * load_page_dependencies
792
+	 * loads things specific to this page class when its loaded.  Really helps with efficiency.
793
+	 *
794
+	 * @return void
795
+	 * @throws DomainException
796
+	 * @throws EE_Error
797
+	 * @throws InvalidArgumentException
798
+	 * @throws InvalidDataTypeException
799
+	 * @throws InvalidInterfaceException
800
+	 * @throws ReflectionException
801
+	 */
802
+	protected function _load_page_dependencies()
803
+	{
804
+		// let's set the current_screen and screen options to override what WP set
805
+		$this->_current_screen = get_current_screen();
806
+		// load admin_notices - global, page class, and view specific
807
+		add_action('admin_notices', [$this, 'admin_notices_global'], 5);
808
+		add_action('admin_notices', [$this, 'admin_notices'], 10);
809
+		if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
810
+			add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
811
+		}
812
+		// load network admin_notices - global, page class, and view specific
813
+		add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
814
+		if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
815
+			add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
816
+		}
817
+		// this will save any per_page screen options if they are present
818
+		$this->_set_per_page_screen_options();
819
+		// setup list table properties
820
+		$this->_set_list_table();
821
+		// child classes can "register" a metabox to be automatically handled via the _page_config array property.
822
+		// However in some cases the metaboxes will need to be added within a route handling callback.
823
+		add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
824
+		// hack because promos admin was loading the edited promotion object in the metaboxes callback
825
+		// which should NOT be generated on non-UI requests like POST updates/inserts
826
+		if (
827
+			$this->class_name === 'Promotions_Admin_Page'
828
+			&& ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
829
+		) {
830
+			$this->addRegisteredMetaBoxes();
831
+		}
832
+		$this->_add_screen_columns();
833
+		// add screen options - global, page child class, and view specific
834
+		$this->_add_global_screen_options();
835
+		$this->_add_screen_options();
836
+		$add_screen_options = "_add_screen_options_{$this->_current_view}";
837
+		if (method_exists($this, $add_screen_options)) {
838
+			$this->{$add_screen_options}();
839
+		}
840
+		// add help tab(s) - set via page_config and qtips.
841
+		$this->_add_help_tabs();
842
+		$this->_add_qtips();
843
+		// add feature_pointers - global, page child class, and view specific
844
+		$this->_add_feature_pointers();
845
+		$this->_add_global_feature_pointers();
846
+		$add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
847
+		if (method_exists($this, $add_feature_pointer)) {
848
+			$this->{$add_feature_pointer}();
849
+		}
850
+		// enqueue scripts/styles - global, page class, and view specific
851
+		add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
852
+		add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles'], 10);
853
+		if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
854
+			add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_{$this->_current_view}"], 15);
855
+		}
856
+		add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 100);
857
+		// admin_print_footer_scripts - global, page child class, and view specific.
858
+		// NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
859
+		// In most cases that's doing_it_wrong().  But adding hidden container elements etc.
860
+		// is a good use case. Notice the late priority we're giving these
861
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
862
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
863
+		if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
864
+			add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_{$this->_current_view}"], 101);
865
+		}
866
+		// admin footer scripts
867
+		add_action('admin_footer', [$this, 'admin_footer_global'], 99);
868
+		add_action('admin_footer', [$this, 'admin_footer'], 100);
869
+		if (method_exists($this, "admin_footer_{$this->_current_view}")) {
870
+			add_action('admin_footer', [$this, "admin_footer_{$this->_current_view}"], 101);
871
+		}
872
+		do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
873
+		// targeted hook
874
+		do_action(
875
+			"FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
876
+		);
877
+	}
878
+
879
+
880
+	/**
881
+	 * _set_defaults
882
+	 * This sets some global defaults for class properties.
883
+	 */
884
+	private function _set_defaults()
885
+	{
886
+		$this->_current_screen       = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
887
+		$this->_event                = $this->_template_path = $this->_column_template_path = null;
888
+		$this->_nav_tabs             = $this->_views = $this->_page_routes = [];
889
+		$this->_page_config          = $this->_default_route_query_args = [];
890
+		$this->_default_nav_tab_name = 'overview';
891
+		// init template args
892
+		$this->set_template_args(
893
+			[
894
+				'admin_page_header'  => '',
895
+				'admin_page_content' => '',
896
+				'post_body_content'  => '',
897
+				'before_list_table'  => '',
898
+				'after_list_table'   => '',
899
+			]
900
+		);
901
+	}
902
+
903
+
904
+	/**
905
+	 * route_admin_request
906
+	 *
907
+	 * @return void
908
+	 * @throws InvalidArgumentException
909
+	 * @throws InvalidInterfaceException
910
+	 * @throws InvalidDataTypeException
911
+	 * @throws EE_Error
912
+	 * @throws ReflectionException
913
+	 * @see    _route_admin_request()
914
+	 */
915
+	public function route_admin_request()
916
+	{
917
+		try {
918
+			$this->_route_admin_request();
919
+		} catch (EE_Error $e) {
920
+			$e->get_error();
921
+		}
922
+	}
923
+
924
+
925
+	public function set_wp_page_slug($wp_page_slug)
926
+	{
927
+		$this->_wp_page_slug = $wp_page_slug;
928
+		// if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
929
+		if (is_network_admin()) {
930
+			$this->_wp_page_slug .= '-network';
931
+		}
932
+	}
933
+
934
+
935
+	/**
936
+	 * _verify_routes
937
+	 * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
938
+	 * we know if we need to drop out.
939
+	 *
940
+	 * @return bool
941
+	 * @throws EE_Error
942
+	 */
943
+	protected function _verify_routes()
944
+	{
945
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
946
+		if (! $this->_current_page && ! $this->request->isAjax()) {
947
+			return false;
948
+		}
949
+		$this->_route = false;
950
+		// check that the page_routes array is not empty
951
+		if (empty($this->_page_routes)) {
952
+			// user error msg
953
+			$error_msg = sprintf(
954
+				esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
955
+				$this->_admin_page_title
956
+			);
957
+			// developer error msg
958
+			$error_msg .= '||' . $error_msg
959
+						  . esc_html__(
960
+							  ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
961
+							  'event_espresso'
962
+						  );
963
+			throw new EE_Error($error_msg);
964
+		}
965
+		// and that the requested page route exists
966
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
967
+			$this->_route        = $this->_page_routes[ $this->_req_action ];
968
+			$this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
969
+		} else {
970
+			// user error msg
971
+			$error_msg = sprintf(
972
+				esc_html__(
973
+					'The requested page route does not exist for the %s admin page.',
974
+					'event_espresso'
975
+				),
976
+				$this->_admin_page_title
977
+			);
978
+			// developer error msg
979
+			$error_msg .= '||' . $error_msg
980
+						  . sprintf(
981
+							  esc_html__(
982
+								  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
983
+								  'event_espresso'
984
+							  ),
985
+							  $this->_req_action
986
+						  );
987
+			throw new EE_Error($error_msg);
988
+		}
989
+		// and that a default route exists
990
+		if (! array_key_exists('default', $this->_page_routes)) {
991
+			// user error msg
992
+			$error_msg = sprintf(
993
+				esc_html__(
994
+					'A default page route has not been set for the % admin page.',
995
+					'event_espresso'
996
+				),
997
+				$this->_admin_page_title
998
+			);
999
+			// developer error msg
1000
+			$error_msg .= '||' . $error_msg
1001
+						  . esc_html__(
1002
+							  ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
1003
+							  'event_espresso'
1004
+						  );
1005
+			throw new EE_Error($error_msg);
1006
+		}
1007
+
1008
+		// first lets' catch if the UI request has EVER been set.
1009
+		if ($this->_is_UI_request === null) {
1010
+			// lets set if this is a UI request or not.
1011
+			$this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, 'bool');
1012
+			// wait a minute... we might have a noheader in the route array
1013
+			$this->_is_UI_request = ! (
1014
+				is_array($this->_route) && isset($this->_route['noheader']) && $this->_route['noheader']
1015
+			)
1016
+				? $this->_is_UI_request
1017
+				: false;
1018
+		}
1019
+		$this->_set_current_labels();
1020
+		return true;
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 * this method simply verifies a given route and makes sure its an actual route available for the loaded page
1026
+	 *
1027
+	 * @param string $route the route name we're verifying
1028
+	 * @return bool we'll throw an exception if this isn't a valid route.
1029
+	 * @throws EE_Error
1030
+	 */
1031
+	protected function _verify_route($route)
1032
+	{
1033
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
1034
+			return true;
1035
+		}
1036
+		// user error msg
1037
+		$error_msg = sprintf(
1038
+			esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1039
+			$this->_admin_page_title
1040
+		);
1041
+		// developer error msg
1042
+		$error_msg .= '||' . $error_msg
1043
+					  . sprintf(
1044
+						  esc_html__(
1045
+							  ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1046
+							  'event_espresso'
1047
+						  ),
1048
+						  $route
1049
+					  );
1050
+		throw new EE_Error($error_msg);
1051
+	}
1052
+
1053
+
1054
+	/**
1055
+	 * perform nonce verification
1056
+	 * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1057
+	 * using this method (and save retyping!)
1058
+	 *
1059
+	 * @param string $nonce     The nonce sent
1060
+	 * @param string $nonce_ref The nonce reference string (name0)
1061
+	 * @return void
1062
+	 * @throws EE_Error
1063
+	 * @throws InvalidArgumentException
1064
+	 * @throws InvalidDataTypeException
1065
+	 * @throws InvalidInterfaceException
1066
+	 */
1067
+	protected function _verify_nonce($nonce, $nonce_ref)
1068
+	{
1069
+		// verify nonce against expected value
1070
+		if (! wp_verify_nonce($nonce, $nonce_ref)) {
1071
+			// these are not the droids you are looking for !!!
1072
+			$msg = sprintf(
1073
+				esc_html__('%sNonce Fail.%s', 'event_espresso'),
1074
+				'<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1075
+				'</a>'
1076
+			);
1077
+			if (WP_DEBUG) {
1078
+				$msg .= "\n  ";
1079
+				$msg .= sprintf(
1080
+					esc_html__(
1081
+						'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1082
+						'event_espresso'
1083
+					),
1084
+					__CLASS__
1085
+				);
1086
+			}
1087
+			if (! $this->request->isAjax()) {
1088
+				wp_die($msg);
1089
+			}
1090
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1091
+			$this->_return_json();
1092
+		}
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 * _route_admin_request()
1098
+	 * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1099
+	 * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1100
+	 * in the page routes and then will try to load the corresponding method.
1101
+	 *
1102
+	 * @return void
1103
+	 * @throws EE_Error
1104
+	 * @throws InvalidArgumentException
1105
+	 * @throws InvalidDataTypeException
1106
+	 * @throws InvalidInterfaceException
1107
+	 * @throws ReflectionException
1108
+	 */
1109
+	protected function _route_admin_request()
1110
+	{
1111
+		if (! $this->_is_UI_request) {
1112
+			$this->_verify_routes();
1113
+		}
1114
+		$nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1115
+		if ($this->_req_action !== 'default' && $nonce_check) {
1116
+			// set nonce from post data
1117
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
1118
+			$this->_verify_nonce($nonce, $this->_req_nonce);
1119
+		}
1120
+		// set the nav_tabs array but ONLY if this is  UI_request
1121
+		if ($this->_is_UI_request) {
1122
+			$this->_set_nav_tabs();
1123
+		}
1124
+		// grab callback function
1125
+		$func = is_array($this->_route) && isset($this->_route['func'])
1126
+			? $this->_route['func']
1127
+			: $this->_route;
1128
+		// check if callback has args
1129
+		$args = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : [];
1130
+		// action right before calling route
1131
+		// (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1132
+		if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1133
+			do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1134
+		}
1135
+		// strip _wp_http_referer from the server REQUEST_URI
1136
+		// else it grows in length on every submission due to recursion,
1137
+		// ultimately causing a "Request-URI Too Large" error
1138
+		$this->request->unSetRequestParam('_wp_http_referer');
1139
+		$this->request->unSetServerParam('_wp_http_referer');
1140
+		$cleaner_request_uri = remove_query_arg(
1141
+			'_wp_http_referer',
1142
+			wp_unslash($this->request->getServerParam('REQUEST_URI'))
1143
+		);
1144
+		$this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1145
+		$this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1146
+		$route_callback = [];
1147
+		if (! empty($func)) {
1148
+			if (is_array($func)) {
1149
+				$route_callback = $func;
1150
+			} elseif (is_string($func)) {
1151
+				if (strpos($func, '::') !== false) {
1152
+					$route_callback = explode('::', $func);
1153
+				} elseif (method_exists($this, $func)) {
1154
+					$route_callback = [$this, $func];
1155
+				} else {
1156
+					$route_callback = $func;
1157
+				}
1158
+			}
1159
+			[$class, $method] = $route_callback;
1160
+			// is it neither a class method NOR a standalone function?
1161
+			if (! is_callable($route_callback)) {
1162
+				// user error msg
1163
+				$error_msg = esc_html__(
1164
+					'An error occurred. The  requested page route could not be found.',
1165
+					'event_espresso'
1166
+				);
1167
+				// developer error msg
1168
+				$error_msg .= '||';
1169
+				$error_msg .= sprintf(
1170
+					esc_html__(
1171
+						'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1172
+						'event_espresso'
1173
+					),
1174
+					$method
1175
+				);
1176
+				throw new DomainException($error_msg);
1177
+			}
1178
+			if ($class !== $this && ! in_array($this, $args)) {
1179
+				// send along this admin page object for access by addons.
1180
+				$args['admin_page'] = $this;
1181
+			}
1182
+
1183
+			try {
1184
+				call_user_func_array($route_callback, $args);
1185
+			} catch (Throwable $throwable) {
1186
+				$arg_keys = array_keys($args);
1187
+				$nice_args = [];
1188
+				foreach ($args as $key => $arg) {
1189
+					$nice_args[ $key ] = is_object($arg) ? get_class($arg) : $arg_keys[ $key ];
1190
+				}
1191
+				new ExceptionStackTraceDisplay(
1192
+						new RuntimeException(
1193
+							sprintf(
1194
+								esc_html__(
1195
+									'Page route "%1$s" with the supplied arguments (%2$s) threw the following exception: %3$s',
1196
+									'event_espresso'
1197
+								),
1198
+								$method,
1199
+								implode(', ', $nice_args),
1200
+								$throwable->getMessage()
1201
+							),
1202
+							$throwable->getCode(),
1203
+							$throwable
1204
+						)
1205
+				);
1206
+			}
1207
+		}
1208
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1209
+		// then we need to reset the routing properties to the new route.
1210
+		// now if UI request is FALSE and noheader is true AND we have a headers_sent_route in the route array then let's set UI_request to true because the no header route has a second func after headers have been sent.
1211
+		if (
1212
+			$this->_is_UI_request === false
1213
+			&& is_array($this->_route)
1214
+			&& ! empty($this->_route['headers_sent_route'])
1215
+		) {
1216
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1217
+		}
1218
+	}
1219
+
1220
+
1221
+	/**
1222
+	 * This method just allows the resetting of page properties in the case where a no headers
1223
+	 * route redirects to a headers route in its route config.
1224
+	 *
1225
+	 * @param string $new_route New (non header) route to redirect to.
1226
+	 * @return   void
1227
+	 * @throws ReflectionException
1228
+	 * @throws InvalidArgumentException
1229
+	 * @throws InvalidInterfaceException
1230
+	 * @throws InvalidDataTypeException
1231
+	 * @throws EE_Error
1232
+	 * @since   4.3.0
1233
+	 */
1234
+	protected function _reset_routing_properties($new_route)
1235
+	{
1236
+		$this->_is_UI_request = true;
1237
+		// now we set the current route to whatever the headers_sent_route is set at
1238
+		$this->request->setRequestParam('action', $new_route);
1239
+		// rerun page setup
1240
+		$this->_page_setup();
1241
+	}
1242
+
1243
+
1244
+	/**
1245
+	 * _add_query_arg
1246
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1247
+	 *(internally just uses EEH_URL's function with the same name)
1248
+	 *
1249
+	 * @param array  $args
1250
+	 * @param string $url
1251
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1252
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1253
+	 *                                        Example usage: If the current page is:
1254
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1255
+	 *                                        &action=default&event_id=20&month_range=March%202015
1256
+	 *                                        &_wpnonce=5467821
1257
+	 *                                        and you call:
1258
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1259
+	 *                                        array(
1260
+	 *                                        'action' => 'resend_something',
1261
+	 *                                        'page=>espresso_registrations'
1262
+	 *                                        ),
1263
+	 *                                        $some_url,
1264
+	 *                                        true
1265
+	 *                                        );
1266
+	 *                                        It will produce a url in this structure:
1267
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1268
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1269
+	 *                                        month_range]=March%202015
1270
+	 * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1271
+	 * @param int    $context
1272
+	 * @return string
1273
+	 */
1274
+	public static function add_query_args_and_nonce(
1275
+		$args = [],
1276
+		$url = '',
1277
+		$sticky = false,
1278
+		$exclude_nonce = false,
1279
+		int $context = EEH_URL::CONTEXT_NONE
1280
+	) {
1281
+		// if there is a _wp_http_referer include the values from the request but only if sticky = true
1282
+		if ($sticky) {
1283
+			/** @var RequestInterface $request */
1284
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1285
+			$request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1286
+			$request->unSetServerParam('_wp_http_referer', true);
1287
+			foreach ($request->requestParams() as $key => $value) {
1288
+				// do not add nonces
1289
+				if (strpos($key, 'nonce') !== false) {
1290
+					continue;
1291
+				}
1292
+				$args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1293
+			}
1294
+		}
1295
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1296
+	}
1297
+
1298
+
1299
+	/**
1300
+	 * This returns a generated link that will load the related help tab.
1301
+	 *
1302
+	 * @param string $help_tab_id the id for the connected help tab
1303
+	 * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1304
+	 * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1305
+	 * @return string              generated link
1306
+	 * @uses EEH_Template::get_help_tab_link()
1307
+	 */
1308
+	protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1309
+	{
1310
+		return EEH_Template::get_help_tab_link(
1311
+			$help_tab_id,
1312
+			$this->page_slug,
1313
+			$this->_req_action,
1314
+			$icon_style,
1315
+			$help_text
1316
+		);
1317
+	}
1318
+
1319
+
1320
+	/**
1321
+	 * _add_help_tabs
1322
+	 * Note child classes define their help tabs within the page_config array.
1323
+	 *
1324
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1325
+	 * @return void
1326
+	 * @throws DomainException
1327
+	 * @throws EE_Error
1328
+	 * @throws ReflectionException
1329
+	 */
1330
+	protected function _add_help_tabs()
1331
+	{
1332
+		if (isset($this->_page_config[ $this->_req_action ])) {
1333
+			$config = $this->_page_config[ $this->_req_action ];
1334
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1335
+			if (is_array($config) && isset($config['help_sidebar'])) {
1336
+				// check that the callback given is valid
1337
+				if (! method_exists($this, $config['help_sidebar'])) {
1338
+					throw new EE_Error(
1339
+						sprintf(
1340
+							esc_html__(
1341
+								'The _page_config array has a callback set for the "help_sidebar" option.  However the callback given (%s) is not a valid callback.  Doublecheck the spelling and make sure this method exists for the class %s',
1342
+								'event_espresso'
1343
+							),
1344
+							$config['help_sidebar'],
1345
+							$this->class_name
1346
+						)
1347
+					);
1348
+				}
1349
+				$content = apply_filters(
1350
+					'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1351
+					$this->{$config['help_sidebar']}()
1352
+				);
1353
+				$this->_current_screen->set_help_sidebar($content);
1354
+			}
1355
+			if (! isset($config['help_tabs'])) {
1356
+				return;
1357
+			} //no help tabs for this route
1358
+			foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1359
+				// we're here so there ARE help tabs!
1360
+				// make sure we've got what we need
1361
+				if (! isset($cfg['title'])) {
1362
+					throw new EE_Error(
1363
+						esc_html__(
1364
+							'The _page_config array is not set up properly for help tabs.  It is missing a title',
1365
+							'event_espresso'
1366
+						)
1367
+					);
1368
+				}
1369
+				if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1370
+					throw new EE_Error(
1371
+						esc_html__(
1372
+							'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
1373
+							'event_espresso'
1374
+						)
1375
+					);
1376
+				}
1377
+				// first priority goes to content.
1378
+				if (! empty($cfg['content'])) {
1379
+					$content = ! empty($cfg['content']) ? $cfg['content'] : null;
1380
+					// second priority goes to filename
1381
+				} elseif (! empty($cfg['filename'])) {
1382
+					$file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1383
+					// it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1384
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1385
+															 . basename($this->_get_dir())
1386
+															 . '/help_tabs/'
1387
+															 . $cfg['filename']
1388
+															 . '.help_tab.php' : $file_path;
1389
+					// if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1390
+					if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1391
+						EE_Error::add_error(
1392
+							sprintf(
1393
+								esc_html__(
1394
+									'The filename given for the help tab %s is not a valid file and there is no other configuration for the tab content.  Please check that the string you set for the help tab on this route (%s) is the correct spelling.  The file should be in %s',
1395
+									'event_espresso'
1396
+								),
1397
+								$tab_id,
1398
+								key($config),
1399
+								$file_path
1400
+							),
1401
+							__FILE__,
1402
+							__FUNCTION__,
1403
+							__LINE__
1404
+						);
1405
+						return;
1406
+					}
1407
+					$template_args['admin_page_obj'] = $this;
1408
+					$content                         = EEH_Template::display_template(
1409
+						$file_path,
1410
+						$template_args,
1411
+						true
1412
+					);
1413
+				} else {
1414
+					$content = '';
1415
+				}
1416
+				// check if callback is valid
1417
+				if (
1418
+					empty($content)
1419
+					&& (
1420
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1421
+					)
1422
+				) {
1423
+					EE_Error::add_error(
1424
+						sprintf(
1425
+							esc_html__(
1426
+								'The callback given for a %s help tab on this page does not content OR a corresponding method for generating the content.  Check the spelling or make sure the method is present.',
1427
+								'event_espresso'
1428
+							),
1429
+							$cfg['title']
1430
+						),
1431
+						__FILE__,
1432
+						__FUNCTION__,
1433
+						__LINE__
1434
+					);
1435
+					return;
1436
+				}
1437
+				// setup config array for help tab method
1438
+				$id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1439
+				$_ht = [
1440
+					'id'       => $id,
1441
+					'title'    => $cfg['title'],
1442
+					'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1443
+					'content'  => $content,
1444
+				];
1445
+				$this->_current_screen->add_help_tab($_ht);
1446
+			}
1447
+		}
1448
+	}
1449
+
1450
+
1451
+	/**
1452
+	 * This simply sets up any qtips that have been defined in the page config
1453
+	 *
1454
+	 * @return void
1455
+	 * @throws ReflectionException
1456
+	 * @throws EE_Error
1457
+	 */
1458
+	protected function _add_qtips()
1459
+	{
1460
+		if (isset($this->_route_config['qtips'])) {
1461
+			$qtips = (array) $this->_route_config['qtips'];
1462
+			// load qtip loader
1463
+			$path = [
1464
+				$this->_get_dir() . '/qtips/',
1465
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1466
+			];
1467
+			EEH_Qtip_Loader::instance()->register($qtips, $path);
1468
+		}
1469
+	}
1470
+
1471
+
1472
+	/**
1473
+	 * _set_nav_tabs
1474
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1475
+	 * wish to add additional tabs or modify accordingly.
1476
+	 *
1477
+	 * @return void
1478
+	 * @throws InvalidArgumentException
1479
+	 * @throws InvalidInterfaceException
1480
+	 * @throws InvalidDataTypeException
1481
+	 */
1482
+	protected function _set_nav_tabs()
1483
+	{
1484
+		$i        = 0;
1485
+		$only_tab = count($this->_page_config) < 2;
1486
+		foreach ($this->_page_config as $slug => $config) {
1487
+			if (! is_array($config) || empty($config['nav'])) {
1488
+				continue;
1489
+			}
1490
+			// no nav tab for this config
1491
+			// check for persistent flag
1492
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1493
+				// nav tab is only to appear when route requested.
1494
+				continue;
1495
+			}
1496
+			if (! $this->check_user_access($slug, true)) {
1497
+				// no nav tab because current user does not have access.
1498
+				continue;
1499
+			}
1500
+			$css_class = $config['css_class'] ?? '';
1501
+			$css_class .= $only_tab ? ' ee-only-tab' : '';
1502
+			$css_class .= " ee-nav-tab__$slug";
1503
+
1504
+			$this->_nav_tabs[ $slug ] = [
1505
+				'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1506
+						['action' => $slug],
1507
+						$this->_admin_base_url
1508
+					),
1509
+				'link_text' => $this->navTabLabel($config['nav'], $slug),
1510
+				'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1511
+				'order'     => $config['nav']['order'] ?? $i,
1512
+			];
1513
+			$i++;
1514
+		}
1515
+		// if $this->_nav_tabs is empty then lets set the default
1516
+		if (empty($this->_nav_tabs)) {
1517
+			$this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1518
+				'url'       => $this->_admin_base_url,
1519
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1520
+				'css_class' => 'nav-tab-active',
1521
+				'order'     => 10,
1522
+			];
1523
+		}
1524
+		// now let's sort the tabs according to order
1525
+		usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1526
+	}
1527
+
1528
+
1529
+	private function navTabLabel(array $nav_tab, string $slug): string
1530
+	{
1531
+		$label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1532
+		$icon  = $nav_tab['icon'] ?? null;
1533
+		$icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1534
+		return '
1535 1535
             <span class="ee-admin-screen-tab__label">
1536 1536
                 ' . $icon . '
1537 1537
                 <span class="ee-nav-label__text">' . $label . '</span>
1538 1538
             </span>';
1539
-    }
1540
-
1541
-
1542
-    /**
1543
-     * _set_current_labels
1544
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1545
-     * property array
1546
-     *
1547
-     * @return void
1548
-     */
1549
-    private function _set_current_labels()
1550
-    {
1551
-        if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1552
-            foreach ($this->_route_config['labels'] as $label => $text) {
1553
-                if (is_array($text)) {
1554
-                    foreach ($text as $sublabel => $subtext) {
1555
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1556
-                    }
1557
-                } else {
1558
-                    $this->_labels[ $label ] = $text;
1559
-                }
1560
-            }
1561
-        }
1562
-    }
1563
-
1564
-
1565
-    /**
1566
-     *        verifies user access for this admin page
1567
-     *
1568
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1569
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1570
-     *                               return false if verify fail.
1571
-     * @return bool
1572
-     * @throws InvalidArgumentException
1573
-     * @throws InvalidDataTypeException
1574
-     * @throws InvalidInterfaceException
1575
-     */
1576
-    public function check_user_access($route_to_check = '', $verify_only = false)
1577
-    {
1578
-        $route_to_check = ! empty($route_to_check) ? $route_to_check : $this->_req_action;
1579
-        $capability     = ! empty($route_to_check)
1580
-                          && isset($this->_page_routes[ $route_to_check ])
1581
-                          && is_array($this->_page_routes[ $route_to_check ])
1582
-                          && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1583
-            ? $this->_page_routes[ $route_to_check ]['capability']
1584
-            : null;
1585
-
1586
-        if (empty($capability) && empty($route_to_check)) {
1587
-            $capability = ! empty($this->_route['capability']) ? $this->_route['capability'] : 'manage_options';
1588
-        } else {
1589
-            $capability = empty($capability) ? 'manage_options' : $capability;
1590
-        }
1591
-
1592
-        $id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1593
-
1594
-        if (
1595
-            ! $this->request->isAjax()
1596
-            && (
1597
-                ! function_exists('is_admin')
1598
-                || ! EE_Registry::instance()->CAP->current_user_can(
1599
-                    $capability,
1600
-                    "{$this->page_slug}_$route_to_check",
1601
-                    $id
1602
-                )
1603
-            )
1604
-        ) {
1605
-            if ($verify_only) {
1606
-                return false;
1607
-            }
1608
-            if (is_user_logged_in()) {
1609
-                wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1610
-            }
1611
-            return false;
1612
-        }
1613
-        return true;
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     * @param string                 $box_id
1619
-     * @param string                 $title
1620
-     * @param callable|string|null   $callback
1621
-     * @param string|array|WP_Screen $screen
1622
-     * @param string                 $context
1623
-     * @param string                 $priority
1624
-     * @param array|null             $callback_args
1625
-     */
1626
-    protected function addMetaBox(
1627
-        string $box_id,
1628
-        string $title,
1629
-        $callback,
1630
-        $screen,
1631
-        string $context = 'normal',
1632
-        string $priority = 'default',
1633
-        ?array $callback_args = null
1634
-    ) {
1635
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1636
-            return;
1637
-        }
1638
-
1639
-        add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1640
-        add_filter(
1641
-            "postbox_classes_{$this->_wp_page_slug}_{$box_id}",
1642
-            function ($classes) {
1643
-                $classes[] = 'ee-admin-container';
1644
-                return $classes;
1645
-            }
1646
-        );
1647
-    }
1648
-
1649
-
1650
-    /**
1651
-     * admin_init_global
1652
-     * This runs all the code that we want executed within the WP admin_init hook.
1653
-     * This method executes for ALL EE Admin pages.
1654
-     *
1655
-     * @return void
1656
-     */
1657
-    public function admin_init_global()
1658
-    {
1659
-    }
1660
-
1661
-
1662
-    /**
1663
-     * wp_loaded_global
1664
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1665
-     * EE_Admin page and will execute on every EE Admin Page load
1666
-     *
1667
-     * @return void
1668
-     */
1669
-    public function wp_loaded()
1670
-    {
1671
-    }
1672
-
1673
-
1674
-    /**
1675
-     * admin_notices
1676
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1677
-     * ALL EE_Admin pages.
1678
-     *
1679
-     * @return void
1680
-     */
1681
-    public function admin_notices_global()
1682
-    {
1683
-        $this->_display_no_javascript_warning();
1684
-        $this->_display_espresso_notices();
1685
-    }
1686
-
1687
-
1688
-    public function network_admin_notices_global()
1689
-    {
1690
-        $this->_display_no_javascript_warning();
1691
-        $this->_display_espresso_notices();
1692
-    }
1693
-
1694
-
1695
-    /**
1696
-     * admin_footer_scripts_global
1697
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1698
-     * will apply on ALL EE_Admin pages.
1699
-     *
1700
-     * @return void
1701
-     */
1702
-    public function admin_footer_scripts_global()
1703
-    {
1704
-        $this->_add_admin_page_ajax_loading_img();
1705
-        $this->_add_admin_page_overlay();
1706
-        // if metaboxes are present we need to add the nonce field
1707
-        if (
1708
-            isset($this->_route_config['metaboxes'])
1709
-            || isset($this->_route_config['list_table'])
1710
-            || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1711
-        ) {
1712
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1713
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1714
-        }
1715
-    }
1716
-
1717
-
1718
-    /**
1719
-     * admin_footer_global
1720
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1721
-     * This particular method will apply on ALL EE_Admin Pages.
1722
-     *
1723
-     * @return void
1724
-     */
1725
-    public function admin_footer_global()
1726
-    {
1727
-        // dialog container for dialog helper
1728
-        echo '
1539
+	}
1540
+
1541
+
1542
+	/**
1543
+	 * _set_current_labels
1544
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1545
+	 * property array
1546
+	 *
1547
+	 * @return void
1548
+	 */
1549
+	private function _set_current_labels()
1550
+	{
1551
+		if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1552
+			foreach ($this->_route_config['labels'] as $label => $text) {
1553
+				if (is_array($text)) {
1554
+					foreach ($text as $sublabel => $subtext) {
1555
+						$this->_labels[ $label ][ $sublabel ] = $subtext;
1556
+					}
1557
+				} else {
1558
+					$this->_labels[ $label ] = $text;
1559
+				}
1560
+			}
1561
+		}
1562
+	}
1563
+
1564
+
1565
+	/**
1566
+	 *        verifies user access for this admin page
1567
+	 *
1568
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1569
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1570
+	 *                               return false if verify fail.
1571
+	 * @return bool
1572
+	 * @throws InvalidArgumentException
1573
+	 * @throws InvalidDataTypeException
1574
+	 * @throws InvalidInterfaceException
1575
+	 */
1576
+	public function check_user_access($route_to_check = '', $verify_only = false)
1577
+	{
1578
+		$route_to_check = ! empty($route_to_check) ? $route_to_check : $this->_req_action;
1579
+		$capability     = ! empty($route_to_check)
1580
+						  && isset($this->_page_routes[ $route_to_check ])
1581
+						  && is_array($this->_page_routes[ $route_to_check ])
1582
+						  && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1583
+			? $this->_page_routes[ $route_to_check ]['capability']
1584
+			: null;
1585
+
1586
+		if (empty($capability) && empty($route_to_check)) {
1587
+			$capability = ! empty($this->_route['capability']) ? $this->_route['capability'] : 'manage_options';
1588
+		} else {
1589
+			$capability = empty($capability) ? 'manage_options' : $capability;
1590
+		}
1591
+
1592
+		$id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1593
+
1594
+		if (
1595
+			! $this->request->isAjax()
1596
+			&& (
1597
+				! function_exists('is_admin')
1598
+				|| ! EE_Registry::instance()->CAP->current_user_can(
1599
+					$capability,
1600
+					"{$this->page_slug}_$route_to_check",
1601
+					$id
1602
+				)
1603
+			)
1604
+		) {
1605
+			if ($verify_only) {
1606
+				return false;
1607
+			}
1608
+			if (is_user_logged_in()) {
1609
+				wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1610
+			}
1611
+			return false;
1612
+		}
1613
+		return true;
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 * @param string                 $box_id
1619
+	 * @param string                 $title
1620
+	 * @param callable|string|null   $callback
1621
+	 * @param string|array|WP_Screen $screen
1622
+	 * @param string                 $context
1623
+	 * @param string                 $priority
1624
+	 * @param array|null             $callback_args
1625
+	 */
1626
+	protected function addMetaBox(
1627
+		string $box_id,
1628
+		string $title,
1629
+		$callback,
1630
+		$screen,
1631
+		string $context = 'normal',
1632
+		string $priority = 'default',
1633
+		?array $callback_args = null
1634
+	) {
1635
+		if (! (is_callable($callback) || ! function_exists($callback))) {
1636
+			return;
1637
+		}
1638
+
1639
+		add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1640
+		add_filter(
1641
+			"postbox_classes_{$this->_wp_page_slug}_{$box_id}",
1642
+			function ($classes) {
1643
+				$classes[] = 'ee-admin-container';
1644
+				return $classes;
1645
+			}
1646
+		);
1647
+	}
1648
+
1649
+
1650
+	/**
1651
+	 * admin_init_global
1652
+	 * This runs all the code that we want executed within the WP admin_init hook.
1653
+	 * This method executes for ALL EE Admin pages.
1654
+	 *
1655
+	 * @return void
1656
+	 */
1657
+	public function admin_init_global()
1658
+	{
1659
+	}
1660
+
1661
+
1662
+	/**
1663
+	 * wp_loaded_global
1664
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1665
+	 * EE_Admin page and will execute on every EE Admin Page load
1666
+	 *
1667
+	 * @return void
1668
+	 */
1669
+	public function wp_loaded()
1670
+	{
1671
+	}
1672
+
1673
+
1674
+	/**
1675
+	 * admin_notices
1676
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1677
+	 * ALL EE_Admin pages.
1678
+	 *
1679
+	 * @return void
1680
+	 */
1681
+	public function admin_notices_global()
1682
+	{
1683
+		$this->_display_no_javascript_warning();
1684
+		$this->_display_espresso_notices();
1685
+	}
1686
+
1687
+
1688
+	public function network_admin_notices_global()
1689
+	{
1690
+		$this->_display_no_javascript_warning();
1691
+		$this->_display_espresso_notices();
1692
+	}
1693
+
1694
+
1695
+	/**
1696
+	 * admin_footer_scripts_global
1697
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1698
+	 * will apply on ALL EE_Admin pages.
1699
+	 *
1700
+	 * @return void
1701
+	 */
1702
+	public function admin_footer_scripts_global()
1703
+	{
1704
+		$this->_add_admin_page_ajax_loading_img();
1705
+		$this->_add_admin_page_overlay();
1706
+		// if metaboxes are present we need to add the nonce field
1707
+		if (
1708
+			isset($this->_route_config['metaboxes'])
1709
+			|| isset($this->_route_config['list_table'])
1710
+			|| (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1711
+		) {
1712
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1713
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1714
+		}
1715
+	}
1716
+
1717
+
1718
+	/**
1719
+	 * admin_footer_global
1720
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1721
+	 * This particular method will apply on ALL EE_Admin Pages.
1722
+	 *
1723
+	 * @return void
1724
+	 */
1725
+	public function admin_footer_global()
1726
+	{
1727
+		// dialog container for dialog helper
1728
+		echo '
1729 1729
         <div class="ee-admin-dialog-container auto-hide hidden">
1730 1730
             <div class="ee-notices"></div>
1731 1731
             <div class="ee-admin-dialog-container-inner-content"></div>
1732 1732
         </div>
1733 1733
         ';
1734 1734
 
1735
-        // current set timezone for timezone js
1736
-        echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1737
-    }
1738
-
1739
-
1740
-    /**
1741
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1742
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1743
-     * help popups then in your templates or your content you set "triggers" for the content using the
1744
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1745
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1746
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1747
-     * for the
1748
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1749
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1750
-     *    'help_trigger_id' => array(
1751
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1752
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1753
-     *    )
1754
-     * );
1755
-     * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1756
-     *
1757
-     * @param array $help_array
1758
-     * @param bool  $display
1759
-     * @return string content
1760
-     * @throws DomainException
1761
-     * @throws EE_Error
1762
-     */
1763
-    protected function _set_help_popup_content($help_array = [], $display = false)
1764
-    {
1765
-        $content    = '';
1766
-        $help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1767
-        // loop through the array and setup content
1768
-        foreach ($help_array as $trigger => $help) {
1769
-            // make sure the array is setup properly
1770
-            if (! isset($help['title'], $help['content'])) {
1771
-                throw new EE_Error(
1772
-                    esc_html__(
1773
-                        'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
1774
-                        'event_espresso'
1775
-                    )
1776
-                );
1777
-            }
1778
-            // we're good so let's setup the template vars and then assign parsed template content to our content.
1779
-            $template_args = [
1780
-                'help_popup_id'      => $trigger,
1781
-                'help_popup_title'   => $help['title'],
1782
-                'help_popup_content' => $help['content'],
1783
-            ];
1784
-            $content       .= EEH_Template::display_template(
1785
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1786
-                $template_args,
1787
-                true
1788
-            );
1789
-        }
1790
-        if ($display) {
1791
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1792
-            return '';
1793
-        }
1794
-        return $content;
1795
-    }
1796
-
1797
-
1798
-    /**
1799
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1800
-     *
1801
-     * @return array properly formatted array for help popup content
1802
-     * @throws EE_Error
1803
-     */
1804
-    private function _get_help_content()
1805
-    {
1806
-        // what is the method we're looking for?
1807
-        $method_name = '_help_popup_content_' . $this->_req_action;
1808
-        // if method doesn't exist let's get out.
1809
-        if (! method_exists($this, $method_name)) {
1810
-            return [];
1811
-        }
1812
-        // k we're good to go let's retrieve the help array
1813
-        $help_array = $this->{$method_name}();
1814
-        // make sure we've got an array!
1815
-        if (! is_array($help_array)) {
1816
-            throw new EE_Error(
1817
-                esc_html__(
1818
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1819
-                    'event_espresso'
1820
-                )
1821
-            );
1822
-        }
1823
-        return $help_array;
1824
-    }
1825
-
1826
-
1827
-    /**
1828
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1829
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1830
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1831
-     *
1832
-     * @param string  $trigger_id reference for retrieving the trigger content for the popup
1833
-     * @param boolean $display    if false then we return the trigger string
1834
-     * @param array   $dimensions an array of dimensions for the box (array(h,w))
1835
-     * @return string
1836
-     * @throws DomainException
1837
-     * @throws EE_Error
1838
-     */
1839
-    protected function _set_help_trigger($trigger_id, $display = true, $dimensions = ['400', '640'])
1840
-    {
1841
-        if ($this->request->isAjax()) {
1842
-            return '';
1843
-        }
1844
-        // let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1845
-        $help_array   = $this->_get_help_content();
1846
-        $help_content = '';
1847
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1848
-            $help_array[ $trigger_id ] = [
1849
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1850
-                'content' => esc_html__(
1851
-                    'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1852
-                    'event_espresso'
1853
-                ),
1854
-            ];
1855
-            $help_content              = $this->_set_help_popup_content($help_array);
1856
-        }
1857
-        // let's setup the trigger
1858
-        $content = '<a class="ee-dialog" href="?height='
1859
-                   . esc_attr($dimensions[0])
1860
-                   . '&width='
1861
-                   . esc_attr($dimensions[1])
1862
-                   . '&inlineId='
1863
-                   . esc_attr($trigger_id)
1864
-                   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1865
-        $content .= $help_content;
1866
-        if ($display) {
1867
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1868
-            return '';
1869
-        }
1870
-        return $content;
1871
-    }
1872
-
1873
-
1874
-    /**
1875
-     * _add_global_screen_options
1876
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1877
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1878
-     *
1879
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1880
-     *         see also WP_Screen object documents...
1881
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1882
-     * @abstract
1883
-     * @return void
1884
-     */
1885
-    private function _add_global_screen_options()
1886
-    {
1887
-    }
1888
-
1889
-
1890
-    /**
1891
-     * _add_global_feature_pointers
1892
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1893
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1894
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1895
-     *
1896
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1897
-     *         extended) also see:
1898
-     * @link   http://eamann.com/tech/wordpress-portland/
1899
-     * @abstract
1900
-     * @return void
1901
-     */
1902
-    private function _add_global_feature_pointers()
1903
-    {
1904
-    }
1905
-
1906
-
1907
-    /**
1908
-     * load_global_scripts_styles
1909
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1910
-     *
1911
-     * @return void
1912
-     */
1913
-    public function load_global_scripts_styles()
1914
-    {
1915
-        // add debugging styles
1916
-        if (WP_DEBUG) {
1917
-            add_action('admin_head', [$this, 'add_xdebug_style']);
1918
-        }
1919
-        // taking care of metaboxes
1920
-        if (
1921
-            empty($this->_cpt_route)
1922
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1923
-        ) {
1924
-            wp_enqueue_script('dashboard');
1925
-        }
1926
-
1927
-        wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1928
-        wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1929
-        // LOCALIZED DATA
1930
-        // localize script for ajax lazy loading
1931
-        wp_localize_script(
1932
-            EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1933
-            'eeLazyLoadingContainers',
1934
-            apply_filters(
1935
-                'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1936
-                ['espresso_news_post_box_content']
1937
-            )
1938
-        );
1939
-        StatusChangeNotice::loadAssets();
1940
-
1941
-        add_filter(
1942
-            'admin_body_class',
1943
-            function ($classes) {
1944
-                if (strpos($classes, 'espresso-admin') === false) {
1945
-                    $classes .= ' espresso-admin';
1946
-                }
1947
-                return $classes;
1948
-            }
1949
-        );
1950
-    }
1951
-
1952
-
1953
-    /**
1954
-     *        admin_footer_scripts_eei18n_js_strings
1955
-     *
1956
-     * @return        void
1957
-     */
1958
-    public function admin_footer_scripts_eei18n_js_strings()
1959
-    {
1960
-        EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1961
-        EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1962
-            __(
1963
-                'Are you absolutely sure you want to delete this item?\nThis action will delete ALL DATA associated with this item!!!\nThis can NOT be undone!!!',
1964
-                'event_espresso'
1965
-            )
1966
-        );
1967
-        EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1968
-        EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1969
-        EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1970
-        EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1971
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1972
-        EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1973
-        EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1974
-        EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1975
-        EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1976
-        EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1977
-        EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1978
-        EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1979
-        EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1980
-        EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1981
-        EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1982
-        EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1983
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1984
-        EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1985
-        EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1986
-        EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1987
-        EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1988
-        EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1989
-        EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1990
-        EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1991
-        EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1992
-        EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1993
-        EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1994
-        EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1995
-        EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1996
-        EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1997
-        EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1998
-        EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1999
-        EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
2000
-        EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
2001
-        EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
2002
-        EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
2003
-        EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
2004
-        EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
2005
-    }
2006
-
2007
-
2008
-    /**
2009
-     *        load enhanced xdebug styles for ppl with failing eyesight
2010
-     *
2011
-     * @return        void
2012
-     */
2013
-    public function add_xdebug_style()
2014
-    {
2015
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2016
-    }
2017
-
2018
-
2019
-    /************************/
2020
-    /** LIST TABLE METHODS **/
2021
-    /************************/
2022
-    /**
2023
-     * this sets up the list table if the current view requires it.
2024
-     *
2025
-     * @return void
2026
-     * @throws EE_Error
2027
-     * @throws InvalidArgumentException
2028
-     * @throws InvalidDataTypeException
2029
-     * @throws InvalidInterfaceException
2030
-     */
2031
-    protected function _set_list_table()
2032
-    {
2033
-        // first is this a list_table view?
2034
-        if (! isset($this->_route_config['list_table'])) {
2035
-            return;
2036
-        } //not a list_table view so get out.
2037
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
2038
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2039
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2040
-            // user error msg
2041
-            $error_msg = esc_html__(
2042
-                'An error occurred. The requested list table views could not be found.',
2043
-                'event_espresso'
2044
-            );
2045
-            // developer error msg
2046
-            $error_msg .= '||'
2047
-                          . sprintf(
2048
-                              esc_html__(
2049
-                                  'List table views for "%s" route could not be setup. Check that you have the corresponding method, "%s" set up for defining list_table_views for this route.',
2050
-                                  'event_espresso'
2051
-                              ),
2052
-                              $this->_req_action,
2053
-                              $list_table_view
2054
-                          );
2055
-            throw new EE_Error($error_msg);
2056
-        }
2057
-        // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2058
-        $this->_views = apply_filters(
2059
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2060
-            $this->_views
2061
-        );
2062
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2063
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2064
-        $this->_set_list_table_view();
2065
-        $this->_set_list_table_object();
2066
-    }
2067
-
2068
-
2069
-    /**
2070
-     * set current view for List Table
2071
-     *
2072
-     * @return void
2073
-     */
2074
-    protected function _set_list_table_view()
2075
-    {
2076
-        $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2077
-        $status      = $this->request->getRequestParam('status', null, 'key');
2078
-        $this->_view = $status && array_key_exists($status, $this->_views)
2079
-            ? $status
2080
-            : $this->_view;
2081
-    }
2082
-
2083
-
2084
-    /**
2085
-     * _set_list_table_object
2086
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2087
-     *
2088
-     * @throws InvalidInterfaceException
2089
-     * @throws InvalidArgumentException
2090
-     * @throws InvalidDataTypeException
2091
-     * @throws EE_Error
2092
-     * @throws InvalidInterfaceException
2093
-     */
2094
-    protected function _set_list_table_object()
2095
-    {
2096
-        if (isset($this->_route_config['list_table'])) {
2097
-            if (! class_exists($this->_route_config['list_table'])) {
2098
-                throw new EE_Error(
2099
-                    sprintf(
2100
-                        esc_html__(
2101
-                            'The %s class defined for the list table does not exist.  Please check the spelling of the class ref in the $_page_config property on %s.',
2102
-                            'event_espresso'
2103
-                        ),
2104
-                        $this->_route_config['list_table'],
2105
-                        $this->class_name
2106
-                    )
2107
-                );
2108
-            }
2109
-            $this->_list_table_object = $this->loader->getShared(
2110
-                $this->_route_config['list_table'],
2111
-                [
2112
-                    $this,
2113
-                    LoaderFactory::getShared(AdminListTableFilters::class)
2114
-                ]
2115
-            );
2116
-        }
2117
-    }
2118
-
2119
-
2120
-    /**
2121
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2122
-     *
2123
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2124
-     *                                                    urls.  The array should be indexed by the view it is being
2125
-     *                                                    added to.
2126
-     * @return array
2127
-     */
2128
-    public function get_list_table_view_RLs($extra_query_args = [])
2129
-    {
2130
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2131
-        if (empty($this->_views)) {
2132
-            $this->_views = [];
2133
-        }
2134
-        // cycle thru views
2135
-        foreach ($this->_views as $key => $view) {
2136
-            $query_args = [];
2137
-            // check for current view
2138
-            $this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2139
-            $query_args['action']                        = $this->_req_action;
2140
-            $query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2141
-            $query_args['status']                        = $view['slug'];
2142
-            // merge any other arguments sent in.
2143
-            if (isset($extra_query_args[ $view['slug'] ])) {
2144
-                foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2145
-                    $query_args[] = $extra_query_arg;
2146
-                }
2147
-            }
2148
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2149
-        }
2150
-        return $this->_views;
2151
-    }
2152
-
2153
-
2154
-    /**
2155
-     * _entries_per_page_dropdown
2156
-     * generates a dropdown box for selecting the number of visible rows in an admin page list table
2157
-     *
2158
-     * @param int $max_entries total number of rows in the table
2159
-     * @return string
2160
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2161
-     *                         WP does it.
2162
-     */
2163
-    protected function _entries_per_page_dropdown($max_entries = 0)
2164
-    {
2165
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2166
-        $values   = [10, 25, 50, 100];
2167
-        $per_page = $this->request->getRequestParam('per_page', 10, 'int');
2168
-        if ($max_entries) {
2169
-            $values[] = $max_entries;
2170
-            sort($values);
2171
-        }
2172
-        $entries_per_page_dropdown = '
1735
+		// current set timezone for timezone js
1736
+		echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1737
+	}
1738
+
1739
+
1740
+	/**
1741
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1742
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1743
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1744
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1745
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1746
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1747
+	 * for the
1748
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1749
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1750
+	 *    'help_trigger_id' => array(
1751
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1752
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1753
+	 *    )
1754
+	 * );
1755
+	 * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1756
+	 *
1757
+	 * @param array $help_array
1758
+	 * @param bool  $display
1759
+	 * @return string content
1760
+	 * @throws DomainException
1761
+	 * @throws EE_Error
1762
+	 */
1763
+	protected function _set_help_popup_content($help_array = [], $display = false)
1764
+	{
1765
+		$content    = '';
1766
+		$help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1767
+		// loop through the array and setup content
1768
+		foreach ($help_array as $trigger => $help) {
1769
+			// make sure the array is setup properly
1770
+			if (! isset($help['title'], $help['content'])) {
1771
+				throw new EE_Error(
1772
+					esc_html__(
1773
+						'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
1774
+						'event_espresso'
1775
+					)
1776
+				);
1777
+			}
1778
+			// we're good so let's setup the template vars and then assign parsed template content to our content.
1779
+			$template_args = [
1780
+				'help_popup_id'      => $trigger,
1781
+				'help_popup_title'   => $help['title'],
1782
+				'help_popup_content' => $help['content'],
1783
+			];
1784
+			$content       .= EEH_Template::display_template(
1785
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1786
+				$template_args,
1787
+				true
1788
+			);
1789
+		}
1790
+		if ($display) {
1791
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1792
+			return '';
1793
+		}
1794
+		return $content;
1795
+	}
1796
+
1797
+
1798
+	/**
1799
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1800
+	 *
1801
+	 * @return array properly formatted array for help popup content
1802
+	 * @throws EE_Error
1803
+	 */
1804
+	private function _get_help_content()
1805
+	{
1806
+		// what is the method we're looking for?
1807
+		$method_name = '_help_popup_content_' . $this->_req_action;
1808
+		// if method doesn't exist let's get out.
1809
+		if (! method_exists($this, $method_name)) {
1810
+			return [];
1811
+		}
1812
+		// k we're good to go let's retrieve the help array
1813
+		$help_array = $this->{$method_name}();
1814
+		// make sure we've got an array!
1815
+		if (! is_array($help_array)) {
1816
+			throw new EE_Error(
1817
+				esc_html__(
1818
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1819
+					'event_espresso'
1820
+				)
1821
+			);
1822
+		}
1823
+		return $help_array;
1824
+	}
1825
+
1826
+
1827
+	/**
1828
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1829
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1830
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1831
+	 *
1832
+	 * @param string  $trigger_id reference for retrieving the trigger content for the popup
1833
+	 * @param boolean $display    if false then we return the trigger string
1834
+	 * @param array   $dimensions an array of dimensions for the box (array(h,w))
1835
+	 * @return string
1836
+	 * @throws DomainException
1837
+	 * @throws EE_Error
1838
+	 */
1839
+	protected function _set_help_trigger($trigger_id, $display = true, $dimensions = ['400', '640'])
1840
+	{
1841
+		if ($this->request->isAjax()) {
1842
+			return '';
1843
+		}
1844
+		// let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1845
+		$help_array   = $this->_get_help_content();
1846
+		$help_content = '';
1847
+		if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1848
+			$help_array[ $trigger_id ] = [
1849
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1850
+				'content' => esc_html__(
1851
+					'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1852
+					'event_espresso'
1853
+				),
1854
+			];
1855
+			$help_content              = $this->_set_help_popup_content($help_array);
1856
+		}
1857
+		// let's setup the trigger
1858
+		$content = '<a class="ee-dialog" href="?height='
1859
+				   . esc_attr($dimensions[0])
1860
+				   . '&width='
1861
+				   . esc_attr($dimensions[1])
1862
+				   . '&inlineId='
1863
+				   . esc_attr($trigger_id)
1864
+				   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1865
+		$content .= $help_content;
1866
+		if ($display) {
1867
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1868
+			return '';
1869
+		}
1870
+		return $content;
1871
+	}
1872
+
1873
+
1874
+	/**
1875
+	 * _add_global_screen_options
1876
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1877
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1878
+	 *
1879
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1880
+	 *         see also WP_Screen object documents...
1881
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1882
+	 * @abstract
1883
+	 * @return void
1884
+	 */
1885
+	private function _add_global_screen_options()
1886
+	{
1887
+	}
1888
+
1889
+
1890
+	/**
1891
+	 * _add_global_feature_pointers
1892
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1893
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1894
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1895
+	 *
1896
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1897
+	 *         extended) also see:
1898
+	 * @link   http://eamann.com/tech/wordpress-portland/
1899
+	 * @abstract
1900
+	 * @return void
1901
+	 */
1902
+	private function _add_global_feature_pointers()
1903
+	{
1904
+	}
1905
+
1906
+
1907
+	/**
1908
+	 * load_global_scripts_styles
1909
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1910
+	 *
1911
+	 * @return void
1912
+	 */
1913
+	public function load_global_scripts_styles()
1914
+	{
1915
+		// add debugging styles
1916
+		if (WP_DEBUG) {
1917
+			add_action('admin_head', [$this, 'add_xdebug_style']);
1918
+		}
1919
+		// taking care of metaboxes
1920
+		if (
1921
+			empty($this->_cpt_route)
1922
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1923
+		) {
1924
+			wp_enqueue_script('dashboard');
1925
+		}
1926
+
1927
+		wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1928
+		wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1929
+		// LOCALIZED DATA
1930
+		// localize script for ajax lazy loading
1931
+		wp_localize_script(
1932
+			EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1933
+			'eeLazyLoadingContainers',
1934
+			apply_filters(
1935
+				'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1936
+				['espresso_news_post_box_content']
1937
+			)
1938
+		);
1939
+		StatusChangeNotice::loadAssets();
1940
+
1941
+		add_filter(
1942
+			'admin_body_class',
1943
+			function ($classes) {
1944
+				if (strpos($classes, 'espresso-admin') === false) {
1945
+					$classes .= ' espresso-admin';
1946
+				}
1947
+				return $classes;
1948
+			}
1949
+		);
1950
+	}
1951
+
1952
+
1953
+	/**
1954
+	 *        admin_footer_scripts_eei18n_js_strings
1955
+	 *
1956
+	 * @return        void
1957
+	 */
1958
+	public function admin_footer_scripts_eei18n_js_strings()
1959
+	{
1960
+		EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1961
+		EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1962
+			__(
1963
+				'Are you absolutely sure you want to delete this item?\nThis action will delete ALL DATA associated with this item!!!\nThis can NOT be undone!!!',
1964
+				'event_espresso'
1965
+			)
1966
+		);
1967
+		EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1968
+		EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1969
+		EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1970
+		EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1971
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1972
+		EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1973
+		EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1974
+		EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1975
+		EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1976
+		EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1977
+		EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1978
+		EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1979
+		EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1980
+		EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1981
+		EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1982
+		EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1983
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1984
+		EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1985
+		EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1986
+		EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1987
+		EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1988
+		EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1989
+		EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1990
+		EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1991
+		EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1992
+		EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1993
+		EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1994
+		EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1995
+		EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1996
+		EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1997
+		EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1998
+		EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1999
+		EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
2000
+		EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
2001
+		EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
2002
+		EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
2003
+		EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
2004
+		EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
2005
+	}
2006
+
2007
+
2008
+	/**
2009
+	 *        load enhanced xdebug styles for ppl with failing eyesight
2010
+	 *
2011
+	 * @return        void
2012
+	 */
2013
+	public function add_xdebug_style()
2014
+	{
2015
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2016
+	}
2017
+
2018
+
2019
+	/************************/
2020
+	/** LIST TABLE METHODS **/
2021
+	/************************/
2022
+	/**
2023
+	 * this sets up the list table if the current view requires it.
2024
+	 *
2025
+	 * @return void
2026
+	 * @throws EE_Error
2027
+	 * @throws InvalidArgumentException
2028
+	 * @throws InvalidDataTypeException
2029
+	 * @throws InvalidInterfaceException
2030
+	 */
2031
+	protected function _set_list_table()
2032
+	{
2033
+		// first is this a list_table view?
2034
+		if (! isset($this->_route_config['list_table'])) {
2035
+			return;
2036
+		} //not a list_table view so get out.
2037
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
2038
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
2039
+		if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2040
+			// user error msg
2041
+			$error_msg = esc_html__(
2042
+				'An error occurred. The requested list table views could not be found.',
2043
+				'event_espresso'
2044
+			);
2045
+			// developer error msg
2046
+			$error_msg .= '||'
2047
+						  . sprintf(
2048
+							  esc_html__(
2049
+								  'List table views for "%s" route could not be setup. Check that you have the corresponding method, "%s" set up for defining list_table_views for this route.',
2050
+								  'event_espresso'
2051
+							  ),
2052
+							  $this->_req_action,
2053
+							  $list_table_view
2054
+						  );
2055
+			throw new EE_Error($error_msg);
2056
+		}
2057
+		// let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2058
+		$this->_views = apply_filters(
2059
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2060
+			$this->_views
2061
+		);
2062
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2063
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2064
+		$this->_set_list_table_view();
2065
+		$this->_set_list_table_object();
2066
+	}
2067
+
2068
+
2069
+	/**
2070
+	 * set current view for List Table
2071
+	 *
2072
+	 * @return void
2073
+	 */
2074
+	protected function _set_list_table_view()
2075
+	{
2076
+		$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2077
+		$status      = $this->request->getRequestParam('status', null, 'key');
2078
+		$this->_view = $status && array_key_exists($status, $this->_views)
2079
+			? $status
2080
+			: $this->_view;
2081
+	}
2082
+
2083
+
2084
+	/**
2085
+	 * _set_list_table_object
2086
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2087
+	 *
2088
+	 * @throws InvalidInterfaceException
2089
+	 * @throws InvalidArgumentException
2090
+	 * @throws InvalidDataTypeException
2091
+	 * @throws EE_Error
2092
+	 * @throws InvalidInterfaceException
2093
+	 */
2094
+	protected function _set_list_table_object()
2095
+	{
2096
+		if (isset($this->_route_config['list_table'])) {
2097
+			if (! class_exists($this->_route_config['list_table'])) {
2098
+				throw new EE_Error(
2099
+					sprintf(
2100
+						esc_html__(
2101
+							'The %s class defined for the list table does not exist.  Please check the spelling of the class ref in the $_page_config property on %s.',
2102
+							'event_espresso'
2103
+						),
2104
+						$this->_route_config['list_table'],
2105
+						$this->class_name
2106
+					)
2107
+				);
2108
+			}
2109
+			$this->_list_table_object = $this->loader->getShared(
2110
+				$this->_route_config['list_table'],
2111
+				[
2112
+					$this,
2113
+					LoaderFactory::getShared(AdminListTableFilters::class)
2114
+				]
2115
+			);
2116
+		}
2117
+	}
2118
+
2119
+
2120
+	/**
2121
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2122
+	 *
2123
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2124
+	 *                                                    urls.  The array should be indexed by the view it is being
2125
+	 *                                                    added to.
2126
+	 * @return array
2127
+	 */
2128
+	public function get_list_table_view_RLs($extra_query_args = [])
2129
+	{
2130
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2131
+		if (empty($this->_views)) {
2132
+			$this->_views = [];
2133
+		}
2134
+		// cycle thru views
2135
+		foreach ($this->_views as $key => $view) {
2136
+			$query_args = [];
2137
+			// check for current view
2138
+			$this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2139
+			$query_args['action']                        = $this->_req_action;
2140
+			$query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2141
+			$query_args['status']                        = $view['slug'];
2142
+			// merge any other arguments sent in.
2143
+			if (isset($extra_query_args[ $view['slug'] ])) {
2144
+				foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2145
+					$query_args[] = $extra_query_arg;
2146
+				}
2147
+			}
2148
+			$this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2149
+		}
2150
+		return $this->_views;
2151
+	}
2152
+
2153
+
2154
+	/**
2155
+	 * _entries_per_page_dropdown
2156
+	 * generates a dropdown box for selecting the number of visible rows in an admin page list table
2157
+	 *
2158
+	 * @param int $max_entries total number of rows in the table
2159
+	 * @return string
2160
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2161
+	 *                         WP does it.
2162
+	 */
2163
+	protected function _entries_per_page_dropdown($max_entries = 0)
2164
+	{
2165
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2166
+		$values   = [10, 25, 50, 100];
2167
+		$per_page = $this->request->getRequestParam('per_page', 10, 'int');
2168
+		if ($max_entries) {
2169
+			$values[] = $max_entries;
2170
+			sort($values);
2171
+		}
2172
+		$entries_per_page_dropdown = '
2173 2173
 			<div id="entries-per-page-dv" class="alignleft actions">
2174 2174
 				<label class="hide-if-no-js">
2175 2175
 					Show
2176 2176
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2177
-        foreach ($values as $value) {
2178
-            if ($value < $max_entries) {
2179
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2180
-                $entries_per_page_dropdown .= '
2177
+		foreach ($values as $value) {
2178
+			if ($value < $max_entries) {
2179
+				$selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2180
+				$entries_per_page_dropdown .= '
2181 2181
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2182
-            }
2183
-        }
2184
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2185
-        $entries_per_page_dropdown .= '
2182
+			}
2183
+		}
2184
+		$selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2185
+		$entries_per_page_dropdown .= '
2186 2186
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2187
-        $entries_per_page_dropdown .= '
2187
+		$entries_per_page_dropdown .= '
2188 2188
 					</select>
2189 2189
 					entries
2190 2190
 				</label>
2191 2191
 				<input id="entries-per-page-btn" class="button button--secondary" type="submit" value="Go" >
2192 2192
 			</div>
2193 2193
 		';
2194
-        return $entries_per_page_dropdown;
2195
-    }
2196
-
2197
-
2198
-    /**
2199
-     *        _set_search_attributes
2200
-     *
2201
-     * @return        void
2202
-     */
2203
-    public function _set_search_attributes()
2204
-    {
2205
-        $this->_template_args['search']['btn_label'] = sprintf(
2206
-            esc_html__('Search %s', 'event_espresso'),
2207
-            empty($this->_search_btn_label) ? $this->page_label
2208
-                : $this->_search_btn_label
2209
-        );
2210
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2211
-    }
2212
-
2213
-
2214
-
2215
-    /*** END LIST TABLE METHODS **/
2216
-
2217
-    /**
2218
-     * @return void
2219
-     * @throws EE_Error
2220
-     */
2221
-    public function addRegisteredMetaBoxes()
2222
-    {
2223
-        remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2224
-        $this->_add_registered_meta_boxes();
2225
-    }
2226
-
2227
-
2228
-    /**
2229
-     * _add_registered_metaboxes
2230
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2231
-     *
2232
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2233
-     * @return void
2234
-     * @throws EE_Error
2235
-     */
2236
-    private function _add_registered_meta_boxes()
2237
-    {
2238
-        // we only add meta boxes if the page_route calls for it
2239
-        if (
2240
-            is_array($this->_route_config)
2241
-            && isset($this->_route_config['metaboxes'])
2242
-            && is_array($this->_route_config['metaboxes'])
2243
-        ) {
2244
-            // this simply loops through the callbacks provided
2245
-            // and checks if there is a corresponding callback registered by the child
2246
-            // if there is then we go ahead and process the metabox loader.
2247
-            foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2248
-                // first check for Closures
2249
-                if ($metabox_callback instanceof Closure) {
2250
-                    $result = $metabox_callback();
2251
-                } elseif (is_callable($metabox_callback)) {
2252
-                    $result = call_user_func($metabox_callback);
2253
-                } elseif (method_exists($this, $metabox_callback)) {
2254
-                    $result = $this->{$metabox_callback}();
2255
-                } else {
2256
-                    $result = false;
2257
-                }
2258
-                if ($result === false) {
2259
-                    // user error msg
2260
-                    $error_msg = esc_html__(
2261
-                        'An error occurred. The  requested metabox could not be found.',
2262
-                        'event_espresso'
2263
-                    );
2264
-                    // developer error msg
2265
-                    $error_msg .= '||'
2266
-                                  . sprintf(
2267
-                                      esc_html__(
2268
-                                          'The metabox with the string "%s" could not be called. Check that the spelling for method names and actions in the "_page_config[\'metaboxes\']" array are all correct.',
2269
-                                          'event_espresso'
2270
-                                      ),
2271
-                                      $metabox_callback
2272
-                                  );
2273
-                    throw new EE_Error($error_msg);
2274
-                }
2275
-                unset($this->_route_config['metaboxes'][ $key ]);
2276
-            }
2277
-        }
2278
-    }
2279
-
2280
-
2281
-    /**
2282
-     * _add_screen_columns
2283
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2284
-     * the dynamic column template and we'll setup the column options for the page.
2285
-     *
2286
-     * @return void
2287
-     */
2288
-    private function _add_screen_columns()
2289
-    {
2290
-        if (
2291
-            is_array($this->_route_config)
2292
-            && isset($this->_route_config['columns'])
2293
-            && is_array($this->_route_config['columns'])
2294
-            && count($this->_route_config['columns']) === 2
2295
-        ) {
2296
-            add_screen_option(
2297
-                'layout_columns',
2298
-                [
2299
-                    'max'     => (int) $this->_route_config['columns'][0],
2300
-                    'default' => (int) $this->_route_config['columns'][1],
2301
-                ]
2302
-            );
2303
-            $this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2304
-            $screen_id                                           = $this->_current_screen->id;
2305
-            $screen_columns                                      = (int) get_user_option("screen_layout_{$screen_id}");
2306
-            $total_columns                                       = ! empty($screen_columns)
2307
-                ? $screen_columns
2308
-                : $this->_route_config['columns'][1];
2309
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2310
-            $this->_template_args['current_page']                = $this->_wp_page_slug;
2311
-            $this->_template_args['screen']                      = $this->_current_screen;
2312
-            $this->_column_template_path                         = EE_ADMIN_TEMPLATE
2313
-                                                                   . 'admin_details_metabox_column_wrapper.template.php';
2314
-            // finally if we don't have has_metaboxes set in the route config
2315
-            // let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2316
-            $this->_route_config['has_metaboxes'] = true;
2317
-        }
2318
-    }
2319
-
2320
-
2321
-
2322
-    /** GLOBALLY AVAILABLE METABOXES **/
2323
-
2324
-
2325
-    /**
2326
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2327
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2328
-     * these get loaded on.
2329
-     */
2330
-    private function _espresso_news_post_box()
2331
-    {
2332
-        $news_box_title = apply_filters(
2333
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2334
-            esc_html__('New @ Event Espresso', 'event_espresso')
2335
-        );
2336
-        $this->addMetaBox(
2337
-            'espresso_news_post_box',
2338
-            $news_box_title,
2339
-            [
2340
-                $this,
2341
-                'espresso_news_post_box',
2342
-            ],
2343
-            $this->_wp_page_slug,
2344
-            'side',
2345
-            'low'
2346
-        );
2347
-    }
2348
-
2349
-
2350
-    /**
2351
-     * Code for setting up espresso ratings request metabox.
2352
-     */
2353
-    protected function _espresso_ratings_request()
2354
-    {
2355
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2356
-            return;
2357
-        }
2358
-        $ratings_box_title = apply_filters(
2359
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2360
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2361
-        );
2362
-        $this->addMetaBox(
2363
-            'espresso_ratings_request',
2364
-            $ratings_box_title,
2365
-            [
2366
-                $this,
2367
-                'espresso_ratings_request',
2368
-            ],
2369
-            $this->_wp_page_slug,
2370
-            'side'
2371
-        );
2372
-    }
2373
-
2374
-
2375
-    /**
2376
-     * Code for setting up espresso ratings request metabox content.
2377
-     *
2378
-     * @throws DomainException
2379
-     */
2380
-    public function espresso_ratings_request()
2381
-    {
2382
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2383
-    }
2384
-
2385
-
2386
-    public static function cached_rss_display($rss_id, $url)
2387
-    {
2388
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2389
-                     . esc_html__('Loading&#8230;', 'event_espresso')
2390
-                     . '</p><p class="hide-if-js">'
2391
-                     . esc_html__('This widget requires JavaScript.', 'event_espresso')
2392
-                     . '</p>';
2393
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2394
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2395
-        $post      = '</div>' . "\n";
2396
-        $cache_key = 'ee_rss_' . md5($rss_id);
2397
-        $output    = get_transient($cache_key);
2398
-        if ($output !== false) {
2399
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2400
-            return true;
2401
-        }
2402
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2403
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2404
-            return false;
2405
-        }
2406
-        ob_start();
2407
-        wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2408
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2409
-        return true;
2410
-    }
2411
-
2412
-
2413
-    public function espresso_news_post_box()
2414
-    {
2415
-        ?>
2194
+		return $entries_per_page_dropdown;
2195
+	}
2196
+
2197
+
2198
+	/**
2199
+	 *        _set_search_attributes
2200
+	 *
2201
+	 * @return        void
2202
+	 */
2203
+	public function _set_search_attributes()
2204
+	{
2205
+		$this->_template_args['search']['btn_label'] = sprintf(
2206
+			esc_html__('Search %s', 'event_espresso'),
2207
+			empty($this->_search_btn_label) ? $this->page_label
2208
+				: $this->_search_btn_label
2209
+		);
2210
+		$this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2211
+	}
2212
+
2213
+
2214
+
2215
+	/*** END LIST TABLE METHODS **/
2216
+
2217
+	/**
2218
+	 * @return void
2219
+	 * @throws EE_Error
2220
+	 */
2221
+	public function addRegisteredMetaBoxes()
2222
+	{
2223
+		remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2224
+		$this->_add_registered_meta_boxes();
2225
+	}
2226
+
2227
+
2228
+	/**
2229
+	 * _add_registered_metaboxes
2230
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2231
+	 *
2232
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2233
+	 * @return void
2234
+	 * @throws EE_Error
2235
+	 */
2236
+	private function _add_registered_meta_boxes()
2237
+	{
2238
+		// we only add meta boxes if the page_route calls for it
2239
+		if (
2240
+			is_array($this->_route_config)
2241
+			&& isset($this->_route_config['metaboxes'])
2242
+			&& is_array($this->_route_config['metaboxes'])
2243
+		) {
2244
+			// this simply loops through the callbacks provided
2245
+			// and checks if there is a corresponding callback registered by the child
2246
+			// if there is then we go ahead and process the metabox loader.
2247
+			foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2248
+				// first check for Closures
2249
+				if ($metabox_callback instanceof Closure) {
2250
+					$result = $metabox_callback();
2251
+				} elseif (is_callable($metabox_callback)) {
2252
+					$result = call_user_func($metabox_callback);
2253
+				} elseif (method_exists($this, $metabox_callback)) {
2254
+					$result = $this->{$metabox_callback}();
2255
+				} else {
2256
+					$result = false;
2257
+				}
2258
+				if ($result === false) {
2259
+					// user error msg
2260
+					$error_msg = esc_html__(
2261
+						'An error occurred. The  requested metabox could not be found.',
2262
+						'event_espresso'
2263
+					);
2264
+					// developer error msg
2265
+					$error_msg .= '||'
2266
+								  . sprintf(
2267
+									  esc_html__(
2268
+										  'The metabox with the string "%s" could not be called. Check that the spelling for method names and actions in the "_page_config[\'metaboxes\']" array are all correct.',
2269
+										  'event_espresso'
2270
+									  ),
2271
+									  $metabox_callback
2272
+								  );
2273
+					throw new EE_Error($error_msg);
2274
+				}
2275
+				unset($this->_route_config['metaboxes'][ $key ]);
2276
+			}
2277
+		}
2278
+	}
2279
+
2280
+
2281
+	/**
2282
+	 * _add_screen_columns
2283
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2284
+	 * the dynamic column template and we'll setup the column options for the page.
2285
+	 *
2286
+	 * @return void
2287
+	 */
2288
+	private function _add_screen_columns()
2289
+	{
2290
+		if (
2291
+			is_array($this->_route_config)
2292
+			&& isset($this->_route_config['columns'])
2293
+			&& is_array($this->_route_config['columns'])
2294
+			&& count($this->_route_config['columns']) === 2
2295
+		) {
2296
+			add_screen_option(
2297
+				'layout_columns',
2298
+				[
2299
+					'max'     => (int) $this->_route_config['columns'][0],
2300
+					'default' => (int) $this->_route_config['columns'][1],
2301
+				]
2302
+			);
2303
+			$this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2304
+			$screen_id                                           = $this->_current_screen->id;
2305
+			$screen_columns                                      = (int) get_user_option("screen_layout_{$screen_id}");
2306
+			$total_columns                                       = ! empty($screen_columns)
2307
+				? $screen_columns
2308
+				: $this->_route_config['columns'][1];
2309
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2310
+			$this->_template_args['current_page']                = $this->_wp_page_slug;
2311
+			$this->_template_args['screen']                      = $this->_current_screen;
2312
+			$this->_column_template_path                         = EE_ADMIN_TEMPLATE
2313
+																   . 'admin_details_metabox_column_wrapper.template.php';
2314
+			// finally if we don't have has_metaboxes set in the route config
2315
+			// let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2316
+			$this->_route_config['has_metaboxes'] = true;
2317
+		}
2318
+	}
2319
+
2320
+
2321
+
2322
+	/** GLOBALLY AVAILABLE METABOXES **/
2323
+
2324
+
2325
+	/**
2326
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2327
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2328
+	 * these get loaded on.
2329
+	 */
2330
+	private function _espresso_news_post_box()
2331
+	{
2332
+		$news_box_title = apply_filters(
2333
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2334
+			esc_html__('New @ Event Espresso', 'event_espresso')
2335
+		);
2336
+		$this->addMetaBox(
2337
+			'espresso_news_post_box',
2338
+			$news_box_title,
2339
+			[
2340
+				$this,
2341
+				'espresso_news_post_box',
2342
+			],
2343
+			$this->_wp_page_slug,
2344
+			'side',
2345
+			'low'
2346
+		);
2347
+	}
2348
+
2349
+
2350
+	/**
2351
+	 * Code for setting up espresso ratings request metabox.
2352
+	 */
2353
+	protected function _espresso_ratings_request()
2354
+	{
2355
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2356
+			return;
2357
+		}
2358
+		$ratings_box_title = apply_filters(
2359
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2360
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2361
+		);
2362
+		$this->addMetaBox(
2363
+			'espresso_ratings_request',
2364
+			$ratings_box_title,
2365
+			[
2366
+				$this,
2367
+				'espresso_ratings_request',
2368
+			],
2369
+			$this->_wp_page_slug,
2370
+			'side'
2371
+		);
2372
+	}
2373
+
2374
+
2375
+	/**
2376
+	 * Code for setting up espresso ratings request metabox content.
2377
+	 *
2378
+	 * @throws DomainException
2379
+	 */
2380
+	public function espresso_ratings_request()
2381
+	{
2382
+		EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2383
+	}
2384
+
2385
+
2386
+	public static function cached_rss_display($rss_id, $url)
2387
+	{
2388
+		$loading   = '<p class="widget-loading hide-if-no-js">'
2389
+					 . esc_html__('Loading&#8230;', 'event_espresso')
2390
+					 . '</p><p class="hide-if-js">'
2391
+					 . esc_html__('This widget requires JavaScript.', 'event_espresso')
2392
+					 . '</p>';
2393
+		$pre       = '<div class="espresso-rss-display">' . "\n\t";
2394
+		$pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2395
+		$post      = '</div>' . "\n";
2396
+		$cache_key = 'ee_rss_' . md5($rss_id);
2397
+		$output    = get_transient($cache_key);
2398
+		if ($output !== false) {
2399
+			echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2400
+			return true;
2401
+		}
2402
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2403
+			echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2404
+			return false;
2405
+		}
2406
+		ob_start();
2407
+		wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2408
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2409
+		return true;
2410
+	}
2411
+
2412
+
2413
+	public function espresso_news_post_box()
2414
+	{
2415
+		?>
2416 2416
         <div class="padding">
2417 2417
             <div id="espresso_news_post_box_content" class="infolinks">
2418 2418
                 <?php
2419
-                // Get RSS Feed(s)
2420
-                EE_Admin_Page::cached_rss_display(
2421
-                    'espresso_news_post_box_content',
2422
-                    esc_url_raw(
2423
-                        apply_filters(
2424
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2425
-                            'https://eventespresso.com/feed/'
2426
-                        )
2427
-                    )
2428
-                );
2429
-                ?>
2419
+				// Get RSS Feed(s)
2420
+				EE_Admin_Page::cached_rss_display(
2421
+					'espresso_news_post_box_content',
2422
+					esc_url_raw(
2423
+						apply_filters(
2424
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2425
+							'https://eventespresso.com/feed/'
2426
+						)
2427
+					)
2428
+				);
2429
+				?>
2430 2430
             </div>
2431 2431
             <?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2432 2432
         </div>
2433 2433
         <?php
2434
-    }
2435
-
2436
-
2437
-    private function _espresso_links_post_box()
2438
-    {
2439
-        // Hiding until we actually have content to put in here...
2440
-        // $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2441
-    }
2442
-
2443
-
2444
-    public function espresso_links_post_box()
2445
-    {
2446
-        // Hiding until we actually have content to put in here...
2447
-        // EEH_Template::display_template(
2448
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2449
-        // );
2450
-    }
2451
-
2452
-
2453
-    protected function _espresso_sponsors_post_box()
2454
-    {
2455
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2456
-            $this->addMetaBox(
2457
-                'espresso_sponsors_post_box',
2458
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2459
-                [$this, 'espresso_sponsors_post_box'],
2460
-                $this->_wp_page_slug,
2461
-                'side'
2462
-            );
2463
-        }
2464
-    }
2465
-
2466
-
2467
-    public function espresso_sponsors_post_box()
2468
-    {
2469
-        EEH_Template::display_template(
2470
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2471
-        );
2472
-    }
2473
-
2474
-
2475
-    /**
2476
-     * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2477
-     * present in the _page_config array, then we'll use that for the metabox label.
2478
-     * Otherwise we'll just use publish
2479
-     * (publishbox itself could be an array of labels indexed by routes)
2480
-     *
2481
-     * @return string
2482
-     * @since   $VID:$
2483
-     */
2484
-    protected function getPublishBoxTitle(): string
2485
-    {
2486
-        $publish_box_title = esc_html__('Publish', 'event_espresso');
2487
-        if (! empty($this->_labels['publishbox'])) {
2488
-            if (is_array($this->_labels['publishbox'])) {
2489
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2490
-            } else {
2491
-                $publish_box_title = $this->_labels['publishbox'];
2492
-            }
2493
-        }
2494
-        return apply_filters(
2495
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2496
-            $publish_box_title,
2497
-            $this->_req_action,
2498
-            $this
2499
-        );
2500
-    }
2501
-
2502
-
2503
-    /**
2504
-     * @throws EE_Error
2505
-     */
2506
-    private function _publish_post_box()
2507
-    {
2508
-        $title = $this->getPublishBoxTitle();
2509
-        if (empty($this->_template_args['save_buttons'])) {
2510
-            $this->_set_publish_post_box_vars(
2511
-                sanitize_key($title),
2512
-                "espresso_{$this->page_slug}_editor_overview",
2513
-                '',
2514
-                '',
2515
-                true
2516
-            );
2517
-        } else {
2518
-            $this->addPublishPostMetaBoxHiddenFields(
2519
-                sanitize_key($title),
2520
-                ['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2521
-            );
2522
-        }
2523
-        $this->addMetaBox(
2524
-            "espresso_{$this->page_slug}_editor_overview",
2525
-            $title,
2526
-            [$this, 'editor_overview'],
2527
-            $this->_current_screen->id,
2528
-            'side',
2529
-            'high'
2530
-        );
2531
-    }
2532
-
2533
-
2534
-    public function editor_overview()
2535
-    {
2536
-        /**
2537
-         * @var string $publish_box_extra_content
2538
-         * @var string $publish_hidden_fields
2539
-         * @var string $publish_delete_link
2540
-         * @var string $save_buttons
2541
-         */
2542
-        // if we have extra content set let's add it in if not make sure its empty
2543
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2544
-        echo EEH_Template::display_template(
2545
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2546
-            $this->_template_args,
2547
-            true
2548
-        );
2549
-    }
2550
-
2551
-
2552
-    /** end of globally available metaboxes section **/
2553
-
2554
-
2555
-    /**
2556
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2557
-     * Note: currently there is no validation for this.  However, if you want the delete button, the
2558
-     * save, and save and close buttons to work properly, then you will want to include a
2559
-     * values for the name and id arguments.
2560
-     *
2561
-     * @param string|null $name                     key used for the action ID (i.e. event_id)
2562
-     * @param int|string  $id                       id attached to the item published
2563
-     * @param string|null $delete                   page route callback for the delete action
2564
-     * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2565
-     * @param boolean     $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2566
-     *                                              or just the "Save" button
2567
-     * @throws EE_Error
2568
-     * @throws InvalidArgumentException
2569
-     * @throws InvalidDataTypeException
2570
-     * @throws InvalidInterfaceException
2571
-     * @todo  Add in validation for name/id arguments.
2572
-     */
2573
-    protected function _set_publish_post_box_vars(
2574
-        ?string $name = '',
2575
-        $id = 0,
2576
-        ?string $delete = '',
2577
-        ?string $save_close_redirect_URL = '',
2578
-        bool $both_btns = true
2579
-    ) {
2580
-        // if Save & Close, use a custom redirect URL or default to the main page?
2581
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2582
-            ? $save_close_redirect_URL
2583
-            : $this->_admin_base_url;
2584
-        // create the Save & Close and Save buttons
2585
-        $this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2586
-        // if we have extra content set let's add it in if not make sure its empty
2587
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2588
-        if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2589
-            // make sure we have a default if just true is sent.
2590
-            $delete      = ! empty($delete) ? $delete : 'delete';
2591
-            $this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2592
-                $delete,
2593
-                $delete,
2594
-                [$name => $id],
2595
-                'submitdelete deletion button button--outline button--caution'
2596
-            );
2597
-        }
2598
-        if (! isset($this->_template_args['publish_delete_link'])) {
2599
-            $this->_template_args['publish_delete_link'] = '';
2600
-        }
2601
-        if (! empty($name) && ! empty($id)) {
2602
-            $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2603
-        }
2604
-        $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2605
-        // add hidden fields
2606
-        $this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2607
-        foreach ($hidden_fields as $hidden_field) {
2608
-            $this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2609
-        }
2610
-    }
2611
-
2612
-
2613
-    /**
2614
-     * @param string|null $name
2615
-     * @param int|string  $id
2616
-     * @param string|null $delete
2617
-     * @param string|null $save_close_redirect_URL
2618
-     * @param bool        $both_btns
2619
-     * @throws EE_Error
2620
-     */
2621
-    public function set_publish_post_box_vars(
2622
-        ?string $name = '',
2623
-        $id = 0,
2624
-        ?string $delete = '',
2625
-        ?string $save_close_redirect_URL = '',
2626
-        bool $both_btns = false
2627
-    ) {
2628
-        $this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2629
-    }
2630
-
2631
-
2632
-    protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2633
-    {
2634
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2635
-    }
2636
-
2637
-
2638
-    /**
2639
-     * displays an error message to ppl who have javascript disabled
2640
-     *
2641
-     * @return void
2642
-     */
2643
-    private function _display_no_javascript_warning()
2644
-    {
2645
-        ?>
2434
+	}
2435
+
2436
+
2437
+	private function _espresso_links_post_box()
2438
+	{
2439
+		// Hiding until we actually have content to put in here...
2440
+		// $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2441
+	}
2442
+
2443
+
2444
+	public function espresso_links_post_box()
2445
+	{
2446
+		// Hiding until we actually have content to put in here...
2447
+		// EEH_Template::display_template(
2448
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2449
+		// );
2450
+	}
2451
+
2452
+
2453
+	protected function _espresso_sponsors_post_box()
2454
+	{
2455
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2456
+			$this->addMetaBox(
2457
+				'espresso_sponsors_post_box',
2458
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2459
+				[$this, 'espresso_sponsors_post_box'],
2460
+				$this->_wp_page_slug,
2461
+				'side'
2462
+			);
2463
+		}
2464
+	}
2465
+
2466
+
2467
+	public function espresso_sponsors_post_box()
2468
+	{
2469
+		EEH_Template::display_template(
2470
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2471
+		);
2472
+	}
2473
+
2474
+
2475
+	/**
2476
+	 * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2477
+	 * present in the _page_config array, then we'll use that for the metabox label.
2478
+	 * Otherwise we'll just use publish
2479
+	 * (publishbox itself could be an array of labels indexed by routes)
2480
+	 *
2481
+	 * @return string
2482
+	 * @since   $VID:$
2483
+	 */
2484
+	protected function getPublishBoxTitle(): string
2485
+	{
2486
+		$publish_box_title = esc_html__('Publish', 'event_espresso');
2487
+		if (! empty($this->_labels['publishbox'])) {
2488
+			if (is_array($this->_labels['publishbox'])) {
2489
+				$publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2490
+			} else {
2491
+				$publish_box_title = $this->_labels['publishbox'];
2492
+			}
2493
+		}
2494
+		return apply_filters(
2495
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2496
+			$publish_box_title,
2497
+			$this->_req_action,
2498
+			$this
2499
+		);
2500
+	}
2501
+
2502
+
2503
+	/**
2504
+	 * @throws EE_Error
2505
+	 */
2506
+	private function _publish_post_box()
2507
+	{
2508
+		$title = $this->getPublishBoxTitle();
2509
+		if (empty($this->_template_args['save_buttons'])) {
2510
+			$this->_set_publish_post_box_vars(
2511
+				sanitize_key($title),
2512
+				"espresso_{$this->page_slug}_editor_overview",
2513
+				'',
2514
+				'',
2515
+				true
2516
+			);
2517
+		} else {
2518
+			$this->addPublishPostMetaBoxHiddenFields(
2519
+				sanitize_key($title),
2520
+				['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2521
+			);
2522
+		}
2523
+		$this->addMetaBox(
2524
+			"espresso_{$this->page_slug}_editor_overview",
2525
+			$title,
2526
+			[$this, 'editor_overview'],
2527
+			$this->_current_screen->id,
2528
+			'side',
2529
+			'high'
2530
+		);
2531
+	}
2532
+
2533
+
2534
+	public function editor_overview()
2535
+	{
2536
+		/**
2537
+		 * @var string $publish_box_extra_content
2538
+		 * @var string $publish_hidden_fields
2539
+		 * @var string $publish_delete_link
2540
+		 * @var string $save_buttons
2541
+		 */
2542
+		// if we have extra content set let's add it in if not make sure its empty
2543
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2544
+		echo EEH_Template::display_template(
2545
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2546
+			$this->_template_args,
2547
+			true
2548
+		);
2549
+	}
2550
+
2551
+
2552
+	/** end of globally available metaboxes section **/
2553
+
2554
+
2555
+	/**
2556
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2557
+	 * Note: currently there is no validation for this.  However, if you want the delete button, the
2558
+	 * save, and save and close buttons to work properly, then you will want to include a
2559
+	 * values for the name and id arguments.
2560
+	 *
2561
+	 * @param string|null $name                     key used for the action ID (i.e. event_id)
2562
+	 * @param int|string  $id                       id attached to the item published
2563
+	 * @param string|null $delete                   page route callback for the delete action
2564
+	 * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2565
+	 * @param boolean     $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2566
+	 *                                              or just the "Save" button
2567
+	 * @throws EE_Error
2568
+	 * @throws InvalidArgumentException
2569
+	 * @throws InvalidDataTypeException
2570
+	 * @throws InvalidInterfaceException
2571
+	 * @todo  Add in validation for name/id arguments.
2572
+	 */
2573
+	protected function _set_publish_post_box_vars(
2574
+		?string $name = '',
2575
+		$id = 0,
2576
+		?string $delete = '',
2577
+		?string $save_close_redirect_URL = '',
2578
+		bool $both_btns = true
2579
+	) {
2580
+		// if Save & Close, use a custom redirect URL or default to the main page?
2581
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2582
+			? $save_close_redirect_URL
2583
+			: $this->_admin_base_url;
2584
+		// create the Save & Close and Save buttons
2585
+		$this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2586
+		// if we have extra content set let's add it in if not make sure its empty
2587
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2588
+		if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2589
+			// make sure we have a default if just true is sent.
2590
+			$delete      = ! empty($delete) ? $delete : 'delete';
2591
+			$this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2592
+				$delete,
2593
+				$delete,
2594
+				[$name => $id],
2595
+				'submitdelete deletion button button--outline button--caution'
2596
+			);
2597
+		}
2598
+		if (! isset($this->_template_args['publish_delete_link'])) {
2599
+			$this->_template_args['publish_delete_link'] = '';
2600
+		}
2601
+		if (! empty($name) && ! empty($id)) {
2602
+			$this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2603
+		}
2604
+		$hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2605
+		// add hidden fields
2606
+		$this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2607
+		foreach ($hidden_fields as $hidden_field) {
2608
+			$this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2609
+		}
2610
+	}
2611
+
2612
+
2613
+	/**
2614
+	 * @param string|null $name
2615
+	 * @param int|string  $id
2616
+	 * @param string|null $delete
2617
+	 * @param string|null $save_close_redirect_URL
2618
+	 * @param bool        $both_btns
2619
+	 * @throws EE_Error
2620
+	 */
2621
+	public function set_publish_post_box_vars(
2622
+		?string $name = '',
2623
+		$id = 0,
2624
+		?string $delete = '',
2625
+		?string $save_close_redirect_URL = '',
2626
+		bool $both_btns = false
2627
+	) {
2628
+		$this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2629
+	}
2630
+
2631
+
2632
+	protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2633
+	{
2634
+		$this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2635
+	}
2636
+
2637
+
2638
+	/**
2639
+	 * displays an error message to ppl who have javascript disabled
2640
+	 *
2641
+	 * @return void
2642
+	 */
2643
+	private function _display_no_javascript_warning()
2644
+	{
2645
+		?>
2646 2646
         <noscript>
2647 2647
             <div id="no-js-message" class="error">
2648 2648
                 <p style="font-size:1.3em;">
2649 2649
                     <span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2650 2650
                     <?php esc_html_e(
2651
-                        'Javascript is currently turned off for your browser. Javascript must be enabled in order for all of the features on this page to function properly. Please turn your javascript back on.',
2652
-                        'event_espresso'
2653
-                    ); ?>
2651
+						'Javascript is currently turned off for your browser. Javascript must be enabled in order for all of the features on this page to function properly. Please turn your javascript back on.',
2652
+						'event_espresso'
2653
+					); ?>
2654 2654
                 </p>
2655 2655
             </div>
2656 2656
         </noscript>
2657 2657
         <?php
2658
-    }
2659
-
2660
-
2661
-    /**
2662
-     * displays espresso success and/or error notices
2663
-     *
2664
-     * @return void
2665
-     */
2666
-    protected function _display_espresso_notices()
2667
-    {
2668
-        $notices = $this->_get_transient(true);
2669
-        echo stripslashes($notices);
2670
-    }
2671
-
2672
-
2673
-    /**
2674
-     * spinny things pacify the masses
2675
-     *
2676
-     * @return void
2677
-     */
2678
-    protected function _add_admin_page_ajax_loading_img()
2679
-    {
2680
-        ?>
2658
+	}
2659
+
2660
+
2661
+	/**
2662
+	 * displays espresso success and/or error notices
2663
+	 *
2664
+	 * @return void
2665
+	 */
2666
+	protected function _display_espresso_notices()
2667
+	{
2668
+		$notices = $this->_get_transient(true);
2669
+		echo stripslashes($notices);
2670
+	}
2671
+
2672
+
2673
+	/**
2674
+	 * spinny things pacify the masses
2675
+	 *
2676
+	 * @return void
2677
+	 */
2678
+	protected function _add_admin_page_ajax_loading_img()
2679
+	{
2680
+		?>
2681 2681
         <div id="espresso-ajax-loading" class="ajax-loading-grey">
2682 2682
             <span class="ee-spinner ee-spin"></span><span class="hidden"><?php
2683
-                esc_html_e('loading...', 'event_espresso'); ?></span>
2683
+				esc_html_e('loading...', 'event_espresso'); ?></span>
2684 2684
         </div>
2685 2685
         <?php
2686
-    }
2686
+	}
2687 2687
 
2688 2688
 
2689
-    /**
2690
-     * add admin page overlay for modal boxes
2691
-     *
2692
-     * @return void
2693
-     */
2694
-    protected function _add_admin_page_overlay()
2695
-    {
2696
-        ?>
2689
+	/**
2690
+	 * add admin page overlay for modal boxes
2691
+	 *
2692
+	 * @return void
2693
+	 */
2694
+	protected function _add_admin_page_overlay()
2695
+	{
2696
+		?>
2697 2697
         <div id="espresso-admin-page-overlay-dv" class=""></div>
2698 2698
         <?php
2699
-    }
2700
-
2701
-
2702
-    /**
2703
-     * facade for $this->addMetaBox()
2704
-     *
2705
-     * @param string  $action        where the metabox gets displayed
2706
-     * @param string  $title         Title of Metabox (output in metabox header)
2707
-     * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2708
-     *                               instead of the one created in here.
2709
-     * @param array   $callback_args an array of args supplied for the metabox
2710
-     * @param string  $column        what metabox column
2711
-     * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2712
-     * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2713
-     *                               created but just set our own callback for wp's add_meta_box.
2714
-     * @throws DomainException
2715
-     */
2716
-    public function _add_admin_page_meta_box(
2717
-        $action,
2718
-        $title,
2719
-        $callback,
2720
-        $callback_args,
2721
-        $column = 'normal',
2722
-        $priority = 'high',
2723
-        $create_func = true
2724
-    ) {
2725
-        do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2726
-        // if we have empty callback args and we want to automatically create the metabox callback then we need to make sure the callback args are generated.
2727
-        if (empty($callback_args) && $create_func) {
2728
-            $callback_args = [
2729
-                'template_path' => $this->_template_path,
2730
-                'template_args' => $this->_template_args,
2731
-            ];
2732
-        }
2733
-        // if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2734
-        $call_back_func = $create_func
2735
-            ? static function ($post, $metabox) {
2736
-                do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2737
-                echo EEH_Template::display_template(
2738
-                    $metabox['args']['template_path'],
2739
-                    $metabox['args']['template_args'],
2740
-                    true
2741
-                );
2742
-            }
2743
-            : $callback;
2744
-        $this->addMetaBox(
2745
-            str_replace('_', '-', $action) . '-mbox',
2746
-            $title,
2747
-            $call_back_func,
2748
-            $this->_wp_page_slug,
2749
-            $column,
2750
-            $priority,
2751
-            $callback_args
2752
-        );
2753
-    }
2754
-
2755
-
2756
-    /**
2757
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2758
-     *
2759
-     * @throws DomainException
2760
-     * @throws EE_Error
2761
-     * @throws InvalidArgumentException
2762
-     * @throws InvalidDataTypeException
2763
-     * @throws InvalidInterfaceException
2764
-     */
2765
-    public function display_admin_page_with_metabox_columns()
2766
-    {
2767
-        $this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2768
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2769
-            $this->_column_template_path,
2770
-            $this->_template_args,
2771
-            true
2772
-        );
2773
-        // the final wrapper
2774
-        $this->admin_page_wrapper();
2775
-    }
2776
-
2777
-
2778
-    /**
2779
-     * generates  HTML wrapper for an admin details page
2780
-     *
2781
-     * @return void
2782
-     * @throws DomainException
2783
-     * @throws EE_Error
2784
-     * @throws InvalidArgumentException
2785
-     * @throws InvalidDataTypeException
2786
-     * @throws InvalidInterfaceException
2787
-     */
2788
-    public function display_admin_page_with_sidebar()
2789
-    {
2790
-        $this->_display_admin_page(true);
2791
-    }
2792
-
2793
-
2794
-    /**
2795
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2796
-     *
2797
-     * @return void
2798
-     * @throws DomainException
2799
-     * @throws EE_Error
2800
-     * @throws InvalidArgumentException
2801
-     * @throws InvalidDataTypeException
2802
-     * @throws InvalidInterfaceException
2803
-     */
2804
-    public function display_admin_page_with_no_sidebar()
2805
-    {
2806
-        $this->_display_admin_page();
2807
-    }
2808
-
2809
-
2810
-    /**
2811
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2812
-     *
2813
-     * @return void
2814
-     * @throws DomainException
2815
-     * @throws EE_Error
2816
-     * @throws InvalidArgumentException
2817
-     * @throws InvalidDataTypeException
2818
-     * @throws InvalidInterfaceException
2819
-     */
2820
-    public function display_about_admin_page()
2821
-    {
2822
-        $this->_display_admin_page(false, true);
2823
-    }
2824
-
2825
-
2826
-    /**
2827
-     * display_admin_page
2828
-     * contains the code for actually displaying an admin page
2829
-     *
2830
-     * @param boolean $sidebar true with sidebar, false without
2831
-     * @param boolean $about   use the about admin wrapper instead of the default.
2832
-     * @return void
2833
-     * @throws DomainException
2834
-     * @throws EE_Error
2835
-     * @throws InvalidArgumentException
2836
-     * @throws InvalidDataTypeException
2837
-     * @throws InvalidInterfaceException
2838
-     */
2839
-    private function _display_admin_page($sidebar = false, $about = false)
2840
-    {
2841
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2842
-        // custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2843
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2844
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2845
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2846
-
2847
-        $post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2848
-
2849
-        $this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2850
-                                                  && $this->_req_action !== 'data_reset'
2851
-                                                  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2852
-                                                  && strpos($post_body_content, 'wp-list-table') === false;
2853
-
2854
-        $this->_template_args['current_page']                 = $this->_wp_page_slug;
2855
-        $this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2856
-            ? 'poststuff'
2857
-            : 'espresso-default-admin';
2858
-        $this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2859
-                                                                    'event-espresso_page_espresso_',
2860
-                                                                    '',
2861
-                                                                    $this->_wp_page_slug
2862
-                                                                ) . ' ' . $this->_req_action . '-route';
2863
-
2864
-        $template_path = $sidebar
2865
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2866
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2867
-        if ($this->request->isAjax()) {
2868
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2869
-        }
2870
-        $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2871
-
2872
-        $this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2873
-        $this->_template_args['before_admin_page_content'] = $post_body_content;
2874
-        $this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2875
-        $this->_template_args['admin_page_content']        = EEH_Template::display_template(
2876
-            $template_path,
2877
-            $this->_template_args,
2878
-            true
2879
-        );
2880
-        // the final template wrapper
2881
-        $this->admin_page_wrapper($about);
2882
-    }
2883
-
2884
-
2885
-    /**
2886
-     * This is used to display caf preview pages.
2887
-     *
2888
-     * @param string $utm_campaign_source what is the key used for google analytics link
2889
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2890
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2891
-     * @return void
2892
-     * @throws DomainException
2893
-     * @throws EE_Error
2894
-     * @throws InvalidArgumentException
2895
-     * @throws InvalidDataTypeException
2896
-     * @throws InvalidInterfaceException
2897
-     * @since 4.3.2
2898
-     */
2899
-    public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2900
-    {
2901
-        // let's generate a default preview action button if there isn't one already present.
2902
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2903
-            'Upgrade to Event Espresso 4 Right Now',
2904
-            'event_espresso'
2905
-        );
2906
-        $buy_now_url                                   = add_query_arg(
2907
-            [
2908
-                'ee_ver'       => 'ee4',
2909
-                'utm_source'   => 'ee4_plugin_admin',
2910
-                'utm_medium'   => 'link',
2911
-                'utm_campaign' => $utm_campaign_source,
2912
-                'utm_content'  => 'buy_now_button',
2913
-            ],
2914
-            'https://eventespresso.com/pricing/'
2915
-        );
2916
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2917
-            ? $this->get_action_link_or_button(
2918
-                '',
2919
-                'buy_now',
2920
-                [],
2921
-                'button button--primary button--big',
2922
-                esc_url_raw($buy_now_url),
2923
-                true
2924
-            )
2925
-            : $this->_template_args['preview_action_button'];
2926
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2927
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2928
-            $this->_template_args,
2929
-            true
2930
-        );
2931
-        $this->_display_admin_page($display_sidebar);
2932
-    }
2933
-
2934
-
2935
-    /**
2936
-     * display_admin_list_table_page_with_sidebar
2937
-     * generates HTML wrapper for an admin_page with list_table
2938
-     *
2939
-     * @return void
2940
-     * @throws DomainException
2941
-     * @throws EE_Error
2942
-     * @throws InvalidArgumentException
2943
-     * @throws InvalidDataTypeException
2944
-     * @throws InvalidInterfaceException
2945
-     */
2946
-    public function display_admin_list_table_page_with_sidebar()
2947
-    {
2948
-        $this->_display_admin_list_table_page(true);
2949
-    }
2950
-
2951
-
2952
-    /**
2953
-     * display_admin_list_table_page_with_no_sidebar
2954
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2955
-     *
2956
-     * @return void
2957
-     * @throws DomainException
2958
-     * @throws EE_Error
2959
-     * @throws InvalidArgumentException
2960
-     * @throws InvalidDataTypeException
2961
-     * @throws InvalidInterfaceException
2962
-     */
2963
-    public function display_admin_list_table_page_with_no_sidebar()
2964
-    {
2965
-        $this->_display_admin_list_table_page();
2966
-    }
2967
-
2968
-
2969
-    /**
2970
-     * generates html wrapper for an admin_list_table page
2971
-     *
2972
-     * @param boolean $sidebar whether to display with sidebar or not.
2973
-     * @return void
2974
-     * @throws DomainException
2975
-     * @throws EE_Error
2976
-     * @throws InvalidArgumentException
2977
-     * @throws InvalidDataTypeException
2978
-     * @throws InvalidInterfaceException
2979
-     */
2980
-    private function _display_admin_list_table_page($sidebar = false)
2981
-    {
2982
-        // setup search attributes
2983
-        $this->_set_search_attributes();
2984
-        $this->_template_args['current_page']     = $this->_wp_page_slug;
2985
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2986
-        $this->_template_args['table_url']        = $this->request->isAjax()
2987
-            ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2988
-            : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2989
-        $this->_template_args['list_table']       = $this->_list_table_object;
2990
-        $this->_template_args['current_route']    = $this->_req_action;
2991
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2992
-        $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2993
-        if (! empty($ajax_sorting_callback)) {
2994
-            $sortable_list_table_form_fields = wp_nonce_field(
2995
-                $ajax_sorting_callback . '_nonce',
2996
-                $ajax_sorting_callback . '_nonce',
2997
-                false,
2998
-                false
2999
-            );
3000
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
3001
-                                                . $this->page_slug
3002
-                                                . '" />';
3003
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
3004
-                                                . $ajax_sorting_callback
3005
-                                                . '" />';
3006
-        } else {
3007
-            $sortable_list_table_form_fields = '';
3008
-        }
3009
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3010
-
3011
-        $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
3012
-
3013
-        $nonce_ref          = $this->_req_action . '_nonce';
3014
-        $hidden_form_fields .= '
2699
+	}
2700
+
2701
+
2702
+	/**
2703
+	 * facade for $this->addMetaBox()
2704
+	 *
2705
+	 * @param string  $action        where the metabox gets displayed
2706
+	 * @param string  $title         Title of Metabox (output in metabox header)
2707
+	 * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2708
+	 *                               instead of the one created in here.
2709
+	 * @param array   $callback_args an array of args supplied for the metabox
2710
+	 * @param string  $column        what metabox column
2711
+	 * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2712
+	 * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2713
+	 *                               created but just set our own callback for wp's add_meta_box.
2714
+	 * @throws DomainException
2715
+	 */
2716
+	public function _add_admin_page_meta_box(
2717
+		$action,
2718
+		$title,
2719
+		$callback,
2720
+		$callback_args,
2721
+		$column = 'normal',
2722
+		$priority = 'high',
2723
+		$create_func = true
2724
+	) {
2725
+		do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2726
+		// if we have empty callback args and we want to automatically create the metabox callback then we need to make sure the callback args are generated.
2727
+		if (empty($callback_args) && $create_func) {
2728
+			$callback_args = [
2729
+				'template_path' => $this->_template_path,
2730
+				'template_args' => $this->_template_args,
2731
+			];
2732
+		}
2733
+		// if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2734
+		$call_back_func = $create_func
2735
+			? static function ($post, $metabox) {
2736
+				do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2737
+				echo EEH_Template::display_template(
2738
+					$metabox['args']['template_path'],
2739
+					$metabox['args']['template_args'],
2740
+					true
2741
+				);
2742
+			}
2743
+			: $callback;
2744
+		$this->addMetaBox(
2745
+			str_replace('_', '-', $action) . '-mbox',
2746
+			$title,
2747
+			$call_back_func,
2748
+			$this->_wp_page_slug,
2749
+			$column,
2750
+			$priority,
2751
+			$callback_args
2752
+		);
2753
+	}
2754
+
2755
+
2756
+	/**
2757
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2758
+	 *
2759
+	 * @throws DomainException
2760
+	 * @throws EE_Error
2761
+	 * @throws InvalidArgumentException
2762
+	 * @throws InvalidDataTypeException
2763
+	 * @throws InvalidInterfaceException
2764
+	 */
2765
+	public function display_admin_page_with_metabox_columns()
2766
+	{
2767
+		$this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2768
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2769
+			$this->_column_template_path,
2770
+			$this->_template_args,
2771
+			true
2772
+		);
2773
+		// the final wrapper
2774
+		$this->admin_page_wrapper();
2775
+	}
2776
+
2777
+
2778
+	/**
2779
+	 * generates  HTML wrapper for an admin details page
2780
+	 *
2781
+	 * @return void
2782
+	 * @throws DomainException
2783
+	 * @throws EE_Error
2784
+	 * @throws InvalidArgumentException
2785
+	 * @throws InvalidDataTypeException
2786
+	 * @throws InvalidInterfaceException
2787
+	 */
2788
+	public function display_admin_page_with_sidebar()
2789
+	{
2790
+		$this->_display_admin_page(true);
2791
+	}
2792
+
2793
+
2794
+	/**
2795
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2796
+	 *
2797
+	 * @return void
2798
+	 * @throws DomainException
2799
+	 * @throws EE_Error
2800
+	 * @throws InvalidArgumentException
2801
+	 * @throws InvalidDataTypeException
2802
+	 * @throws InvalidInterfaceException
2803
+	 */
2804
+	public function display_admin_page_with_no_sidebar()
2805
+	{
2806
+		$this->_display_admin_page();
2807
+	}
2808
+
2809
+
2810
+	/**
2811
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2812
+	 *
2813
+	 * @return void
2814
+	 * @throws DomainException
2815
+	 * @throws EE_Error
2816
+	 * @throws InvalidArgumentException
2817
+	 * @throws InvalidDataTypeException
2818
+	 * @throws InvalidInterfaceException
2819
+	 */
2820
+	public function display_about_admin_page()
2821
+	{
2822
+		$this->_display_admin_page(false, true);
2823
+	}
2824
+
2825
+
2826
+	/**
2827
+	 * display_admin_page
2828
+	 * contains the code for actually displaying an admin page
2829
+	 *
2830
+	 * @param boolean $sidebar true with sidebar, false without
2831
+	 * @param boolean $about   use the about admin wrapper instead of the default.
2832
+	 * @return void
2833
+	 * @throws DomainException
2834
+	 * @throws EE_Error
2835
+	 * @throws InvalidArgumentException
2836
+	 * @throws InvalidDataTypeException
2837
+	 * @throws InvalidInterfaceException
2838
+	 */
2839
+	private function _display_admin_page($sidebar = false, $about = false)
2840
+	{
2841
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2842
+		// custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2843
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2844
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2845
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2846
+
2847
+		$post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2848
+
2849
+		$this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2850
+												  && $this->_req_action !== 'data_reset'
2851
+												  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2852
+												  && strpos($post_body_content, 'wp-list-table') === false;
2853
+
2854
+		$this->_template_args['current_page']                 = $this->_wp_page_slug;
2855
+		$this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2856
+			? 'poststuff'
2857
+			: 'espresso-default-admin';
2858
+		$this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2859
+																	'event-espresso_page_espresso_',
2860
+																	'',
2861
+																	$this->_wp_page_slug
2862
+																) . ' ' . $this->_req_action . '-route';
2863
+
2864
+		$template_path = $sidebar
2865
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2866
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2867
+		if ($this->request->isAjax()) {
2868
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2869
+		}
2870
+		$template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2871
+
2872
+		$this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2873
+		$this->_template_args['before_admin_page_content'] = $post_body_content;
2874
+		$this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2875
+		$this->_template_args['admin_page_content']        = EEH_Template::display_template(
2876
+			$template_path,
2877
+			$this->_template_args,
2878
+			true
2879
+		);
2880
+		// the final template wrapper
2881
+		$this->admin_page_wrapper($about);
2882
+	}
2883
+
2884
+
2885
+	/**
2886
+	 * This is used to display caf preview pages.
2887
+	 *
2888
+	 * @param string $utm_campaign_source what is the key used for google analytics link
2889
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2890
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2891
+	 * @return void
2892
+	 * @throws DomainException
2893
+	 * @throws EE_Error
2894
+	 * @throws InvalidArgumentException
2895
+	 * @throws InvalidDataTypeException
2896
+	 * @throws InvalidInterfaceException
2897
+	 * @since 4.3.2
2898
+	 */
2899
+	public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2900
+	{
2901
+		// let's generate a default preview action button if there isn't one already present.
2902
+		$this->_labels['buttons']['buy_now']           = esc_html__(
2903
+			'Upgrade to Event Espresso 4 Right Now',
2904
+			'event_espresso'
2905
+		);
2906
+		$buy_now_url                                   = add_query_arg(
2907
+			[
2908
+				'ee_ver'       => 'ee4',
2909
+				'utm_source'   => 'ee4_plugin_admin',
2910
+				'utm_medium'   => 'link',
2911
+				'utm_campaign' => $utm_campaign_source,
2912
+				'utm_content'  => 'buy_now_button',
2913
+			],
2914
+			'https://eventespresso.com/pricing/'
2915
+		);
2916
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2917
+			? $this->get_action_link_or_button(
2918
+				'',
2919
+				'buy_now',
2920
+				[],
2921
+				'button button--primary button--big',
2922
+				esc_url_raw($buy_now_url),
2923
+				true
2924
+			)
2925
+			: $this->_template_args['preview_action_button'];
2926
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
2927
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2928
+			$this->_template_args,
2929
+			true
2930
+		);
2931
+		$this->_display_admin_page($display_sidebar);
2932
+	}
2933
+
2934
+
2935
+	/**
2936
+	 * display_admin_list_table_page_with_sidebar
2937
+	 * generates HTML wrapper for an admin_page with list_table
2938
+	 *
2939
+	 * @return void
2940
+	 * @throws DomainException
2941
+	 * @throws EE_Error
2942
+	 * @throws InvalidArgumentException
2943
+	 * @throws InvalidDataTypeException
2944
+	 * @throws InvalidInterfaceException
2945
+	 */
2946
+	public function display_admin_list_table_page_with_sidebar()
2947
+	{
2948
+		$this->_display_admin_list_table_page(true);
2949
+	}
2950
+
2951
+
2952
+	/**
2953
+	 * display_admin_list_table_page_with_no_sidebar
2954
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2955
+	 *
2956
+	 * @return void
2957
+	 * @throws DomainException
2958
+	 * @throws EE_Error
2959
+	 * @throws InvalidArgumentException
2960
+	 * @throws InvalidDataTypeException
2961
+	 * @throws InvalidInterfaceException
2962
+	 */
2963
+	public function display_admin_list_table_page_with_no_sidebar()
2964
+	{
2965
+		$this->_display_admin_list_table_page();
2966
+	}
2967
+
2968
+
2969
+	/**
2970
+	 * generates html wrapper for an admin_list_table page
2971
+	 *
2972
+	 * @param boolean $sidebar whether to display with sidebar or not.
2973
+	 * @return void
2974
+	 * @throws DomainException
2975
+	 * @throws EE_Error
2976
+	 * @throws InvalidArgumentException
2977
+	 * @throws InvalidDataTypeException
2978
+	 * @throws InvalidInterfaceException
2979
+	 */
2980
+	private function _display_admin_list_table_page($sidebar = false)
2981
+	{
2982
+		// setup search attributes
2983
+		$this->_set_search_attributes();
2984
+		$this->_template_args['current_page']     = $this->_wp_page_slug;
2985
+		$template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2986
+		$this->_template_args['table_url']        = $this->request->isAjax()
2987
+			? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2988
+			: add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2989
+		$this->_template_args['list_table']       = $this->_list_table_object;
2990
+		$this->_template_args['current_route']    = $this->_req_action;
2991
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2992
+		$ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2993
+		if (! empty($ajax_sorting_callback)) {
2994
+			$sortable_list_table_form_fields = wp_nonce_field(
2995
+				$ajax_sorting_callback . '_nonce',
2996
+				$ajax_sorting_callback . '_nonce',
2997
+				false,
2998
+				false
2999
+			);
3000
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
3001
+												. $this->page_slug
3002
+												. '" />';
3003
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
3004
+												. $ajax_sorting_callback
3005
+												. '" />';
3006
+		} else {
3007
+			$sortable_list_table_form_fields = '';
3008
+		}
3009
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3010
+
3011
+		$hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
3012
+
3013
+		$nonce_ref          = $this->_req_action . '_nonce';
3014
+		$hidden_form_fields .= '
3015 3015
             <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
3016 3016
 
3017
-        $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
3018
-        // display message about search results?
3019
-        $search                                    = $this->request->getRequestParam('s');
3020
-        $this->_template_args['before_list_table'] .= ! empty($search)
3021
-            ? '<p class="ee-search-results">' . sprintf(
3022
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3023
-                trim($search, '%')
3024
-            ) . '</p>'
3025
-            : '';
3026
-        // filter before_list_table template arg
3027
-        $this->_template_args['before_list_table'] = apply_filters(
3028
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3029
-            $this->_template_args['before_list_table'],
3030
-            $this->page_slug,
3031
-            $this->request->requestParams(),
3032
-            $this->_req_action
3033
-        );
3034
-        // convert to array and filter again
3035
-        // arrays are easier to inject new items in a specific location,
3036
-        // but would not be backwards compatible, so we have to add a new filter
3037
-        $this->_template_args['before_list_table'] = implode(
3038
-            " \n",
3039
-            (array) apply_filters(
3040
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3041
-                (array) $this->_template_args['before_list_table'],
3042
-                $this->page_slug,
3043
-                $this->request->requestParams(),
3044
-                $this->_req_action
3045
-            )
3046
-        );
3047
-        // filter after_list_table template arg
3048
-        $this->_template_args['after_list_table'] = apply_filters(
3049
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3050
-            $this->_template_args['after_list_table'],
3051
-            $this->page_slug,
3052
-            $this->request->requestParams(),
3053
-            $this->_req_action
3054
-        );
3055
-        // convert to array and filter again
3056
-        // arrays are easier to inject new items in a specific location,
3057
-        // but would not be backwards compatible, so we have to add a new filter
3058
-        $this->_template_args['after_list_table']   = implode(
3059
-            " \n",
3060
-            (array) apply_filters(
3061
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3062
-                (array) $this->_template_args['after_list_table'],
3063
-                $this->page_slug,
3064
-                $this->request->requestParams(),
3065
-                $this->_req_action
3066
-            )
3067
-        );
3068
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3069
-            $template_path,
3070
-            $this->_template_args,
3071
-            true
3072
-        );
3073
-        // the final template wrapper
3074
-        if ($sidebar) {
3075
-            $this->display_admin_page_with_sidebar();
3076
-        } else {
3077
-            $this->display_admin_page_with_no_sidebar();
3078
-        }
3079
-    }
3080
-
3081
-
3082
-    /**
3083
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3084
-     * html string for the legend.
3085
-     * $items are expected in an array in the following format:
3086
-     * $legend_items = array(
3087
-     *        'item_id' => array(
3088
-     *            'icon' => 'http://url_to_icon_being_described.png',
3089
-     *            'desc' => esc_html__('localized description of item');
3090
-     *        )
3091
-     * );
3092
-     *
3093
-     * @param array $items see above for format of array
3094
-     * @return string html string of legend
3095
-     * @throws DomainException
3096
-     */
3097
-    protected function _display_legend($items)
3098
-    {
3099
-        $this->_template_args['items'] = apply_filters(
3100
-            'FHEE__EE_Admin_Page___display_legend__items',
3101
-            (array) $items,
3102
-            $this
3103
-        );
3104
-        /** @var StatusChangeNotice $status_change_notice */
3105
-        $status_change_notice                         = $this->loader->getShared(
3106
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3107
-        );
3108
-        $this->_template_args['status_change_notice'] = $status_change_notice->display(
3109
-            '__admin-legend',
3110
-            $this->page_slug
3111
-        );
3112
-        return EEH_Template::display_template(
3113
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3114
-            $this->_template_args,
3115
-            true
3116
-        );
3117
-    }
3118
-
3119
-
3120
-    /**
3121
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3122
-     * The returned json object is created from an array in the following format:
3123
-     * array(
3124
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3125
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3126
-     *  'notices' => '', // - contains any EE_Error formatted notices
3127
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3128
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3129
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3130
-     *  that might be included in here)
3131
-     * )
3132
-     * The json object is populated by whatever is set in the $_template_args property.
3133
-     *
3134
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3135
-     *                                 instead of displayed.
3136
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3137
-     * @return void
3138
-     * @throws EE_Error
3139
-     * @throws InvalidArgumentException
3140
-     * @throws InvalidDataTypeException
3141
-     * @throws InvalidInterfaceException
3142
-     */
3143
-    protected function _return_json($sticky_notices = false, $notices_arguments = [])
3144
-    {
3145
-        // make sure any EE_Error notices have been handled.
3146
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3147
-        $data = isset($this->_template_args['data']) ? $this->_template_args['data'] : [];
3148
-        unset($this->_template_args['data']);
3149
-        $json = [
3150
-            'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3151
-            'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3152
-            'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3153
-            'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3154
-            'notices'   => EE_Error::get_notices(),
3155
-            'content'   => isset($this->_template_args['admin_page_content'])
3156
-                ? $this->_template_args['admin_page_content'] : '',
3157
-            'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3158
-            'isEEajax'  => true
3159
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3160
-        ];
3161
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3162
-        if (null === error_get_last() || ! headers_sent()) {
3163
-            header('Content-Type: application/json; charset=UTF-8');
3164
-        }
3165
-        echo wp_json_encode($json);
3166
-        exit();
3167
-    }
3168
-
3169
-
3170
-    /**
3171
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3172
-     *
3173
-     * @return void
3174
-     * @throws EE_Error
3175
-     * @throws InvalidArgumentException
3176
-     * @throws InvalidDataTypeException
3177
-     * @throws InvalidInterfaceException
3178
-     */
3179
-    public function return_json()
3180
-    {
3181
-        if ($this->request->isAjax()) {
3182
-            $this->_return_json();
3183
-        } else {
3184
-            throw new EE_Error(
3185
-                sprintf(
3186
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3187
-                    __FUNCTION__
3188
-                )
3189
-            );
3190
-        }
3191
-    }
3192
-
3193
-
3194
-    /**
3195
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3196
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3197
-     *
3198
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3199
-     */
3200
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3201
-    {
3202
-        $this->_hook_obj = $hook_obj;
3203
-    }
3204
-
3205
-
3206
-    /**
3207
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3208
-     *
3209
-     * @param boolean $about whether to use the special about page wrapper or default.
3210
-     * @return void
3211
-     * @throws DomainException
3212
-     * @throws EE_Error
3213
-     * @throws InvalidArgumentException
3214
-     * @throws InvalidDataTypeException
3215
-     * @throws InvalidInterfaceException
3216
-     */
3217
-    public function admin_page_wrapper($about = false)
3218
-    {
3219
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3220
-        $this->_nav_tabs                          = $this->_get_main_nav_tabs();
3221
-        $this->_template_args['nav_tabs']         = $this->_nav_tabs;
3222
-        $this->_template_args['admin_page_title'] = $this->_admin_page_title;
3223
-
3224
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3225
-            "FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3226
-            $this->_template_args['before_admin_page_content'] ?? ''
3227
-        );
3228
-
3229
-        $this->_template_args['after_admin_page_content'] = apply_filters(
3230
-            "FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3231
-            $this->_template_args['after_admin_page_content'] ?? ''
3232
-        );
3233
-        $this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3234
-
3235
-        if ($this->request->isAjax()) {
3236
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3237
-            // $template_path,
3238
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3239
-                $this->_template_args,
3240
-                true
3241
-            );
3242
-            $this->_return_json();
3243
-        }
3244
-        // load settings page wrapper template
3245
-        $template_path = $about
3246
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3247
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3248
-
3249
-        EEH_Template::display_template($template_path, $this->_template_args);
3250
-    }
3251
-
3252
-
3253
-    /**
3254
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3255
-     *
3256
-     * @return string html
3257
-     * @throws EE_Error
3258
-     */
3259
-    protected function _get_main_nav_tabs()
3260
-    {
3261
-        // let's generate the html using the EEH_Tabbed_Content helper.
3262
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3263
-        // (rather than setting in the page_routes array)
3264
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3265
-    }
3266
-
3267
-
3268
-    /**
3269
-     *        sort nav tabs
3270
-     *
3271
-     * @param $a
3272
-     * @param $b
3273
-     * @return int
3274
-     */
3275
-    private function _sort_nav_tabs($a, $b)
3276
-    {
3277
-        if ($a['order'] === $b['order']) {
3278
-            return 0;
3279
-        }
3280
-        return ($a['order'] < $b['order']) ? -1 : 1;
3281
-    }
3282
-
3283
-
3284
-    /**
3285
-     * generates HTML for the forms used on admin pages
3286
-     *
3287
-     * @param array  $input_vars - array of input field details
3288
-     * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3289
-     * @param bool   $id
3290
-     * @return array|string
3291
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3292
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3293
-     */
3294
-    protected function _generate_admin_form_fields($input_vars = [], $generator = 'string', $id = false)
3295
-    {
3296
-        return $generator === 'string'
3297
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3298
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3299
-    }
3300
-
3301
-
3302
-    /**
3303
-     * generates the "Save" and "Save & Close" buttons for edit forms
3304
-     *
3305
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3306
-     *                                   Close" button.
3307
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3308
-     *                                   'Save', [1] => 'save & close')
3309
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3310
-     *                                   via the "name" value in the button).  We can also use this to just dump
3311
-     *                                   default actions by submitting some other value.
3312
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3313
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3314
-     *                                   close (normal form handling).
3315
-     */
3316
-    protected function _set_save_buttons($both = true, $text = [], $actions = [], $referrer = null)
3317
-    {
3318
-        // make sure $text and $actions are in an array
3319
-        $text          = (array) $text;
3320
-        $actions       = (array) $actions;
3321
-        $referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3322
-        $button_text   = ! empty($text)
3323
-            ? $text
3324
-            : [
3325
-                esc_html__('Save', 'event_espresso'),
3326
-                esc_html__('Save and Close', 'event_espresso'),
3327
-            ];
3328
-        $default_names = ['save', 'save_and_close'];
3329
-        $buttons       = '';
3330
-        foreach ($button_text as $key => $button) {
3331
-            $ref     = $default_names[ $key ];
3332
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3333
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3334
-                        . 'value="' . $button . '" name="' . $name . '" '
3335
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3336
-            if (! $both) {
3337
-                break;
3338
-            }
3339
-        }
3340
-        // add in a hidden index for the current page (so save and close redirects properly)
3341
-        $buttons                              .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3342
-                                                 . $referrer_url
3343
-                                                 . '" />';
3344
-        $this->_template_args['save_buttons'] = $buttons;
3345
-    }
3346
-
3347
-
3348
-    /**
3349
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3350
-     *
3351
-     * @param string $route
3352
-     * @param array  $additional_hidden_fields
3353
-     * @see   $this->_set_add_edit_form_tags() for details on params
3354
-     * @since 4.6.0
3355
-     */
3356
-    public function set_add_edit_form_tags($route = '', $additional_hidden_fields = [])
3357
-    {
3358
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3359
-    }
3360
-
3361
-
3362
-    /**
3363
-     * set form open and close tags on add/edit pages.
3364
-     *
3365
-     * @param string $route                    the route you want the form to direct to
3366
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3367
-     * @return void
3368
-     */
3369
-    protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = [])
3370
-    {
3371
-        if (empty($route)) {
3372
-            $user_msg = esc_html__(
3373
-                'An error occurred. No action was set for this page\'s form.',
3374
-                'event_espresso'
3375
-            );
3376
-            $dev_msg  = $user_msg . "\n"
3377
-                        . sprintf(
3378
-                            esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3379
-                            __FUNCTION__,
3380
-                            __CLASS__
3381
-                        );
3382
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3383
-        }
3384
-        // open form
3385
-        $action                                            = $this->_admin_base_url;
3386
-        $this->_template_args['before_admin_page_content'] = "
3017
+		$this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
3018
+		// display message about search results?
3019
+		$search                                    = $this->request->getRequestParam('s');
3020
+		$this->_template_args['before_list_table'] .= ! empty($search)
3021
+			? '<p class="ee-search-results">' . sprintf(
3022
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3023
+				trim($search, '%')
3024
+			) . '</p>'
3025
+			: '';
3026
+		// filter before_list_table template arg
3027
+		$this->_template_args['before_list_table'] = apply_filters(
3028
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3029
+			$this->_template_args['before_list_table'],
3030
+			$this->page_slug,
3031
+			$this->request->requestParams(),
3032
+			$this->_req_action
3033
+		);
3034
+		// convert to array and filter again
3035
+		// arrays are easier to inject new items in a specific location,
3036
+		// but would not be backwards compatible, so we have to add a new filter
3037
+		$this->_template_args['before_list_table'] = implode(
3038
+			" \n",
3039
+			(array) apply_filters(
3040
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3041
+				(array) $this->_template_args['before_list_table'],
3042
+				$this->page_slug,
3043
+				$this->request->requestParams(),
3044
+				$this->_req_action
3045
+			)
3046
+		);
3047
+		// filter after_list_table template arg
3048
+		$this->_template_args['after_list_table'] = apply_filters(
3049
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3050
+			$this->_template_args['after_list_table'],
3051
+			$this->page_slug,
3052
+			$this->request->requestParams(),
3053
+			$this->_req_action
3054
+		);
3055
+		// convert to array and filter again
3056
+		// arrays are easier to inject new items in a specific location,
3057
+		// but would not be backwards compatible, so we have to add a new filter
3058
+		$this->_template_args['after_list_table']   = implode(
3059
+			" \n",
3060
+			(array) apply_filters(
3061
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3062
+				(array) $this->_template_args['after_list_table'],
3063
+				$this->page_slug,
3064
+				$this->request->requestParams(),
3065
+				$this->_req_action
3066
+			)
3067
+		);
3068
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3069
+			$template_path,
3070
+			$this->_template_args,
3071
+			true
3072
+		);
3073
+		// the final template wrapper
3074
+		if ($sidebar) {
3075
+			$this->display_admin_page_with_sidebar();
3076
+		} else {
3077
+			$this->display_admin_page_with_no_sidebar();
3078
+		}
3079
+	}
3080
+
3081
+
3082
+	/**
3083
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3084
+	 * html string for the legend.
3085
+	 * $items are expected in an array in the following format:
3086
+	 * $legend_items = array(
3087
+	 *        'item_id' => array(
3088
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3089
+	 *            'desc' => esc_html__('localized description of item');
3090
+	 *        )
3091
+	 * );
3092
+	 *
3093
+	 * @param array $items see above for format of array
3094
+	 * @return string html string of legend
3095
+	 * @throws DomainException
3096
+	 */
3097
+	protected function _display_legend($items)
3098
+	{
3099
+		$this->_template_args['items'] = apply_filters(
3100
+			'FHEE__EE_Admin_Page___display_legend__items',
3101
+			(array) $items,
3102
+			$this
3103
+		);
3104
+		/** @var StatusChangeNotice $status_change_notice */
3105
+		$status_change_notice                         = $this->loader->getShared(
3106
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3107
+		);
3108
+		$this->_template_args['status_change_notice'] = $status_change_notice->display(
3109
+			'__admin-legend',
3110
+			$this->page_slug
3111
+		);
3112
+		return EEH_Template::display_template(
3113
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3114
+			$this->_template_args,
3115
+			true
3116
+		);
3117
+	}
3118
+
3119
+
3120
+	/**
3121
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3122
+	 * The returned json object is created from an array in the following format:
3123
+	 * array(
3124
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3125
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3126
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3127
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3128
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3129
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3130
+	 *  that might be included in here)
3131
+	 * )
3132
+	 * The json object is populated by whatever is set in the $_template_args property.
3133
+	 *
3134
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3135
+	 *                                 instead of displayed.
3136
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3137
+	 * @return void
3138
+	 * @throws EE_Error
3139
+	 * @throws InvalidArgumentException
3140
+	 * @throws InvalidDataTypeException
3141
+	 * @throws InvalidInterfaceException
3142
+	 */
3143
+	protected function _return_json($sticky_notices = false, $notices_arguments = [])
3144
+	{
3145
+		// make sure any EE_Error notices have been handled.
3146
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3147
+		$data = isset($this->_template_args['data']) ? $this->_template_args['data'] : [];
3148
+		unset($this->_template_args['data']);
3149
+		$json = [
3150
+			'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3151
+			'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3152
+			'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3153
+			'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3154
+			'notices'   => EE_Error::get_notices(),
3155
+			'content'   => isset($this->_template_args['admin_page_content'])
3156
+				? $this->_template_args['admin_page_content'] : '',
3157
+			'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3158
+			'isEEajax'  => true
3159
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3160
+		];
3161
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3162
+		if (null === error_get_last() || ! headers_sent()) {
3163
+			header('Content-Type: application/json; charset=UTF-8');
3164
+		}
3165
+		echo wp_json_encode($json);
3166
+		exit();
3167
+	}
3168
+
3169
+
3170
+	/**
3171
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3172
+	 *
3173
+	 * @return void
3174
+	 * @throws EE_Error
3175
+	 * @throws InvalidArgumentException
3176
+	 * @throws InvalidDataTypeException
3177
+	 * @throws InvalidInterfaceException
3178
+	 */
3179
+	public function return_json()
3180
+	{
3181
+		if ($this->request->isAjax()) {
3182
+			$this->_return_json();
3183
+		} else {
3184
+			throw new EE_Error(
3185
+				sprintf(
3186
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3187
+					__FUNCTION__
3188
+				)
3189
+			);
3190
+		}
3191
+	}
3192
+
3193
+
3194
+	/**
3195
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3196
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3197
+	 *
3198
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3199
+	 */
3200
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3201
+	{
3202
+		$this->_hook_obj = $hook_obj;
3203
+	}
3204
+
3205
+
3206
+	/**
3207
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3208
+	 *
3209
+	 * @param boolean $about whether to use the special about page wrapper or default.
3210
+	 * @return void
3211
+	 * @throws DomainException
3212
+	 * @throws EE_Error
3213
+	 * @throws InvalidArgumentException
3214
+	 * @throws InvalidDataTypeException
3215
+	 * @throws InvalidInterfaceException
3216
+	 */
3217
+	public function admin_page_wrapper($about = false)
3218
+	{
3219
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3220
+		$this->_nav_tabs                          = $this->_get_main_nav_tabs();
3221
+		$this->_template_args['nav_tabs']         = $this->_nav_tabs;
3222
+		$this->_template_args['admin_page_title'] = $this->_admin_page_title;
3223
+
3224
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3225
+			"FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3226
+			$this->_template_args['before_admin_page_content'] ?? ''
3227
+		);
3228
+
3229
+		$this->_template_args['after_admin_page_content'] = apply_filters(
3230
+			"FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3231
+			$this->_template_args['after_admin_page_content'] ?? ''
3232
+		);
3233
+		$this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3234
+
3235
+		if ($this->request->isAjax()) {
3236
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3237
+			// $template_path,
3238
+				EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3239
+				$this->_template_args,
3240
+				true
3241
+			);
3242
+			$this->_return_json();
3243
+		}
3244
+		// load settings page wrapper template
3245
+		$template_path = $about
3246
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3247
+			: EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3248
+
3249
+		EEH_Template::display_template($template_path, $this->_template_args);
3250
+	}
3251
+
3252
+
3253
+	/**
3254
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3255
+	 *
3256
+	 * @return string html
3257
+	 * @throws EE_Error
3258
+	 */
3259
+	protected function _get_main_nav_tabs()
3260
+	{
3261
+		// let's generate the html using the EEH_Tabbed_Content helper.
3262
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3263
+		// (rather than setting in the page_routes array)
3264
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3265
+	}
3266
+
3267
+
3268
+	/**
3269
+	 *        sort nav tabs
3270
+	 *
3271
+	 * @param $a
3272
+	 * @param $b
3273
+	 * @return int
3274
+	 */
3275
+	private function _sort_nav_tabs($a, $b)
3276
+	{
3277
+		if ($a['order'] === $b['order']) {
3278
+			return 0;
3279
+		}
3280
+		return ($a['order'] < $b['order']) ? -1 : 1;
3281
+	}
3282
+
3283
+
3284
+	/**
3285
+	 * generates HTML for the forms used on admin pages
3286
+	 *
3287
+	 * @param array  $input_vars - array of input field details
3288
+	 * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3289
+	 * @param bool   $id
3290
+	 * @return array|string
3291
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3292
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3293
+	 */
3294
+	protected function _generate_admin_form_fields($input_vars = [], $generator = 'string', $id = false)
3295
+	{
3296
+		return $generator === 'string'
3297
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3298
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3299
+	}
3300
+
3301
+
3302
+	/**
3303
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3304
+	 *
3305
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3306
+	 *                                   Close" button.
3307
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3308
+	 *                                   'Save', [1] => 'save & close')
3309
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3310
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3311
+	 *                                   default actions by submitting some other value.
3312
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3313
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3314
+	 *                                   close (normal form handling).
3315
+	 */
3316
+	protected function _set_save_buttons($both = true, $text = [], $actions = [], $referrer = null)
3317
+	{
3318
+		// make sure $text and $actions are in an array
3319
+		$text          = (array) $text;
3320
+		$actions       = (array) $actions;
3321
+		$referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3322
+		$button_text   = ! empty($text)
3323
+			? $text
3324
+			: [
3325
+				esc_html__('Save', 'event_espresso'),
3326
+				esc_html__('Save and Close', 'event_espresso'),
3327
+			];
3328
+		$default_names = ['save', 'save_and_close'];
3329
+		$buttons       = '';
3330
+		foreach ($button_text as $key => $button) {
3331
+			$ref     = $default_names[ $key ];
3332
+			$name    = ! empty($actions) ? $actions[ $key ] : $ref;
3333
+			$buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3334
+						. 'value="' . $button . '" name="' . $name . '" '
3335
+						. 'id="' . $this->_current_view . '_' . $ref . '" />';
3336
+			if (! $both) {
3337
+				break;
3338
+			}
3339
+		}
3340
+		// add in a hidden index for the current page (so save and close redirects properly)
3341
+		$buttons                              .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3342
+												 . $referrer_url
3343
+												 . '" />';
3344
+		$this->_template_args['save_buttons'] = $buttons;
3345
+	}
3346
+
3347
+
3348
+	/**
3349
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3350
+	 *
3351
+	 * @param string $route
3352
+	 * @param array  $additional_hidden_fields
3353
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3354
+	 * @since 4.6.0
3355
+	 */
3356
+	public function set_add_edit_form_tags($route = '', $additional_hidden_fields = [])
3357
+	{
3358
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3359
+	}
3360
+
3361
+
3362
+	/**
3363
+	 * set form open and close tags on add/edit pages.
3364
+	 *
3365
+	 * @param string $route                    the route you want the form to direct to
3366
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3367
+	 * @return void
3368
+	 */
3369
+	protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = [])
3370
+	{
3371
+		if (empty($route)) {
3372
+			$user_msg = esc_html__(
3373
+				'An error occurred. No action was set for this page\'s form.',
3374
+				'event_espresso'
3375
+			);
3376
+			$dev_msg  = $user_msg . "\n"
3377
+						. sprintf(
3378
+							esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3379
+							__FUNCTION__,
3380
+							__CLASS__
3381
+						);
3382
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3383
+		}
3384
+		// open form
3385
+		$action                                            = $this->_admin_base_url;
3386
+		$this->_template_args['before_admin_page_content'] = "
3387 3387
             <form name='form' method='post' action='{$action}' id='{$route}_event_form' class='ee-admin-page-form' >
3388 3388
             ";
3389
-        // add nonce
3390
-        $nonce                                             =
3391
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3392
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3393
-        // add REQUIRED form action
3394
-        $hidden_fields = [
3395
-            'action' => ['type' => 'hidden', 'value' => $route],
3396
-        ];
3397
-        // merge arrays
3398
-        $hidden_fields = is_array($additional_hidden_fields)
3399
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3400
-            : $hidden_fields;
3401
-        // generate form fields
3402
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3403
-        // add fields to form
3404
-        foreach ((array) $form_fields as $form_field) {
3405
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3406
-        }
3407
-        // close form
3408
-        $this->_template_args['after_admin_page_content'] = '</form>';
3409
-    }
3410
-
3411
-
3412
-    /**
3413
-     * Public Wrapper for _redirect_after_action() method since its
3414
-     * discovered it would be useful for external code to have access.
3415
-     *
3416
-     * @param bool   $success
3417
-     * @param string $what
3418
-     * @param string $action_desc
3419
-     * @param array  $query_args
3420
-     * @param bool   $override_overwrite
3421
-     * @throws EE_Error
3422
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3423
-     * @since 4.5.0
3424
-     */
3425
-    public function redirect_after_action(
3426
-        $success = false,
3427
-        $what = 'item',
3428
-        $action_desc = 'processed',
3429
-        $query_args = [],
3430
-        $override_overwrite = false
3431
-    ) {
3432
-        $this->_redirect_after_action(
3433
-            $success,
3434
-            $what,
3435
-            $action_desc,
3436
-            $query_args,
3437
-            $override_overwrite
3438
-        );
3439
-    }
3440
-
3441
-
3442
-    /**
3443
-     * Helper method for merging existing request data with the returned redirect url.
3444
-     *
3445
-     * This is typically used for redirects after an action so that if the original view was a filtered view those
3446
-     * filters are still applied.
3447
-     *
3448
-     * @param array $new_route_data
3449
-     * @return array
3450
-     */
3451
-    protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data)
3452
-    {
3453
-        foreach ($this->request->requestParams() as $ref => $value) {
3454
-            // unset nonces
3455
-            if (strpos($ref, 'nonce') !== false) {
3456
-                $this->request->unSetRequestParam($ref);
3457
-                continue;
3458
-            }
3459
-            // urlencode values.
3460
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3461
-            $this->request->setRequestParam($ref, $value);
3462
-        }
3463
-        return array_merge($this->request->requestParams(), $new_route_data);
3464
-    }
3465
-
3466
-
3467
-    /**
3468
-     * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3469
-     * @param string           $what               - what the action was performed on
3470
-     * @param string           $action_desc        - what was done ie: updated, deleted, etc
3471
-     * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3472
-     * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3473
-     *                                             this allows you to override this so that they show.
3474
-     * @return void
3475
-     * @throws EE_Error
3476
-     * @throws InvalidArgumentException
3477
-     * @throws InvalidDataTypeException
3478
-     * @throws InvalidInterfaceException
3479
-     */
3480
-    protected function _redirect_after_action(
3481
-        $success = 0,
3482
-        string $what = 'item',
3483
-        string $action_desc = 'processed',
3484
-        array $query_args = [],
3485
-        bool $override_overwrite = false
3486
-    ) {
3487
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3488
-        $notices = EE_Error::get_notices(false);
3489
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3490
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3491
-            EE_Error::overwrite_success();
3492
-        }
3493
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3494
-            // how many records affected ? more than one record ? or just one ?
3495
-            EE_Error::add_success(
3496
-                sprintf(
3497
-                    esc_html(
3498
-                        _n(
3499
-                            'The "%1$s" has been successfully %2$s.',
3500
-                            'The "%1$s" have been successfully %2$s.',
3501
-                            $success,
3502
-                            'event_espresso'
3503
-                        )
3504
-                    ),
3505
-                    $what,
3506
-                    $action_desc
3507
-                ),
3508
-                __FILE__,
3509
-                __FUNCTION__,
3510
-                __LINE__
3511
-            );
3512
-        }
3513
-        // check that $query_args isn't something crazy
3514
-        if (! is_array($query_args)) {
3515
-            $query_args = [];
3516
-        }
3517
-        /**
3518
-         * Allow injecting actions before the query_args are modified for possible different
3519
-         * redirections on save and close actions
3520
-         *
3521
-         * @param array $query_args       The original query_args array coming into the
3522
-         *                                method.
3523
-         * @since 4.2.0
3524
-         */
3525
-        do_action(
3526
-            "AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3527
-            $query_args
3528
-        );
3529
-        // set redirect url.
3530
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3531
-        // otherwise we go with whatever is set as the _admin_base_url
3532
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3533
-        // calculate where we're going (if we have a "save and close" button pushed)
3534
-        if (
3535
-            $this->request->requestParamIsSet('save_and_close')
3536
-            && $this->request->requestParamIsSet('save_and_close_referrer')
3537
-        ) {
3538
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3539
-            $parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', 'url'));
3540
-            // regenerate query args array from referrer URL
3541
-            parse_str($parsed_url['query'], $query_args);
3542
-            // correct page and action will be in the query args now
3543
-            $redirect_url = admin_url('admin.php');
3544
-        }
3545
-        // merge any default query_args set in _default_route_query_args property
3546
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3547
-            $args_to_merge = [];
3548
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3549
-                // is there a wp_referer array in our _default_route_query_args property?
3550
-                if ($query_param === 'wp_referer') {
3551
-                    $query_value = (array) $query_value;
3552
-                    foreach ($query_value as $reference => $value) {
3553
-                        if (strpos($reference, 'nonce') !== false) {
3554
-                            continue;
3555
-                        }
3556
-                        // finally we will override any arguments in the referer with
3557
-                        // what might be set on the _default_route_query_args array.
3558
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3559
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3560
-                        } else {
3561
-                            $args_to_merge[ $reference ] = urlencode($value);
3562
-                        }
3563
-                    }
3564
-                    continue;
3565
-                }
3566
-                $args_to_merge[ $query_param ] = $query_value;
3567
-            }
3568
-            // now let's merge these arguments but override with what was specifically sent in to the
3569
-            // redirect.
3570
-            $query_args = array_merge($args_to_merge, $query_args);
3571
-        }
3572
-        $this->_process_notices($query_args);
3573
-        // generate redirect url
3574
-        // if redirecting to anything other than the main page, add a nonce
3575
-        if (isset($query_args['action'])) {
3576
-            // manually generate wp_nonce and merge that with the query vars
3577
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3578
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3579
-        }
3580
-        // we're adding some hooks and filters in here for processing any things just before redirects
3581
-        // (example: an admin page has done an insert or update and we want to run something after that).
3582
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3583
-        $redirect_url = apply_filters(
3584
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3585
-            EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3586
-            $query_args
3587
-        );
3588
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3589
-        if ($this->request->isAjax()) {
3590
-            $default_data                    = [
3591
-                'close'        => true,
3592
-                'redirect_url' => $redirect_url,
3593
-                'where'        => 'main',
3594
-                'what'         => 'append',
3595
-            ];
3596
-            $this->_template_args['success'] = $success;
3597
-            $this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3598
-                $default_data,
3599
-                $this->_template_args['data']
3600
-            ) : $default_data;
3601
-            $this->_return_json();
3602
-        }
3603
-        wp_safe_redirect($redirect_url);
3604
-        exit();
3605
-    }
3606
-
3607
-
3608
-    /**
3609
-     * process any notices before redirecting (or returning ajax request)
3610
-     * This method sets the $this->_template_args['notices'] attribute;
3611
-     *
3612
-     * @param array $query_args         any query args that need to be used for notice transient ('action')
3613
-     * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3614
-     *                                  page_routes haven't been defined yet.
3615
-     * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3616
-     *                                  still save a transient for the notice.
3617
-     * @return void
3618
-     * @throws EE_Error
3619
-     * @throws InvalidArgumentException
3620
-     * @throws InvalidDataTypeException
3621
-     * @throws InvalidInterfaceException
3622
-     */
3623
-    protected function _process_notices($query_args = [], $skip_route_verify = false, $sticky_notices = true)
3624
-    {
3625
-        // first let's set individual error properties if doing_ajax and the properties aren't already set.
3626
-        if ($this->request->isAjax()) {
3627
-            $notices = EE_Error::get_notices(false);
3628
-            if (empty($this->_template_args['success'])) {
3629
-                $this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3630
-            }
3631
-            if (empty($this->_template_args['errors'])) {
3632
-                $this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3633
-            }
3634
-            if (empty($this->_template_args['attention'])) {
3635
-                $this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3636
-            }
3637
-        }
3638
-        $this->_template_args['notices'] = EE_Error::get_notices();
3639
-        // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3640
-        if (! $this->request->isAjax() || $sticky_notices) {
3641
-            $route = isset($query_args['action']) ? $query_args['action'] : 'default';
3642
-            $this->_add_transient(
3643
-                $route,
3644
-                $this->_template_args['notices'],
3645
-                true,
3646
-                $skip_route_verify
3647
-            );
3648
-        }
3649
-    }
3650
-
3651
-
3652
-    /**
3653
-     * get_action_link_or_button
3654
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3655
-     *
3656
-     * @param string $action        use this to indicate which action the url is generated with.
3657
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3658
-     *                              property.
3659
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3660
-     * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3661
-     * @param string $base_url      If this is not provided
3662
-     *                              the _admin_base_url will be used as the default for the button base_url.
3663
-     *                              Otherwise this value will be used.
3664
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3665
-     * @return string
3666
-     * @throws InvalidArgumentException
3667
-     * @throws InvalidInterfaceException
3668
-     * @throws InvalidDataTypeException
3669
-     * @throws EE_Error
3670
-     */
3671
-    public function get_action_link_or_button(
3672
-        $action,
3673
-        $type = 'add',
3674
-        $extra_request = [],
3675
-        $class = 'button button--primary',
3676
-        $base_url = '',
3677
-        $exclude_nonce = false
3678
-    ) {
3679
-        // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3680
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3681
-            throw new EE_Error(
3682
-                sprintf(
3683
-                    esc_html__(
3684
-                        'There is no page route for given action for the button.  This action was given: %s',
3685
-                        'event_espresso'
3686
-                    ),
3687
-                    $action
3688
-                )
3689
-            );
3690
-        }
3691
-        if (! isset($this->_labels['buttons'][ $type ])) {
3692
-            throw new EE_Error(
3693
-                sprintf(
3694
-                    esc_html__(
3695
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3696
-                        'event_espresso'
3697
-                    ),
3698
-                    $type
3699
-                )
3700
-            );
3701
-        }
3702
-        // finally check user access for this button.
3703
-        $has_access = $this->check_user_access($action, true);
3704
-        if (! $has_access) {
3705
-            return '';
3706
-        }
3707
-        $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3708
-        $query_args = [
3709
-            'action' => $action,
3710
-        ];
3711
-        // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3712
-        if (! empty($extra_request)) {
3713
-            $query_args = array_merge($extra_request, $query_args);
3714
-        }
3715
-        $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3716
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3717
-    }
3718
-
3719
-
3720
-    /**
3721
-     * _per_page_screen_option
3722
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3723
-     *
3724
-     * @return void
3725
-     * @throws InvalidArgumentException
3726
-     * @throws InvalidInterfaceException
3727
-     * @throws InvalidDataTypeException
3728
-     */
3729
-    protected function _per_page_screen_option()
3730
-    {
3731
-        $option = 'per_page';
3732
-        $args   = [
3733
-            'label'   => apply_filters(
3734
-                'FHEE__EE_Admin_Page___per_page_screen_options___label',
3735
-                $this->_admin_page_title,
3736
-                $this
3737
-            ),
3738
-            'default' => (int) apply_filters(
3739
-                'FHEE__EE_Admin_Page___per_page_screen_options__default',
3740
-                20
3741
-            ),
3742
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3743
-        ];
3744
-        // ONLY add the screen option if the user has access to it.
3745
-        if ($this->check_user_access($this->_current_view, true)) {
3746
-            add_screen_option($option, $args);
3747
-        }
3748
-    }
3749
-
3750
-
3751
-    /**
3752
-     * set_per_page_screen_option
3753
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3754
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3755
-     * admin_menu.
3756
-     *
3757
-     * @return void
3758
-     */
3759
-    private function _set_per_page_screen_options()
3760
-    {
3761
-        if ($this->request->requestParamIsSet('wp_screen_options')) {
3762
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3763
-            if (! $user = wp_get_current_user()) {
3764
-                return;
3765
-            }
3766
-            $option = $this->request->getRequestParam('wp_screen_options[option]', '', 'key');
3767
-            if (! $option) {
3768
-                return;
3769
-            }
3770
-            $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, 'int');
3771
-            $map_option = $option;
3772
-            $option     = str_replace('-', '_', $option);
3773
-            switch ($map_option) {
3774
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3775
-                    $max_value = apply_filters(
3776
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3777
-                        999,
3778
-                        $this->_current_page,
3779
-                        $this->_current_view
3780
-                    );
3781
-                    if ($value < 1) {
3782
-                        return;
3783
-                    }
3784
-                    $value = min($value, $max_value);
3785
-                    break;
3786
-                default:
3787
-                    $value = apply_filters(
3788
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3789
-                        false,
3790
-                        $option,
3791
-                        $value
3792
-                    );
3793
-                    if (false === $value) {
3794
-                        return;
3795
-                    }
3796
-                    break;
3797
-            }
3798
-            update_user_meta($user->ID, $option, $value);
3799
-            wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3800
-            exit;
3801
-        }
3802
-    }
3803
-
3804
-
3805
-    /**
3806
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3807
-     *
3808
-     * @param array $data array that will be assigned to template args.
3809
-     */
3810
-    public function set_template_args($data)
3811
-    {
3812
-        $this->_template_args = array_merge($this->_template_args, (array) $data);
3813
-    }
3814
-
3815
-
3816
-    /**
3817
-     * This makes available the WP transient system for temporarily moving data between routes
3818
-     *
3819
-     * @param string $route             the route that should receive the transient
3820
-     * @param array  $data              the data that gets sent
3821
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3822
-     *                                  normal route transient.
3823
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3824
-     *                                  when we are adding a transient before page_routes have been defined.
3825
-     * @return void
3826
-     * @throws EE_Error
3827
-     */
3828
-    protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3829
-    {
3830
-        $user_id = get_current_user_id();
3831
-        if (! $skip_route_verify) {
3832
-            $this->_verify_route($route);
3833
-        }
3834
-        // now let's set the string for what kind of transient we're setting
3835
-        $transient = $notices
3836
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3837
-            : 'rte_tx_' . $route . '_' . $user_id;
3838
-        $data      = $notices ? ['notices' => $data] : $data;
3839
-        // is there already a transient for this route?  If there is then let's ADD to that transient
3840
-        $existing = is_multisite() && is_network_admin()
3841
-            ? get_site_transient($transient)
3842
-            : get_transient($transient);
3843
-        if ($existing) {
3844
-            $data = array_merge((array) $data, (array) $existing);
3845
-        }
3846
-        if (is_multisite() && is_network_admin()) {
3847
-            set_site_transient($transient, $data, 8);
3848
-        } else {
3849
-            set_transient($transient, $data, 8);
3850
-        }
3851
-    }
3852
-
3853
-
3854
-    /**
3855
-     * this retrieves the temporary transient that has been set for moving data between routes.
3856
-     *
3857
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3858
-     * @param string $route
3859
-     * @return mixed data
3860
-     */
3861
-    protected function _get_transient($notices = false, $route = '')
3862
-    {
3863
-        $user_id   = get_current_user_id();
3864
-        $route     = ! $route ? $this->_req_action : $route;
3865
-        $transient = $notices
3866
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3867
-            : 'rte_tx_' . $route . '_' . $user_id;
3868
-        $data      = is_multisite() && is_network_admin()
3869
-            ? get_site_transient($transient)
3870
-            : get_transient($transient);
3871
-        // delete transient after retrieval (just in case it hasn't expired);
3872
-        if (is_multisite() && is_network_admin()) {
3873
-            delete_site_transient($transient);
3874
-        } else {
3875
-            delete_transient($transient);
3876
-        }
3877
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3878
-    }
3879
-
3880
-
3881
-    /**
3882
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3883
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3884
-     * default route callback on the EE_Admin page you want it run.)
3885
-     *
3886
-     * @return void
3887
-     */
3888
-    protected function _transient_garbage_collection()
3889
-    {
3890
-        global $wpdb;
3891
-        // retrieve all existing transients
3892
-        $query =
3893
-            "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3894
-        if ($results = $wpdb->get_results($query)) {
3895
-            foreach ($results as $result) {
3896
-                $transient = str_replace('_transient_', '', $result->option_name);
3897
-                get_transient($transient);
3898
-                if (is_multisite() && is_network_admin()) {
3899
-                    get_site_transient($transient);
3900
-                }
3901
-            }
3902
-        }
3903
-    }
3904
-
3905
-
3906
-    /**
3907
-     * get_view
3908
-     *
3909
-     * @return string content of _view property
3910
-     */
3911
-    public function get_view()
3912
-    {
3913
-        return $this->_view;
3914
-    }
3915
-
3916
-
3917
-    /**
3918
-     * getter for the protected $_views property
3919
-     *
3920
-     * @return array
3921
-     */
3922
-    public function get_views()
3923
-    {
3924
-        return $this->_views;
3925
-    }
3926
-
3927
-
3928
-    /**
3929
-     * get_current_page
3930
-     *
3931
-     * @return string _current_page property value
3932
-     */
3933
-    public function get_current_page()
3934
-    {
3935
-        return $this->_current_page;
3936
-    }
3937
-
3938
-
3939
-    /**
3940
-     * get_current_view
3941
-     *
3942
-     * @return string _current_view property value
3943
-     */
3944
-    public function get_current_view()
3945
-    {
3946
-        return $this->_current_view;
3947
-    }
3948
-
3949
-
3950
-    /**
3951
-     * get_current_screen
3952
-     *
3953
-     * @return object The current WP_Screen object
3954
-     */
3955
-    public function get_current_screen()
3956
-    {
3957
-        return $this->_current_screen;
3958
-    }
3959
-
3960
-
3961
-    /**
3962
-     * get_current_page_view_url
3963
-     *
3964
-     * @return string This returns the url for the current_page_view.
3965
-     */
3966
-    public function get_current_page_view_url()
3967
-    {
3968
-        return $this->_current_page_view_url;
3969
-    }
3970
-
3971
-
3972
-    /**
3973
-     * just returns the Request
3974
-     *
3975
-     * @return RequestInterface
3976
-     */
3977
-    public function get_request()
3978
-    {
3979
-        return $this->request;
3980
-    }
3981
-
3982
-
3983
-    /**
3984
-     * just returns the _req_data property
3985
-     *
3986
-     * @return array
3987
-     */
3988
-    public function get_request_data()
3989
-    {
3990
-        return $this->request->requestParams();
3991
-    }
3992
-
3993
-
3994
-    /**
3995
-     * returns the _req_data protected property
3996
-     *
3997
-     * @return string
3998
-     */
3999
-    public function get_req_action()
4000
-    {
4001
-        return $this->_req_action;
4002
-    }
4003
-
4004
-
4005
-    /**
4006
-     * @return bool  value of $_is_caf property
4007
-     */
4008
-    public function is_caf()
4009
-    {
4010
-        return $this->_is_caf;
4011
-    }
4012
-
4013
-
4014
-    /**
4015
-     * @return mixed
4016
-     */
4017
-    public function default_espresso_metaboxes()
4018
-    {
4019
-        return $this->_default_espresso_metaboxes;
4020
-    }
4021
-
4022
-
4023
-    /**
4024
-     * @return mixed
4025
-     */
4026
-    public function admin_base_url()
4027
-    {
4028
-        return $this->_admin_base_url;
4029
-    }
4030
-
4031
-
4032
-    /**
4033
-     * @return mixed
4034
-     */
4035
-    public function wp_page_slug()
4036
-    {
4037
-        return $this->_wp_page_slug;
4038
-    }
4039
-
4040
-
4041
-    /**
4042
-     * updates  espresso configuration settings
4043
-     *
4044
-     * @param string                   $tab
4045
-     * @param EE_Config_Base|EE_Config $config
4046
-     * @param string                   $file file where error occurred
4047
-     * @param string                   $func function  where error occurred
4048
-     * @param string                   $line line no where error occurred
4049
-     * @return boolean
4050
-     */
4051
-    protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4052
-    {
4053
-        // remove any options that are NOT going to be saved with the config settings.
4054
-        if (isset($config->core->ee_ueip_optin)) {
4055
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4056
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4057
-            update_option('ee_ueip_has_notified', true);
4058
-        }
4059
-        // and save it (note we're also doing the network save here)
4060
-        $net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4061
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4062
-        if ($config_saved && $net_saved) {
4063
-            EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4064
-            return true;
4065
-        }
4066
-        EE_Error::add_error(
4067
-            sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4068
-            $file,
4069
-            $func,
4070
-            $line
4071
-        );
4072
-        return false;
4073
-    }
4074
-
4075
-
4076
-    /**
4077
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4078
-     *
4079
-     * @return array
4080
-     */
4081
-    public function get_yes_no_values()
4082
-    {
4083
-        return $this->_yes_no_values;
4084
-    }
4085
-
4086
-
4087
-    /**
4088
-     * @return string
4089
-     * @throws ReflectionException
4090
-     * @since $VID:$
4091
-     */
4092
-    protected function _get_dir()
4093
-    {
4094
-        $reflector = new ReflectionClass($this->class_name);
4095
-        return dirname($reflector->getFileName());
4096
-    }
4097
-
4098
-
4099
-    /**
4100
-     * A helper for getting a "next link".
4101
-     *
4102
-     * @param string $url   The url to link to
4103
-     * @param string $class The class to use.
4104
-     * @return string
4105
-     */
4106
-    protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4107
-    {
4108
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4109
-    }
4110
-
4111
-
4112
-    /**
4113
-     * A helper for getting a "previous link".
4114
-     *
4115
-     * @param string $url   The url to link to
4116
-     * @param string $class The class to use.
4117
-     * @return string
4118
-     */
4119
-    protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4120
-    {
4121
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4122
-    }
4123
-
4124
-
4125
-
4126
-
4127
-
4128
-
4129
-
4130
-    // below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4131
-
4132
-
4133
-    /**
4134
-     * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4135
-     * knows that the _REG_ID isn't in the req_data array but CAN obtain it, the caller should ADD the _REG_ID to the
4136
-     * _req_data array.
4137
-     *
4138
-     * @return bool success/fail
4139
-     * @throws EE_Error
4140
-     * @throws InvalidArgumentException
4141
-     * @throws ReflectionException
4142
-     * @throws InvalidDataTypeException
4143
-     * @throws InvalidInterfaceException
4144
-     */
4145
-    protected function _process_resend_registration()
4146
-    {
4147
-        $this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4148
-        do_action(
4149
-            'AHEE__EE_Admin_Page___process_resend_registration',
4150
-            $this->_template_args['success'],
4151
-            $this->request->requestParams()
4152
-        );
4153
-        return $this->_template_args['success'];
4154
-    }
4155
-
4156
-
4157
-    /**
4158
-     * This automatically processes any payment message notifications when manual payment has been applied.
4159
-     *
4160
-     * @param EE_Payment $payment
4161
-     * @return bool success/fail
4162
-     */
4163
-    protected function _process_payment_notification(EE_Payment $payment)
4164
-    {
4165
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4166
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4167
-        $this->_template_args['success'] = apply_filters(
4168
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4169
-            false,
4170
-            $payment
4171
-        );
4172
-        return $this->_template_args['success'];
4173
-    }
4174
-
4175
-
4176
-    /**
4177
-     * @param EEM_Base      $entity_model
4178
-     * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4179
-     * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4180
-     * @param string        $delete_column  name of the field that denotes whether entity is trashed
4181
-     * @param callable|null $callback       called after entity is trashed, restored, or deleted
4182
-     * @return int|float
4183
-     * @throws EE_Error
4184
-     */
4185
-    protected function trashRestoreDeleteEntities(
4186
-        EEM_Base $entity_model,
4187
-        $entity_PK_name,
4188
-        $action = EE_Admin_List_Table::ACTION_DELETE,
4189
-        $delete_column = '',
4190
-        callable $callback = null
4191
-    ) {
4192
-        $entity_PK      = $entity_model->get_primary_key_field();
4193
-        $entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4194
-        $entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4195
-        // grab ID if deleting a single entity
4196
-        if ($this->request->requestParamIsSet($entity_PK_name)) {
4197
-            $ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4198
-            return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4199
-        }
4200
-        // or grab checkbox array if bulk deleting
4201
-        $checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4202
-        if (empty($checkboxes)) {
4203
-            return 0;
4204
-        }
4205
-        $success = 0;
4206
-        $IDs     = array_keys($checkboxes);
4207
-        // cycle thru bulk action checkboxes
4208
-        foreach ($IDs as $ID) {
4209
-            // increment $success
4210
-            if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4211
-                $success++;
4212
-            }
4213
-        }
4214
-        $count = (int) count($checkboxes);
4215
-        // if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4216
-        // otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4217
-        return $success === $count ? $count : $success / $count;
4218
-    }
4219
-
4220
-
4221
-    /**
4222
-     * @param EE_Primary_Key_Field_Base $entity_PK
4223
-     * @return string
4224
-     * @throws EE_Error
4225
-     * @since   4.10.30.p
4226
-     */
4227
-    private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK)
4228
-    {
4229
-        $entity_PK_type = $entity_PK->getSchemaType();
4230
-        switch ($entity_PK_type) {
4231
-            case 'boolean':
4232
-                return 'bool';
4233
-            case 'integer':
4234
-                return 'int';
4235
-            case 'number':
4236
-                return 'float';
4237
-            case 'string':
4238
-                return 'string';
4239
-        }
4240
-        throw new RuntimeException(
4241
-            sprintf(
4242
-                esc_html__(
4243
-                    '"%1$s" is an invalid schema type for the %2$s primary key.',
4244
-                    'event_espresso'
4245
-                ),
4246
-                $entity_PK_type,
4247
-                $entity_PK->get_name()
4248
-            )
4249
-        );
4250
-    }
4251
-
4252
-
4253
-    /**
4254
-     * @param EEM_Base      $entity_model
4255
-     * @param int|string    $entity_ID
4256
-     * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4257
-     * @param string        $delete_column name of the field that denotes whether entity is trashed
4258
-     * @param callable|null $callback      called after entity is trashed, restored, or deleted
4259
-     * @return bool
4260
-     */
4261
-    protected function trashRestoreDeleteEntity(
4262
-        EEM_Base $entity_model,
4263
-        $entity_ID,
4264
-        string $action,
4265
-        string $delete_column,
4266
-        ?callable $callback = null
4267
-    ): bool {
4268
-        $entity_ID = absint($entity_ID);
4269
-        if (! $entity_ID) {
4270
-            $this->trashRestoreDeleteError($action, $entity_model);
4271
-        }
4272
-        $result = 0;
4273
-        try {
4274
-            $entity = $entity_model->get_one_by_ID($entity_ID);
4275
-            if (! $entity instanceof EE_Base_Class) {
4276
-                throw new DomainException(
4277
-                    sprintf(
4278
-                        esc_html__(
4279
-                            'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4280
-                            'event_espresso'
4281
-                        ),
4282
-                        str_replace('EEM_', '', $entity_model->get_this_model_name()),
4283
-                        $entity_ID
4284
-                    )
4285
-                );
4286
-            }
4287
-            switch ($action) {
4288
-                case EE_Admin_List_Table::ACTION_DELETE:
4289
-                    $result = (bool) $entity->delete_permanently();
4290
-                    break;
4291
-                case EE_Admin_List_Table::ACTION_RESTORE:
4292
-                    $result = $entity->delete_or_restore(false);
4293
-                    break;
4294
-                case EE_Admin_List_Table::ACTION_TRASH:
4295
-                    $result = $entity->delete_or_restore();
4296
-                    break;
4297
-            }
4298
-        } catch (Exception $exception) {
4299
-            $this->trashRestoreDeleteError($action, $entity_model, $exception);
4300
-        }
4301
-        if (is_callable($callback)) {
4302
-            call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4303
-        }
4304
-        return $result;
4305
-    }
4306
-
4307
-
4308
-    /**
4309
-     * @param EEM_Base $entity_model
4310
-     * @param string   $delete_column
4311
-     * @since 4.10.30.p
4312
-     */
4313
-    private function validateDeleteColumn(EEM_Base $entity_model, $delete_column)
4314
-    {
4315
-        if (empty($delete_column)) {
4316
-            throw new DomainException(
4317
-                sprintf(
4318
-                    esc_html__(
4319
-                        'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4320
-                        'event_espresso'
4321
-                    ),
4322
-                    $entity_model->get_this_model_name()
4323
-                )
4324
-            );
4325
-        }
4326
-        if (! $entity_model->has_field($delete_column)) {
4327
-            throw new DomainException(
4328
-                sprintf(
4329
-                    esc_html__(
4330
-                        'The %1$s field does not exist on the %2$s model.',
4331
-                        'event_espresso'
4332
-                    ),
4333
-                    $delete_column,
4334
-                    $entity_model->get_this_model_name()
4335
-                )
4336
-            );
4337
-        }
4338
-    }
4339
-
4340
-
4341
-    /**
4342
-     * @param EEM_Base       $entity_model
4343
-     * @param Exception|null $exception
4344
-     * @param string         $action
4345
-     * @since 4.10.30.p
4346
-     */
4347
-    private function trashRestoreDeleteError($action, EEM_Base $entity_model, Exception $exception = null)
4348
-    {
4349
-        if ($exception instanceof Exception) {
4350
-            throw new RuntimeException(
4351
-                sprintf(
4352
-                    esc_html__(
4353
-                        'Could not %1$s the %2$s because the following error occurred: %3$s',
4354
-                        'event_espresso'
4355
-                    ),
4356
-                    $action,
4357
-                    $entity_model->get_this_model_name(),
4358
-                    $exception->getMessage()
4359
-                )
4360
-            );
4361
-        }
4362
-        throw new RuntimeException(
4363
-            sprintf(
4364
-                esc_html__(
4365
-                    'Could not %1$s the %2$s because an invalid ID was received.',
4366
-                    'event_espresso'
4367
-                ),
4368
-                $action,
4369
-                $entity_model->get_this_model_name()
4370
-            )
4371
-        );
4372
-    }
3389
+		// add nonce
3390
+		$nonce                                             =
3391
+			wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3392
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3393
+		// add REQUIRED form action
3394
+		$hidden_fields = [
3395
+			'action' => ['type' => 'hidden', 'value' => $route],
3396
+		];
3397
+		// merge arrays
3398
+		$hidden_fields = is_array($additional_hidden_fields)
3399
+			? array_merge($hidden_fields, $additional_hidden_fields)
3400
+			: $hidden_fields;
3401
+		// generate form fields
3402
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3403
+		// add fields to form
3404
+		foreach ((array) $form_fields as $form_field) {
3405
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3406
+		}
3407
+		// close form
3408
+		$this->_template_args['after_admin_page_content'] = '</form>';
3409
+	}
3410
+
3411
+
3412
+	/**
3413
+	 * Public Wrapper for _redirect_after_action() method since its
3414
+	 * discovered it would be useful for external code to have access.
3415
+	 *
3416
+	 * @param bool   $success
3417
+	 * @param string $what
3418
+	 * @param string $action_desc
3419
+	 * @param array  $query_args
3420
+	 * @param bool   $override_overwrite
3421
+	 * @throws EE_Error
3422
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3423
+	 * @since 4.5.0
3424
+	 */
3425
+	public function redirect_after_action(
3426
+		$success = false,
3427
+		$what = 'item',
3428
+		$action_desc = 'processed',
3429
+		$query_args = [],
3430
+		$override_overwrite = false
3431
+	) {
3432
+		$this->_redirect_after_action(
3433
+			$success,
3434
+			$what,
3435
+			$action_desc,
3436
+			$query_args,
3437
+			$override_overwrite
3438
+		);
3439
+	}
3440
+
3441
+
3442
+	/**
3443
+	 * Helper method for merging existing request data with the returned redirect url.
3444
+	 *
3445
+	 * This is typically used for redirects after an action so that if the original view was a filtered view those
3446
+	 * filters are still applied.
3447
+	 *
3448
+	 * @param array $new_route_data
3449
+	 * @return array
3450
+	 */
3451
+	protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data)
3452
+	{
3453
+		foreach ($this->request->requestParams() as $ref => $value) {
3454
+			// unset nonces
3455
+			if (strpos($ref, 'nonce') !== false) {
3456
+				$this->request->unSetRequestParam($ref);
3457
+				continue;
3458
+			}
3459
+			// urlencode values.
3460
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3461
+			$this->request->setRequestParam($ref, $value);
3462
+		}
3463
+		return array_merge($this->request->requestParams(), $new_route_data);
3464
+	}
3465
+
3466
+
3467
+	/**
3468
+	 * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3469
+	 * @param string           $what               - what the action was performed on
3470
+	 * @param string           $action_desc        - what was done ie: updated, deleted, etc
3471
+	 * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3472
+	 * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3473
+	 *                                             this allows you to override this so that they show.
3474
+	 * @return void
3475
+	 * @throws EE_Error
3476
+	 * @throws InvalidArgumentException
3477
+	 * @throws InvalidDataTypeException
3478
+	 * @throws InvalidInterfaceException
3479
+	 */
3480
+	protected function _redirect_after_action(
3481
+		$success = 0,
3482
+		string $what = 'item',
3483
+		string $action_desc = 'processed',
3484
+		array $query_args = [],
3485
+		bool $override_overwrite = false
3486
+	) {
3487
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3488
+		$notices = EE_Error::get_notices(false);
3489
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3490
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3491
+			EE_Error::overwrite_success();
3492
+		}
3493
+		if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3494
+			// how many records affected ? more than one record ? or just one ?
3495
+			EE_Error::add_success(
3496
+				sprintf(
3497
+					esc_html(
3498
+						_n(
3499
+							'The "%1$s" has been successfully %2$s.',
3500
+							'The "%1$s" have been successfully %2$s.',
3501
+							$success,
3502
+							'event_espresso'
3503
+						)
3504
+					),
3505
+					$what,
3506
+					$action_desc
3507
+				),
3508
+				__FILE__,
3509
+				__FUNCTION__,
3510
+				__LINE__
3511
+			);
3512
+		}
3513
+		// check that $query_args isn't something crazy
3514
+		if (! is_array($query_args)) {
3515
+			$query_args = [];
3516
+		}
3517
+		/**
3518
+		 * Allow injecting actions before the query_args are modified for possible different
3519
+		 * redirections on save and close actions
3520
+		 *
3521
+		 * @param array $query_args       The original query_args array coming into the
3522
+		 *                                method.
3523
+		 * @since 4.2.0
3524
+		 */
3525
+		do_action(
3526
+			"AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3527
+			$query_args
3528
+		);
3529
+		// set redirect url.
3530
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3531
+		// otherwise we go with whatever is set as the _admin_base_url
3532
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3533
+		// calculate where we're going (if we have a "save and close" button pushed)
3534
+		if (
3535
+			$this->request->requestParamIsSet('save_and_close')
3536
+			&& $this->request->requestParamIsSet('save_and_close_referrer')
3537
+		) {
3538
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3539
+			$parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', 'url'));
3540
+			// regenerate query args array from referrer URL
3541
+			parse_str($parsed_url['query'], $query_args);
3542
+			// correct page and action will be in the query args now
3543
+			$redirect_url = admin_url('admin.php');
3544
+		}
3545
+		// merge any default query_args set in _default_route_query_args property
3546
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3547
+			$args_to_merge = [];
3548
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3549
+				// is there a wp_referer array in our _default_route_query_args property?
3550
+				if ($query_param === 'wp_referer') {
3551
+					$query_value = (array) $query_value;
3552
+					foreach ($query_value as $reference => $value) {
3553
+						if (strpos($reference, 'nonce') !== false) {
3554
+							continue;
3555
+						}
3556
+						// finally we will override any arguments in the referer with
3557
+						// what might be set on the _default_route_query_args array.
3558
+						if (isset($this->_default_route_query_args[ $reference ])) {
3559
+							$args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3560
+						} else {
3561
+							$args_to_merge[ $reference ] = urlencode($value);
3562
+						}
3563
+					}
3564
+					continue;
3565
+				}
3566
+				$args_to_merge[ $query_param ] = $query_value;
3567
+			}
3568
+			// now let's merge these arguments but override with what was specifically sent in to the
3569
+			// redirect.
3570
+			$query_args = array_merge($args_to_merge, $query_args);
3571
+		}
3572
+		$this->_process_notices($query_args);
3573
+		// generate redirect url
3574
+		// if redirecting to anything other than the main page, add a nonce
3575
+		if (isset($query_args['action'])) {
3576
+			// manually generate wp_nonce and merge that with the query vars
3577
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3578
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3579
+		}
3580
+		// we're adding some hooks and filters in here for processing any things just before redirects
3581
+		// (example: an admin page has done an insert or update and we want to run something after that).
3582
+		do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3583
+		$redirect_url = apply_filters(
3584
+			'FHEE_redirect_' . $this->class_name . $this->_req_action,
3585
+			EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3586
+			$query_args
3587
+		);
3588
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3589
+		if ($this->request->isAjax()) {
3590
+			$default_data                    = [
3591
+				'close'        => true,
3592
+				'redirect_url' => $redirect_url,
3593
+				'where'        => 'main',
3594
+				'what'         => 'append',
3595
+			];
3596
+			$this->_template_args['success'] = $success;
3597
+			$this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3598
+				$default_data,
3599
+				$this->_template_args['data']
3600
+			) : $default_data;
3601
+			$this->_return_json();
3602
+		}
3603
+		wp_safe_redirect($redirect_url);
3604
+		exit();
3605
+	}
3606
+
3607
+
3608
+	/**
3609
+	 * process any notices before redirecting (or returning ajax request)
3610
+	 * This method sets the $this->_template_args['notices'] attribute;
3611
+	 *
3612
+	 * @param array $query_args         any query args that need to be used for notice transient ('action')
3613
+	 * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3614
+	 *                                  page_routes haven't been defined yet.
3615
+	 * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3616
+	 *                                  still save a transient for the notice.
3617
+	 * @return void
3618
+	 * @throws EE_Error
3619
+	 * @throws InvalidArgumentException
3620
+	 * @throws InvalidDataTypeException
3621
+	 * @throws InvalidInterfaceException
3622
+	 */
3623
+	protected function _process_notices($query_args = [], $skip_route_verify = false, $sticky_notices = true)
3624
+	{
3625
+		// first let's set individual error properties if doing_ajax and the properties aren't already set.
3626
+		if ($this->request->isAjax()) {
3627
+			$notices = EE_Error::get_notices(false);
3628
+			if (empty($this->_template_args['success'])) {
3629
+				$this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3630
+			}
3631
+			if (empty($this->_template_args['errors'])) {
3632
+				$this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3633
+			}
3634
+			if (empty($this->_template_args['attention'])) {
3635
+				$this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3636
+			}
3637
+		}
3638
+		$this->_template_args['notices'] = EE_Error::get_notices();
3639
+		// IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3640
+		if (! $this->request->isAjax() || $sticky_notices) {
3641
+			$route = isset($query_args['action']) ? $query_args['action'] : 'default';
3642
+			$this->_add_transient(
3643
+				$route,
3644
+				$this->_template_args['notices'],
3645
+				true,
3646
+				$skip_route_verify
3647
+			);
3648
+		}
3649
+	}
3650
+
3651
+
3652
+	/**
3653
+	 * get_action_link_or_button
3654
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3655
+	 *
3656
+	 * @param string $action        use this to indicate which action the url is generated with.
3657
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3658
+	 *                              property.
3659
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3660
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3661
+	 * @param string $base_url      If this is not provided
3662
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3663
+	 *                              Otherwise this value will be used.
3664
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3665
+	 * @return string
3666
+	 * @throws InvalidArgumentException
3667
+	 * @throws InvalidInterfaceException
3668
+	 * @throws InvalidDataTypeException
3669
+	 * @throws EE_Error
3670
+	 */
3671
+	public function get_action_link_or_button(
3672
+		$action,
3673
+		$type = 'add',
3674
+		$extra_request = [],
3675
+		$class = 'button button--primary',
3676
+		$base_url = '',
3677
+		$exclude_nonce = false
3678
+	) {
3679
+		// first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3680
+		if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3681
+			throw new EE_Error(
3682
+				sprintf(
3683
+					esc_html__(
3684
+						'There is no page route for given action for the button.  This action was given: %s',
3685
+						'event_espresso'
3686
+					),
3687
+					$action
3688
+				)
3689
+			);
3690
+		}
3691
+		if (! isset($this->_labels['buttons'][ $type ])) {
3692
+			throw new EE_Error(
3693
+				sprintf(
3694
+					esc_html__(
3695
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3696
+						'event_espresso'
3697
+					),
3698
+					$type
3699
+				)
3700
+			);
3701
+		}
3702
+		// finally check user access for this button.
3703
+		$has_access = $this->check_user_access($action, true);
3704
+		if (! $has_access) {
3705
+			return '';
3706
+		}
3707
+		$_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3708
+		$query_args = [
3709
+			'action' => $action,
3710
+		];
3711
+		// merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3712
+		if (! empty($extra_request)) {
3713
+			$query_args = array_merge($extra_request, $query_args);
3714
+		}
3715
+		$url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3716
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3717
+	}
3718
+
3719
+
3720
+	/**
3721
+	 * _per_page_screen_option
3722
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3723
+	 *
3724
+	 * @return void
3725
+	 * @throws InvalidArgumentException
3726
+	 * @throws InvalidInterfaceException
3727
+	 * @throws InvalidDataTypeException
3728
+	 */
3729
+	protected function _per_page_screen_option()
3730
+	{
3731
+		$option = 'per_page';
3732
+		$args   = [
3733
+			'label'   => apply_filters(
3734
+				'FHEE__EE_Admin_Page___per_page_screen_options___label',
3735
+				$this->_admin_page_title,
3736
+				$this
3737
+			),
3738
+			'default' => (int) apply_filters(
3739
+				'FHEE__EE_Admin_Page___per_page_screen_options__default',
3740
+				20
3741
+			),
3742
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3743
+		];
3744
+		// ONLY add the screen option if the user has access to it.
3745
+		if ($this->check_user_access($this->_current_view, true)) {
3746
+			add_screen_option($option, $args);
3747
+		}
3748
+	}
3749
+
3750
+
3751
+	/**
3752
+	 * set_per_page_screen_option
3753
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3754
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3755
+	 * admin_menu.
3756
+	 *
3757
+	 * @return void
3758
+	 */
3759
+	private function _set_per_page_screen_options()
3760
+	{
3761
+		if ($this->request->requestParamIsSet('wp_screen_options')) {
3762
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3763
+			if (! $user = wp_get_current_user()) {
3764
+				return;
3765
+			}
3766
+			$option = $this->request->getRequestParam('wp_screen_options[option]', '', 'key');
3767
+			if (! $option) {
3768
+				return;
3769
+			}
3770
+			$value      = $this->request->getRequestParam('wp_screen_options[value]', 0, 'int');
3771
+			$map_option = $option;
3772
+			$option     = str_replace('-', '_', $option);
3773
+			switch ($map_option) {
3774
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3775
+					$max_value = apply_filters(
3776
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3777
+						999,
3778
+						$this->_current_page,
3779
+						$this->_current_view
3780
+					);
3781
+					if ($value < 1) {
3782
+						return;
3783
+					}
3784
+					$value = min($value, $max_value);
3785
+					break;
3786
+				default:
3787
+					$value = apply_filters(
3788
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3789
+						false,
3790
+						$option,
3791
+						$value
3792
+					);
3793
+					if (false === $value) {
3794
+						return;
3795
+					}
3796
+					break;
3797
+			}
3798
+			update_user_meta($user->ID, $option, $value);
3799
+			wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3800
+			exit;
3801
+		}
3802
+	}
3803
+
3804
+
3805
+	/**
3806
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3807
+	 *
3808
+	 * @param array $data array that will be assigned to template args.
3809
+	 */
3810
+	public function set_template_args($data)
3811
+	{
3812
+		$this->_template_args = array_merge($this->_template_args, (array) $data);
3813
+	}
3814
+
3815
+
3816
+	/**
3817
+	 * This makes available the WP transient system for temporarily moving data between routes
3818
+	 *
3819
+	 * @param string $route             the route that should receive the transient
3820
+	 * @param array  $data              the data that gets sent
3821
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3822
+	 *                                  normal route transient.
3823
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3824
+	 *                                  when we are adding a transient before page_routes have been defined.
3825
+	 * @return void
3826
+	 * @throws EE_Error
3827
+	 */
3828
+	protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3829
+	{
3830
+		$user_id = get_current_user_id();
3831
+		if (! $skip_route_verify) {
3832
+			$this->_verify_route($route);
3833
+		}
3834
+		// now let's set the string for what kind of transient we're setting
3835
+		$transient = $notices
3836
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3837
+			: 'rte_tx_' . $route . '_' . $user_id;
3838
+		$data      = $notices ? ['notices' => $data] : $data;
3839
+		// is there already a transient for this route?  If there is then let's ADD to that transient
3840
+		$existing = is_multisite() && is_network_admin()
3841
+			? get_site_transient($transient)
3842
+			: get_transient($transient);
3843
+		if ($existing) {
3844
+			$data = array_merge((array) $data, (array) $existing);
3845
+		}
3846
+		if (is_multisite() && is_network_admin()) {
3847
+			set_site_transient($transient, $data, 8);
3848
+		} else {
3849
+			set_transient($transient, $data, 8);
3850
+		}
3851
+	}
3852
+
3853
+
3854
+	/**
3855
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3856
+	 *
3857
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3858
+	 * @param string $route
3859
+	 * @return mixed data
3860
+	 */
3861
+	protected function _get_transient($notices = false, $route = '')
3862
+	{
3863
+		$user_id   = get_current_user_id();
3864
+		$route     = ! $route ? $this->_req_action : $route;
3865
+		$transient = $notices
3866
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3867
+			: 'rte_tx_' . $route . '_' . $user_id;
3868
+		$data      = is_multisite() && is_network_admin()
3869
+			? get_site_transient($transient)
3870
+			: get_transient($transient);
3871
+		// delete transient after retrieval (just in case it hasn't expired);
3872
+		if (is_multisite() && is_network_admin()) {
3873
+			delete_site_transient($transient);
3874
+		} else {
3875
+			delete_transient($transient);
3876
+		}
3877
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3878
+	}
3879
+
3880
+
3881
+	/**
3882
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3883
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3884
+	 * default route callback on the EE_Admin page you want it run.)
3885
+	 *
3886
+	 * @return void
3887
+	 */
3888
+	protected function _transient_garbage_collection()
3889
+	{
3890
+		global $wpdb;
3891
+		// retrieve all existing transients
3892
+		$query =
3893
+			"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3894
+		if ($results = $wpdb->get_results($query)) {
3895
+			foreach ($results as $result) {
3896
+				$transient = str_replace('_transient_', '', $result->option_name);
3897
+				get_transient($transient);
3898
+				if (is_multisite() && is_network_admin()) {
3899
+					get_site_transient($transient);
3900
+				}
3901
+			}
3902
+		}
3903
+	}
3904
+
3905
+
3906
+	/**
3907
+	 * get_view
3908
+	 *
3909
+	 * @return string content of _view property
3910
+	 */
3911
+	public function get_view()
3912
+	{
3913
+		return $this->_view;
3914
+	}
3915
+
3916
+
3917
+	/**
3918
+	 * getter for the protected $_views property
3919
+	 *
3920
+	 * @return array
3921
+	 */
3922
+	public function get_views()
3923
+	{
3924
+		return $this->_views;
3925
+	}
3926
+
3927
+
3928
+	/**
3929
+	 * get_current_page
3930
+	 *
3931
+	 * @return string _current_page property value
3932
+	 */
3933
+	public function get_current_page()
3934
+	{
3935
+		return $this->_current_page;
3936
+	}
3937
+
3938
+
3939
+	/**
3940
+	 * get_current_view
3941
+	 *
3942
+	 * @return string _current_view property value
3943
+	 */
3944
+	public function get_current_view()
3945
+	{
3946
+		return $this->_current_view;
3947
+	}
3948
+
3949
+
3950
+	/**
3951
+	 * get_current_screen
3952
+	 *
3953
+	 * @return object The current WP_Screen object
3954
+	 */
3955
+	public function get_current_screen()
3956
+	{
3957
+		return $this->_current_screen;
3958
+	}
3959
+
3960
+
3961
+	/**
3962
+	 * get_current_page_view_url
3963
+	 *
3964
+	 * @return string This returns the url for the current_page_view.
3965
+	 */
3966
+	public function get_current_page_view_url()
3967
+	{
3968
+		return $this->_current_page_view_url;
3969
+	}
3970
+
3971
+
3972
+	/**
3973
+	 * just returns the Request
3974
+	 *
3975
+	 * @return RequestInterface
3976
+	 */
3977
+	public function get_request()
3978
+	{
3979
+		return $this->request;
3980
+	}
3981
+
3982
+
3983
+	/**
3984
+	 * just returns the _req_data property
3985
+	 *
3986
+	 * @return array
3987
+	 */
3988
+	public function get_request_data()
3989
+	{
3990
+		return $this->request->requestParams();
3991
+	}
3992
+
3993
+
3994
+	/**
3995
+	 * returns the _req_data protected property
3996
+	 *
3997
+	 * @return string
3998
+	 */
3999
+	public function get_req_action()
4000
+	{
4001
+		return $this->_req_action;
4002
+	}
4003
+
4004
+
4005
+	/**
4006
+	 * @return bool  value of $_is_caf property
4007
+	 */
4008
+	public function is_caf()
4009
+	{
4010
+		return $this->_is_caf;
4011
+	}
4012
+
4013
+
4014
+	/**
4015
+	 * @return mixed
4016
+	 */
4017
+	public function default_espresso_metaboxes()
4018
+	{
4019
+		return $this->_default_espresso_metaboxes;
4020
+	}
4021
+
4022
+
4023
+	/**
4024
+	 * @return mixed
4025
+	 */
4026
+	public function admin_base_url()
4027
+	{
4028
+		return $this->_admin_base_url;
4029
+	}
4030
+
4031
+
4032
+	/**
4033
+	 * @return mixed
4034
+	 */
4035
+	public function wp_page_slug()
4036
+	{
4037
+		return $this->_wp_page_slug;
4038
+	}
4039
+
4040
+
4041
+	/**
4042
+	 * updates  espresso configuration settings
4043
+	 *
4044
+	 * @param string                   $tab
4045
+	 * @param EE_Config_Base|EE_Config $config
4046
+	 * @param string                   $file file where error occurred
4047
+	 * @param string                   $func function  where error occurred
4048
+	 * @param string                   $line line no where error occurred
4049
+	 * @return boolean
4050
+	 */
4051
+	protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4052
+	{
4053
+		// remove any options that are NOT going to be saved with the config settings.
4054
+		if (isset($config->core->ee_ueip_optin)) {
4055
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4056
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4057
+			update_option('ee_ueip_has_notified', true);
4058
+		}
4059
+		// and save it (note we're also doing the network save here)
4060
+		$net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4061
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4062
+		if ($config_saved && $net_saved) {
4063
+			EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4064
+			return true;
4065
+		}
4066
+		EE_Error::add_error(
4067
+			sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4068
+			$file,
4069
+			$func,
4070
+			$line
4071
+		);
4072
+		return false;
4073
+	}
4074
+
4075
+
4076
+	/**
4077
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4078
+	 *
4079
+	 * @return array
4080
+	 */
4081
+	public function get_yes_no_values()
4082
+	{
4083
+		return $this->_yes_no_values;
4084
+	}
4085
+
4086
+
4087
+	/**
4088
+	 * @return string
4089
+	 * @throws ReflectionException
4090
+	 * @since $VID:$
4091
+	 */
4092
+	protected function _get_dir()
4093
+	{
4094
+		$reflector = new ReflectionClass($this->class_name);
4095
+		return dirname($reflector->getFileName());
4096
+	}
4097
+
4098
+
4099
+	/**
4100
+	 * A helper for getting a "next link".
4101
+	 *
4102
+	 * @param string $url   The url to link to
4103
+	 * @param string $class The class to use.
4104
+	 * @return string
4105
+	 */
4106
+	protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4107
+	{
4108
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4109
+	}
4110
+
4111
+
4112
+	/**
4113
+	 * A helper for getting a "previous link".
4114
+	 *
4115
+	 * @param string $url   The url to link to
4116
+	 * @param string $class The class to use.
4117
+	 * @return string
4118
+	 */
4119
+	protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4120
+	{
4121
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4122
+	}
4123
+
4124
+
4125
+
4126
+
4127
+
4128
+
4129
+
4130
+	// below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4131
+
4132
+
4133
+	/**
4134
+	 * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4135
+	 * knows that the _REG_ID isn't in the req_data array but CAN obtain it, the caller should ADD the _REG_ID to the
4136
+	 * _req_data array.
4137
+	 *
4138
+	 * @return bool success/fail
4139
+	 * @throws EE_Error
4140
+	 * @throws InvalidArgumentException
4141
+	 * @throws ReflectionException
4142
+	 * @throws InvalidDataTypeException
4143
+	 * @throws InvalidInterfaceException
4144
+	 */
4145
+	protected function _process_resend_registration()
4146
+	{
4147
+		$this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4148
+		do_action(
4149
+			'AHEE__EE_Admin_Page___process_resend_registration',
4150
+			$this->_template_args['success'],
4151
+			$this->request->requestParams()
4152
+		);
4153
+		return $this->_template_args['success'];
4154
+	}
4155
+
4156
+
4157
+	/**
4158
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4159
+	 *
4160
+	 * @param EE_Payment $payment
4161
+	 * @return bool success/fail
4162
+	 */
4163
+	protected function _process_payment_notification(EE_Payment $payment)
4164
+	{
4165
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4166
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4167
+		$this->_template_args['success'] = apply_filters(
4168
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4169
+			false,
4170
+			$payment
4171
+		);
4172
+		return $this->_template_args['success'];
4173
+	}
4174
+
4175
+
4176
+	/**
4177
+	 * @param EEM_Base      $entity_model
4178
+	 * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4179
+	 * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4180
+	 * @param string        $delete_column  name of the field that denotes whether entity is trashed
4181
+	 * @param callable|null $callback       called after entity is trashed, restored, or deleted
4182
+	 * @return int|float
4183
+	 * @throws EE_Error
4184
+	 */
4185
+	protected function trashRestoreDeleteEntities(
4186
+		EEM_Base $entity_model,
4187
+		$entity_PK_name,
4188
+		$action = EE_Admin_List_Table::ACTION_DELETE,
4189
+		$delete_column = '',
4190
+		callable $callback = null
4191
+	) {
4192
+		$entity_PK      = $entity_model->get_primary_key_field();
4193
+		$entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4194
+		$entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4195
+		// grab ID if deleting a single entity
4196
+		if ($this->request->requestParamIsSet($entity_PK_name)) {
4197
+			$ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4198
+			return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4199
+		}
4200
+		// or grab checkbox array if bulk deleting
4201
+		$checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4202
+		if (empty($checkboxes)) {
4203
+			return 0;
4204
+		}
4205
+		$success = 0;
4206
+		$IDs     = array_keys($checkboxes);
4207
+		// cycle thru bulk action checkboxes
4208
+		foreach ($IDs as $ID) {
4209
+			// increment $success
4210
+			if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4211
+				$success++;
4212
+			}
4213
+		}
4214
+		$count = (int) count($checkboxes);
4215
+		// if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4216
+		// otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4217
+		return $success === $count ? $count : $success / $count;
4218
+	}
4219
+
4220
+
4221
+	/**
4222
+	 * @param EE_Primary_Key_Field_Base $entity_PK
4223
+	 * @return string
4224
+	 * @throws EE_Error
4225
+	 * @since   4.10.30.p
4226
+	 */
4227
+	private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK)
4228
+	{
4229
+		$entity_PK_type = $entity_PK->getSchemaType();
4230
+		switch ($entity_PK_type) {
4231
+			case 'boolean':
4232
+				return 'bool';
4233
+			case 'integer':
4234
+				return 'int';
4235
+			case 'number':
4236
+				return 'float';
4237
+			case 'string':
4238
+				return 'string';
4239
+		}
4240
+		throw new RuntimeException(
4241
+			sprintf(
4242
+				esc_html__(
4243
+					'"%1$s" is an invalid schema type for the %2$s primary key.',
4244
+					'event_espresso'
4245
+				),
4246
+				$entity_PK_type,
4247
+				$entity_PK->get_name()
4248
+			)
4249
+		);
4250
+	}
4251
+
4252
+
4253
+	/**
4254
+	 * @param EEM_Base      $entity_model
4255
+	 * @param int|string    $entity_ID
4256
+	 * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4257
+	 * @param string        $delete_column name of the field that denotes whether entity is trashed
4258
+	 * @param callable|null $callback      called after entity is trashed, restored, or deleted
4259
+	 * @return bool
4260
+	 */
4261
+	protected function trashRestoreDeleteEntity(
4262
+		EEM_Base $entity_model,
4263
+		$entity_ID,
4264
+		string $action,
4265
+		string $delete_column,
4266
+		?callable $callback = null
4267
+	): bool {
4268
+		$entity_ID = absint($entity_ID);
4269
+		if (! $entity_ID) {
4270
+			$this->trashRestoreDeleteError($action, $entity_model);
4271
+		}
4272
+		$result = 0;
4273
+		try {
4274
+			$entity = $entity_model->get_one_by_ID($entity_ID);
4275
+			if (! $entity instanceof EE_Base_Class) {
4276
+				throw new DomainException(
4277
+					sprintf(
4278
+						esc_html__(
4279
+							'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4280
+							'event_espresso'
4281
+						),
4282
+						str_replace('EEM_', '', $entity_model->get_this_model_name()),
4283
+						$entity_ID
4284
+					)
4285
+				);
4286
+			}
4287
+			switch ($action) {
4288
+				case EE_Admin_List_Table::ACTION_DELETE:
4289
+					$result = (bool) $entity->delete_permanently();
4290
+					break;
4291
+				case EE_Admin_List_Table::ACTION_RESTORE:
4292
+					$result = $entity->delete_or_restore(false);
4293
+					break;
4294
+				case EE_Admin_List_Table::ACTION_TRASH:
4295
+					$result = $entity->delete_or_restore();
4296
+					break;
4297
+			}
4298
+		} catch (Exception $exception) {
4299
+			$this->trashRestoreDeleteError($action, $entity_model, $exception);
4300
+		}
4301
+		if (is_callable($callback)) {
4302
+			call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4303
+		}
4304
+		return $result;
4305
+	}
4306
+
4307
+
4308
+	/**
4309
+	 * @param EEM_Base $entity_model
4310
+	 * @param string   $delete_column
4311
+	 * @since 4.10.30.p
4312
+	 */
4313
+	private function validateDeleteColumn(EEM_Base $entity_model, $delete_column)
4314
+	{
4315
+		if (empty($delete_column)) {
4316
+			throw new DomainException(
4317
+				sprintf(
4318
+					esc_html__(
4319
+						'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4320
+						'event_espresso'
4321
+					),
4322
+					$entity_model->get_this_model_name()
4323
+				)
4324
+			);
4325
+		}
4326
+		if (! $entity_model->has_field($delete_column)) {
4327
+			throw new DomainException(
4328
+				sprintf(
4329
+					esc_html__(
4330
+						'The %1$s field does not exist on the %2$s model.',
4331
+						'event_espresso'
4332
+					),
4333
+					$delete_column,
4334
+					$entity_model->get_this_model_name()
4335
+				)
4336
+			);
4337
+		}
4338
+	}
4339
+
4340
+
4341
+	/**
4342
+	 * @param EEM_Base       $entity_model
4343
+	 * @param Exception|null $exception
4344
+	 * @param string         $action
4345
+	 * @since 4.10.30.p
4346
+	 */
4347
+	private function trashRestoreDeleteError($action, EEM_Base $entity_model, Exception $exception = null)
4348
+	{
4349
+		if ($exception instanceof Exception) {
4350
+			throw new RuntimeException(
4351
+				sprintf(
4352
+					esc_html__(
4353
+						'Could not %1$s the %2$s because the following error occurred: %3$s',
4354
+						'event_espresso'
4355
+					),
4356
+					$action,
4357
+					$entity_model->get_this_model_name(),
4358
+					$exception->getMessage()
4359
+				)
4360
+			);
4361
+		}
4362
+		throw new RuntimeException(
4363
+			sprintf(
4364
+				esc_html__(
4365
+					'Could not %1$s the %2$s because an invalid ID was received.',
4366
+					'event_espresso'
4367
+				),
4368
+				$action,
4369
+				$entity_model->get_this_model_name()
4370
+			)
4371
+		);
4372
+	}
4373 4373
 }
Please login to merge, or discard this patch.
Spacing   +177 added lines, -177 removed lines patch added patch discarded remove patch
@@ -638,7 +638,7 @@  discard block
 block discarded – undo
638 638
         $ee_menu_slugs = (array) $ee_menu_slugs;
639 639
         if (
640 640
             ! $this->request->isAjax()
641
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
641
+            && ( ! $this->_current_page || ! isset($ee_menu_slugs[$this->_current_page]))
642 642
         ) {
643 643
             return;
644 644
         }
@@ -658,7 +658,7 @@  discard block
 block discarded – undo
658 658
             : $req_action;
659 659
 
660 660
         $this->_current_view = $this->_req_action;
661
-        $this->_req_nonce    = $this->_req_action . '_nonce';
661
+        $this->_req_nonce    = $this->_req_action.'_nonce';
662 662
         $this->_define_page_props();
663 663
         $this->_current_page_view_url = add_query_arg(
664 664
             ['page' => $this->_current_page, 'action' => $this->_current_view],
@@ -682,33 +682,33 @@  discard block
 block discarded – undo
682 682
         }
683 683
         // filter routes and page_config so addons can add their stuff. Filtering done per class
684 684
         $this->_page_routes = apply_filters(
685
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
685
+            'FHEE__'.$this->class_name.'__page_setup__page_routes',
686 686
             $this->_page_routes,
687 687
             $this
688 688
         );
689 689
         $this->_page_config = apply_filters(
690
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
690
+            'FHEE__'.$this->class_name.'__page_setup__page_config',
691 691
             $this->_page_config,
692 692
             $this
693 693
         );
694 694
         if ($this->base_class_name !== '') {
695 695
             $this->_page_routes = apply_filters(
696
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
696
+                'FHEE__'.$this->base_class_name.'__page_setup__page_routes',
697 697
                 $this->_page_routes,
698 698
                 $this
699 699
             );
700 700
             $this->_page_config = apply_filters(
701
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
701
+                'FHEE__'.$this->base_class_name.'__page_setup__page_config',
702 702
                 $this->_page_config,
703 703
                 $this
704 704
             );
705 705
         }
706 706
         // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
707 707
         // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
708
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
708
+        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view)) {
709 709
             add_action(
710 710
                 'AHEE__EE_Admin_Page__route_admin_request',
711
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
711
+                [$this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view],
712 712
                 10,
713 713
                 2
714 714
             );
@@ -721,8 +721,8 @@  discard block
 block discarded – undo
721 721
             if ($this->_is_UI_request) {
722 722
                 // admin_init stuff - global, all views for this page class, specific view
723 723
                 add_action('admin_init', [$this, 'admin_init'], 10);
724
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
725
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
724
+                if (method_exists($this, 'admin_init_'.$this->_current_view)) {
725
+                    add_action('admin_init', [$this, 'admin_init_'.$this->_current_view], 15);
726 726
                 }
727 727
             } else {
728 728
                 // hijack regular WP loading and route admin request immediately
@@ -741,12 +741,12 @@  discard block
 block discarded – undo
741 741
      */
742 742
     private function _do_other_page_hooks()
743 743
     {
744
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
744
+        $registered_pages = apply_filters('FHEE_do_other_page_hooks_'.$this->page_slug, []);
745 745
         foreach ($registered_pages as $page) {
746 746
             // now let's setup the file name and class that should be present
747 747
             $classname = str_replace('.class.php', '', $page);
748 748
             // autoloaders should take care of loading file
749
-            if (! class_exists($classname)) {
749
+            if ( ! class_exists($classname)) {
750 750
                 $error_msg[] = sprintf(
751 751
                     esc_html__(
752 752
                         'Something went wrong with loading the %s admin hooks page.',
@@ -763,7 +763,7 @@  discard block
 block discarded – undo
763 763
                                    ),
764 764
                                    $page,
765 765
                                    '<br />',
766
-                                   '<strong>' . $classname . '</strong>'
766
+                                   '<strong>'.$classname.'</strong>'
767 767
                                );
768 768
                 throw new EE_Error(implode('||', $error_msg));
769 769
             }
@@ -806,13 +806,13 @@  discard block
 block discarded – undo
806 806
         // load admin_notices - global, page class, and view specific
807 807
         add_action('admin_notices', [$this, 'admin_notices_global'], 5);
808 808
         add_action('admin_notices', [$this, 'admin_notices'], 10);
809
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
810
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
809
+        if (method_exists($this, 'admin_notices_'.$this->_current_view)) {
810
+            add_action('admin_notices', [$this, 'admin_notices_'.$this->_current_view], 15);
811 811
         }
812 812
         // load network admin_notices - global, page class, and view specific
813 813
         add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
814
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
815
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
814
+        if (method_exists($this, 'network_admin_notices_'.$this->_current_view)) {
815
+            add_action('network_admin_notices', [$this, 'network_admin_notices_'.$this->_current_view]);
816 816
         }
817 817
         // this will save any per_page screen options if they are present
818 818
         $this->_set_per_page_screen_options();
@@ -943,7 +943,7 @@  discard block
 block discarded – undo
943 943
     protected function _verify_routes()
944 944
     {
945 945
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
946
-        if (! $this->_current_page && ! $this->request->isAjax()) {
946
+        if ( ! $this->_current_page && ! $this->request->isAjax()) {
947 947
             return false;
948 948
         }
949 949
         $this->_route = false;
@@ -955,7 +955,7 @@  discard block
 block discarded – undo
955 955
                 $this->_admin_page_title
956 956
             );
957 957
             // developer error msg
958
-            $error_msg .= '||' . $error_msg
958
+            $error_msg .= '||'.$error_msg
959 959
                           . esc_html__(
960 960
                               ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
961 961
                               'event_espresso'
@@ -964,8 +964,8 @@  discard block
 block discarded – undo
964 964
         }
965 965
         // and that the requested page route exists
966 966
         if (array_key_exists($this->_req_action, $this->_page_routes)) {
967
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
968
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
967
+            $this->_route        = $this->_page_routes[$this->_req_action];
968
+            $this->_route_config = $this->_page_config[$this->_req_action] ?? [];
969 969
         } else {
970 970
             // user error msg
971 971
             $error_msg = sprintf(
@@ -976,7 +976,7 @@  discard block
 block discarded – undo
976 976
                 $this->_admin_page_title
977 977
             );
978 978
             // developer error msg
979
-            $error_msg .= '||' . $error_msg
979
+            $error_msg .= '||'.$error_msg
980 980
                           . sprintf(
981 981
                               esc_html__(
982 982
                                   ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
@@ -987,7 +987,7 @@  discard block
 block discarded – undo
987 987
             throw new EE_Error($error_msg);
988 988
         }
989 989
         // and that a default route exists
990
-        if (! array_key_exists('default', $this->_page_routes)) {
990
+        if ( ! array_key_exists('default', $this->_page_routes)) {
991 991
             // user error msg
992 992
             $error_msg = sprintf(
993 993
                 esc_html__(
@@ -997,7 +997,7 @@  discard block
 block discarded – undo
997 997
                 $this->_admin_page_title
998 998
             );
999 999
             // developer error msg
1000
-            $error_msg .= '||' . $error_msg
1000
+            $error_msg .= '||'.$error_msg
1001 1001
                           . esc_html__(
1002 1002
                               ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
1003 1003
                               'event_espresso'
@@ -1039,7 +1039,7 @@  discard block
 block discarded – undo
1039 1039
             $this->_admin_page_title
1040 1040
         );
1041 1041
         // developer error msg
1042
-        $error_msg .= '||' . $error_msg
1042
+        $error_msg .= '||'.$error_msg
1043 1043
                       . sprintf(
1044 1044
                           esc_html__(
1045 1045
                               ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
@@ -1067,7 +1067,7 @@  discard block
 block discarded – undo
1067 1067
     protected function _verify_nonce($nonce, $nonce_ref)
1068 1068
     {
1069 1069
         // verify nonce against expected value
1070
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1070
+        if ( ! wp_verify_nonce($nonce, $nonce_ref)) {
1071 1071
             // these are not the droids you are looking for !!!
1072 1072
             $msg = sprintf(
1073 1073
                 esc_html__('%sNonce Fail.%s', 'event_espresso'),
@@ -1084,7 +1084,7 @@  discard block
 block discarded – undo
1084 1084
                     __CLASS__
1085 1085
                 );
1086 1086
             }
1087
-            if (! $this->request->isAjax()) {
1087
+            if ( ! $this->request->isAjax()) {
1088 1088
                 wp_die($msg);
1089 1089
             }
1090 1090
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
@@ -1108,7 +1108,7 @@  discard block
 block discarded – undo
1108 1108
      */
1109 1109
     protected function _route_admin_request()
1110 1110
     {
1111
-        if (! $this->_is_UI_request) {
1111
+        if ( ! $this->_is_UI_request) {
1112 1112
             $this->_verify_routes();
1113 1113
         }
1114 1114
         $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
@@ -1129,7 +1129,7 @@  discard block
 block discarded – undo
1129 1129
         $args = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : [];
1130 1130
         // action right before calling route
1131 1131
         // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1132
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1132
+        if ( ! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1133 1133
             do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1134 1134
         }
1135 1135
         // strip _wp_http_referer from the server REQUEST_URI
@@ -1144,7 +1144,7 @@  discard block
 block discarded – undo
1144 1144
         $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1145 1145
         $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1146 1146
         $route_callback = [];
1147
-        if (! empty($func)) {
1147
+        if ( ! empty($func)) {
1148 1148
             if (is_array($func)) {
1149 1149
                 $route_callback = $func;
1150 1150
             } elseif (is_string($func)) {
@@ -1158,7 +1158,7 @@  discard block
 block discarded – undo
1158 1158
             }
1159 1159
             [$class, $method] = $route_callback;
1160 1160
             // is it neither a class method NOR a standalone function?
1161
-            if (! is_callable($route_callback)) {
1161
+            if ( ! is_callable($route_callback)) {
1162 1162
                 // user error msg
1163 1163
                 $error_msg = esc_html__(
1164 1164
                     'An error occurred. The  requested page route could not be found.',
@@ -1186,7 +1186,7 @@  discard block
 block discarded – undo
1186 1186
                 $arg_keys = array_keys($args);
1187 1187
                 $nice_args = [];
1188 1188
                 foreach ($args as $key => $arg) {
1189
-                    $nice_args[ $key ] = is_object($arg) ? get_class($arg) : $arg_keys[ $key ];
1189
+                    $nice_args[$key] = is_object($arg) ? get_class($arg) : $arg_keys[$key];
1190 1190
                 }
1191 1191
                 new ExceptionStackTraceDisplay(
1192 1192
                         new RuntimeException(
@@ -1289,7 +1289,7 @@  discard block
 block discarded – undo
1289 1289
                 if (strpos($key, 'nonce') !== false) {
1290 1290
                     continue;
1291 1291
                 }
1292
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1292
+                $args['wp_referer['.$key.']'] = is_string($value) ? htmlspecialchars($value) : $value;
1293 1293
             }
1294 1294
         }
1295 1295
         return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
@@ -1329,12 +1329,12 @@  discard block
 block discarded – undo
1329 1329
      */
1330 1330
     protected function _add_help_tabs()
1331 1331
     {
1332
-        if (isset($this->_page_config[ $this->_req_action ])) {
1333
-            $config = $this->_page_config[ $this->_req_action ];
1332
+        if (isset($this->_page_config[$this->_req_action])) {
1333
+            $config = $this->_page_config[$this->_req_action];
1334 1334
             // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1335 1335
             if (is_array($config) && isset($config['help_sidebar'])) {
1336 1336
                 // check that the callback given is valid
1337
-                if (! method_exists($this, $config['help_sidebar'])) {
1337
+                if ( ! method_exists($this, $config['help_sidebar'])) {
1338 1338
                     throw new EE_Error(
1339 1339
                         sprintf(
1340 1340
                             esc_html__(
@@ -1347,18 +1347,18 @@  discard block
 block discarded – undo
1347 1347
                     );
1348 1348
                 }
1349 1349
                 $content = apply_filters(
1350
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1350
+                    'FHEE__'.$this->class_name.'__add_help_tabs__help_sidebar',
1351 1351
                     $this->{$config['help_sidebar']}()
1352 1352
                 );
1353 1353
                 $this->_current_screen->set_help_sidebar($content);
1354 1354
             }
1355
-            if (! isset($config['help_tabs'])) {
1355
+            if ( ! isset($config['help_tabs'])) {
1356 1356
                 return;
1357 1357
             } //no help tabs for this route
1358 1358
             foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1359 1359
                 // we're here so there ARE help tabs!
1360 1360
                 // make sure we've got what we need
1361
-                if (! isset($cfg['title'])) {
1361
+                if ( ! isset($cfg['title'])) {
1362 1362
                     throw new EE_Error(
1363 1363
                         esc_html__(
1364 1364
                             'The _page_config array is not set up properly for help tabs.  It is missing a title',
@@ -1366,7 +1366,7 @@  discard block
 block discarded – undo
1366 1366
                         )
1367 1367
                     );
1368 1368
                 }
1369
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1369
+                if ( ! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1370 1370
                     throw new EE_Error(
1371 1371
                         esc_html__(
1372 1372
                             'The _page_config array is not setup properly for help tabs. It is missing a either a filename reference, or a callback reference or a content reference so there is no way to know the content for the help tab',
@@ -1375,11 +1375,11 @@  discard block
 block discarded – undo
1375 1375
                     );
1376 1376
                 }
1377 1377
                 // first priority goes to content.
1378
-                if (! empty($cfg['content'])) {
1378
+                if ( ! empty($cfg['content'])) {
1379 1379
                     $content = ! empty($cfg['content']) ? $cfg['content'] : null;
1380 1380
                     // second priority goes to filename
1381
-                } elseif (! empty($cfg['filename'])) {
1382
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1381
+                } elseif ( ! empty($cfg['filename'])) {
1382
+                    $file_path = $this->_get_dir().'/help_tabs/'.$cfg['filename'].'.help_tab.php';
1383 1383
                     // it's possible that the file is located on decaf route (and above sets up for caf route, if this is the case then lets check decaf route too)
1384 1384
                     $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1385 1385
                                                              . basename($this->_get_dir())
@@ -1387,7 +1387,7 @@  discard block
 block discarded – undo
1387 1387
                                                              . $cfg['filename']
1388 1388
                                                              . '.help_tab.php' : $file_path;
1389 1389
                     // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1390
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1390
+                    if ( ! isset($cfg['callback']) && ! is_readable($file_path)) {
1391 1391
                         EE_Error::add_error(
1392 1392
                             sprintf(
1393 1393
                                 esc_html__(
@@ -1435,7 +1435,7 @@  discard block
 block discarded – undo
1435 1435
                     return;
1436 1436
                 }
1437 1437
                 // setup config array for help tab method
1438
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1438
+                $id  = $this->page_slug.'-'.$this->_req_action.'-'.$tab_id;
1439 1439
                 $_ht = [
1440 1440
                     'id'       => $id,
1441 1441
                     'title'    => $cfg['title'],
@@ -1461,8 +1461,8 @@  discard block
 block discarded – undo
1461 1461
             $qtips = (array) $this->_route_config['qtips'];
1462 1462
             // load qtip loader
1463 1463
             $path = [
1464
-                $this->_get_dir() . '/qtips/',
1465
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1464
+                $this->_get_dir().'/qtips/',
1465
+                EE_ADMIN_PAGES.basename($this->_get_dir()).'/qtips/',
1466 1466
             ];
1467 1467
             EEH_Qtip_Loader::instance()->register($qtips, $path);
1468 1468
         }
@@ -1484,7 +1484,7 @@  discard block
 block discarded – undo
1484 1484
         $i        = 0;
1485 1485
         $only_tab = count($this->_page_config) < 2;
1486 1486
         foreach ($this->_page_config as $slug => $config) {
1487
-            if (! is_array($config) || empty($config['nav'])) {
1487
+            if ( ! is_array($config) || empty($config['nav'])) {
1488 1488
                 continue;
1489 1489
             }
1490 1490
             // no nav tab for this config
@@ -1493,7 +1493,7 @@  discard block
 block discarded – undo
1493 1493
                 // nav tab is only to appear when route requested.
1494 1494
                 continue;
1495 1495
             }
1496
-            if (! $this->check_user_access($slug, true)) {
1496
+            if ( ! $this->check_user_access($slug, true)) {
1497 1497
                 // no nav tab because current user does not have access.
1498 1498
                 continue;
1499 1499
             }
@@ -1501,20 +1501,20 @@  discard block
 block discarded – undo
1501 1501
             $css_class .= $only_tab ? ' ee-only-tab' : '';
1502 1502
             $css_class .= " ee-nav-tab__$slug";
1503 1503
 
1504
-            $this->_nav_tabs[ $slug ] = [
1504
+            $this->_nav_tabs[$slug] = [
1505 1505
                 'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1506 1506
                         ['action' => $slug],
1507 1507
                         $this->_admin_base_url
1508 1508
                     ),
1509 1509
                 'link_text' => $this->navTabLabel($config['nav'], $slug),
1510
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1510
+                'css_class' => $this->_req_action === $slug ? $css_class.' nav-tab-active' : $css_class,
1511 1511
                 'order'     => $config['nav']['order'] ?? $i,
1512 1512
             ];
1513 1513
             $i++;
1514 1514
         }
1515 1515
         // if $this->_nav_tabs is empty then lets set the default
1516 1516
         if (empty($this->_nav_tabs)) {
1517
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1517
+            $this->_nav_tabs[$this->_default_nav_tab_name] = [
1518 1518
                 'url'       => $this->_admin_base_url,
1519 1519
                 'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1520 1520
                 'css_class' => 'nav-tab-active',
@@ -1530,11 +1530,11 @@  discard block
 block discarded – undo
1530 1530
     {
1531 1531
         $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1532 1532
         $icon  = $nav_tab['icon'] ?? null;
1533
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1533
+        $icon  = $icon ? '<span class="dashicons '.$icon.'"></span>' : '';
1534 1534
         return '
1535 1535
             <span class="ee-admin-screen-tab__label">
1536
-                ' . $icon . '
1537
-                <span class="ee-nav-label__text">' . $label . '</span>
1536
+                ' . $icon.'
1537
+                <span class="ee-nav-label__text">' . $label.'</span>
1538 1538
             </span>';
1539 1539
     }
1540 1540
 
@@ -1552,10 +1552,10 @@  discard block
 block discarded – undo
1552 1552
             foreach ($this->_route_config['labels'] as $label => $text) {
1553 1553
                 if (is_array($text)) {
1554 1554
                     foreach ($text as $sublabel => $subtext) {
1555
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1555
+                        $this->_labels[$label][$sublabel] = $subtext;
1556 1556
                     }
1557 1557
                 } else {
1558
-                    $this->_labels[ $label ] = $text;
1558
+                    $this->_labels[$label] = $text;
1559 1559
                 }
1560 1560
             }
1561 1561
         }
@@ -1577,10 +1577,10 @@  discard block
 block discarded – undo
1577 1577
     {
1578 1578
         $route_to_check = ! empty($route_to_check) ? $route_to_check : $this->_req_action;
1579 1579
         $capability     = ! empty($route_to_check)
1580
-                          && isset($this->_page_routes[ $route_to_check ])
1581
-                          && is_array($this->_page_routes[ $route_to_check ])
1582
-                          && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1583
-            ? $this->_page_routes[ $route_to_check ]['capability']
1580
+                          && isset($this->_page_routes[$route_to_check])
1581
+                          && is_array($this->_page_routes[$route_to_check])
1582
+                          && ! empty($this->_page_routes[$route_to_check]['capability'])
1583
+            ? $this->_page_routes[$route_to_check]['capability']
1584 1584
             : null;
1585 1585
 
1586 1586
         if (empty($capability) && empty($route_to_check)) {
@@ -1632,14 +1632,14 @@  discard block
 block discarded – undo
1632 1632
         string $priority = 'default',
1633 1633
         ?array $callback_args = null
1634 1634
     ) {
1635
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1635
+        if ( ! (is_callable($callback) || ! function_exists($callback))) {
1636 1636
             return;
1637 1637
         }
1638 1638
 
1639 1639
         add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1640 1640
         add_filter(
1641 1641
             "postbox_classes_{$this->_wp_page_slug}_{$box_id}",
1642
-            function ($classes) {
1642
+            function($classes) {
1643 1643
                 $classes[] = 'ee-admin-container';
1644 1644
                 return $classes;
1645 1645
             }
@@ -1733,7 +1733,7 @@  discard block
 block discarded – undo
1733 1733
         ';
1734 1734
 
1735 1735
         // current set timezone for timezone js
1736
-        echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1736
+        echo '<span id="current_timezone" class="hidden">'.esc_html(EEH_DTT_Helper::get_timezone()).'</span>';
1737 1737
     }
1738 1738
 
1739 1739
 
@@ -1767,7 +1767,7 @@  discard block
 block discarded – undo
1767 1767
         // loop through the array and setup content
1768 1768
         foreach ($help_array as $trigger => $help) {
1769 1769
             // make sure the array is setup properly
1770
-            if (! isset($help['title'], $help['content'])) {
1770
+            if ( ! isset($help['title'], $help['content'])) {
1771 1771
                 throw new EE_Error(
1772 1772
                     esc_html__(
1773 1773
                         'Does not look like the popup content array has been setup correctly.  Might want to double check that.  Read the comments for the _get_help_popup_content method found in "EE_Admin_Page" class',
@@ -1781,8 +1781,8 @@  discard block
 block discarded – undo
1781 1781
                 'help_popup_title'   => $help['title'],
1782 1782
                 'help_popup_content' => $help['content'],
1783 1783
             ];
1784
-            $content       .= EEH_Template::display_template(
1785
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1784
+            $content .= EEH_Template::display_template(
1785
+                EE_ADMIN_TEMPLATE.'admin_help_popup.template.php',
1786 1786
                 $template_args,
1787 1787
                 true
1788 1788
             );
@@ -1804,15 +1804,15 @@  discard block
 block discarded – undo
1804 1804
     private function _get_help_content()
1805 1805
     {
1806 1806
         // what is the method we're looking for?
1807
-        $method_name = '_help_popup_content_' . $this->_req_action;
1807
+        $method_name = '_help_popup_content_'.$this->_req_action;
1808 1808
         // if method doesn't exist let's get out.
1809
-        if (! method_exists($this, $method_name)) {
1809
+        if ( ! method_exists($this, $method_name)) {
1810 1810
             return [];
1811 1811
         }
1812 1812
         // k we're good to go let's retrieve the help array
1813 1813
         $help_array = $this->{$method_name}();
1814 1814
         // make sure we've got an array!
1815
-        if (! is_array($help_array)) {
1815
+        if ( ! is_array($help_array)) {
1816 1816
             throw new EE_Error(
1817 1817
                 esc_html__(
1818 1818
                     'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
@@ -1844,15 +1844,15 @@  discard block
 block discarded – undo
1844 1844
         // let's check and see if there is any content set for this popup.  If there isn't then we'll include a default title and content so that developers know something needs to be corrected
1845 1845
         $help_array   = $this->_get_help_content();
1846 1846
         $help_content = '';
1847
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1848
-            $help_array[ $trigger_id ] = [
1847
+        if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1848
+            $help_array[$trigger_id] = [
1849 1849
                 'title'   => esc_html__('Missing Content', 'event_espresso'),
1850 1850
                 'content' => esc_html__(
1851 1851
                     'A trigger has been set that doesn\'t have any corresponding content. Make sure you have set the help content. (see the "_set_help_popup_content" method in the EE_Admin_Page for instructions.)',
1852 1852
                     'event_espresso'
1853 1853
                 ),
1854 1854
             ];
1855
-            $help_content              = $this->_set_help_popup_content($help_array);
1855
+            $help_content = $this->_set_help_popup_content($help_array);
1856 1856
         }
1857 1857
         // let's setup the trigger
1858 1858
         $content = '<a class="ee-dialog" href="?height='
@@ -1940,7 +1940,7 @@  discard block
 block discarded – undo
1940 1940
 
1941 1941
         add_filter(
1942 1942
             'admin_body_class',
1943
-            function ($classes) {
1943
+            function($classes) {
1944 1944
                 if (strpos($classes, 'espresso-admin') === false) {
1945 1945
                     $classes .= ' espresso-admin';
1946 1946
                 }
@@ -2031,12 +2031,12 @@  discard block
 block discarded – undo
2031 2031
     protected function _set_list_table()
2032 2032
     {
2033 2033
         // first is this a list_table view?
2034
-        if (! isset($this->_route_config['list_table'])) {
2034
+        if ( ! isset($this->_route_config['list_table'])) {
2035 2035
             return;
2036 2036
         } //not a list_table view so get out.
2037 2037
         // list table functions are per view specific (because some admin pages might have more than one list table!)
2038
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2039
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2038
+        $list_table_view = '_set_list_table_views_'.$this->_req_action;
2039
+        if ( ! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2040 2040
             // user error msg
2041 2041
             $error_msg = esc_html__(
2042 2042
                 'An error occurred. The requested list table views could not be found.',
@@ -2056,10 +2056,10 @@  discard block
 block discarded – undo
2056 2056
         }
2057 2057
         // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2058 2058
         $this->_views = apply_filters(
2059
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2059
+            'FHEE_list_table_views_'.$this->page_slug.'_'.$this->_req_action,
2060 2060
             $this->_views
2061 2061
         );
2062
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2062
+        $this->_views = apply_filters('FHEE_list_table_views_'.$this->page_slug, $this->_views);
2063 2063
         $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2064 2064
         $this->_set_list_table_view();
2065 2065
         $this->_set_list_table_object();
@@ -2094,7 +2094,7 @@  discard block
 block discarded – undo
2094 2094
     protected function _set_list_table_object()
2095 2095
     {
2096 2096
         if (isset($this->_route_config['list_table'])) {
2097
-            if (! class_exists($this->_route_config['list_table'])) {
2097
+            if ( ! class_exists($this->_route_config['list_table'])) {
2098 2098
                 throw new EE_Error(
2099 2099
                     sprintf(
2100 2100
                         esc_html__(
@@ -2135,17 +2135,17 @@  discard block
 block discarded – undo
2135 2135
         foreach ($this->_views as $key => $view) {
2136 2136
             $query_args = [];
2137 2137
             // check for current view
2138
-            $this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2138
+            $this->_views[$key]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2139 2139
             $query_args['action']                        = $this->_req_action;
2140
-            $query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2140
+            $query_args[$this->_req_action.'_nonce'] = wp_create_nonce($query_args['action'].'_nonce');
2141 2141
             $query_args['status']                        = $view['slug'];
2142 2142
             // merge any other arguments sent in.
2143
-            if (isset($extra_query_args[ $view['slug'] ])) {
2144
-                foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2143
+            if (isset($extra_query_args[$view['slug']])) {
2144
+                foreach ($extra_query_args[$view['slug']] as $extra_query_arg) {
2145 2145
                     $query_args[] = $extra_query_arg;
2146 2146
                 }
2147 2147
             }
2148
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2148
+            $this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2149 2149
         }
2150 2150
         return $this->_views;
2151 2151
     }
@@ -2176,14 +2176,14 @@  discard block
 block discarded – undo
2176 2176
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2177 2177
         foreach ($values as $value) {
2178 2178
             if ($value < $max_entries) {
2179
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2179
+                $selected = $value === $per_page ? ' selected="'.$per_page.'"' : '';
2180 2180
                 $entries_per_page_dropdown .= '
2181
-						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2181
+						<option value="' . $value.'"'.$selected.'>'.$value.'&nbsp;&nbsp;</option>';
2182 2182
             }
2183 2183
         }
2184
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2184
+        $selected = $max_entries === $per_page ? ' selected="'.$per_page.'"' : '';
2185 2185
         $entries_per_page_dropdown .= '
2186
-						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2186
+						<option value="' . $max_entries.'"'.$selected.'>All&nbsp;&nbsp;</option>';
2187 2187
         $entries_per_page_dropdown .= '
2188 2188
 					</select>
2189 2189
 					entries
@@ -2207,7 +2207,7 @@  discard block
 block discarded – undo
2207 2207
             empty($this->_search_btn_label) ? $this->page_label
2208 2208
                 : $this->_search_btn_label
2209 2209
         );
2210
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2210
+        $this->_template_args['search']['callback'] = 'search_'.$this->page_slug;
2211 2211
     }
2212 2212
 
2213 2213
 
@@ -2272,7 +2272,7 @@  discard block
 block discarded – undo
2272 2272
                                   );
2273 2273
                     throw new EE_Error($error_msg);
2274 2274
                 }
2275
-                unset($this->_route_config['metaboxes'][ $key ]);
2275
+                unset($this->_route_config['metaboxes'][$key]);
2276 2276
             }
2277 2277
         }
2278 2278
     }
@@ -2306,7 +2306,7 @@  discard block
 block discarded – undo
2306 2306
             $total_columns                                       = ! empty($screen_columns)
2307 2307
                 ? $screen_columns
2308 2308
                 : $this->_route_config['columns'][1];
2309
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2309
+            $this->_template_args['current_screen_widget_class'] = 'columns-'.$total_columns;
2310 2310
             $this->_template_args['current_page']                = $this->_wp_page_slug;
2311 2311
             $this->_template_args['screen']                      = $this->_current_screen;
2312 2312
             $this->_column_template_path                         = EE_ADMIN_TEMPLATE
@@ -2352,7 +2352,7 @@  discard block
 block discarded – undo
2352 2352
      */
2353 2353
     protected function _espresso_ratings_request()
2354 2354
     {
2355
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2355
+        if ( ! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2356 2356
             return;
2357 2357
         }
2358 2358
         $ratings_box_title = apply_filters(
@@ -2379,28 +2379,28 @@  discard block
 block discarded – undo
2379 2379
      */
2380 2380
     public function espresso_ratings_request()
2381 2381
     {
2382
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2382
+        EEH_Template::display_template(EE_ADMIN_TEMPLATE.'espresso_ratings_request_content.template.php');
2383 2383
     }
2384 2384
 
2385 2385
 
2386 2386
     public static function cached_rss_display($rss_id, $url)
2387 2387
     {
2388
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2388
+        $loading = '<p class="widget-loading hide-if-no-js">'
2389 2389
                      . esc_html__('Loading&#8230;', 'event_espresso')
2390 2390
                      . '</p><p class="hide-if-js">'
2391 2391
                      . esc_html__('This widget requires JavaScript.', 'event_espresso')
2392 2392
                      . '</p>';
2393
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2394
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2395
-        $post      = '</div>' . "\n";
2396
-        $cache_key = 'ee_rss_' . md5($rss_id);
2393
+        $pre       = '<div class="espresso-rss-display">'."\n\t";
2394
+        $pre .= '<span id="'.esc_attr($rss_id).'_url" class="hidden">'.esc_url_raw($url).'</span>';
2395
+        $post      = '</div>'."\n";
2396
+        $cache_key = 'ee_rss_'.md5($rss_id);
2397 2397
         $output    = get_transient($cache_key);
2398 2398
         if ($output !== false) {
2399
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2399
+            echo wp_kses($pre.$output.$post, AllowedTags::getWithFormTags());
2400 2400
             return true;
2401 2401
         }
2402
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2403
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2402
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
2403
+            echo wp_kses($pre.$loading.$post, AllowedTags::getWithFormTags());
2404 2404
             return false;
2405 2405
         }
2406 2406
         ob_start();
@@ -2467,7 +2467,7 @@  discard block
 block discarded – undo
2467 2467
     public function espresso_sponsors_post_box()
2468 2468
     {
2469 2469
         EEH_Template::display_template(
2470
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2470
+            EE_ADMIN_TEMPLATE.'admin_general_metabox_contents_espresso_sponsors.template.php'
2471 2471
         );
2472 2472
     }
2473 2473
 
@@ -2484,9 +2484,9 @@  discard block
 block discarded – undo
2484 2484
     protected function getPublishBoxTitle(): string
2485 2485
     {
2486 2486
         $publish_box_title = esc_html__('Publish', 'event_espresso');
2487
-        if (! empty($this->_labels['publishbox'])) {
2487
+        if ( ! empty($this->_labels['publishbox'])) {
2488 2488
             if (is_array($this->_labels['publishbox'])) {
2489
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2489
+                $publish_box_title = $this->_labels['publishbox'][$this->_req_action] ?? $publish_box_title;
2490 2490
             } else {
2491 2491
                 $publish_box_title = $this->_labels['publishbox'];
2492 2492
             }
@@ -2542,7 +2542,7 @@  discard block
 block discarded – undo
2542 2542
         // if we have extra content set let's add it in if not make sure its empty
2543 2543
         $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2544 2544
         echo EEH_Template::display_template(
2545
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2545
+            EE_ADMIN_TEMPLATE.'admin_details_publish_metabox.template.php',
2546 2546
             $this->_template_args,
2547 2547
             true
2548 2548
         );
@@ -2587,7 +2587,7 @@  discard block
 block discarded – undo
2587 2587
         $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2588 2588
         if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2589 2589
             // make sure we have a default if just true is sent.
2590
-            $delete      = ! empty($delete) ? $delete : 'delete';
2590
+            $delete = ! empty($delete) ? $delete : 'delete';
2591 2591
             $this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2592 2592
                 $delete,
2593 2593
                 $delete,
@@ -2595,10 +2595,10 @@  discard block
 block discarded – undo
2595 2595
                 'submitdelete deletion button button--outline button--caution'
2596 2596
             );
2597 2597
         }
2598
-        if (! isset($this->_template_args['publish_delete_link'])) {
2598
+        if ( ! isset($this->_template_args['publish_delete_link'])) {
2599 2599
             $this->_template_args['publish_delete_link'] = '';
2600 2600
         }
2601
-        if (! empty($name) && ! empty($id)) {
2601
+        if ( ! empty($name) && ! empty($id)) {
2602 2602
             $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2603 2603
         }
2604 2604
         $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
@@ -2631,7 +2631,7 @@  discard block
 block discarded – undo
2631 2631
 
2632 2632
     protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2633 2633
     {
2634
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2634
+        $this->publish_post_meta_box_hidden_fields[$field_name] = $field_attributes;
2635 2635
     }
2636 2636
 
2637 2637
 
@@ -2732,7 +2732,7 @@  discard block
 block discarded – undo
2732 2732
         }
2733 2733
         // if $create_func is true (default) then we automatically create the function for displaying the actual meta box.  If false then we take the $callback reference passed through and use it instead (so callers can define their own callback function/method if they wish)
2734 2734
         $call_back_func = $create_func
2735
-            ? static function ($post, $metabox) {
2735
+            ? static function($post, $metabox) {
2736 2736
                 do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2737 2737
                 echo EEH_Template::display_template(
2738 2738
                     $metabox['args']['template_path'],
@@ -2742,7 +2742,7 @@  discard block
 block discarded – undo
2742 2742
             }
2743 2743
             : $callback;
2744 2744
         $this->addMetaBox(
2745
-            str_replace('_', '-', $action) . '-mbox',
2745
+            str_replace('_', '-', $action).'-mbox',
2746 2746
             $title,
2747 2747
             $call_back_func,
2748 2748
             $this->_wp_page_slug,
@@ -2859,13 +2859,13 @@  discard block
 block discarded – undo
2859 2859
                                                                     'event-espresso_page_espresso_',
2860 2860
                                                                     '',
2861 2861
                                                                     $this->_wp_page_slug
2862
-                                                                ) . ' ' . $this->_req_action . '-route';
2862
+                                                                ).' '.$this->_req_action.'-route';
2863 2863
 
2864 2864
         $template_path = $sidebar
2865 2865
             ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2866
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2866
+            : EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar.template.php';
2867 2867
         if ($this->request->isAjax()) {
2868
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2868
+            $template_path = EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar_ajax.template.php';
2869 2869
         }
2870 2870
         $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2871 2871
 
@@ -2899,11 +2899,11 @@  discard block
 block discarded – undo
2899 2899
     public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2900 2900
     {
2901 2901
         // let's generate a default preview action button if there isn't one already present.
2902
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2902
+        $this->_labels['buttons']['buy_now'] = esc_html__(
2903 2903
             'Upgrade to Event Espresso 4 Right Now',
2904 2904
             'event_espresso'
2905 2905
         );
2906
-        $buy_now_url                                   = add_query_arg(
2906
+        $buy_now_url = add_query_arg(
2907 2907
             [
2908 2908
                 'ee_ver'       => 'ee4',
2909 2909
                 'utm_source'   => 'ee4_plugin_admin',
@@ -2923,8 +2923,8 @@  discard block
 block discarded – undo
2923 2923
                 true
2924 2924
             )
2925 2925
             : $this->_template_args['preview_action_button'];
2926
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2927
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2926
+        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2927
+            EE_ADMIN_TEMPLATE.'admin_caf_full_page_preview.template.php',
2928 2928
             $this->_template_args,
2929 2929
             true
2930 2930
         );
@@ -2982,7 +2982,7 @@  discard block
 block discarded – undo
2982 2982
         // setup search attributes
2983 2983
         $this->_set_search_attributes();
2984 2984
         $this->_template_args['current_page']     = $this->_wp_page_slug;
2985
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2985
+        $template_path                            = EE_ADMIN_TEMPLATE.'admin_list_wrapper.template.php';
2986 2986
         $this->_template_args['table_url']        = $this->request->isAjax()
2987 2987
             ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2988 2988
             : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
@@ -2990,10 +2990,10 @@  discard block
 block discarded – undo
2990 2990
         $this->_template_args['current_route']    = $this->_req_action;
2991 2991
         $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2992 2992
         $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2993
-        if (! empty($ajax_sorting_callback)) {
2993
+        if ( ! empty($ajax_sorting_callback)) {
2994 2994
             $sortable_list_table_form_fields = wp_nonce_field(
2995
-                $ajax_sorting_callback . '_nonce',
2996
-                $ajax_sorting_callback . '_nonce',
2995
+                $ajax_sorting_callback.'_nonce',
2996
+                $ajax_sorting_callback.'_nonce',
2997 2997
                 false,
2998 2998
                 false
2999 2999
             );
@@ -3010,18 +3010,18 @@  discard block
 block discarded – undo
3010 3010
 
3011 3011
         $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
3012 3012
 
3013
-        $nonce_ref          = $this->_req_action . '_nonce';
3013
+        $nonce_ref          = $this->_req_action.'_nonce';
3014 3014
         $hidden_form_fields .= '
3015
-            <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
3015
+            <input type="hidden" name="' . $nonce_ref.'" value="'.wp_create_nonce($nonce_ref).'">';
3016 3016
 
3017 3017
         $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
3018 3018
         // display message about search results?
3019
-        $search                                    = $this->request->getRequestParam('s');
3019
+        $search = $this->request->getRequestParam('s');
3020 3020
         $this->_template_args['before_list_table'] .= ! empty($search)
3021
-            ? '<p class="ee-search-results">' . sprintf(
3021
+            ? '<p class="ee-search-results">'.sprintf(
3022 3022
                 esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3023 3023
                 trim($search, '%')
3024
-            ) . '</p>'
3024
+            ).'</p>'
3025 3025
             : '';
3026 3026
         // filter before_list_table template arg
3027 3027
         $this->_template_args['before_list_table'] = apply_filters(
@@ -3055,7 +3055,7 @@  discard block
 block discarded – undo
3055 3055
         // convert to array and filter again
3056 3056
         // arrays are easier to inject new items in a specific location,
3057 3057
         // but would not be backwards compatible, so we have to add a new filter
3058
-        $this->_template_args['after_list_table']   = implode(
3058
+        $this->_template_args['after_list_table'] = implode(
3059 3059
             " \n",
3060 3060
             (array) apply_filters(
3061 3061
                 'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
@@ -3110,7 +3110,7 @@  discard block
 block discarded – undo
3110 3110
             $this->page_slug
3111 3111
         );
3112 3112
         return EEH_Template::display_template(
3113
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3113
+            EE_ADMIN_TEMPLATE.'admin_details_legend.template.php',
3114 3114
             $this->_template_args,
3115 3115
             true
3116 3116
         );
@@ -3235,7 +3235,7 @@  discard block
 block discarded – undo
3235 3235
         if ($this->request->isAjax()) {
3236 3236
             $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3237 3237
             // $template_path,
3238
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3238
+                EE_ADMIN_TEMPLATE.'admin_wrapper_ajax.template.php',
3239 3239
                 $this->_template_args,
3240 3240
                 true
3241 3241
             );
@@ -3244,7 +3244,7 @@  discard block
 block discarded – undo
3244 3244
         // load settings page wrapper template
3245 3245
         $template_path = $about
3246 3246
             ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3247
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3247
+            : EE_ADMIN_TEMPLATE.'admin_wrapper.template.php';
3248 3248
 
3249 3249
         EEH_Template::display_template($template_path, $this->_template_args);
3250 3250
     }
@@ -3328,17 +3328,17 @@  discard block
 block discarded – undo
3328 3328
         $default_names = ['save', 'save_and_close'];
3329 3329
         $buttons       = '';
3330 3330
         foreach ($button_text as $key => $button) {
3331
-            $ref     = $default_names[ $key ];
3332
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3333
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3334
-                        . 'value="' . $button . '" name="' . $name . '" '
3335
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3336
-            if (! $both) {
3331
+            $ref     = $default_names[$key];
3332
+            $name    = ! empty($actions) ? $actions[$key] : $ref;
3333
+            $buttons .= '<input type="submit" class="button button--primary '.$ref.'" '
3334
+                        . 'value="'.$button.'" name="'.$name.'" '
3335
+                        . 'id="'.$this->_current_view.'_'.$ref.'" />';
3336
+            if ( ! $both) {
3337 3337
                 break;
3338 3338
             }
3339 3339
         }
3340 3340
         // add in a hidden index for the current page (so save and close redirects properly)
3341
-        $buttons                              .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3341
+        $buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3342 3342
                                                  . $referrer_url
3343 3343
                                                  . '" />';
3344 3344
         $this->_template_args['save_buttons'] = $buttons;
@@ -3373,13 +3373,13 @@  discard block
 block discarded – undo
3373 3373
                 'An error occurred. No action was set for this page\'s form.',
3374 3374
                 'event_espresso'
3375 3375
             );
3376
-            $dev_msg  = $user_msg . "\n"
3376
+            $dev_msg = $user_msg."\n"
3377 3377
                         . sprintf(
3378 3378
                             esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3379 3379
                             __FUNCTION__,
3380 3380
                             __CLASS__
3381 3381
                         );
3382
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3382
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
3383 3383
         }
3384 3384
         // open form
3385 3385
         $action                                            = $this->_admin_base_url;
@@ -3387,9 +3387,9 @@  discard block
 block discarded – undo
3387 3387
             <form name='form' method='post' action='{$action}' id='{$route}_event_form' class='ee-admin-page-form' >
3388 3388
             ";
3389 3389
         // add nonce
3390
-        $nonce                                             =
3391
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3392
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3390
+        $nonce =
3391
+            wp_nonce_field($route.'_nonce', $route.'_nonce', false, false);
3392
+        $this->_template_args['before_admin_page_content'] .= "\n\t".$nonce;
3393 3393
         // add REQUIRED form action
3394 3394
         $hidden_fields = [
3395 3395
             'action' => ['type' => 'hidden', 'value' => $route],
@@ -3402,7 +3402,7 @@  discard block
 block discarded – undo
3402 3402
         $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3403 3403
         // add fields to form
3404 3404
         foreach ((array) $form_fields as $form_field) {
3405
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3405
+            $this->_template_args['before_admin_page_content'] .= "\n\t".$form_field['field'];
3406 3406
         }
3407 3407
         // close form
3408 3408
         $this->_template_args['after_admin_page_content'] = '</form>';
@@ -3487,10 +3487,10 @@  discard block
 block discarded – undo
3487 3487
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3488 3488
         $notices = EE_Error::get_notices(false);
3489 3489
         // overwrite default success messages //BUT ONLY if overwrite not overridden
3490
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3490
+        if ( ! $override_overwrite || ! empty($notices['errors'])) {
3491 3491
             EE_Error::overwrite_success();
3492 3492
         }
3493
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3493
+        if ( ! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3494 3494
             // how many records affected ? more than one record ? or just one ?
3495 3495
             EE_Error::add_success(
3496 3496
                 sprintf(
@@ -3511,7 +3511,7 @@  discard block
 block discarded – undo
3511 3511
             );
3512 3512
         }
3513 3513
         // check that $query_args isn't something crazy
3514
-        if (! is_array($query_args)) {
3514
+        if ( ! is_array($query_args)) {
3515 3515
             $query_args = [];
3516 3516
         }
3517 3517
         /**
@@ -3543,7 +3543,7 @@  discard block
 block discarded – undo
3543 3543
             $redirect_url = admin_url('admin.php');
3544 3544
         }
3545 3545
         // merge any default query_args set in _default_route_query_args property
3546
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3546
+        if ( ! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3547 3547
             $args_to_merge = [];
3548 3548
             foreach ($this->_default_route_query_args as $query_param => $query_value) {
3549 3549
                 // is there a wp_referer array in our _default_route_query_args property?
@@ -3555,15 +3555,15 @@  discard block
 block discarded – undo
3555 3555
                         }
3556 3556
                         // finally we will override any arguments in the referer with
3557 3557
                         // what might be set on the _default_route_query_args array.
3558
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3559
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3558
+                        if (isset($this->_default_route_query_args[$reference])) {
3559
+                            $args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3560 3560
                         } else {
3561
-                            $args_to_merge[ $reference ] = urlencode($value);
3561
+                            $args_to_merge[$reference] = urlencode($value);
3562 3562
                         }
3563 3563
                     }
3564 3564
                     continue;
3565 3565
                 }
3566
-                $args_to_merge[ $query_param ] = $query_value;
3566
+                $args_to_merge[$query_param] = $query_value;
3567 3567
             }
3568 3568
             // now let's merge these arguments but override with what was specifically sent in to the
3569 3569
             // redirect.
@@ -3575,19 +3575,19 @@  discard block
 block discarded – undo
3575 3575
         if (isset($query_args['action'])) {
3576 3576
             // manually generate wp_nonce and merge that with the query vars
3577 3577
             // becuz the wp_nonce_url function wrecks havoc on some vars
3578
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3578
+            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'].'_nonce');
3579 3579
         }
3580 3580
         // we're adding some hooks and filters in here for processing any things just before redirects
3581 3581
         // (example: an admin page has done an insert or update and we want to run something after that).
3582
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3582
+        do_action('AHEE_redirect_'.$this->class_name.$this->_req_action, $query_args);
3583 3583
         $redirect_url = apply_filters(
3584
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3584
+            'FHEE_redirect_'.$this->class_name.$this->_req_action,
3585 3585
             EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3586 3586
             $query_args
3587 3587
         );
3588 3588
         // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3589 3589
         if ($this->request->isAjax()) {
3590
-            $default_data                    = [
3590
+            $default_data = [
3591 3591
                 'close'        => true,
3592 3592
                 'redirect_url' => $redirect_url,
3593 3593
                 'where'        => 'main',
@@ -3637,7 +3637,7 @@  discard block
 block discarded – undo
3637 3637
         }
3638 3638
         $this->_template_args['notices'] = EE_Error::get_notices();
3639 3639
         // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3640
-        if (! $this->request->isAjax() || $sticky_notices) {
3640
+        if ( ! $this->request->isAjax() || $sticky_notices) {
3641 3641
             $route = isset($query_args['action']) ? $query_args['action'] : 'default';
3642 3642
             $this->_add_transient(
3643 3643
                 $route,
@@ -3677,7 +3677,7 @@  discard block
 block discarded – undo
3677 3677
         $exclude_nonce = false
3678 3678
     ) {
3679 3679
         // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3680
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3680
+        if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3681 3681
             throw new EE_Error(
3682 3682
                 sprintf(
3683 3683
                     esc_html__(
@@ -3688,7 +3688,7 @@  discard block
 block discarded – undo
3688 3688
                 )
3689 3689
             );
3690 3690
         }
3691
-        if (! isset($this->_labels['buttons'][ $type ])) {
3691
+        if ( ! isset($this->_labels['buttons'][$type])) {
3692 3692
             throw new EE_Error(
3693 3693
                 sprintf(
3694 3694
                     esc_html__(
@@ -3701,7 +3701,7 @@  discard block
 block discarded – undo
3701 3701
         }
3702 3702
         // finally check user access for this button.
3703 3703
         $has_access = $this->check_user_access($action, true);
3704
-        if (! $has_access) {
3704
+        if ( ! $has_access) {
3705 3705
             return '';
3706 3706
         }
3707 3707
         $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
@@ -3709,11 +3709,11 @@  discard block
 block discarded – undo
3709 3709
             'action' => $action,
3710 3710
         ];
3711 3711
         // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3712
-        if (! empty($extra_request)) {
3712
+        if ( ! empty($extra_request)) {
3713 3713
             $query_args = array_merge($extra_request, $query_args);
3714 3714
         }
3715 3715
         $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3716
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3716
+        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3717 3717
     }
3718 3718
 
3719 3719
 
@@ -3739,7 +3739,7 @@  discard block
 block discarded – undo
3739 3739
                 'FHEE__EE_Admin_Page___per_page_screen_options__default',
3740 3740
                 20
3741 3741
             ),
3742
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3742
+            'option'  => $this->_current_page.'_'.$this->_current_view.'_per_page',
3743 3743
         ];
3744 3744
         // ONLY add the screen option if the user has access to it.
3745 3745
         if ($this->check_user_access($this->_current_view, true)) {
@@ -3760,18 +3760,18 @@  discard block
 block discarded – undo
3760 3760
     {
3761 3761
         if ($this->request->requestParamIsSet('wp_screen_options')) {
3762 3762
             check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3763
-            if (! $user = wp_get_current_user()) {
3763
+            if ( ! $user = wp_get_current_user()) {
3764 3764
                 return;
3765 3765
             }
3766 3766
             $option = $this->request->getRequestParam('wp_screen_options[option]', '', 'key');
3767
-            if (! $option) {
3767
+            if ( ! $option) {
3768 3768
                 return;
3769 3769
             }
3770 3770
             $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, 'int');
3771 3771
             $map_option = $option;
3772 3772
             $option     = str_replace('-', '_', $option);
3773 3773
             switch ($map_option) {
3774
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3774
+                case $this->_current_page.'_'.$this->_current_view.'_per_page':
3775 3775
                     $max_value = apply_filters(
3776 3776
                         'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3777 3777
                         999,
@@ -3828,13 +3828,13 @@  discard block
 block discarded – undo
3828 3828
     protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3829 3829
     {
3830 3830
         $user_id = get_current_user_id();
3831
-        if (! $skip_route_verify) {
3831
+        if ( ! $skip_route_verify) {
3832 3832
             $this->_verify_route($route);
3833 3833
         }
3834 3834
         // now let's set the string for what kind of transient we're setting
3835 3835
         $transient = $notices
3836
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3837
-            : 'rte_tx_' . $route . '_' . $user_id;
3836
+            ? 'ee_rte_n_tx_'.$route.'_'.$user_id
3837
+            : 'rte_tx_'.$route.'_'.$user_id;
3838 3838
         $data      = $notices ? ['notices' => $data] : $data;
3839 3839
         // is there already a transient for this route?  If there is then let's ADD to that transient
3840 3840
         $existing = is_multisite() && is_network_admin()
@@ -3863,8 +3863,8 @@  discard block
 block discarded – undo
3863 3863
         $user_id   = get_current_user_id();
3864 3864
         $route     = ! $route ? $this->_req_action : $route;
3865 3865
         $transient = $notices
3866
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3867
-            : 'rte_tx_' . $route . '_' . $user_id;
3866
+            ? 'ee_rte_n_tx_'.$route.'_'.$user_id
3867
+            : 'rte_tx_'.$route.'_'.$user_id;
3868 3868
         $data      = is_multisite() && is_network_admin()
3869 3869
             ? get_site_transient($transient)
3870 3870
             : get_transient($transient);
@@ -4105,7 +4105,7 @@  discard block
 block discarded – undo
4105 4105
      */
4106 4106
     protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4107 4107
     {
4108
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4108
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4109 4109
     }
4110 4110
 
4111 4111
 
@@ -4118,7 +4118,7 @@  discard block
 block discarded – undo
4118 4118
      */
4119 4119
     protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4120 4120
     {
4121
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4121
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4122 4122
     }
4123 4123
 
4124 4124
 
@@ -4266,13 +4266,13 @@  discard block
 block discarded – undo
4266 4266
         ?callable $callback = null
4267 4267
     ): bool {
4268 4268
         $entity_ID = absint($entity_ID);
4269
-        if (! $entity_ID) {
4269
+        if ( ! $entity_ID) {
4270 4270
             $this->trashRestoreDeleteError($action, $entity_model);
4271 4271
         }
4272 4272
         $result = 0;
4273 4273
         try {
4274 4274
             $entity = $entity_model->get_one_by_ID($entity_ID);
4275
-            if (! $entity instanceof EE_Base_Class) {
4275
+            if ( ! $entity instanceof EE_Base_Class) {
4276 4276
                 throw new DomainException(
4277 4277
                     sprintf(
4278 4278
                         esc_html__(
@@ -4323,7 +4323,7 @@  discard block
 block discarded – undo
4323 4323
                 )
4324 4324
             );
4325 4325
         }
4326
-        if (! $entity_model->has_field($delete_column)) {
4326
+        if ( ! $entity_model->has_field($delete_column)) {
4327 4327
             throw new DomainException(
4328 4328
                 sprintf(
4329 4329
                     esc_html__(
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/admin/EspressoLegacyAdmin.php 1 patch
Indentation   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -17,125 +17,125 @@
 block discarded – undo
17 17
  */
18 18
 class EspressoLegacyAdmin extends AdminRoute
19 19
 {
20
-    /**
21
-     * @var LegacyAccountingAssetManager $asset_manager
22
-     */
23
-    protected $asset_manager;
20
+	/**
21
+	 * @var LegacyAccountingAssetManager $asset_manager
22
+	 */
23
+	protected $asset_manager;
24 24
 
25 25
 
26
-    /**
27
-     * returns true if the current request matches this route
28
-     *
29
-     * @return bool
30
-     * @since   $VID:$
31
-     */
32
-    public function matchesCurrentRequest(): bool
33
-    {
34
-        global $pagenow;
35
-        return ($pagenow === 'admin.php' || $pagenow === 'admin-ajax.php') && parent::matchesCurrentRequest();
36
-    }
26
+	/**
27
+	 * returns true if the current request matches this route
28
+	 *
29
+	 * @return bool
30
+	 * @since   $VID:$
31
+	 */
32
+	public function matchesCurrentRequest(): bool
33
+	{
34
+		global $pagenow;
35
+		return ($pagenow === 'admin.php' || $pagenow === 'admin-ajax.php') && parent::matchesCurrentRequest();
36
+	}
37 37
 
38 38
 
39
-    /**
40
-     * @since $VID:$
41
-     */
42
-    protected function registerDependencies()
43
-    {
44
-        $asset_manger_dependencies = [
45
-            'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
46
-            'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
47
-            'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
48
-        ];
49
-        $this->dependency_map->registerDependencies(JqueryAssetManager::class, $asset_manger_dependencies);
50
-        $this->dependency_map->registerDependencies(EspressoLegacyAdminAssetManager::class, $asset_manger_dependencies);
51
-        $this->dependency_map->registerDependencies(
52
-            LegacyAccountingAssetManager::class,
53
-            ['EE_Currency_Config' => EE_Dependency_Map::load_from_cache] + $asset_manger_dependencies
54
-        );
55
-        $this->dependency_map->registerDependencies(
56
-            'EE_Admin_Transactions_List_Table',
57
-            [
58
-                null,
59
-                'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
60
-            ]
61
-        );
62
-        $this->dependency_map->registerDependencies(
63
-            'EventEspresso\caffeinated\modules\recaptcha_invisible\RecaptchaAdminSettings',
64
-            ['EE_Registration_Config' => EE_Dependency_Map::load_from_cache]
65
-        );
66
-        $this->dependency_map->registerDependencies(
67
-            'EventEspresso\admin_pages\general_settings\OrganizationSettings',
68
-            [
69
-                'EE_Registry'                                             => EE_Dependency_Map::load_from_cache,
70
-                'EE_Organization_Config'                                  => EE_Dependency_Map::load_from_cache,
71
-                'EE_Core_Config'                                          => EE_Dependency_Map::load_from_cache,
72
-                'EE_Network_Core_Config'                                  => EE_Dependency_Map::load_from_cache,
73
-                'EventEspresso\core\services\address\CountrySubRegionDao' => EE_Dependency_Map::load_from_cache,
74
-            ]
75
-        );
76
-        $this->dependency_map->registerDependencies(
77
-            'EventEspresso\core\services\address\CountrySubRegionDao',
78
-            [
79
-                'EEM_State'                                            => EE_Dependency_Map::load_from_cache,
80
-                'EventEspresso\core\services\validators\JsonValidator' => EE_Dependency_Map::load_from_cache
81
-            ]
82
-        );
83
-        $this->dependency_map->registerDependencies(
84
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
85
-            [
86
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
87
-                'EEM_Registration'                            => EE_Dependency_Map::load_from_cache,
88
-                null,
89
-            ]
90
-        );
91
-        $this->dependency_map->registerDependencies(
92
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
93
-            [
94
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
95
-                'EEM_Attendee'                                => EE_Dependency_Map::load_from_cache,
96
-            ]
97
-        );
98
-        $this->dependency_map->registerDependencies(
99
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
100
-            [
101
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
102
-                'EEM_Datetime'                                => EE_Dependency_Map::load_from_cache,
103
-            ]
104
-        );
105
-        $this->dependency_map->registerDependencies(
106
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
107
-            [
108
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
109
-                'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
110
-            ]
111
-        );
112
-        $this->dependency_map->registerDependencies(
113
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
114
-            [
115
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
116
-                'EEM_Ticket'                                  => EE_Dependency_Map::load_from_cache,
117
-            ]
118
-        );
119
-        $this->dependency_map->registerDependencies(
120
-            'EventEspresso\core\services\admin\AdminListTableFilters',
121
-            [
122
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
123
-            ]
124
-        );
125
-    }
39
+	/**
40
+	 * @since $VID:$
41
+	 */
42
+	protected function registerDependencies()
43
+	{
44
+		$asset_manger_dependencies = [
45
+			'EventEspresso\core\domain\Domain'                   => EE_Dependency_Map::load_from_cache,
46
+			'EventEspresso\core\services\assets\AssetCollection' => EE_Dependency_Map::load_new_object,
47
+			'EventEspresso\core\services\assets\Registry'        => EE_Dependency_Map::load_from_cache,
48
+		];
49
+		$this->dependency_map->registerDependencies(JqueryAssetManager::class, $asset_manger_dependencies);
50
+		$this->dependency_map->registerDependencies(EspressoLegacyAdminAssetManager::class, $asset_manger_dependencies);
51
+		$this->dependency_map->registerDependencies(
52
+			LegacyAccountingAssetManager::class,
53
+			['EE_Currency_Config' => EE_Dependency_Map::load_from_cache] + $asset_manger_dependencies
54
+		);
55
+		$this->dependency_map->registerDependencies(
56
+			'EE_Admin_Transactions_List_Table',
57
+			[
58
+				null,
59
+				'EventEspresso\core\domain\values\session\SessionLifespan' => EE_Dependency_Map::load_from_cache,
60
+			]
61
+		);
62
+		$this->dependency_map->registerDependencies(
63
+			'EventEspresso\caffeinated\modules\recaptcha_invisible\RecaptchaAdminSettings',
64
+			['EE_Registration_Config' => EE_Dependency_Map::load_from_cache]
65
+		);
66
+		$this->dependency_map->registerDependencies(
67
+			'EventEspresso\admin_pages\general_settings\OrganizationSettings',
68
+			[
69
+				'EE_Registry'                                             => EE_Dependency_Map::load_from_cache,
70
+				'EE_Organization_Config'                                  => EE_Dependency_Map::load_from_cache,
71
+				'EE_Core_Config'                                          => EE_Dependency_Map::load_from_cache,
72
+				'EE_Network_Core_Config'                                  => EE_Dependency_Map::load_from_cache,
73
+				'EventEspresso\core\services\address\CountrySubRegionDao' => EE_Dependency_Map::load_from_cache,
74
+			]
75
+		);
76
+		$this->dependency_map->registerDependencies(
77
+			'EventEspresso\core\services\address\CountrySubRegionDao',
78
+			[
79
+				'EEM_State'                                            => EE_Dependency_Map::load_from_cache,
80
+				'EventEspresso\core\services\validators\JsonValidator' => EE_Dependency_Map::load_from_cache
81
+			]
82
+		);
83
+		$this->dependency_map->registerDependencies(
84
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
85
+			[
86
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
87
+				'EEM_Registration'                            => EE_Dependency_Map::load_from_cache,
88
+				null,
89
+			]
90
+		);
91
+		$this->dependency_map->registerDependencies(
92
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
93
+			[
94
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
95
+				'EEM_Attendee'                                => EE_Dependency_Map::load_from_cache,
96
+			]
97
+		);
98
+		$this->dependency_map->registerDependencies(
99
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
100
+			[
101
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
102
+				'EEM_Datetime'                                => EE_Dependency_Map::load_from_cache,
103
+			]
104
+		);
105
+		$this->dependency_map->registerDependencies(
106
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
107
+			[
108
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
109
+				'EEM_Event'                                   => EE_Dependency_Map::load_from_cache,
110
+			]
111
+		);
112
+		$this->dependency_map->registerDependencies(
113
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
114
+			[
115
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
116
+				'EEM_Ticket'                                  => EE_Dependency_Map::load_from_cache,
117
+			]
118
+		);
119
+		$this->dependency_map->registerDependencies(
120
+			'EventEspresso\core\services\admin\AdminListTableFilters',
121
+			[
122
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
123
+			]
124
+		);
125
+	}
126 126
 
127 127
 
128
-    /**
129
-     * implements logic required to run during request
130
-     *
131
-     * @return bool
132
-     * @since   $VID:$
133
-     */
134
-    protected function requestHandler(): bool
135
-    {
136
-        $this->loader->getShared(JqueryAssetManager::class);
137
-        $this->loader->getShared(EspressoLegacyAdminAssetManager::class);
138
-        $this->loader->getShared(LegacyAccountingAssetManager::class);
139
-        return true;
140
-    }
128
+	/**
129
+	 * implements logic required to run during request
130
+	 *
131
+	 * @return bool
132
+	 * @since   $VID:$
133
+	 */
134
+	protected function requestHandler(): bool
135
+	{
136
+		$this->loader->getShared(JqueryAssetManager::class);
137
+		$this->loader->getShared(EspressoLegacyAdminAssetManager::class);
138
+		$this->loader->getShared(LegacyAccountingAssetManager::class);
139
+		return true;
140
+	}
141 141
 }
Please login to merge, or discard this patch.
core/domain/entities/routing/handlers/admin/EspressoEventsAdmin.php 1 patch
Indentation   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -14,36 +14,36 @@
 block discarded – undo
14 14
  */
15 15
 class EspressoEventsAdmin extends AdminRoute
16 16
 {
17
-    /**
18
-     * returns true if the current request matches this route
19
-     *
20
-     * @return bool
21
-     * @since   $VID:$
22
-     */
23
-    public function matchesCurrentRequest(): bool
24
-    {
25
-        global $pagenow;
26
-        return parent::matchesCurrentRequest()
27
-               && $pagenow
28
-               && $pagenow === 'admin.php'
29
-               && $this->request->getRequestParam('page') === 'espresso_events';
30
-    }
17
+	/**
18
+	 * returns true if the current request matches this route
19
+	 *
20
+	 * @return bool
21
+	 * @since   $VID:$
22
+	 */
23
+	public function matchesCurrentRequest(): bool
24
+	{
25
+		global $pagenow;
26
+		return parent::matchesCurrentRequest()
27
+			   && $pagenow
28
+			   && $pagenow === 'admin.php'
29
+			   && $this->request->getRequestParam('page') === 'espresso_events';
30
+	}
31 31
 
32 32
 
33
-    /**
34
-     * @since $VID:$
35
-     */
36
-    protected function registerDependencies()
37
-    {
38
-        $this->dependency_map->registerDependencies(
39
-            'EventEspresso\core\domain\services\admin\events\default_settings\AdvancedEditorAdminFormSection',
40
-            AdminRoute::getDefaultDependencies()
41
-        );
42
-        $this->dependency_map->registerDependencies(
43
-            'EventEspresso\core\services\admin\AdminListTableFilters',
44
-            [
45
-                'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
46
-            ]
47
-        );
48
-    }
33
+	/**
34
+	 * @since $VID:$
35
+	 */
36
+	protected function registerDependencies()
37
+	{
38
+		$this->dependency_map->registerDependencies(
39
+			'EventEspresso\core\domain\services\admin\events\default_settings\AdvancedEditorAdminFormSection',
40
+			AdminRoute::getDefaultDependencies()
41
+		);
42
+		$this->dependency_map->registerDependencies(
43
+			'EventEspresso\core\services\admin\AdminListTableFilters',
44
+			[
45
+				'EventEspresso\core\services\request\Request' => EE_Dependency_Map::load_from_cache,
46
+			]
47
+		);
48
+	}
49 49
 }
Please login to merge, or discard this patch.
core/EE_Capabilities.core.php 2 patches
Indentation   +1391 added lines, -1391 removed lines patch added patch discarded remove patch
@@ -13,986 +13,986 @@  discard block
 block discarded – undo
13 13
  */
14 14
 final class EE_Capabilities extends EE_Base
15 15
 {
16
-    const ROLE_ADMINISTRATOR        = 'administrator';
17
-
18
-    const ROLE_EVENTS_ADMINISTRATOR = 'ee_events_administrator';
19
-
20
-
21
-    /**
22
-     * the name of the wp option used to store caps previously initialized
23
-     */
24
-    const option_name = 'ee_caps_initialized';
25
-
26
-    /**
27
-     * instance of EE_Capabilities object
28
-     *
29
-     * @var EE_Capabilities
30
-     */
31
-    private static $_instance;
32
-
33
-
34
-    /**
35
-     * This is a map of caps that correspond to a default WP_Role.
36
-     * Array is indexed by Role and values are ee capabilities.
37
-     *
38
-     * @since 4.5.0
39
-     *
40
-     * @var array
41
-     */
42
-    private $capabilities_map = [];
43
-
44
-    /**
45
-     * This used to hold an array of EE_Meta_Capability_Map objects
46
-     * that define the granular capabilities mapped to for a user depending on context.
47
-     *
48
-     * @var EE_Meta_Capability_Map[]
49
-     */
50
-    private $_meta_caps = [];
51
-
52
-    /**
53
-     * The internal $capabilities_map needs to be initialized before it can be used.
54
-     * This flag tracks whether that has happened or not.
55
-     * But for this to work, we need three states to indicate:
56
-     *      initialization has not occurred at all
57
-     *      initialization has started but is not complete
58
-     *      initialization is complete
59
-     * The reason this is needed is because the addCaps() method
60
-     * normally requires the $capabilities_map to be initialized,
61
-     * but is also used during the initialization process.
62
-     * So:
63
-     *      If initialized === null, init_caps() will be called before any other methods will run.
64
-     *      If initialized === false, then init_caps() is in the process of running it's logic.
65
-     *      If initialized === true, then init_caps() has completed the initialization process.
66
-     *
67
-     * @var boolean|null $initialized
68
-     */
69
-    private $initialized;
70
-
71
-    /**
72
-     * @var boolean $reset
73
-     */
74
-    private $reset = false;
75
-
76
-
77
-    /**
78
-     * singleton method used to instantiate class object
79
-     *
80
-     * @return EE_Capabilities
81
-     * @since 4.5.0
82
-     *
83
-     */
84
-    public static function instance(): EE_Capabilities
85
-    {
86
-        // check if instantiated, and if not do so.
87
-        if (! self::$_instance instanceof EE_Capabilities) {
88
-            self::$_instance = new self();
89
-        }
90
-        return self::$_instance;
91
-    }
92
-
93
-
94
-    /**
95
-     * private constructor
96
-     *
97
-     * @since 4.5.0
98
-     */
99
-    private function __construct()
100
-    {
101
-    }
102
-
103
-
104
-    /**
105
-     * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
106
-     *
107
-     * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
108
-     *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
109
-     *                    ensures that they are up to date.
110
-     *
111
-     * @since 4.5.0
112
-     * @return bool
113
-     * @throws EE_Error
114
-     */
115
-    public function init_caps(?bool $reset = false): bool
116
-    {
117
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
118
-            return false;
119
-        }
120
-        $this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
121
-        // if reset, then completely delete the cache option and clear the $capabilities_map property.
122
-        if ($this->reset) {
123
-            $this->initialized      = null;
124
-            $this->capabilities_map = [];
125
-            delete_option(self::option_name);
126
-        }
127
-        if ($this->initialized === null) {
128
-            $this->initialized = false;
129
-            do_action(
130
-                'AHEE__EE_Capabilities__init_caps__before_initialization',
131
-                $this->reset
132
-            );
133
-            $this->addCaps($this->_init_caps_map());
134
-            $this->_set_meta_caps();
135
-            do_action(
136
-                'AHEE__EE_Capabilities__init_caps__after_initialization',
137
-                $this->capabilities_map
138
-            );
139
-            $this->initialized = true;
140
-        }
141
-        // reset $this->reset so that it's not stuck on true if init_caps() gets called again
142
-        $this->reset = false;
143
-        return true;
144
-    }
145
-
146
-
147
-    /**
148
-     * This sets the meta caps property.
149
-     *
150
-     * @return void
151
-     * @throws EE_Error
152
-     * @since 4.5.0
153
-     */
154
-    private function _set_meta_caps()
155
-    {
156
-        // get default meta caps and filter the returned array
157
-        $this->_meta_caps = apply_filters(
158
-            'FHEE__EE_Capabilities___set_meta_caps__meta_caps',
159
-            $this->_get_default_meta_caps_array()
160
-        );
161
-        // add filter for map_meta_caps but only if models can query.
162
-        if (! has_filter('map_meta_cap', [$this, 'map_meta_caps'])) {
163
-            add_filter('map_meta_cap', [$this, 'map_meta_caps'], 10, 4);
164
-        }
165
-    }
166
-
167
-
168
-    /**
169
-     * This builds and returns the default meta_caps array only once.
170
-     *
171
-     * @return array
172
-     * @throws EE_Error
173
-     * @since  4.8.28.rc.012
174
-     */
175
-    private function _get_default_meta_caps_array(): array
176
-    {
177
-        static $default_meta_caps = [];
178
-        // make sure we're only ever initializing the default _meta_caps array once if it's empty.
179
-        if (empty($default_meta_caps)) {
180
-            $default_meta_caps = [
181
-                // edits
182
-                new EE_Meta_Capability_Map_Edit(
183
-                    'ee_edit_event',
184
-                    ['Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events']
185
-                ),
186
-                new EE_Meta_Capability_Map_Edit(
187
-                    'ee_edit_venue',
188
-                    ['Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues']
189
-                ),
190
-                new EE_Meta_Capability_Map_Edit(
191
-                    'ee_edit_registration',
192
-                    ['Registration', '', 'ee_edit_others_registrations', '']
193
-                ),
194
-                new EE_Meta_Capability_Map_Edit(
195
-                    'ee_edit_checkin',
196
-                    ['Registration', '', 'ee_edit_others_checkins', '']
197
-                ),
198
-                new EE_Meta_Capability_Map_Messages_Cap(
199
-                    'ee_edit_message',
200
-                    ['Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages']
201
-                ),
202
-                new EE_Meta_Capability_Map_Edit(
203
-                    'ee_edit_default_ticket',
204
-                    ['Ticket', '', 'ee_edit_others_default_tickets', '']
205
-                ),
206
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
207
-                    'ee_edit_question',
208
-                    ['Question', '', '', 'ee_edit_system_questions']
209
-                ),
210
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
211
-                    'ee_edit_question_group',
212
-                    ['Question_Group', '', '', 'ee_edit_system_question_groups']
213
-                ),
214
-                new EE_Meta_Capability_Map_Edit(
215
-                    'ee_edit_payment_method',
216
-                    ['Payment_Method', '', 'ee_edit_others_payment_methods', '']
217
-                ),
218
-                // reads
219
-                new EE_Meta_Capability_Map_Read(
220
-                    'ee_read_event',
221
-                    ['Event', '', 'ee_read_others_events', 'ee_read_private_events']
222
-                ),
223
-                new EE_Meta_Capability_Map_Read(
224
-                    'ee_read_venue',
225
-                    ['Venue', '', 'ee_read_others_venues', 'ee_read_private_venues']
226
-                ),
227
-                new EE_Meta_Capability_Map_Read(
228
-                    'ee_read_registration',
229
-                    ['Registration', '', 'ee_read_others_registrations', '']
230
-                ),
231
-                new EE_Meta_Capability_Map_Read(
232
-                    'ee_read_checkin',
233
-                    ['Registration', '', 'ee_read_others_checkins', '']
234
-                ),
235
-                new EE_Meta_Capability_Map_Messages_Cap(
236
-                    'ee_read_message',
237
-                    ['Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages']
238
-                ),
239
-                new EE_Meta_Capability_Map_Read(
240
-                    'ee_read_default_ticket',
241
-                    ['Ticket', '', 'ee_read_others_default_tickets', '']
242
-                ),
243
-                new EE_Meta_Capability_Map_Read(
244
-                    'ee_read_payment_method',
245
-                    ['Payment_Method', '', 'ee_read_others_payment_methods', '']
246
-                ),
247
-                // deletes
248
-                new EE_Meta_Capability_Map_Delete(
249
-                    'ee_delete_event',
250
-                    [
251
-                        'Event',
252
-                        'ee_delete_published_events',
253
-                        'ee_delete_others_events',
254
-                        'ee_delete_private_events',
255
-                    ]
256
-                ),
257
-                new EE_Meta_Capability_Map_Delete(
258
-                    'ee_delete_venue',
259
-                    [
260
-                        'Venue',
261
-                        'ee_delete_published_venues',
262
-                        'ee_delete_others_venues',
263
-                        'ee_delete_private_venues',
264
-                    ]
265
-                ),
266
-                new EE_Meta_Capability_Map_Delete(
267
-                    'ee_delete_registration',
268
-                    ['Registration', '', 'ee_delete_others_registrations', '']
269
-                ),
270
-                new EE_Meta_Capability_Map_Delete(
271
-                    'ee_delete_checkin',
272
-                    ['Registration', '', 'ee_delete_others_checkins', '']
273
-                ),
274
-                new EE_Meta_Capability_Map_Messages_Cap(
275
-                    'ee_delete_message',
276
-                    ['Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages']
277
-                ),
278
-                new EE_Meta_Capability_Map_Delete(
279
-                    'ee_delete_default_ticket',
280
-                    ['Ticket', '', 'ee_delete_others_default_tickets', '']
281
-                ),
282
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
283
-                    'ee_delete_question',
284
-                    ['Question', '', '', 'delete_system_questions']
285
-                ),
286
-                new EE_Meta_Capability_Map_Registration_Form_Cap(
287
-                    'ee_delete_question_group',
288
-                    ['Question_Group', '', '', 'delete_system_question_groups']
289
-                ),
290
-                new EE_Meta_Capability_Map_Delete(
291
-                    'ee_delete_payment_method',
292
-                    ['Payment_Method', '', 'ee_delete_others_payment_methods', '']
293
-                ),
294
-            ];
295
-        }
296
-        return $default_meta_caps;
297
-    }
298
-
299
-
300
-    /**
301
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
302
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
303
-     *
304
-     * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
305
-     *
306
-     * @param array  $caps    actual users capabilities
307
-     * @param string $cap     initial capability name that is being checked (the "map" key)
308
-     * @param int    $user_id The user id
309
-     * @param array  $args    Adds context to the cap. Typically the object ID.
310
-     * @return array actual users capabilities
311
-     * @throws EE_Error
312
-     * @throws ReflectionException
313
-     * @since 4.5.0
314
-     * @see   wp-includes/capabilities.php
315
-     *
316
-     */
317
-    public function map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
318
-    {
319
-        if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
320
-            // loop through our _meta_caps array
321
-            foreach ($this->_meta_caps as $meta_map) {
322
-                if (! $meta_map instanceof EE_Meta_Capability_Map) {
323
-                    continue;
324
-                }
325
-                // don't load models if there is no object ID in the args
326
-                if (! empty($args[0])) {
327
-                    $meta_map->ensure_is_model();
328
-                }
329
-                $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
330
-            }
331
-        }
332
-        return $caps;
333
-    }
334
-
335
-
336
-    /**
337
-     * This sets up and returns the initial capabilities map for Event Espresso
338
-     * Note this array is filtered.
339
-     * It is assumed that all available EE capabilities are assigned to the administrator role.
340
-     *
341
-     * @return array
342
-     * @since 4.5.0
343
-     *
344
-     */
345
-    private function _init_caps_map(): array
346
-    {
347
-        return apply_filters(
348
-            'FHEE__EE_Capabilities__init_caps_map__caps',
349
-            [
350
-                EE_Capabilities::ROLE_ADMINISTRATOR        => [
351
-                    // basic access
352
-                    'ee_read_ee',
353
-                    // gateways
354
-                    /**
355
-                     * note that with payment method capabilities, although we've implemented
356
-                     * capability mapping which will be used for accessing payment methods owned by
357
-                     * other users.  This is not fully implemented yet in the payment method ui.
358
-                     * Currently only the "plural" caps are in active use.
359
-                     * (Specific payment method caps are in use as well).
360
-                     **/
361
-                    'ee_manage_gateways',
362
-                    'ee_read_payment_methods',
363
-                    'ee_read_others_payment_methods',
364
-                    'ee_edit_payment_methods',
365
-                    'ee_edit_others_payment_methods',
366
-                    'ee_delete_payment_methods',
367
-                    // events
368
-                    'ee_publish_events',
369
-                    'ee_read_private_events',
370
-                    'ee_read_others_events',
371
-                    'ee_read_events',
372
-                    'ee_edit_events',
373
-                    'ee_edit_published_events',
374
-                    'ee_edit_others_events',
375
-                    'ee_edit_private_events',
376
-                    'ee_delete_published_events',
377
-                    'ee_delete_private_events',
378
-                    'ee_delete_events',
379
-                    'ee_delete_others_events',
380
-                    // event categories
381
-                    'ee_manage_event_categories',
382
-                    'ee_edit_event_category',
383
-                    'ee_delete_event_category',
384
-                    'ee_assign_event_category',
385
-                    // venues
386
-                    'ee_publish_venues',
387
-                    'ee_read_venues',
388
-                    'ee_read_others_venues',
389
-                    'ee_read_private_venues',
390
-                    'ee_edit_venues',
391
-                    'ee_edit_others_venues',
392
-                    'ee_edit_published_venues',
393
-                    'ee_edit_private_venues',
394
-                    'ee_delete_venues',
395
-                    'ee_delete_others_venues',
396
-                    'ee_delete_private_venues',
397
-                    'ee_delete_published_venues',
398
-                    // venue categories
399
-                    'ee_manage_venue_categories',
400
-                    'ee_edit_venue_category',
401
-                    'ee_delete_venue_category',
402
-                    'ee_assign_venue_category',
403
-                    // contacts
404
-                    'ee_read_contacts',
405
-                    'ee_edit_contacts',
406
-                    'ee_delete_contacts',
407
-                    // registrations
408
-                    'ee_read_registrations',
409
-                    'ee_read_others_registrations',
410
-                    'ee_edit_registrations',
411
-                    'ee_edit_others_registrations',
412
-                    'ee_delete_registrations',
413
-                    'ee_delete_others_registrations',
414
-                    // checkins
415
-                    'ee_read_others_checkins',
416
-                    'ee_read_checkins',
417
-                    'ee_edit_checkins',
418
-                    'ee_edit_others_checkins',
419
-                    'ee_delete_checkins',
420
-                    'ee_delete_others_checkins',
421
-                    // transactions && payments
422
-                    'ee_read_transaction',
423
-                    'ee_read_transactions',
424
-                    'ee_edit_payments',
425
-                    'ee_delete_payments',
426
-                    // messages
427
-                    'ee_read_messages',
428
-                    'ee_read_others_messages',
429
-                    'ee_read_global_messages',
430
-                    'ee_edit_global_messages',
431
-                    'ee_edit_messages',
432
-                    'ee_edit_others_messages',
433
-                    'ee_delete_messages',
434
-                    'ee_delete_others_messages',
435
-                    'ee_delete_global_messages',
436
-                    'ee_send_message',
437
-                    // tickets
438
-                    'ee_read_default_tickets',
439
-                    'ee_read_others_default_tickets',
440
-                    'ee_edit_default_tickets',
441
-                    'ee_edit_others_default_tickets',
442
-                    'ee_delete_default_tickets',
443
-                    'ee_delete_others_default_tickets',
444
-                    // prices
445
-                    'ee_edit_default_price',
446
-                    'ee_edit_default_prices',
447
-                    'ee_delete_default_price',
448
-                    'ee_delete_default_prices',
449
-                    'ee_edit_default_price_type',
450
-                    'ee_edit_default_price_types',
451
-                    'ee_delete_default_price_type',
452
-                    'ee_delete_default_price_types',
453
-                    'ee_read_default_prices',
454
-                    'ee_read_default_price_types',
455
-                    // registration form
456
-                    'ee_edit_questions',
457
-                    'ee_edit_system_questions',
458
-                    'ee_read_questions',
459
-                    'ee_delete_questions',
460
-                    'ee_edit_question_groups',
461
-                    'ee_read_question_groups',
462
-                    'ee_edit_system_question_groups',
463
-                    'ee_delete_question_groups',
464
-                    // event_type taxonomy
465
-                    'ee_assign_event_type',
466
-                    'ee_manage_event_types',
467
-                    'ee_edit_event_type',
468
-                    'ee_delete_event_type',
469
-                ],
470
-                EE_Capabilities::ROLE_EVENTS_ADMINISTRATOR => [
471
-                    // core wp caps
472
-                    'read',
473
-                    'read_private_pages',
474
-                    'read_private_posts',
475
-                    'edit_users',
476
-                    'edit_posts',
477
-                    'edit_pages',
478
-                    'edit_published_posts',
479
-                    'edit_published_pages',
480
-                    'edit_private_pages',
481
-                    'edit_private_posts',
482
-                    'edit_others_posts',
483
-                    'edit_others_pages',
484
-                    'publish_posts',
485
-                    'publish_pages',
486
-                    'delete_posts',
487
-                    'delete_pages',
488
-                    'delete_private_pages',
489
-                    'delete_private_posts',
490
-                    'delete_published_pages',
491
-                    'delete_published_posts',
492
-                    'delete_others_posts',
493
-                    'delete_others_pages',
494
-                    'manage_categories',
495
-                    'manage_links',
496
-                    'moderate_comments',
497
-                    'unfiltered_html',
498
-                    'upload_files',
499
-                    'export',
500
-                    'import',
501
-                    'list_users',
502
-                    'level_1', // required if user with this role shows up in author dropdowns
503
-                    // basic ee access
504
-                    'ee_read_ee',
505
-                    // events
506
-                    'ee_publish_events',
507
-                    'ee_read_private_events',
508
-                    'ee_read_others_events',
509
-                    'ee_read_event',
510
-                    'ee_read_events',
511
-                    'ee_edit_event',
512
-                    'ee_edit_events',
513
-                    'ee_edit_published_events',
514
-                    'ee_edit_others_events',
515
-                    'ee_edit_private_events',
516
-                    'ee_delete_published_events',
517
-                    'ee_delete_private_events',
518
-                    'ee_delete_event',
519
-                    'ee_delete_events',
520
-                    'ee_delete_others_events',
521
-                    // event categories
522
-                    'ee_manage_event_categories',
523
-                    'ee_edit_event_category',
524
-                    'ee_delete_event_category',
525
-                    'ee_assign_event_category',
526
-                    // venues
527
-                    'ee_publish_venues',
528
-                    'ee_read_venue',
529
-                    'ee_read_venues',
530
-                    'ee_read_others_venues',
531
-                    'ee_read_private_venues',
532
-                    'ee_edit_venue',
533
-                    'ee_edit_venues',
534
-                    'ee_edit_others_venues',
535
-                    'ee_edit_published_venues',
536
-                    'ee_edit_private_venues',
537
-                    'ee_delete_venue',
538
-                    'ee_delete_venues',
539
-                    'ee_delete_others_venues',
540
-                    'ee_delete_private_venues',
541
-                    'ee_delete_published_venues',
542
-                    // venue categories
543
-                    'ee_manage_venue_categories',
544
-                    'ee_edit_venue_category',
545
-                    'ee_delete_venue_category',
546
-                    'ee_assign_venue_category',
547
-                    // contacts
548
-                    'ee_read_contacts',
549
-                    'ee_edit_contacts',
550
-                    'ee_delete_contacts',
551
-                    // registrations
552
-                    'ee_read_registrations',
553
-                    'ee_read_others_registrations',
554
-                    'ee_edit_registration',
555
-                    'ee_edit_registrations',
556
-                    'ee_edit_others_registrations',
557
-                    'ee_delete_registration',
558
-                    'ee_delete_registrations',
559
-                    'ee_delete_others_registrations',
560
-                    // checkins
561
-                    'ee_read_others_checkins',
562
-                    'ee_read_checkins',
563
-                    'ee_edit_checkins',
564
-                    'ee_edit_others_checkins',
565
-                    'ee_delete_checkins',
566
-                    'ee_delete_others_checkins',
567
-                    // transactions && payments
568
-                    'ee_read_transaction',
569
-                    'ee_read_transactions',
570
-                    'ee_edit_payments',
571
-                    'ee_delete_payments',
572
-                    // messages
573
-                    'ee_read_messages',
574
-                    'ee_read_others_messages',
575
-                    'ee_read_global_messages',
576
-                    'ee_edit_global_messages',
577
-                    'ee_edit_messages',
578
-                    'ee_edit_others_messages',
579
-                    'ee_delete_messages',
580
-                    'ee_delete_others_messages',
581
-                    'ee_delete_global_messages',
582
-                    'ee_send_message',
583
-                    // tickets
584
-                    'ee_read_default_tickets',
585
-                    'ee_read_others_default_tickets',
586
-                    'ee_edit_default_tickets',
587
-                    'ee_edit_others_default_tickets',
588
-                    'ee_delete_default_tickets',
589
-                    'ee_delete_others_default_tickets',
590
-                    // prices
591
-                    'ee_edit_default_price',
592
-                    'ee_edit_default_prices',
593
-                    'ee_delete_default_price',
594
-                    'ee_delete_default_prices',
595
-                    'ee_edit_default_price_type',
596
-                    'ee_edit_default_price_types',
597
-                    'ee_delete_default_price_type',
598
-                    'ee_delete_default_price_types',
599
-                    'ee_read_default_prices',
600
-                    'ee_read_default_price_types',
601
-                    // registration form
602
-                    'ee_edit_questions',
603
-                    'ee_edit_system_questions',
604
-                    'ee_read_questions',
605
-                    'ee_delete_questions',
606
-                    'ee_edit_question_groups',
607
-                    'ee_read_question_groups',
608
-                    'ee_edit_system_question_groups',
609
-                    'ee_delete_question_groups',
610
-                    // event_type taxonomy
611
-                    'ee_assign_event_type',
612
-                    'ee_manage_event_types',
613
-                    'ee_edit_event_type',
614
-                    'ee_delete_event_type',
615
-                ],
616
-            ]
617
-        );
618
-    }
619
-
620
-
621
-    /**
622
-     * @return bool
623
-     * @throws EE_Error
624
-     */
625
-    private function setupCapabilitiesMap(): bool
626
-    {
627
-        // if the initialization process hasn't even started, then we need to call init_caps()
628
-        if ($this->initialized === null) {
629
-            return $this->init_caps();
630
-        }
631
-        // unless resetting, get caps from db if we haven't already
632
-        $this->capabilities_map = $this->reset || ! empty($this->capabilities_map)
633
-            ? $this->capabilities_map
634
-            : get_option(self::option_name, []);
635
-        return true;
636
-    }
637
-
638
-
639
-    /**
640
-     * @param bool $update
641
-     * @return bool
642
-     */
643
-    private function updateCapabilitiesMap(bool $update = true): bool
644
-    {
645
-        return $update && update_option(self::option_name, $this->capabilities_map);
646
-    }
647
-
648
-
649
-    /**
650
-     * Adds capabilities to roles.
651
-     *
652
-     * @param array $capabilities_to_add array of capabilities to add, indexed by roles.
653
-     *                                   Note that this should ONLY be called on activation hook
654
-     *                                   otherwise the caps will be added on every request.
655
-     * @return bool
656
-     * @throws EE_Error
657
-     * @since 4.9.42
658
-     */
659
-    public function addCaps(array $capabilities_to_add): bool
660
-    {
661
-        // don't do anything if the capabilities map can not be initialized
662
-        if (! $this->setupCapabilitiesMap()) {
663
-            return false;
664
-        }
665
-        // and filter the array so others can get in on the fun during resets
666
-        $capabilities_to_add     = apply_filters(
667
-            'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
668
-            $capabilities_to_add,
669
-            $this->reset,
670
-            $this->capabilities_map
671
-        );
672
-        $update_capabilities_map = false;
673
-        // if not reset, see what caps are new for each role. if they're new, add them.
674
-        foreach ($capabilities_to_add as $role => $caps_for_role) {
675
-            if (is_array($caps_for_role)) {
676
-                foreach ($caps_for_role as $cap) {
677
-                    if (
678
-                        ! $this->capHasBeenAddedToRole($role, $cap)
679
-                        && $this->add_cap_to_role($role, $cap, true, false)
680
-                    ) {
681
-                        $update_capabilities_map = true;
682
-                    }
683
-                }
684
-            }
685
-        }
686
-        // now let's just save the cap that has been set but only if there's been a change.
687
-        $updated = $this->updateCapabilitiesMap($update_capabilities_map);
688
-        $this->flushWpUser($updated);
689
-        do_action('AHEE__EE_Capabilities__addCaps__complete', $this->capabilities_map, $updated);
690
-        return $updated;
691
-    }
692
-
693
-
694
-    /**
695
-     * Loops through the capabilities map and removes the role caps specified by the incoming array
696
-     *
697
-     * @param array $caps_map map of capabilities to be removed (indexed by roles)
698
-     * @return bool
699
-     * @throws EE_Error
700
-     */
701
-    public function removeCaps(array $caps_map): bool
702
-    {
703
-        // don't do anything if the capabilities map can not be initialized
704
-        if (! $this->setupCapabilitiesMap()) {
705
-            return false;
706
-        }
707
-        $update_capabilities_map = false;
708
-        foreach ($caps_map as $role => $caps_for_role) {
709
-            if (is_array($caps_for_role)) {
710
-                foreach ($caps_for_role as $cap) {
711
-                    if (
712
-                        $this->capHasBeenAddedToRole($role, $cap)
713
-                        && $this->remove_cap_from_role($role, $cap, false)
714
-                    ) {
715
-                        $update_capabilities_map = true;
716
-                    }
717
-                }
718
-            }
719
-        }
720
-        // maybe resave the caps
721
-        $updated = $this->updateCapabilitiesMap($update_capabilities_map);
722
-        $this->flushWpUser($updated);
723
-        return $updated;
724
-    }
725
-
726
-
727
-    /**
728
-     * This ensures that the WP User object cached on the $current_user global in WP has the latest capabilities from
729
-     * the roles on that user.
730
-     *
731
-     * @param bool $flush Default is to flush the WP_User object.  If false, then this method effectively does nothing.
732
-     */
733
-    private function flushWpUser(bool $flush = true)
734
-    {
735
-        if ($flush) {
736
-            $user = wp_get_current_user();
737
-            if ($user instanceof WP_User) {
738
-                $user->get_role_caps();
739
-            }
740
-        }
741
-    }
742
-
743
-
744
-    /**
745
-     * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
746
-     * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
747
-     * this is a wrapper for $wp_role->add_cap()
748
-     *
749
-     * @param string|WP_Role $role  A WordPress role the capability is being added to
750
-     * @param string         $cap   The capability being added to the role
751
-     * @param bool           $grant Whether to grant access to this cap on this role.
752
-     * @param bool           $update_capabilities_map
753
-     * @return bool
754
-     * @throws EE_Error
755
-     * @see   wp-includes/capabilities.php
756
-     * @since 4.5.0
757
-     */
758
-    public function add_cap_to_role(
759
-        $role,
760
-        string $cap,
761
-        bool $grant = true,
762
-        bool $update_capabilities_map = true
763
-    ): bool {
764
-        // capture incoming value for $role because we may need it to create a new WP_Role
765
-        $orig_role = $role;
766
-        $role      = $role instanceof WP_Role ? $role : get_role($role);
767
-        // if the role isn't available then we create it.
768
-        if (! $role instanceof WP_Role) {
769
-            // if a plugin wants to create a specific role name then they should create the role before
770
-            // EE_Capabilities does.  Otherwise this function will create the role name from the slug:
771
-            // - removes any `ee_` namespacing from the start of the slug.
772
-            // - replaces `_` with ` ` (empty space).
773
-            // - sentence case on the resulting string.
774
-            $role_label = ucwords(str_replace(['ee_', '_'], ['', ' '], $orig_role));
775
-            $role       = add_role($orig_role, $role_label);
776
-        }
777
-        if ($role instanceof WP_Role) {
778
-            // don't do anything if the capabilities map can not be initialized
779
-            if (! $this->setupCapabilitiesMap()) {
780
-                return false;
781
-            }
782
-            if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
783
-                $role->add_cap($cap, $grant);
784
-                $this->capabilities_map[ $role->name ][] = $cap;
785
-                $this->updateCapabilitiesMap($update_capabilities_map);
786
-                return true;
787
-            }
788
-        }
789
-        return false;
790
-    }
791
-
792
-
793
-    /**
794
-     * Functions similarly to add_cap_to_role except removes cap from given role.
795
-     * Wrapper for $wp_role->remove_cap()
796
-     *
797
-     * @param string|WP_Role $role A WordPress role the capability is being removed from.
798
-     * @param string         $cap  The capability being removed
799
-     * @param bool           $update_capabilities_map
800
-     * @return bool
801
-     * @throws EE_Error
802
-     * @since 4.5.0
803
-     * @see   wp-includes/capabilities.php
804
-     */
805
-    public function remove_cap_from_role($role, string $cap, bool $update_capabilities_map = true): bool
806
-    {
807
-        // don't do anything if the capabilities map can not be initialized
808
-        if (! $this->setupCapabilitiesMap()) {
809
-            return false;
810
-        }
811
-
812
-        $role = $role instanceof WP_Role ? $role : get_role($role);
813
-        if ($role instanceof WP_Role && $index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
814
-            $role->remove_cap($cap);
815
-            unset($this->capabilities_map[ $role->name ][ $index ]);
816
-            $this->updateCapabilitiesMap($update_capabilities_map);
817
-            return true;
818
-        }
819
-        return false;
820
-    }
821
-
822
-
823
-    /**
824
-     * @param string $role_name
825
-     * @param string $cap
826
-     * @param bool   $get_index
827
-     * @return bool|int|string
828
-     */
829
-    private function capHasBeenAddedToRole(string $role_name = '', string $cap = '', bool $get_index = false)
830
-    {
831
-        if (
832
-            isset($this->capabilities_map[ $role_name ])
833
-            && ($index = array_search($cap, $this->capabilities_map[ $role_name ], true)) !== false
834
-        ) {
835
-            return $get_index ? $index : true;
836
-        }
837
-        return false;
838
-    }
839
-
840
-
841
-    /**
842
-     * Wrapper for the native WP current_user_can() method.
843
-     * This is provided as a handy method for a couple things:
844
-     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
845
-     * write those filters wherever current_user_can is called).
846
-     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
847
-     *
848
-     * @param string $cap     The cap being checked.
849
-     * @param string $context The context where the current_user_can is being called from.
850
-     * @param int|string $id  [optional] ID for entity where current_user_can() is being called from
851
-     *                        (used in map_meta_cap() filters).
852
-     * @return bool  Whether user can or not.
853
-     * @since 4.5.0
854
-     */
855
-    public function current_user_can(string $cap, string $context, $id = 0): bool
856
-    {
857
-        // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
858
-        $filtered_cap = apply_filters(
859
-            'FHEE__EE_Capabilities__current_user_can__cap',
860
-            apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id),
861
-            $context,
862
-            $cap,
863
-            $id
864
-        );
865
-        return ! empty($id) ? current_user_can($filtered_cap, $id) : current_user_can($filtered_cap);
866
-    }
867
-
868
-
869
-    /**
870
-     * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
871
-     *
872
-     * @param int|WP_User $user    Either the user_id or a WP_User object
873
-     * @param string      $cap     The capability string being checked
874
-     * @param string      $context The context where the user_can is being called from (used in filters).
875
-     * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
876
-     *                             filters)
877
-     *
878
-     * @return bool Whether user can or not.
879
-     */
880
-    public function user_can($user, string $cap, string $context, int $id = 0): bool
881
-    {
882
-        // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
883
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
884
-        $filtered_cap = apply_filters(
885
-            'FHEE__EE_Capabilities__user_can__cap',
886
-            $filtered_cap,
887
-            $context,
888
-            $cap,
889
-            $user,
890
-            $id
891
-        );
892
-        return ! empty($id)
893
-            ? user_can($user, $filtered_cap, $id)
894
-            : user_can($user, $filtered_cap);
895
-    }
896
-
897
-
898
-    /**
899
-     * Wrapper for the native WP current_user_can_for_blog() method.
900
-     * This is provided as a handy method for a couple things:
901
-     * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
902
-     * write those filters wherever current_user_can is called).
903
-     * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
904
-     *
905
-     * @param int    $blog_id The blog id that is being checked for.
906
-     * @param string $cap     The cap being checked.
907
-     * @param string $context The context where the current_user_can is being called from.
908
-     * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
909
-     *                        filters.
910
-     *
911
-     * @return bool  Whether user can or not.
912
-     * @since 4.5.0
913
-     *
914
-     */
915
-    public function current_user_can_for_blog(int $blog_id, string $cap, string $context, int $id = 0): bool
916
-    {
917
-        $user_can = ! empty($id)
918
-            ? current_user_can_for_blog($blog_id, $cap, $id)
919
-            : current_user_can($blog_id, $cap);
920
-        // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
921
-        $user_can = apply_filters(
922
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
923
-            $user_can,
924
-            $blog_id,
925
-            $cap,
926
-            $id
927
-        );
928
-        return apply_filters(
929
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
930
-            $user_can,
931
-            $context,
932
-            $blog_id,
933
-            $cap,
934
-            $id
935
-        );
936
-    }
937
-
938
-
939
-    /**
940
-     * This helper method just returns an array of registered EE capabilities.
941
-     *
942
-     * @param string|null $role If empty then the entire role/capability map is returned.
943
-     *                          Otherwise just the capabilities for the given role are returned.
944
-     * @return array
945
-     * @throws EE_Error
946
-     * @since 4.5.0
947
-     */
948
-    public function get_ee_capabilities(?string $role = EE_Capabilities::ROLE_ADMINISTRATOR): array
949
-    {
950
-        if (! $this->initialized) {
951
-            $this->init_caps();
952
-        }
953
-        if ($role === '') {
954
-            return $this->capabilities_map;
955
-        }
956
-        return $this->capabilities_map[ $role ] ?? [];
957
-    }
958
-
959
-
960
-    /**
961
-     * @param bool  $reset      If you need to reset Event Espresso's capabilities,
962
-     *                          then please use the init_caps() method with the "$reset" parameter set to "true"
963
-     * @param array $caps_map   Optional.
964
-     *                          Can be used to send a custom map of roles and capabilities for setting them up.
965
-     *                          Note that this should ONLY be called on activation hook or some other one-time
966
-     *                          task otherwise the caps will be added on every request.
967
-     * @return void
968
-     * @throws EE_Error
969
-     * @deprecated 4.9.42
970
-     */
971
-    public function init_role_caps(bool $reset = false, array $caps_map = [])
972
-    {
973
-        // If this method is called directly and reset is set as 'true',
974
-        // then display a doing it wrong notice, because we want resets to go through init_caps()
975
-        // to guarantee that everything is set up correctly.
976
-        // This prevents the capabilities map getting reset incorrectly by direct calls to this method.
977
-        if ($reset) {
978
-            EE_Error::doing_it_wrong(
979
-                __METHOD__,
980
-                sprintf(
981
-                    esc_html__(
982
-                        'The "%1$s" parameter for the "%2$s" method is deprecated. If you need to reset Event Espresso\'s capabilities, then please use the "%3$s" method with the "%1$s" parameter set to "%4$s".',
983
-                        'event_espresso'
984
-                    ),
985
-                    '$reset',
986
-                    __METHOD__ . '()',
987
-                    'EE_Capabilities::init_caps()',
988
-                    'true'
989
-                ),
990
-                '4.9.42',
991
-                '5.0.0'
992
-            );
993
-        }
994
-        $this->addCaps($caps_map);
995
-    }
16
+	const ROLE_ADMINISTRATOR        = 'administrator';
17
+
18
+	const ROLE_EVENTS_ADMINISTRATOR = 'ee_events_administrator';
19
+
20
+
21
+	/**
22
+	 * the name of the wp option used to store caps previously initialized
23
+	 */
24
+	const option_name = 'ee_caps_initialized';
25
+
26
+	/**
27
+	 * instance of EE_Capabilities object
28
+	 *
29
+	 * @var EE_Capabilities
30
+	 */
31
+	private static $_instance;
32
+
33
+
34
+	/**
35
+	 * This is a map of caps that correspond to a default WP_Role.
36
+	 * Array is indexed by Role and values are ee capabilities.
37
+	 *
38
+	 * @since 4.5.0
39
+	 *
40
+	 * @var array
41
+	 */
42
+	private $capabilities_map = [];
43
+
44
+	/**
45
+	 * This used to hold an array of EE_Meta_Capability_Map objects
46
+	 * that define the granular capabilities mapped to for a user depending on context.
47
+	 *
48
+	 * @var EE_Meta_Capability_Map[]
49
+	 */
50
+	private $_meta_caps = [];
51
+
52
+	/**
53
+	 * The internal $capabilities_map needs to be initialized before it can be used.
54
+	 * This flag tracks whether that has happened or not.
55
+	 * But for this to work, we need three states to indicate:
56
+	 *      initialization has not occurred at all
57
+	 *      initialization has started but is not complete
58
+	 *      initialization is complete
59
+	 * The reason this is needed is because the addCaps() method
60
+	 * normally requires the $capabilities_map to be initialized,
61
+	 * but is also used during the initialization process.
62
+	 * So:
63
+	 *      If initialized === null, init_caps() will be called before any other methods will run.
64
+	 *      If initialized === false, then init_caps() is in the process of running it's logic.
65
+	 *      If initialized === true, then init_caps() has completed the initialization process.
66
+	 *
67
+	 * @var boolean|null $initialized
68
+	 */
69
+	private $initialized;
70
+
71
+	/**
72
+	 * @var boolean $reset
73
+	 */
74
+	private $reset = false;
75
+
76
+
77
+	/**
78
+	 * singleton method used to instantiate class object
79
+	 *
80
+	 * @return EE_Capabilities
81
+	 * @since 4.5.0
82
+	 *
83
+	 */
84
+	public static function instance(): EE_Capabilities
85
+	{
86
+		// check if instantiated, and if not do so.
87
+		if (! self::$_instance instanceof EE_Capabilities) {
88
+			self::$_instance = new self();
89
+		}
90
+		return self::$_instance;
91
+	}
92
+
93
+
94
+	/**
95
+	 * private constructor
96
+	 *
97
+	 * @since 4.5.0
98
+	 */
99
+	private function __construct()
100
+	{
101
+	}
102
+
103
+
104
+	/**
105
+	 * This delays the initialization of the capabilities class until EE_System core is loaded and ready.
106
+	 *
107
+	 * @param bool $reset allows for resetting the default capabilities saved on roles.  Note that this doesn't
108
+	 *                    actually REMOVE any capabilities from existing roles, it just resaves defaults roles and
109
+	 *                    ensures that they are up to date.
110
+	 *
111
+	 * @since 4.5.0
112
+	 * @return bool
113
+	 * @throws EE_Error
114
+	 */
115
+	public function init_caps(?bool $reset = false): bool
116
+	{
117
+		if (! EE_Maintenance_Mode::instance()->models_can_query()) {
118
+			return false;
119
+		}
120
+		$this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
121
+		// if reset, then completely delete the cache option and clear the $capabilities_map property.
122
+		if ($this->reset) {
123
+			$this->initialized      = null;
124
+			$this->capabilities_map = [];
125
+			delete_option(self::option_name);
126
+		}
127
+		if ($this->initialized === null) {
128
+			$this->initialized = false;
129
+			do_action(
130
+				'AHEE__EE_Capabilities__init_caps__before_initialization',
131
+				$this->reset
132
+			);
133
+			$this->addCaps($this->_init_caps_map());
134
+			$this->_set_meta_caps();
135
+			do_action(
136
+				'AHEE__EE_Capabilities__init_caps__after_initialization',
137
+				$this->capabilities_map
138
+			);
139
+			$this->initialized = true;
140
+		}
141
+		// reset $this->reset so that it's not stuck on true if init_caps() gets called again
142
+		$this->reset = false;
143
+		return true;
144
+	}
145
+
146
+
147
+	/**
148
+	 * This sets the meta caps property.
149
+	 *
150
+	 * @return void
151
+	 * @throws EE_Error
152
+	 * @since 4.5.0
153
+	 */
154
+	private function _set_meta_caps()
155
+	{
156
+		// get default meta caps and filter the returned array
157
+		$this->_meta_caps = apply_filters(
158
+			'FHEE__EE_Capabilities___set_meta_caps__meta_caps',
159
+			$this->_get_default_meta_caps_array()
160
+		);
161
+		// add filter for map_meta_caps but only if models can query.
162
+		if (! has_filter('map_meta_cap', [$this, 'map_meta_caps'])) {
163
+			add_filter('map_meta_cap', [$this, 'map_meta_caps'], 10, 4);
164
+		}
165
+	}
166
+
167
+
168
+	/**
169
+	 * This builds and returns the default meta_caps array only once.
170
+	 *
171
+	 * @return array
172
+	 * @throws EE_Error
173
+	 * @since  4.8.28.rc.012
174
+	 */
175
+	private function _get_default_meta_caps_array(): array
176
+	{
177
+		static $default_meta_caps = [];
178
+		// make sure we're only ever initializing the default _meta_caps array once if it's empty.
179
+		if (empty($default_meta_caps)) {
180
+			$default_meta_caps = [
181
+				// edits
182
+				new EE_Meta_Capability_Map_Edit(
183
+					'ee_edit_event',
184
+					['Event', 'ee_edit_published_events', 'ee_edit_others_events', 'ee_edit_private_events']
185
+				),
186
+				new EE_Meta_Capability_Map_Edit(
187
+					'ee_edit_venue',
188
+					['Venue', 'ee_edit_published_venues', 'ee_edit_others_venues', 'ee_edit_private_venues']
189
+				),
190
+				new EE_Meta_Capability_Map_Edit(
191
+					'ee_edit_registration',
192
+					['Registration', '', 'ee_edit_others_registrations', '']
193
+				),
194
+				new EE_Meta_Capability_Map_Edit(
195
+					'ee_edit_checkin',
196
+					['Registration', '', 'ee_edit_others_checkins', '']
197
+				),
198
+				new EE_Meta_Capability_Map_Messages_Cap(
199
+					'ee_edit_message',
200
+					['Message_Template_Group', '', 'ee_edit_others_messages', 'ee_edit_global_messages']
201
+				),
202
+				new EE_Meta_Capability_Map_Edit(
203
+					'ee_edit_default_ticket',
204
+					['Ticket', '', 'ee_edit_others_default_tickets', '']
205
+				),
206
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
207
+					'ee_edit_question',
208
+					['Question', '', '', 'ee_edit_system_questions']
209
+				),
210
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
211
+					'ee_edit_question_group',
212
+					['Question_Group', '', '', 'ee_edit_system_question_groups']
213
+				),
214
+				new EE_Meta_Capability_Map_Edit(
215
+					'ee_edit_payment_method',
216
+					['Payment_Method', '', 'ee_edit_others_payment_methods', '']
217
+				),
218
+				// reads
219
+				new EE_Meta_Capability_Map_Read(
220
+					'ee_read_event',
221
+					['Event', '', 'ee_read_others_events', 'ee_read_private_events']
222
+				),
223
+				new EE_Meta_Capability_Map_Read(
224
+					'ee_read_venue',
225
+					['Venue', '', 'ee_read_others_venues', 'ee_read_private_venues']
226
+				),
227
+				new EE_Meta_Capability_Map_Read(
228
+					'ee_read_registration',
229
+					['Registration', '', 'ee_read_others_registrations', '']
230
+				),
231
+				new EE_Meta_Capability_Map_Read(
232
+					'ee_read_checkin',
233
+					['Registration', '', 'ee_read_others_checkins', '']
234
+				),
235
+				new EE_Meta_Capability_Map_Messages_Cap(
236
+					'ee_read_message',
237
+					['Message_Template_Group', '', 'ee_read_others_messages', 'ee_read_global_messages']
238
+				),
239
+				new EE_Meta_Capability_Map_Read(
240
+					'ee_read_default_ticket',
241
+					['Ticket', '', 'ee_read_others_default_tickets', '']
242
+				),
243
+				new EE_Meta_Capability_Map_Read(
244
+					'ee_read_payment_method',
245
+					['Payment_Method', '', 'ee_read_others_payment_methods', '']
246
+				),
247
+				// deletes
248
+				new EE_Meta_Capability_Map_Delete(
249
+					'ee_delete_event',
250
+					[
251
+						'Event',
252
+						'ee_delete_published_events',
253
+						'ee_delete_others_events',
254
+						'ee_delete_private_events',
255
+					]
256
+				),
257
+				new EE_Meta_Capability_Map_Delete(
258
+					'ee_delete_venue',
259
+					[
260
+						'Venue',
261
+						'ee_delete_published_venues',
262
+						'ee_delete_others_venues',
263
+						'ee_delete_private_venues',
264
+					]
265
+				),
266
+				new EE_Meta_Capability_Map_Delete(
267
+					'ee_delete_registration',
268
+					['Registration', '', 'ee_delete_others_registrations', '']
269
+				),
270
+				new EE_Meta_Capability_Map_Delete(
271
+					'ee_delete_checkin',
272
+					['Registration', '', 'ee_delete_others_checkins', '']
273
+				),
274
+				new EE_Meta_Capability_Map_Messages_Cap(
275
+					'ee_delete_message',
276
+					['Message_Template_Group', '', 'ee_delete_others_messages', 'ee_delete_global_messages']
277
+				),
278
+				new EE_Meta_Capability_Map_Delete(
279
+					'ee_delete_default_ticket',
280
+					['Ticket', '', 'ee_delete_others_default_tickets', '']
281
+				),
282
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
283
+					'ee_delete_question',
284
+					['Question', '', '', 'delete_system_questions']
285
+				),
286
+				new EE_Meta_Capability_Map_Registration_Form_Cap(
287
+					'ee_delete_question_group',
288
+					['Question_Group', '', '', 'delete_system_question_groups']
289
+				),
290
+				new EE_Meta_Capability_Map_Delete(
291
+					'ee_delete_payment_method',
292
+					['Payment_Method', '', 'ee_delete_others_payment_methods', '']
293
+				),
294
+			];
295
+		}
296
+		return $default_meta_caps;
297
+	}
298
+
299
+
300
+	/**
301
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
302
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
303
+	 *
304
+	 * The actual logic is carried out by implementer classes in their definition of _map_meta_caps.
305
+	 *
306
+	 * @param array  $caps    actual users capabilities
307
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
308
+	 * @param int    $user_id The user id
309
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
310
+	 * @return array actual users capabilities
311
+	 * @throws EE_Error
312
+	 * @throws ReflectionException
313
+	 * @since 4.5.0
314
+	 * @see   wp-includes/capabilities.php
315
+	 *
316
+	 */
317
+	public function map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
318
+	{
319
+		if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
320
+			// loop through our _meta_caps array
321
+			foreach ($this->_meta_caps as $meta_map) {
322
+				if (! $meta_map instanceof EE_Meta_Capability_Map) {
323
+					continue;
324
+				}
325
+				// don't load models if there is no object ID in the args
326
+				if (! empty($args[0])) {
327
+					$meta_map->ensure_is_model();
328
+				}
329
+				$caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
330
+			}
331
+		}
332
+		return $caps;
333
+	}
334
+
335
+
336
+	/**
337
+	 * This sets up and returns the initial capabilities map for Event Espresso
338
+	 * Note this array is filtered.
339
+	 * It is assumed that all available EE capabilities are assigned to the administrator role.
340
+	 *
341
+	 * @return array
342
+	 * @since 4.5.0
343
+	 *
344
+	 */
345
+	private function _init_caps_map(): array
346
+	{
347
+		return apply_filters(
348
+			'FHEE__EE_Capabilities__init_caps_map__caps',
349
+			[
350
+				EE_Capabilities::ROLE_ADMINISTRATOR        => [
351
+					// basic access
352
+					'ee_read_ee',
353
+					// gateways
354
+					/**
355
+					 * note that with payment method capabilities, although we've implemented
356
+					 * capability mapping which will be used for accessing payment methods owned by
357
+					 * other users.  This is not fully implemented yet in the payment method ui.
358
+					 * Currently only the "plural" caps are in active use.
359
+					 * (Specific payment method caps are in use as well).
360
+					 **/
361
+					'ee_manage_gateways',
362
+					'ee_read_payment_methods',
363
+					'ee_read_others_payment_methods',
364
+					'ee_edit_payment_methods',
365
+					'ee_edit_others_payment_methods',
366
+					'ee_delete_payment_methods',
367
+					// events
368
+					'ee_publish_events',
369
+					'ee_read_private_events',
370
+					'ee_read_others_events',
371
+					'ee_read_events',
372
+					'ee_edit_events',
373
+					'ee_edit_published_events',
374
+					'ee_edit_others_events',
375
+					'ee_edit_private_events',
376
+					'ee_delete_published_events',
377
+					'ee_delete_private_events',
378
+					'ee_delete_events',
379
+					'ee_delete_others_events',
380
+					// event categories
381
+					'ee_manage_event_categories',
382
+					'ee_edit_event_category',
383
+					'ee_delete_event_category',
384
+					'ee_assign_event_category',
385
+					// venues
386
+					'ee_publish_venues',
387
+					'ee_read_venues',
388
+					'ee_read_others_venues',
389
+					'ee_read_private_venues',
390
+					'ee_edit_venues',
391
+					'ee_edit_others_venues',
392
+					'ee_edit_published_venues',
393
+					'ee_edit_private_venues',
394
+					'ee_delete_venues',
395
+					'ee_delete_others_venues',
396
+					'ee_delete_private_venues',
397
+					'ee_delete_published_venues',
398
+					// venue categories
399
+					'ee_manage_venue_categories',
400
+					'ee_edit_venue_category',
401
+					'ee_delete_venue_category',
402
+					'ee_assign_venue_category',
403
+					// contacts
404
+					'ee_read_contacts',
405
+					'ee_edit_contacts',
406
+					'ee_delete_contacts',
407
+					// registrations
408
+					'ee_read_registrations',
409
+					'ee_read_others_registrations',
410
+					'ee_edit_registrations',
411
+					'ee_edit_others_registrations',
412
+					'ee_delete_registrations',
413
+					'ee_delete_others_registrations',
414
+					// checkins
415
+					'ee_read_others_checkins',
416
+					'ee_read_checkins',
417
+					'ee_edit_checkins',
418
+					'ee_edit_others_checkins',
419
+					'ee_delete_checkins',
420
+					'ee_delete_others_checkins',
421
+					// transactions && payments
422
+					'ee_read_transaction',
423
+					'ee_read_transactions',
424
+					'ee_edit_payments',
425
+					'ee_delete_payments',
426
+					// messages
427
+					'ee_read_messages',
428
+					'ee_read_others_messages',
429
+					'ee_read_global_messages',
430
+					'ee_edit_global_messages',
431
+					'ee_edit_messages',
432
+					'ee_edit_others_messages',
433
+					'ee_delete_messages',
434
+					'ee_delete_others_messages',
435
+					'ee_delete_global_messages',
436
+					'ee_send_message',
437
+					// tickets
438
+					'ee_read_default_tickets',
439
+					'ee_read_others_default_tickets',
440
+					'ee_edit_default_tickets',
441
+					'ee_edit_others_default_tickets',
442
+					'ee_delete_default_tickets',
443
+					'ee_delete_others_default_tickets',
444
+					// prices
445
+					'ee_edit_default_price',
446
+					'ee_edit_default_prices',
447
+					'ee_delete_default_price',
448
+					'ee_delete_default_prices',
449
+					'ee_edit_default_price_type',
450
+					'ee_edit_default_price_types',
451
+					'ee_delete_default_price_type',
452
+					'ee_delete_default_price_types',
453
+					'ee_read_default_prices',
454
+					'ee_read_default_price_types',
455
+					// registration form
456
+					'ee_edit_questions',
457
+					'ee_edit_system_questions',
458
+					'ee_read_questions',
459
+					'ee_delete_questions',
460
+					'ee_edit_question_groups',
461
+					'ee_read_question_groups',
462
+					'ee_edit_system_question_groups',
463
+					'ee_delete_question_groups',
464
+					// event_type taxonomy
465
+					'ee_assign_event_type',
466
+					'ee_manage_event_types',
467
+					'ee_edit_event_type',
468
+					'ee_delete_event_type',
469
+				],
470
+				EE_Capabilities::ROLE_EVENTS_ADMINISTRATOR => [
471
+					// core wp caps
472
+					'read',
473
+					'read_private_pages',
474
+					'read_private_posts',
475
+					'edit_users',
476
+					'edit_posts',
477
+					'edit_pages',
478
+					'edit_published_posts',
479
+					'edit_published_pages',
480
+					'edit_private_pages',
481
+					'edit_private_posts',
482
+					'edit_others_posts',
483
+					'edit_others_pages',
484
+					'publish_posts',
485
+					'publish_pages',
486
+					'delete_posts',
487
+					'delete_pages',
488
+					'delete_private_pages',
489
+					'delete_private_posts',
490
+					'delete_published_pages',
491
+					'delete_published_posts',
492
+					'delete_others_posts',
493
+					'delete_others_pages',
494
+					'manage_categories',
495
+					'manage_links',
496
+					'moderate_comments',
497
+					'unfiltered_html',
498
+					'upload_files',
499
+					'export',
500
+					'import',
501
+					'list_users',
502
+					'level_1', // required if user with this role shows up in author dropdowns
503
+					// basic ee access
504
+					'ee_read_ee',
505
+					// events
506
+					'ee_publish_events',
507
+					'ee_read_private_events',
508
+					'ee_read_others_events',
509
+					'ee_read_event',
510
+					'ee_read_events',
511
+					'ee_edit_event',
512
+					'ee_edit_events',
513
+					'ee_edit_published_events',
514
+					'ee_edit_others_events',
515
+					'ee_edit_private_events',
516
+					'ee_delete_published_events',
517
+					'ee_delete_private_events',
518
+					'ee_delete_event',
519
+					'ee_delete_events',
520
+					'ee_delete_others_events',
521
+					// event categories
522
+					'ee_manage_event_categories',
523
+					'ee_edit_event_category',
524
+					'ee_delete_event_category',
525
+					'ee_assign_event_category',
526
+					// venues
527
+					'ee_publish_venues',
528
+					'ee_read_venue',
529
+					'ee_read_venues',
530
+					'ee_read_others_venues',
531
+					'ee_read_private_venues',
532
+					'ee_edit_venue',
533
+					'ee_edit_venues',
534
+					'ee_edit_others_venues',
535
+					'ee_edit_published_venues',
536
+					'ee_edit_private_venues',
537
+					'ee_delete_venue',
538
+					'ee_delete_venues',
539
+					'ee_delete_others_venues',
540
+					'ee_delete_private_venues',
541
+					'ee_delete_published_venues',
542
+					// venue categories
543
+					'ee_manage_venue_categories',
544
+					'ee_edit_venue_category',
545
+					'ee_delete_venue_category',
546
+					'ee_assign_venue_category',
547
+					// contacts
548
+					'ee_read_contacts',
549
+					'ee_edit_contacts',
550
+					'ee_delete_contacts',
551
+					// registrations
552
+					'ee_read_registrations',
553
+					'ee_read_others_registrations',
554
+					'ee_edit_registration',
555
+					'ee_edit_registrations',
556
+					'ee_edit_others_registrations',
557
+					'ee_delete_registration',
558
+					'ee_delete_registrations',
559
+					'ee_delete_others_registrations',
560
+					// checkins
561
+					'ee_read_others_checkins',
562
+					'ee_read_checkins',
563
+					'ee_edit_checkins',
564
+					'ee_edit_others_checkins',
565
+					'ee_delete_checkins',
566
+					'ee_delete_others_checkins',
567
+					// transactions && payments
568
+					'ee_read_transaction',
569
+					'ee_read_transactions',
570
+					'ee_edit_payments',
571
+					'ee_delete_payments',
572
+					// messages
573
+					'ee_read_messages',
574
+					'ee_read_others_messages',
575
+					'ee_read_global_messages',
576
+					'ee_edit_global_messages',
577
+					'ee_edit_messages',
578
+					'ee_edit_others_messages',
579
+					'ee_delete_messages',
580
+					'ee_delete_others_messages',
581
+					'ee_delete_global_messages',
582
+					'ee_send_message',
583
+					// tickets
584
+					'ee_read_default_tickets',
585
+					'ee_read_others_default_tickets',
586
+					'ee_edit_default_tickets',
587
+					'ee_edit_others_default_tickets',
588
+					'ee_delete_default_tickets',
589
+					'ee_delete_others_default_tickets',
590
+					// prices
591
+					'ee_edit_default_price',
592
+					'ee_edit_default_prices',
593
+					'ee_delete_default_price',
594
+					'ee_delete_default_prices',
595
+					'ee_edit_default_price_type',
596
+					'ee_edit_default_price_types',
597
+					'ee_delete_default_price_type',
598
+					'ee_delete_default_price_types',
599
+					'ee_read_default_prices',
600
+					'ee_read_default_price_types',
601
+					// registration form
602
+					'ee_edit_questions',
603
+					'ee_edit_system_questions',
604
+					'ee_read_questions',
605
+					'ee_delete_questions',
606
+					'ee_edit_question_groups',
607
+					'ee_read_question_groups',
608
+					'ee_edit_system_question_groups',
609
+					'ee_delete_question_groups',
610
+					// event_type taxonomy
611
+					'ee_assign_event_type',
612
+					'ee_manage_event_types',
613
+					'ee_edit_event_type',
614
+					'ee_delete_event_type',
615
+				],
616
+			]
617
+		);
618
+	}
619
+
620
+
621
+	/**
622
+	 * @return bool
623
+	 * @throws EE_Error
624
+	 */
625
+	private function setupCapabilitiesMap(): bool
626
+	{
627
+		// if the initialization process hasn't even started, then we need to call init_caps()
628
+		if ($this->initialized === null) {
629
+			return $this->init_caps();
630
+		}
631
+		// unless resetting, get caps from db if we haven't already
632
+		$this->capabilities_map = $this->reset || ! empty($this->capabilities_map)
633
+			? $this->capabilities_map
634
+			: get_option(self::option_name, []);
635
+		return true;
636
+	}
637
+
638
+
639
+	/**
640
+	 * @param bool $update
641
+	 * @return bool
642
+	 */
643
+	private function updateCapabilitiesMap(bool $update = true): bool
644
+	{
645
+		return $update && update_option(self::option_name, $this->capabilities_map);
646
+	}
647
+
648
+
649
+	/**
650
+	 * Adds capabilities to roles.
651
+	 *
652
+	 * @param array $capabilities_to_add array of capabilities to add, indexed by roles.
653
+	 *                                   Note that this should ONLY be called on activation hook
654
+	 *                                   otherwise the caps will be added on every request.
655
+	 * @return bool
656
+	 * @throws EE_Error
657
+	 * @since 4.9.42
658
+	 */
659
+	public function addCaps(array $capabilities_to_add): bool
660
+	{
661
+		// don't do anything if the capabilities map can not be initialized
662
+		if (! $this->setupCapabilitiesMap()) {
663
+			return false;
664
+		}
665
+		// and filter the array so others can get in on the fun during resets
666
+		$capabilities_to_add     = apply_filters(
667
+			'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
668
+			$capabilities_to_add,
669
+			$this->reset,
670
+			$this->capabilities_map
671
+		);
672
+		$update_capabilities_map = false;
673
+		// if not reset, see what caps are new for each role. if they're new, add them.
674
+		foreach ($capabilities_to_add as $role => $caps_for_role) {
675
+			if (is_array($caps_for_role)) {
676
+				foreach ($caps_for_role as $cap) {
677
+					if (
678
+						! $this->capHasBeenAddedToRole($role, $cap)
679
+						&& $this->add_cap_to_role($role, $cap, true, false)
680
+					) {
681
+						$update_capabilities_map = true;
682
+					}
683
+				}
684
+			}
685
+		}
686
+		// now let's just save the cap that has been set but only if there's been a change.
687
+		$updated = $this->updateCapabilitiesMap($update_capabilities_map);
688
+		$this->flushWpUser($updated);
689
+		do_action('AHEE__EE_Capabilities__addCaps__complete', $this->capabilities_map, $updated);
690
+		return $updated;
691
+	}
692
+
693
+
694
+	/**
695
+	 * Loops through the capabilities map and removes the role caps specified by the incoming array
696
+	 *
697
+	 * @param array $caps_map map of capabilities to be removed (indexed by roles)
698
+	 * @return bool
699
+	 * @throws EE_Error
700
+	 */
701
+	public function removeCaps(array $caps_map): bool
702
+	{
703
+		// don't do anything if the capabilities map can not be initialized
704
+		if (! $this->setupCapabilitiesMap()) {
705
+			return false;
706
+		}
707
+		$update_capabilities_map = false;
708
+		foreach ($caps_map as $role => $caps_for_role) {
709
+			if (is_array($caps_for_role)) {
710
+				foreach ($caps_for_role as $cap) {
711
+					if (
712
+						$this->capHasBeenAddedToRole($role, $cap)
713
+						&& $this->remove_cap_from_role($role, $cap, false)
714
+					) {
715
+						$update_capabilities_map = true;
716
+					}
717
+				}
718
+			}
719
+		}
720
+		// maybe resave the caps
721
+		$updated = $this->updateCapabilitiesMap($update_capabilities_map);
722
+		$this->flushWpUser($updated);
723
+		return $updated;
724
+	}
725
+
726
+
727
+	/**
728
+	 * This ensures that the WP User object cached on the $current_user global in WP has the latest capabilities from
729
+	 * the roles on that user.
730
+	 *
731
+	 * @param bool $flush Default is to flush the WP_User object.  If false, then this method effectively does nothing.
732
+	 */
733
+	private function flushWpUser(bool $flush = true)
734
+	{
735
+		if ($flush) {
736
+			$user = wp_get_current_user();
737
+			if ($user instanceof WP_User) {
738
+				$user->get_role_caps();
739
+			}
740
+		}
741
+	}
742
+
743
+
744
+	/**
745
+	 * This method sets a capability on a role.  Note this should only be done on activation, or if you have something
746
+	 * specific to prevent the cap from being added on every page load (adding caps are persistent to the db). Note.
747
+	 * this is a wrapper for $wp_role->add_cap()
748
+	 *
749
+	 * @param string|WP_Role $role  A WordPress role the capability is being added to
750
+	 * @param string         $cap   The capability being added to the role
751
+	 * @param bool           $grant Whether to grant access to this cap on this role.
752
+	 * @param bool           $update_capabilities_map
753
+	 * @return bool
754
+	 * @throws EE_Error
755
+	 * @see   wp-includes/capabilities.php
756
+	 * @since 4.5.0
757
+	 */
758
+	public function add_cap_to_role(
759
+		$role,
760
+		string $cap,
761
+		bool $grant = true,
762
+		bool $update_capabilities_map = true
763
+	): bool {
764
+		// capture incoming value for $role because we may need it to create a new WP_Role
765
+		$orig_role = $role;
766
+		$role      = $role instanceof WP_Role ? $role : get_role($role);
767
+		// if the role isn't available then we create it.
768
+		if (! $role instanceof WP_Role) {
769
+			// if a plugin wants to create a specific role name then they should create the role before
770
+			// EE_Capabilities does.  Otherwise this function will create the role name from the slug:
771
+			// - removes any `ee_` namespacing from the start of the slug.
772
+			// - replaces `_` with ` ` (empty space).
773
+			// - sentence case on the resulting string.
774
+			$role_label = ucwords(str_replace(['ee_', '_'], ['', ' '], $orig_role));
775
+			$role       = add_role($orig_role, $role_label);
776
+		}
777
+		if ($role instanceof WP_Role) {
778
+			// don't do anything if the capabilities map can not be initialized
779
+			if (! $this->setupCapabilitiesMap()) {
780
+				return false;
781
+			}
782
+			if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
783
+				$role->add_cap($cap, $grant);
784
+				$this->capabilities_map[ $role->name ][] = $cap;
785
+				$this->updateCapabilitiesMap($update_capabilities_map);
786
+				return true;
787
+			}
788
+		}
789
+		return false;
790
+	}
791
+
792
+
793
+	/**
794
+	 * Functions similarly to add_cap_to_role except removes cap from given role.
795
+	 * Wrapper for $wp_role->remove_cap()
796
+	 *
797
+	 * @param string|WP_Role $role A WordPress role the capability is being removed from.
798
+	 * @param string         $cap  The capability being removed
799
+	 * @param bool           $update_capabilities_map
800
+	 * @return bool
801
+	 * @throws EE_Error
802
+	 * @since 4.5.0
803
+	 * @see   wp-includes/capabilities.php
804
+	 */
805
+	public function remove_cap_from_role($role, string $cap, bool $update_capabilities_map = true): bool
806
+	{
807
+		// don't do anything if the capabilities map can not be initialized
808
+		if (! $this->setupCapabilitiesMap()) {
809
+			return false;
810
+		}
811
+
812
+		$role = $role instanceof WP_Role ? $role : get_role($role);
813
+		if ($role instanceof WP_Role && $index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
814
+			$role->remove_cap($cap);
815
+			unset($this->capabilities_map[ $role->name ][ $index ]);
816
+			$this->updateCapabilitiesMap($update_capabilities_map);
817
+			return true;
818
+		}
819
+		return false;
820
+	}
821
+
822
+
823
+	/**
824
+	 * @param string $role_name
825
+	 * @param string $cap
826
+	 * @param bool   $get_index
827
+	 * @return bool|int|string
828
+	 */
829
+	private function capHasBeenAddedToRole(string $role_name = '', string $cap = '', bool $get_index = false)
830
+	{
831
+		if (
832
+			isset($this->capabilities_map[ $role_name ])
833
+			&& ($index = array_search($cap, $this->capabilities_map[ $role_name ], true)) !== false
834
+		) {
835
+			return $get_index ? $index : true;
836
+		}
837
+		return false;
838
+	}
839
+
840
+
841
+	/**
842
+	 * Wrapper for the native WP current_user_can() method.
843
+	 * This is provided as a handy method for a couple things:
844
+	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
845
+	 * write those filters wherever current_user_can is called).
846
+	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
847
+	 *
848
+	 * @param string $cap     The cap being checked.
849
+	 * @param string $context The context where the current_user_can is being called from.
850
+	 * @param int|string $id  [optional] ID for entity where current_user_can() is being called from
851
+	 *                        (used in map_meta_cap() filters).
852
+	 * @return bool  Whether user can or not.
853
+	 * @since 4.5.0
854
+	 */
855
+	public function current_user_can(string $cap, string $context, $id = 0): bool
856
+	{
857
+		// apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
858
+		$filtered_cap = apply_filters(
859
+			'FHEE__EE_Capabilities__current_user_can__cap',
860
+			apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id),
861
+			$context,
862
+			$cap,
863
+			$id
864
+		);
865
+		return ! empty($id) ? current_user_can($filtered_cap, $id) : current_user_can($filtered_cap);
866
+	}
867
+
868
+
869
+	/**
870
+	 * This is a wrapper for the WP user_can() function and follows the same style as the other wrappers in this class.
871
+	 *
872
+	 * @param int|WP_User $user    Either the user_id or a WP_User object
873
+	 * @param string      $cap     The capability string being checked
874
+	 * @param string      $context The context where the user_can is being called from (used in filters).
875
+	 * @param int         $id      Optional. Id for item where user_can is being called from ( used in map_meta_cap()
876
+	 *                             filters)
877
+	 *
878
+	 * @return bool Whether user can or not.
879
+	 */
880
+	public function user_can($user, string $cap, string $context, int $id = 0): bool
881
+	{
882
+		// apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
883
+		$filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
884
+		$filtered_cap = apply_filters(
885
+			'FHEE__EE_Capabilities__user_can__cap',
886
+			$filtered_cap,
887
+			$context,
888
+			$cap,
889
+			$user,
890
+			$id
891
+		);
892
+		return ! empty($id)
893
+			? user_can($user, $filtered_cap, $id)
894
+			: user_can($user, $filtered_cap);
895
+	}
896
+
897
+
898
+	/**
899
+	 * Wrapper for the native WP current_user_can_for_blog() method.
900
+	 * This is provided as a handy method for a couple things:
901
+	 * 1. Using the context string it allows for targeted filtering by addons for a specific check (without having to
902
+	 * write those filters wherever current_user_can is called).
903
+	 * 2. Explicit passing of $id from a given context ( useful in the cases of map_meta_cap filters )
904
+	 *
905
+	 * @param int    $blog_id The blog id that is being checked for.
906
+	 * @param string $cap     The cap being checked.
907
+	 * @param string $context The context where the current_user_can is being called from.
908
+	 * @param int    $id      Optional. Id for item where current_user_can is being called from (used in map_meta_cap()
909
+	 *                        filters.
910
+	 *
911
+	 * @return bool  Whether user can or not.
912
+	 * @since 4.5.0
913
+	 *
914
+	 */
915
+	public function current_user_can_for_blog(int $blog_id, string $cap, string $context, int $id = 0): bool
916
+	{
917
+		$user_can = ! empty($id)
918
+			? current_user_can_for_blog($blog_id, $cap, $id)
919
+			: current_user_can($blog_id, $cap);
920
+		// apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
921
+		$user_can = apply_filters(
922
+			'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
923
+			$user_can,
924
+			$blog_id,
925
+			$cap,
926
+			$id
927
+		);
928
+		return apply_filters(
929
+			'FHEE__EE_Capabilities__current_user_can_for_blog__user_can',
930
+			$user_can,
931
+			$context,
932
+			$blog_id,
933
+			$cap,
934
+			$id
935
+		);
936
+	}
937
+
938
+
939
+	/**
940
+	 * This helper method just returns an array of registered EE capabilities.
941
+	 *
942
+	 * @param string|null $role If empty then the entire role/capability map is returned.
943
+	 *                          Otherwise just the capabilities for the given role are returned.
944
+	 * @return array
945
+	 * @throws EE_Error
946
+	 * @since 4.5.0
947
+	 */
948
+	public function get_ee_capabilities(?string $role = EE_Capabilities::ROLE_ADMINISTRATOR): array
949
+	{
950
+		if (! $this->initialized) {
951
+			$this->init_caps();
952
+		}
953
+		if ($role === '') {
954
+			return $this->capabilities_map;
955
+		}
956
+		return $this->capabilities_map[ $role ] ?? [];
957
+	}
958
+
959
+
960
+	/**
961
+	 * @param bool  $reset      If you need to reset Event Espresso's capabilities,
962
+	 *                          then please use the init_caps() method with the "$reset" parameter set to "true"
963
+	 * @param array $caps_map   Optional.
964
+	 *                          Can be used to send a custom map of roles and capabilities for setting them up.
965
+	 *                          Note that this should ONLY be called on activation hook or some other one-time
966
+	 *                          task otherwise the caps will be added on every request.
967
+	 * @return void
968
+	 * @throws EE_Error
969
+	 * @deprecated 4.9.42
970
+	 */
971
+	public function init_role_caps(bool $reset = false, array $caps_map = [])
972
+	{
973
+		// If this method is called directly and reset is set as 'true',
974
+		// then display a doing it wrong notice, because we want resets to go through init_caps()
975
+		// to guarantee that everything is set up correctly.
976
+		// This prevents the capabilities map getting reset incorrectly by direct calls to this method.
977
+		if ($reset) {
978
+			EE_Error::doing_it_wrong(
979
+				__METHOD__,
980
+				sprintf(
981
+					esc_html__(
982
+						'The "%1$s" parameter for the "%2$s" method is deprecated. If you need to reset Event Espresso\'s capabilities, then please use the "%3$s" method with the "%1$s" parameter set to "%4$s".',
983
+						'event_espresso'
984
+					),
985
+					'$reset',
986
+					__METHOD__ . '()',
987
+					'EE_Capabilities::init_caps()',
988
+					'true'
989
+				),
990
+				'4.9.42',
991
+				'5.0.0'
992
+			);
993
+		}
994
+		$this->addCaps($caps_map);
995
+	}
996 996
 }
997 997
 
998 998
 
@@ -1008,158 +1008,158 @@  discard block
 block discarded – undo
1008 1008
  */
1009 1009
 abstract class EE_Meta_Capability_Map
1010 1010
 {
1011
-    /**
1012
-     * @var EEM_Base
1013
-     */
1014
-    protected $_model;
1015
-
1016
-    /**
1017
-     * @var string
1018
-     */
1019
-    protected $_model_name;
1020
-
1021
-    /**
1022
-     * @var string
1023
-     */
1024
-    public $meta_cap;
1025
-
1026
-    /**
1027
-     * @var string
1028
-     */
1029
-    public $published_cap = '';
1030
-
1031
-    /**
1032
-     * @var string
1033
-     */
1034
-    public $others_cap = '';
1035
-
1036
-    /**
1037
-     * @var string
1038
-     */
1039
-    public $private_cap = '';
1040
-
1041
-
1042
-    /**
1043
-     * constructor.
1044
-     * Receives the setup arguments for the map.
1045
-     *
1046
-     * @param string $meta_cap   What meta capability is this mapping.
1047
-     * @param array  $map_values array {
1048
-     *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
1049
-     *                           capabilities that don't get mapped to.
1050
-     *
1051
-     * @type         $map_values [0] string A string representing the model name. Required.  String's
1052
-     *                               should always be used when Menu Maps are registered via the
1053
-     *                               plugin API as models are not allowed to be instantiated when
1054
-     *                               in maintenance mode 2 (migrations).
1055
-     * @type         $map_values [1] string represents the capability used for published. Optional.
1056
-     * @type         $map_values [2] string represents the capability used for "others". Optional.
1057
-     * @type         $map_values [3] string represents the capability used for private. Optional.
1058
-     *                               }
1059
-     * @throws EE_Error
1060
-     * @since                        4.5.0
1061
-     *
1062
-     */
1063
-    public function __construct(string $meta_cap, array $map_values)
1064
-    {
1065
-        $this->meta_cap = $meta_cap;
1066
-        // verify there are four args in the $map_values array;
1067
-        if (count($map_values) !== 4) {
1068
-            throw new EE_Error(
1069
-                sprintf(
1070
-                    esc_html__(
1071
-                        'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1072
-                        'event_espresso'
1073
-                    ),
1074
-                    '<br>' . print_r($map_values, true)
1075
-                )
1076
-            );
1077
-        }
1078
-        // set properties
1079
-        $this->_model        = null;
1080
-        $this->_model_name   = $map_values[0];
1081
-        $this->published_cap = (string) $map_values[1];
1082
-        $this->others_cap    = (string) $map_values[2];
1083
-        $this->private_cap   = (string) $map_values[3];
1084
-    }
1085
-
1086
-
1087
-    /**
1088
-     * Makes it so this object stops filtering caps
1089
-     */
1090
-    public function remove_filters()
1091
-    {
1092
-        remove_filter('map_meta_cap', [$this, 'map_meta_caps']);
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
1098
-     *
1099
-     * @return void
1100
-     * @throws EE_Error
1101
-     * @throws ReflectionException
1102
-     * @since 4.5.0
1103
-     */
1104
-    public function ensure_is_model()
1105
-    {
1106
-        // is it already instantiated?
1107
-        if ($this->_model instanceof EEM_Base) {
1108
-            return;
1109
-        }
1110
-        // ensure model name is string
1111
-        $this->_model_name = (string) $this->_model_name;
1112
-        // error proof if the name has EEM in it
1113
-        $this->_model_name = str_replace('EEM', '', $this->_model_name);
1114
-        $this->_model      = EE_Registry::instance()->load_model($this->_model_name);
1115
-        if (! $this->_model instanceof EEM_Base) {
1116
-            throw new EE_Error(
1117
-                sprintf(
1118
-                    esc_html__(
1119
-                        'This string passed in to %s to represent a EEM_Base model class was not able to be used to instantiate the class.   Please ensure that the string is a match for the EEM_Base model name (not including the EEM_ part). This was given: %s',
1120
-                        'event_espresso'
1121
-                    ),
1122
-                    get_class($this),
1123
-                    $this->_model
1124
-                )
1125
-            );
1126
-        }
1127
-    }
1128
-
1129
-
1130
-    /**
1131
-     *
1132
-     * @param $caps
1133
-     * @param $cap
1134
-     * @param $user_id
1135
-     * @param $args
1136
-     *
1137
-     * @return array
1138
-     * @since 4.6.x
1139
-     *
1140
-     * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
1141
-     */
1142
-    public function map_meta_caps($caps, $cap, $user_id, $args): array
1143
-    {
1144
-        return $this->_map_meta_caps($caps, $cap, (int) $user_id, $args);
1145
-    }
1146
-
1147
-
1148
-    /**
1149
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1150
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1151
-     *
1152
-     * @param array  $caps    actual users capabilities
1153
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1154
-     * @param int    $user_id The user id
1155
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1156
-     *
1157
-     * @return array   actual users capabilities
1158
-     * @see   wp-includes/capabilities.php
1159
-     *
1160
-     * @since 4.5.0
1161
-     */
1162
-    abstract protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array;
1011
+	/**
1012
+	 * @var EEM_Base
1013
+	 */
1014
+	protected $_model;
1015
+
1016
+	/**
1017
+	 * @var string
1018
+	 */
1019
+	protected $_model_name;
1020
+
1021
+	/**
1022
+	 * @var string
1023
+	 */
1024
+	public $meta_cap;
1025
+
1026
+	/**
1027
+	 * @var string
1028
+	 */
1029
+	public $published_cap = '';
1030
+
1031
+	/**
1032
+	 * @var string
1033
+	 */
1034
+	public $others_cap = '';
1035
+
1036
+	/**
1037
+	 * @var string
1038
+	 */
1039
+	public $private_cap = '';
1040
+
1041
+
1042
+	/**
1043
+	 * constructor.
1044
+	 * Receives the setup arguments for the map.
1045
+	 *
1046
+	 * @param string $meta_cap   What meta capability is this mapping.
1047
+	 * @param array  $map_values array {
1048
+	 *                           //array of values that MUST match a count of 4.  It's okay to send an empty string for
1049
+	 *                           capabilities that don't get mapped to.
1050
+	 *
1051
+	 * @type         $map_values [0] string A string representing the model name. Required.  String's
1052
+	 *                               should always be used when Menu Maps are registered via the
1053
+	 *                               plugin API as models are not allowed to be instantiated when
1054
+	 *                               in maintenance mode 2 (migrations).
1055
+	 * @type         $map_values [1] string represents the capability used for published. Optional.
1056
+	 * @type         $map_values [2] string represents the capability used for "others". Optional.
1057
+	 * @type         $map_values [3] string represents the capability used for private. Optional.
1058
+	 *                               }
1059
+	 * @throws EE_Error
1060
+	 * @since                        4.5.0
1061
+	 *
1062
+	 */
1063
+	public function __construct(string $meta_cap, array $map_values)
1064
+	{
1065
+		$this->meta_cap = $meta_cap;
1066
+		// verify there are four args in the $map_values array;
1067
+		if (count($map_values) !== 4) {
1068
+			throw new EE_Error(
1069
+				sprintf(
1070
+					esc_html__(
1071
+						'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1072
+						'event_espresso'
1073
+					),
1074
+					'<br>' . print_r($map_values, true)
1075
+				)
1076
+			);
1077
+		}
1078
+		// set properties
1079
+		$this->_model        = null;
1080
+		$this->_model_name   = $map_values[0];
1081
+		$this->published_cap = (string) $map_values[1];
1082
+		$this->others_cap    = (string) $map_values[2];
1083
+		$this->private_cap   = (string) $map_values[3];
1084
+	}
1085
+
1086
+
1087
+	/**
1088
+	 * Makes it so this object stops filtering caps
1089
+	 */
1090
+	public function remove_filters()
1091
+	{
1092
+		remove_filter('map_meta_cap', [$this, 'map_meta_caps']);
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 * This method ensures that the $model property is converted from the model name string to a proper EEM_Base class
1098
+	 *
1099
+	 * @return void
1100
+	 * @throws EE_Error
1101
+	 * @throws ReflectionException
1102
+	 * @since 4.5.0
1103
+	 */
1104
+	public function ensure_is_model()
1105
+	{
1106
+		// is it already instantiated?
1107
+		if ($this->_model instanceof EEM_Base) {
1108
+			return;
1109
+		}
1110
+		// ensure model name is string
1111
+		$this->_model_name = (string) $this->_model_name;
1112
+		// error proof if the name has EEM in it
1113
+		$this->_model_name = str_replace('EEM', '', $this->_model_name);
1114
+		$this->_model      = EE_Registry::instance()->load_model($this->_model_name);
1115
+		if (! $this->_model instanceof EEM_Base) {
1116
+			throw new EE_Error(
1117
+				sprintf(
1118
+					esc_html__(
1119
+						'This string passed in to %s to represent a EEM_Base model class was not able to be used to instantiate the class.   Please ensure that the string is a match for the EEM_Base model name (not including the EEM_ part). This was given: %s',
1120
+						'event_espresso'
1121
+					),
1122
+					get_class($this),
1123
+					$this->_model
1124
+				)
1125
+			);
1126
+		}
1127
+	}
1128
+
1129
+
1130
+	/**
1131
+	 *
1132
+	 * @param $caps
1133
+	 * @param $cap
1134
+	 * @param $user_id
1135
+	 * @param $args
1136
+	 *
1137
+	 * @return array
1138
+	 * @since 4.6.x
1139
+	 *
1140
+	 * @see   EE_Meta_Capability_Map::_map_meta_caps() for docs on params.
1141
+	 */
1142
+	public function map_meta_caps($caps, $cap, $user_id, $args): array
1143
+	{
1144
+		return $this->_map_meta_caps($caps, $cap, (int) $user_id, $args);
1145
+	}
1146
+
1147
+
1148
+	/**
1149
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1150
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1151
+	 *
1152
+	 * @param array  $caps    actual users capabilities
1153
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1154
+	 * @param int    $user_id The user id
1155
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1156
+	 *
1157
+	 * @return array   actual users capabilities
1158
+	 * @see   wp-includes/capabilities.php
1159
+	 *
1160
+	 * @since 4.5.0
1161
+	 */
1162
+	abstract protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array;
1163 1163
 }
1164 1164
 
1165 1165
 
@@ -1174,80 +1174,80 @@  discard block
 block discarded – undo
1174 1174
  */
1175 1175
 class EE_Meta_Capability_Map_Edit extends EE_Meta_Capability_Map
1176 1176
 {
1177
-    /**
1178
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1179
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1180
-     *
1181
-     * @param array  $caps    actual users capabilities
1182
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1183
-     * @param int    $user_id The user id
1184
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1185
-     *
1186
-     * @return array   actual users capabilities
1187
-     * @throws EE_Error
1188
-     * @throws EE_Error
1189
-     * @since 4.5.0
1190
-     * @see   wp-includes/capabilities.php
1191
-     *
1192
-     */
1193
-    protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1194
-    {
1195
-        // only process if we're checking our mapped_cap
1196
-        if ($cap !== $this->meta_cap) {
1197
-            return $caps;
1198
-        }
1199
-
1200
-        // okay it is a meta cap so let's first remove that cap from the $caps array.
1201
-        if (($key = array_search($cap, $caps)) !== false) {
1202
-            unset($caps[ $key ]);
1203
-        }
1204
-
1205
-        /** @var EE_Base_Class $obj */
1206
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1207
-        // if no obj then let's just do cap
1208
-        if (! $obj instanceof EE_Base_Class) {
1209
-            $caps[] = 'do_not_allow';
1210
-            return $caps;
1211
-        }
1212
-        $caps[] = $cap . 's';
1213
-        if ($obj instanceof EE_CPT_Base) {
1214
-            // if the item author is set and the user is the author...
1215
-            if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1216
-                // if obj is published...
1217
-                if ($obj->status() === 'publish') {
1218
-                    $caps[] = $this->published_cap;
1219
-                }
1220
-            } else {
1221
-                // the user is trying to edit someone else's obj
1222
-                if (! empty($this->others_cap)) {
1223
-                    $caps[] = $this->others_cap;
1224
-                }
1225
-                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1226
-                    $caps[] = $this->published_cap;
1227
-                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1228
-                    $caps[] = $this->private_cap;
1229
-                }
1230
-            }
1231
-        } else {
1232
-            // not a cpt object so handled differently
1233
-            $has_cap = false;
1234
-            try {
1235
-                $has_cap = method_exists($obj, 'wp_user')
1236
-                           && $obj->wp_user()
1237
-                           && $obj->wp_user() === $user_id;
1238
-            } catch (Exception $e) {
1239
-                if (WP_DEBUG) {
1240
-                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1241
-                }
1242
-            }
1243
-            if (! $has_cap) {
1244
-                if (! empty($this->others_cap)) {
1245
-                    $caps[] = $this->others_cap;
1246
-                }
1247
-            }
1248
-        }
1249
-        return $caps;
1250
-    }
1177
+	/**
1178
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1179
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1180
+	 *
1181
+	 * @param array  $caps    actual users capabilities
1182
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1183
+	 * @param int    $user_id The user id
1184
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1185
+	 *
1186
+	 * @return array   actual users capabilities
1187
+	 * @throws EE_Error
1188
+	 * @throws EE_Error
1189
+	 * @since 4.5.0
1190
+	 * @see   wp-includes/capabilities.php
1191
+	 *
1192
+	 */
1193
+	protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1194
+	{
1195
+		// only process if we're checking our mapped_cap
1196
+		if ($cap !== $this->meta_cap) {
1197
+			return $caps;
1198
+		}
1199
+
1200
+		// okay it is a meta cap so let's first remove that cap from the $caps array.
1201
+		if (($key = array_search($cap, $caps)) !== false) {
1202
+			unset($caps[ $key ]);
1203
+		}
1204
+
1205
+		/** @var EE_Base_Class $obj */
1206
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1207
+		// if no obj then let's just do cap
1208
+		if (! $obj instanceof EE_Base_Class) {
1209
+			$caps[] = 'do_not_allow';
1210
+			return $caps;
1211
+		}
1212
+		$caps[] = $cap . 's';
1213
+		if ($obj instanceof EE_CPT_Base) {
1214
+			// if the item author is set and the user is the author...
1215
+			if ($obj->wp_user() && $user_id === $obj->wp_user()) {
1216
+				// if obj is published...
1217
+				if ($obj->status() === 'publish') {
1218
+					$caps[] = $this->published_cap;
1219
+				}
1220
+			} else {
1221
+				// the user is trying to edit someone else's obj
1222
+				if (! empty($this->others_cap)) {
1223
+					$caps[] = $this->others_cap;
1224
+				}
1225
+				if (! empty($this->published_cap) && $obj->status() === 'publish') {
1226
+					$caps[] = $this->published_cap;
1227
+				} elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1228
+					$caps[] = $this->private_cap;
1229
+				}
1230
+			}
1231
+		} else {
1232
+			// not a cpt object so handled differently
1233
+			$has_cap = false;
1234
+			try {
1235
+				$has_cap = method_exists($obj, 'wp_user')
1236
+						   && $obj->wp_user()
1237
+						   && $obj->wp_user() === $user_id;
1238
+			} catch (Exception $e) {
1239
+				if (WP_DEBUG) {
1240
+					EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1241
+				}
1242
+			}
1243
+			if (! $has_cap) {
1244
+				if (! empty($this->others_cap)) {
1245
+					$caps[] = $this->others_cap;
1246
+				}
1247
+			}
1248
+		}
1249
+		return $caps;
1250
+	}
1251 1251
 }
1252 1252
 
1253 1253
 
@@ -1263,25 +1263,25 @@  discard block
 block discarded – undo
1263 1263
  */
1264 1264
 class EE_Meta_Capability_Map_Delete extends EE_Meta_Capability_Map_Edit
1265 1265
 {
1266
-    /**
1267
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1268
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1269
-     *
1270
-     * @param array  $caps    actual users capabilities
1271
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1272
-     * @param int    $user_id The user id
1273
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1274
-     *
1275
-     * @return array   actual users capabilities
1276
-     * @throws EE_Error
1277
-     * @since 4.5.0
1278
-     * @see   wp-includes/capabilities.php
1279
-     *
1280
-     */
1281
-    protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1282
-    {
1283
-        return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1284
-    }
1266
+	/**
1267
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1268
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1269
+	 *
1270
+	 * @param array  $caps    actual users capabilities
1271
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1272
+	 * @param int    $user_id The user id
1273
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1274
+	 *
1275
+	 * @return array   actual users capabilities
1276
+	 * @throws EE_Error
1277
+	 * @since 4.5.0
1278
+	 * @see   wp-includes/capabilities.php
1279
+	 *
1280
+	 */
1281
+	protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1282
+	{
1283
+		return parent::_map_meta_caps($caps, $cap, $user_id, $args);
1284
+	}
1285 1285
 }
1286 1286
 
1287 1287
 
@@ -1296,85 +1296,85 @@  discard block
 block discarded – undo
1296 1296
  */
1297 1297
 class EE_Meta_Capability_Map_Read extends EE_Meta_Capability_Map
1298 1298
 {
1299
-    /**
1300
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1301
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1302
-     *
1303
-     * @param array  $caps    actual users capabilities
1304
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1305
-     * @param int    $user_id The user id
1306
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1307
-     *
1308
-     * @return array   actual users capabilities
1309
-     * @throws EE_Error
1310
-     * @throws EE_Error
1311
-     * @since 4.5.0
1312
-     * @see   wp-includes/capabilities.php
1313
-     *
1314
-     */
1315
-    protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1316
-    {
1317
-        // only process if we're checking our mapped cap;
1318
-        if ($cap !== $this->meta_cap) {
1319
-            return $caps;
1320
-        }
1321
-
1322
-        // okay it is a meta cap so let's first remove that cap from the $caps array.
1323
-        if (($key = array_search($cap, $caps)) !== false) {
1324
-            unset($caps[ $key ]);
1325
-        }
1326
-
1327
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1328
-        // if no obj then let's just do cap
1329
-        if (! $obj instanceof EE_Base_Class) {
1330
-            $caps[] = 'do_not_allow';
1331
-            return $caps;
1332
-        }
1333
-
1334
-        $caps[] = $cap . 's';
1335
-        if ($obj instanceof EE_CPT_Base) {
1336
-            $status_obj = get_post_status_object($obj->status());
1337
-            if ($status_obj->public) {
1338
-                return $caps;
1339
-            }
1340
-            // if the item author is set and the user is not the author...
1341
-            if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1342
-                if (! empty($this->others_cap)) {
1343
-                    $caps[] = $this->others_cap;
1344
-                }
1345
-            }
1346
-            // yes this means that if users created the private post, they are able to see it regardless of private cap.
1347
-            if (
1348
-                $status_obj->private
1349
-                && ! empty($this->private_cap)
1350
-                && $obj->wp_user() !== $user_id
1351
-            ) {
1352
-                // the user is trying to view a private object for an object they don't own.
1353
-                $caps[] = $this->private_cap;
1354
-            }
1355
-        } else {
1356
-            // not a cpt object so handled differently
1357
-            $has_cap = false;
1358
-            try {
1359
-                $has_cap = method_exists($obj, 'wp_user')
1360
-                           && $obj->wp_user()
1361
-                           && $obj->wp_user() === $user_id;
1362
-            } catch (Exception $e) {
1363
-                if (WP_DEBUG) {
1364
-                    EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1365
-                }
1366
-            }
1367
-            if (! $has_cap) {
1368
-                if (! empty($this->private_cap)) {
1369
-                    $caps[] = $this->private_cap;
1370
-                }
1371
-                if (! empty($this->others_cap)) {
1372
-                    $caps[] = $this->others_cap;
1373
-                }
1374
-            }
1375
-        }
1376
-        return $caps;
1377
-    }
1299
+	/**
1300
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1301
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1302
+	 *
1303
+	 * @param array  $caps    actual users capabilities
1304
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1305
+	 * @param int    $user_id The user id
1306
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1307
+	 *
1308
+	 * @return array   actual users capabilities
1309
+	 * @throws EE_Error
1310
+	 * @throws EE_Error
1311
+	 * @since 4.5.0
1312
+	 * @see   wp-includes/capabilities.php
1313
+	 *
1314
+	 */
1315
+	protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1316
+	{
1317
+		// only process if we're checking our mapped cap;
1318
+		if ($cap !== $this->meta_cap) {
1319
+			return $caps;
1320
+		}
1321
+
1322
+		// okay it is a meta cap so let's first remove that cap from the $caps array.
1323
+		if (($key = array_search($cap, $caps)) !== false) {
1324
+			unset($caps[ $key ]);
1325
+		}
1326
+
1327
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1328
+		// if no obj then let's just do cap
1329
+		if (! $obj instanceof EE_Base_Class) {
1330
+			$caps[] = 'do_not_allow';
1331
+			return $caps;
1332
+		}
1333
+
1334
+		$caps[] = $cap . 's';
1335
+		if ($obj instanceof EE_CPT_Base) {
1336
+			$status_obj = get_post_status_object($obj->status());
1337
+			if ($status_obj->public) {
1338
+				return $caps;
1339
+			}
1340
+			// if the item author is set and the user is not the author...
1341
+			if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1342
+				if (! empty($this->others_cap)) {
1343
+					$caps[] = $this->others_cap;
1344
+				}
1345
+			}
1346
+			// yes this means that if users created the private post, they are able to see it regardless of private cap.
1347
+			if (
1348
+				$status_obj->private
1349
+				&& ! empty($this->private_cap)
1350
+				&& $obj->wp_user() !== $user_id
1351
+			) {
1352
+				// the user is trying to view a private object for an object they don't own.
1353
+				$caps[] = $this->private_cap;
1354
+			}
1355
+		} else {
1356
+			// not a cpt object so handled differently
1357
+			$has_cap = false;
1358
+			try {
1359
+				$has_cap = method_exists($obj, 'wp_user')
1360
+						   && $obj->wp_user()
1361
+						   && $obj->wp_user() === $user_id;
1362
+			} catch (Exception $e) {
1363
+				if (WP_DEBUG) {
1364
+					EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1365
+				}
1366
+			}
1367
+			if (! $has_cap) {
1368
+				if (! empty($this->private_cap)) {
1369
+					$caps[] = $this->private_cap;
1370
+				}
1371
+				if (! empty($this->others_cap)) {
1372
+					$caps[] = $this->others_cap;
1373
+				}
1374
+			}
1375
+		}
1376
+		return $caps;
1377
+	}
1378 1378
 }
1379 1379
 
1380 1380
 
@@ -1390,55 +1390,55 @@  discard block
 block discarded – undo
1390 1390
  */
1391 1391
 class EE_Meta_Capability_Map_Messages_Cap extends EE_Meta_Capability_Map
1392 1392
 {
1393
-    /**
1394
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1395
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1396
-     *
1397
-     * @param array  $caps    actual users capabilities
1398
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1399
-     * @param int    $user_id The user id
1400
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1401
-     *
1402
-     * @return array   actual users capabilities
1403
-     * @throws EE_Error
1404
-     * @throws EE_Error
1405
-     * @since 4.5.0
1406
-     * @see   wp-includes/capabilities.php
1407
-     *
1408
-     */
1409
-    protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1410
-    {
1411
-        // only process if we're checking our mapped_cap
1412
-        if ($cap !== $this->meta_cap) {
1413
-            return $caps;
1414
-        }
1415
-
1416
-        // okay it is a meta cap so let's first remove that cap from the $caps array.
1417
-        if (($key = array_search($cap, $caps)) !== false) {
1418
-            unset($caps[ $key ]);
1419
-        }
1420
-
1421
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1422
-        // if no obj then let's just do cap
1423
-        if (! $obj instanceof EE_Message_Template_Group) {
1424
-            $caps[] = 'do_not_allow';
1425
-            return $caps;
1426
-        }
1427
-        $caps[]    = $cap . 's';
1428
-        $is_global = $obj->is_global();
1429
-        if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1430
-            if ($is_global) {
1431
-                $caps[] = $this->private_cap;
1432
-            }
1433
-        } else {
1434
-            if ($is_global) {
1435
-                $caps[] = $this->private_cap;
1436
-            } else {
1437
-                $caps[] = $this->others_cap;
1438
-            }
1439
-        }
1440
-        return $caps;
1441
-    }
1393
+	/**
1394
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1395
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1396
+	 *
1397
+	 * @param array  $caps    actual users capabilities
1398
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1399
+	 * @param int    $user_id The user id
1400
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1401
+	 *
1402
+	 * @return array   actual users capabilities
1403
+	 * @throws EE_Error
1404
+	 * @throws EE_Error
1405
+	 * @since 4.5.0
1406
+	 * @see   wp-includes/capabilities.php
1407
+	 *
1408
+	 */
1409
+	protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1410
+	{
1411
+		// only process if we're checking our mapped_cap
1412
+		if ($cap !== $this->meta_cap) {
1413
+			return $caps;
1414
+		}
1415
+
1416
+		// okay it is a meta cap so let's first remove that cap from the $caps array.
1417
+		if (($key = array_search($cap, $caps)) !== false) {
1418
+			unset($caps[ $key ]);
1419
+		}
1420
+
1421
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1422
+		// if no obj then let's just do cap
1423
+		if (! $obj instanceof EE_Message_Template_Group) {
1424
+			$caps[] = 'do_not_allow';
1425
+			return $caps;
1426
+		}
1427
+		$caps[]    = $cap . 's';
1428
+		$is_global = $obj->is_global();
1429
+		if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1430
+			if ($is_global) {
1431
+				$caps[] = $this->private_cap;
1432
+			}
1433
+		} else {
1434
+			if ($is_global) {
1435
+				$caps[] = $this->private_cap;
1436
+			} else {
1437
+				$caps[] = $this->others_cap;
1438
+			}
1439
+		}
1440
+		return $caps;
1441
+	}
1442 1442
 }
1443 1443
 
1444 1444
 
@@ -1454,42 +1454,42 @@  discard block
 block discarded – undo
1454 1454
  */
1455 1455
 class EE_Meta_Capability_Map_Registration_Form_Cap extends EE_Meta_Capability_Map
1456 1456
 {
1457
-    /**
1458
-     * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1459
-     * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1460
-     *
1461
-     * @param array  $caps    actual users capabilities
1462
-     * @param string $cap     initial capability name that is being checked (the "map" key)
1463
-     * @param int    $user_id The user id
1464
-     * @param array  $args    Adds context to the cap. Typically the object ID.
1465
-     * @return array   actual users capabilities
1466
-     * @throws EE_Error
1467
-     * @throws EE_Error
1468
-     * @since 4.5.0
1469
-     * @see   wp-includes/capabilities.php
1470
-     */
1471
-    protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1472
-    {
1473
-        // only process if we're checking our mapped_cap
1474
-        if ($cap !== $this->meta_cap) {
1475
-            return $caps;
1476
-        }
1477
-        // okay it is a meta cap so let's first remove that cap from the $caps array.
1478
-        if (($key = array_search($cap, $caps)) !== false) {
1479
-            unset($caps[ $key ]);
1480
-        }
1481
-        $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1482
-        // if no obj then let's just do cap
1483
-        if (! $obj instanceof EE_Base_Class) {
1484
-            $caps[] = 'do_not_allow';
1485
-            return $caps;
1486
-        }
1487
-        $caps[]    = $cap . 's';
1488
-        $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1489
-        $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1490
-        if ($is_system) {
1491
-            $caps[] = $this->private_cap;
1492
-        }
1493
-        return $caps;
1494
-    }
1457
+	/**
1458
+	 * This is the callback for the wp map_meta_caps() function which allows for ensuring certain caps that act as a
1459
+	 * "meta" for other caps ( i.e. ee_edit_event is a meta for ee_edit_others_events ) work as expected.
1460
+	 *
1461
+	 * @param array  $caps    actual users capabilities
1462
+	 * @param string $cap     initial capability name that is being checked (the "map" key)
1463
+	 * @param int    $user_id The user id
1464
+	 * @param array  $args    Adds context to the cap. Typically the object ID.
1465
+	 * @return array   actual users capabilities
1466
+	 * @throws EE_Error
1467
+	 * @throws EE_Error
1468
+	 * @since 4.5.0
1469
+	 * @see   wp-includes/capabilities.php
1470
+	 */
1471
+	protected function _map_meta_caps(array $caps, string $cap, int $user_id, array $args): array
1472
+	{
1473
+		// only process if we're checking our mapped_cap
1474
+		if ($cap !== $this->meta_cap) {
1475
+			return $caps;
1476
+		}
1477
+		// okay it is a meta cap so let's first remove that cap from the $caps array.
1478
+		if (($key = array_search($cap, $caps)) !== false) {
1479
+			unset($caps[ $key ]);
1480
+		}
1481
+		$obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1482
+		// if no obj then let's just do cap
1483
+		if (! $obj instanceof EE_Base_Class) {
1484
+			$caps[] = 'do_not_allow';
1485
+			return $caps;
1486
+		}
1487
+		$caps[]    = $cap . 's';
1488
+		$is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1489
+		$is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1490
+		if ($is_system) {
1491
+			$caps[] = $this->private_cap;
1492
+		}
1493
+		return $caps;
1494
+	}
1495 1495
 }
Please login to merge, or discard this patch.
Spacing   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
     public static function instance(): EE_Capabilities
85 85
     {
86 86
         // check if instantiated, and if not do so.
87
-        if (! self::$_instance instanceof EE_Capabilities) {
87
+        if ( ! self::$_instance instanceof EE_Capabilities) {
88 88
             self::$_instance = new self();
89 89
         }
90 90
         return self::$_instance;
@@ -114,7 +114,7 @@  discard block
 block discarded – undo
114 114
      */
115 115
     public function init_caps(?bool $reset = false): bool
116 116
     {
117
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
117
+        if ( ! EE_Maintenance_Mode::instance()->models_can_query()) {
118 118
             return false;
119 119
         }
120 120
         $this->reset = filter_var($reset, FILTER_VALIDATE_BOOLEAN);
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
             $this->_get_default_meta_caps_array()
160 160
         );
161 161
         // add filter for map_meta_caps but only if models can query.
162
-        if (! has_filter('map_meta_cap', [$this, 'map_meta_caps'])) {
162
+        if ( ! has_filter('map_meta_cap', [$this, 'map_meta_caps'])) {
163 163
             add_filter('map_meta_cap', [$this, 'map_meta_caps'], 10, 4);
164 164
         }
165 165
     }
@@ -319,11 +319,11 @@  discard block
 block discarded – undo
319 319
         if (did_action('AHEE__EE_System__load_espresso_addons__complete')) {
320 320
             // loop through our _meta_caps array
321 321
             foreach ($this->_meta_caps as $meta_map) {
322
-                if (! $meta_map instanceof EE_Meta_Capability_Map) {
322
+                if ( ! $meta_map instanceof EE_Meta_Capability_Map) {
323 323
                     continue;
324 324
                 }
325 325
                 // don't load models if there is no object ID in the args
326
-                if (! empty($args[0])) {
326
+                if ( ! empty($args[0])) {
327 327
                     $meta_map->ensure_is_model();
328 328
                 }
329 329
                 $caps = $meta_map->map_meta_caps($caps, $cap, $user_id, $args);
@@ -659,11 +659,11 @@  discard block
 block discarded – undo
659 659
     public function addCaps(array $capabilities_to_add): bool
660 660
     {
661 661
         // don't do anything if the capabilities map can not be initialized
662
-        if (! $this->setupCapabilitiesMap()) {
662
+        if ( ! $this->setupCapabilitiesMap()) {
663 663
             return false;
664 664
         }
665 665
         // and filter the array so others can get in on the fun during resets
666
-        $capabilities_to_add     = apply_filters(
666
+        $capabilities_to_add = apply_filters(
667 667
             'FHEE__EE_Capabilities__addCaps__capabilities_to_add',
668 668
             $capabilities_to_add,
669 669
             $this->reset,
@@ -701,7 +701,7 @@  discard block
 block discarded – undo
701 701
     public function removeCaps(array $caps_map): bool
702 702
     {
703 703
         // don't do anything if the capabilities map can not be initialized
704
-        if (! $this->setupCapabilitiesMap()) {
704
+        if ( ! $this->setupCapabilitiesMap()) {
705 705
             return false;
706 706
         }
707 707
         $update_capabilities_map = false;
@@ -765,7 +765,7 @@  discard block
 block discarded – undo
765 765
         $orig_role = $role;
766 766
         $role      = $role instanceof WP_Role ? $role : get_role($role);
767 767
         // if the role isn't available then we create it.
768
-        if (! $role instanceof WP_Role) {
768
+        if ( ! $role instanceof WP_Role) {
769 769
             // if a plugin wants to create a specific role name then they should create the role before
770 770
             // EE_Capabilities does.  Otherwise this function will create the role name from the slug:
771 771
             // - removes any `ee_` namespacing from the start of the slug.
@@ -776,12 +776,12 @@  discard block
 block discarded – undo
776 776
         }
777 777
         if ($role instanceof WP_Role) {
778 778
             // don't do anything if the capabilities map can not be initialized
779
-            if (! $this->setupCapabilitiesMap()) {
779
+            if ( ! $this->setupCapabilitiesMap()) {
780 780
                 return false;
781 781
             }
782
-            if (! $this->capHasBeenAddedToRole($role->name, $cap)) {
782
+            if ( ! $this->capHasBeenAddedToRole($role->name, $cap)) {
783 783
                 $role->add_cap($cap, $grant);
784
-                $this->capabilities_map[ $role->name ][] = $cap;
784
+                $this->capabilities_map[$role->name][] = $cap;
785 785
                 $this->updateCapabilitiesMap($update_capabilities_map);
786 786
                 return true;
787 787
             }
@@ -805,14 +805,14 @@  discard block
 block discarded – undo
805 805
     public function remove_cap_from_role($role, string $cap, bool $update_capabilities_map = true): bool
806 806
     {
807 807
         // don't do anything if the capabilities map can not be initialized
808
-        if (! $this->setupCapabilitiesMap()) {
808
+        if ( ! $this->setupCapabilitiesMap()) {
809 809
             return false;
810 810
         }
811 811
 
812 812
         $role = $role instanceof WP_Role ? $role : get_role($role);
813 813
         if ($role instanceof WP_Role && $index = $this->capHasBeenAddedToRole($role->name, $cap, true)) {
814 814
             $role->remove_cap($cap);
815
-            unset($this->capabilities_map[ $role->name ][ $index ]);
815
+            unset($this->capabilities_map[$role->name][$index]);
816 816
             $this->updateCapabilitiesMap($update_capabilities_map);
817 817
             return true;
818 818
         }
@@ -829,8 +829,8 @@  discard block
 block discarded – undo
829 829
     private function capHasBeenAddedToRole(string $role_name = '', string $cap = '', bool $get_index = false)
830 830
     {
831 831
         if (
832
-            isset($this->capabilities_map[ $role_name ])
833
-            && ($index = array_search($cap, $this->capabilities_map[ $role_name ], true)) !== false
832
+            isset($this->capabilities_map[$role_name])
833
+            && ($index = array_search($cap, $this->capabilities_map[$role_name], true)) !== false
834 834
         ) {
835 835
             return $get_index ? $index : true;
836 836
         }
@@ -857,7 +857,7 @@  discard block
 block discarded – undo
857 857
         // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
858 858
         $filtered_cap = apply_filters(
859 859
             'FHEE__EE_Capabilities__current_user_can__cap',
860
-            apply_filters('FHEE__EE_Capabilities__current_user_can__cap__' . $context, $cap, $id),
860
+            apply_filters('FHEE__EE_Capabilities__current_user_can__cap__'.$context, $cap, $id),
861 861
             $context,
862 862
             $cap,
863 863
             $id
@@ -880,7 +880,7 @@  discard block
 block discarded – undo
880 880
     public function user_can($user, string $cap, string $context, int $id = 0): bool
881 881
     {
882 882
         // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
883
-        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__' . $context, $cap, $user, $id);
883
+        $filtered_cap = apply_filters('FHEE__EE_Capabilities__user_can__cap__'.$context, $cap, $user, $id);
884 884
         $filtered_cap = apply_filters(
885 885
             'FHEE__EE_Capabilities__user_can__cap',
886 886
             $filtered_cap,
@@ -919,7 +919,7 @@  discard block
 block discarded – undo
919 919
             : current_user_can($blog_id, $cap);
920 920
         // apply filters (both a global on just the cap, and context specific.  Global overrides context specific)
921 921
         $user_can = apply_filters(
922
-            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__' . $context,
922
+            'FHEE__EE_Capabilities__current_user_can_for_blog__user_can__'.$context,
923 923
             $user_can,
924 924
             $blog_id,
925 925
             $cap,
@@ -947,13 +947,13 @@  discard block
 block discarded – undo
947 947
      */
948 948
     public function get_ee_capabilities(?string $role = EE_Capabilities::ROLE_ADMINISTRATOR): array
949 949
     {
950
-        if (! $this->initialized) {
950
+        if ( ! $this->initialized) {
951 951
             $this->init_caps();
952 952
         }
953 953
         if ($role === '') {
954 954
             return $this->capabilities_map;
955 955
         }
956
-        return $this->capabilities_map[ $role ] ?? [];
956
+        return $this->capabilities_map[$role] ?? [];
957 957
     }
958 958
 
959 959
 
@@ -983,7 +983,7 @@  discard block
 block discarded – undo
983 983
                         'event_espresso'
984 984
                     ),
985 985
                     '$reset',
986
-                    __METHOD__ . '()',
986
+                    __METHOD__.'()',
987 987
                     'EE_Capabilities::init_caps()',
988 988
                     'true'
989 989
                 ),
@@ -1071,7 +1071,7 @@  discard block
 block discarded – undo
1071 1071
                         'Incoming $map_values array should have a count of four values in it.  This is what was given: %s',
1072 1072
                         'event_espresso'
1073 1073
                     ),
1074
-                    '<br>' . print_r($map_values, true)
1074
+                    '<br>'.print_r($map_values, true)
1075 1075
                 )
1076 1076
             );
1077 1077
         }
@@ -1112,7 +1112,7 @@  discard block
 block discarded – undo
1112 1112
         // error proof if the name has EEM in it
1113 1113
         $this->_model_name = str_replace('EEM', '', $this->_model_name);
1114 1114
         $this->_model      = EE_Registry::instance()->load_model($this->_model_name);
1115
-        if (! $this->_model instanceof EEM_Base) {
1115
+        if ( ! $this->_model instanceof EEM_Base) {
1116 1116
             throw new EE_Error(
1117 1117
                 sprintf(
1118 1118
                     esc_html__(
@@ -1199,17 +1199,17 @@  discard block
 block discarded – undo
1199 1199
 
1200 1200
         // okay it is a meta cap so let's first remove that cap from the $caps array.
1201 1201
         if (($key = array_search($cap, $caps)) !== false) {
1202
-            unset($caps[ $key ]);
1202
+            unset($caps[$key]);
1203 1203
         }
1204 1204
 
1205 1205
         /** @var EE_Base_Class $obj */
1206 1206
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1207 1207
         // if no obj then let's just do cap
1208
-        if (! $obj instanceof EE_Base_Class) {
1208
+        if ( ! $obj instanceof EE_Base_Class) {
1209 1209
             $caps[] = 'do_not_allow';
1210 1210
             return $caps;
1211 1211
         }
1212
-        $caps[] = $cap . 's';
1212
+        $caps[] = $cap.'s';
1213 1213
         if ($obj instanceof EE_CPT_Base) {
1214 1214
             // if the item author is set and the user is the author...
1215 1215
             if ($obj->wp_user() && $user_id === $obj->wp_user()) {
@@ -1219,12 +1219,12 @@  discard block
 block discarded – undo
1219 1219
                 }
1220 1220
             } else {
1221 1221
                 // the user is trying to edit someone else's obj
1222
-                if (! empty($this->others_cap)) {
1222
+                if ( ! empty($this->others_cap)) {
1223 1223
                     $caps[] = $this->others_cap;
1224 1224
                 }
1225
-                if (! empty($this->published_cap) && $obj->status() === 'publish') {
1225
+                if ( ! empty($this->published_cap) && $obj->status() === 'publish') {
1226 1226
                     $caps[] = $this->published_cap;
1227
-                } elseif (! empty($this->private_cap) && $obj->status() === 'private') {
1227
+                } elseif ( ! empty($this->private_cap) && $obj->status() === 'private') {
1228 1228
                     $caps[] = $this->private_cap;
1229 1229
                 }
1230 1230
             }
@@ -1240,8 +1240,8 @@  discard block
 block discarded – undo
1240 1240
                     EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1241 1241
                 }
1242 1242
             }
1243
-            if (! $has_cap) {
1244
-                if (! empty($this->others_cap)) {
1243
+            if ( ! $has_cap) {
1244
+                if ( ! empty($this->others_cap)) {
1245 1245
                     $caps[] = $this->others_cap;
1246 1246
                 }
1247 1247
             }
@@ -1321,17 +1321,17 @@  discard block
 block discarded – undo
1321 1321
 
1322 1322
         // okay it is a meta cap so let's first remove that cap from the $caps array.
1323 1323
         if (($key = array_search($cap, $caps)) !== false) {
1324
-            unset($caps[ $key ]);
1324
+            unset($caps[$key]);
1325 1325
         }
1326 1326
 
1327 1327
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1328 1328
         // if no obj then let's just do cap
1329
-        if (! $obj instanceof EE_Base_Class) {
1329
+        if ( ! $obj instanceof EE_Base_Class) {
1330 1330
             $caps[] = 'do_not_allow';
1331 1331
             return $caps;
1332 1332
         }
1333 1333
 
1334
-        $caps[] = $cap . 's';
1334
+        $caps[] = $cap.'s';
1335 1335
         if ($obj instanceof EE_CPT_Base) {
1336 1336
             $status_obj = get_post_status_object($obj->status());
1337 1337
             if ($status_obj->public) {
@@ -1339,7 +1339,7 @@  discard block
 block discarded – undo
1339 1339
             }
1340 1340
             // if the item author is set and the user is not the author...
1341 1341
             if ($obj->wp_user() && $obj->wp_user() !== $user_id) {
1342
-                if (! empty($this->others_cap)) {
1342
+                if ( ! empty($this->others_cap)) {
1343 1343
                     $caps[] = $this->others_cap;
1344 1344
                 }
1345 1345
             }
@@ -1364,11 +1364,11 @@  discard block
 block discarded – undo
1364 1364
                     EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1365 1365
                 }
1366 1366
             }
1367
-            if (! $has_cap) {
1368
-                if (! empty($this->private_cap)) {
1367
+            if ( ! $has_cap) {
1368
+                if ( ! empty($this->private_cap)) {
1369 1369
                     $caps[] = $this->private_cap;
1370 1370
                 }
1371
-                if (! empty($this->others_cap)) {
1371
+                if ( ! empty($this->others_cap)) {
1372 1372
                     $caps[] = $this->others_cap;
1373 1373
                 }
1374 1374
             }
@@ -1415,16 +1415,16 @@  discard block
 block discarded – undo
1415 1415
 
1416 1416
         // okay it is a meta cap so let's first remove that cap from the $caps array.
1417 1417
         if (($key = array_search($cap, $caps)) !== false) {
1418
-            unset($caps[ $key ]);
1418
+            unset($caps[$key]);
1419 1419
         }
1420 1420
 
1421 1421
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1422 1422
         // if no obj then let's just do cap
1423
-        if (! $obj instanceof EE_Message_Template_Group) {
1423
+        if ( ! $obj instanceof EE_Message_Template_Group) {
1424 1424
             $caps[] = 'do_not_allow';
1425 1425
             return $caps;
1426 1426
         }
1427
-        $caps[]    = $cap . 's';
1427
+        $caps[]    = $cap.'s';
1428 1428
         $is_global = $obj->is_global();
1429 1429
         if ($obj->wp_user() && $obj->wp_user() === $user_id) {
1430 1430
             if ($is_global) {
@@ -1476,15 +1476,15 @@  discard block
 block discarded – undo
1476 1476
         }
1477 1477
         // okay it is a meta cap so let's first remove that cap from the $caps array.
1478 1478
         if (($key = array_search($cap, $caps)) !== false) {
1479
-            unset($caps[ $key ]);
1479
+            unset($caps[$key]);
1480 1480
         }
1481 1481
         $obj = ! empty($args[0]) ? $this->_model->get_one_by_ID($args[0]) : null;
1482 1482
         // if no obj then let's just do cap
1483
-        if (! $obj instanceof EE_Base_Class) {
1483
+        if ( ! $obj instanceof EE_Base_Class) {
1484 1484
             $caps[] = 'do_not_allow';
1485 1485
             return $caps;
1486 1486
         }
1487
-        $caps[]    = $cap . 's';
1487
+        $caps[]    = $cap.'s';
1488 1488
         $is_system = $obj instanceof EE_Question_Group ? $obj->system_group() : false;
1489 1489
         $is_system = $obj instanceof EE_Question ? $obj->is_system_question() : $is_system;
1490 1490
         if ($is_system) {
Please login to merge, or discard this patch.
core/services/admin/AdminListTableFilters.php 2 patches
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -11,67 +11,67 @@  discard block
 block discarded – undo
11 11
  */
12 12
 class AdminListTableFilters
13 13
 {
14
-    /**
15
-     * @var RequestInterface
16
-     */
17
-    protected RequestInterface $request;
18
-
19
-    protected string           $search_term;
20
-
21
-    protected ?string          $orderby;
22
-
23
-    protected ?string          $order;
24
-
25
-    protected ?string          $detached;
26
-
27
-    protected ?string          $post_mime_type;
28
-
29
-
30
-    public function __construct(RequestInterface $request)
31
-    {
32
-        $this->request = $request;
33
-    }
34
-
35
-
36
-    /**
37
-     * Sets the parameters from request
38
-     *
39
-     * @return void
40
-     */
41
-    private function setRequestParams(): void
42
-    {
43
-        $this->search_term    = $this->request->getRequestParam('s', '');
44
-        $this->orderby        = $this->request->getRequestParam('orderby');
45
-        $this->order          = $this->request->getRequestParam('order');
46
-        $this->post_mime_type = $this->request->getRequestParam('post_mime_type');
47
-        $this->detached       = $this->request->getRequestParam('detached');
48
-    }
49
-
50
-
51
-    /**
52
-     * Displays the search box with reset button
53
-     *
54
-     * @param string $text     The 'submit' button label.
55
-     * @param string $input_id ID attribute value for the search input field.
56
-     * @param string $url      Reset URL
57
-     * @return void
58
-     */
59
-    public function searchBox(string $text, string $input_id, string $url): void
60
-    {
61
-        $this->setRequestParams();
62
-        if (! empty($this->orderby)) {
63
-            echo '<input type="hidden" name="orderby" value="' . esc_attr($this->orderby) . '" />';
64
-        }
65
-        if (! empty($this->order)) {
66
-            echo '<input type="hidden" name="order" value="' . esc_attr($this->order) . '" />';
67
-        }
68
-        if (! empty($this->post_mime_type)) {
69
-            echo '<input type="hidden" name="post_mime_type" value="' . esc_attr($this->post_mime_type) . '" />';
70
-        }
71
-        if (! empty($this->detached)) {
72
-            echo '<input type="hidden" name="detached" value="' . esc_attr($this->detached) . '" />';
73
-        }
74
-        ?>
14
+	/**
15
+	 * @var RequestInterface
16
+	 */
17
+	protected RequestInterface $request;
18
+
19
+	protected string           $search_term;
20
+
21
+	protected ?string          $orderby;
22
+
23
+	protected ?string          $order;
24
+
25
+	protected ?string          $detached;
26
+
27
+	protected ?string          $post_mime_type;
28
+
29
+
30
+	public function __construct(RequestInterface $request)
31
+	{
32
+		$this->request = $request;
33
+	}
34
+
35
+
36
+	/**
37
+	 * Sets the parameters from request
38
+	 *
39
+	 * @return void
40
+	 */
41
+	private function setRequestParams(): void
42
+	{
43
+		$this->search_term    = $this->request->getRequestParam('s', '');
44
+		$this->orderby        = $this->request->getRequestParam('orderby');
45
+		$this->order          = $this->request->getRequestParam('order');
46
+		$this->post_mime_type = $this->request->getRequestParam('post_mime_type');
47
+		$this->detached       = $this->request->getRequestParam('detached');
48
+	}
49
+
50
+
51
+	/**
52
+	 * Displays the search box with reset button
53
+	 *
54
+	 * @param string $text     The 'submit' button label.
55
+	 * @param string $input_id ID attribute value for the search input field.
56
+	 * @param string $url      Reset URL
57
+	 * @return void
58
+	 */
59
+	public function searchBox(string $text, string $input_id, string $url): void
60
+	{
61
+		$this->setRequestParams();
62
+		if (! empty($this->orderby)) {
63
+			echo '<input type="hidden" name="orderby" value="' . esc_attr($this->orderby) . '" />';
64
+		}
65
+		if (! empty($this->order)) {
66
+			echo '<input type="hidden" name="order" value="' . esc_attr($this->order) . '" />';
67
+		}
68
+		if (! empty($this->post_mime_type)) {
69
+			echo '<input type="hidden" name="post_mime_type" value="' . esc_attr($this->post_mime_type) . '" />';
70
+		}
71
+		if (! empty($this->detached)) {
72
+			echo '<input type="hidden" name="detached" value="' . esc_attr($this->detached) . '" />';
73
+		}
74
+		?>
75 75
         <p class="search-box">
76 76
             <label class="screen-reader-text" for="<?php echo esc_attr($input_id); ?>"><?php echo $text; ?>:</label>
77 77
             <input type="search"
@@ -81,36 +81,36 @@  discard block
 block discarded – undo
81 81
             />
82 82
             <?php submit_button($text, '', '', false, ['id' => 'search-submit']); ?>
83 83
             <?php
84
-            if (! empty($this->search_term)) {
85
-                echo wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags());
86
-            }
87
-            ?>
84
+			if (! empty($this->search_term)) {
85
+				echo wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags());
86
+			}
87
+			?>
88 88
         </p>
89 89
         <?php
90
-    }
91
-
92
-
93
-    /**
94
-     * filters
95
-     * This receives the filters array from children _get_table_filters() and assembles the string including the filter
96
-     * button.
97
-     *
98
-     * @param string[] $filters
99
-     * @param string   $url Reset URL
100
-     * @return void  echos html showing filters
101
-     */
102
-    public function filters(array $filters, string $url): void
103
-    {
104
-        $use_filters = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
105
-        $use_filters = $use_filters ? 'yes' : 'no';
106
-
107
-        $filters_html = '';
108
-        foreach ($filters as $filter) {
109
-            $filters_html .= wp_kses($filter, AllowedTags::getWithFormTags());
110
-        }
111
-        $filter_submit_btn_text = esc_html__('Filter', 'event_espresso');
112
-
113
-        echo "
90
+	}
91
+
92
+
93
+	/**
94
+	 * filters
95
+	 * This receives the filters array from children _get_table_filters() and assembles the string including the filter
96
+	 * button.
97
+	 *
98
+	 * @param string[] $filters
99
+	 * @param string   $url Reset URL
100
+	 * @return void  echos html showing filters
101
+	 */
102
+	public function filters(array $filters, string $url): void
103
+	{
104
+		$use_filters = $this->request->getRequestParam('use_filters', false, DataType::BOOL);
105
+		$use_filters = $use_filters ? 'yes' : 'no';
106
+
107
+		$filters_html = '';
108
+		foreach ($filters as $filter) {
109
+			$filters_html .= wp_kses($filter, AllowedTags::getWithFormTags());
110
+		}
111
+		$filter_submit_btn_text = esc_html__('Filter', 'event_espresso');
112
+
113
+		echo "
114 114
         <div class='ee-list-table-filters actions alignleft'>
115 115
            $filters_html
116 116
             <span class='ee-list-table-filters__submit-buttons'>
@@ -123,20 +123,20 @@  discard block
 block discarded – undo
123 123
                 " . wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags()) . "
124 124
             </span>
125 125
         </div>";
126
-    }
126
+	}
127 127
 
128 128
 
129
-    /**
130
-     * @param string $url Reset URL
131
-     * @return string
132
-     */
133
-    private function generateResetButton(string $url): string
134
-    {
135
-        return '<a class="ee-aria-tooltip button button--icon-only"
129
+	/**
130
+	 * @param string $url Reset URL
131
+	 * @return string
132
+	 */
133
+	private function generateResetButton(string $url): string
134
+	{
135
+		return '<a class="ee-aria-tooltip button button--icon-only"
136 136
             href="' . esc_url_raw($url) . '"
137 137
             aria-label="' . esc_attr__('Reset Filters', 'event_espresso') . '"
138 138
         >
139 139
             <span class="dashicons dashicons-update"></span>
140 140
         </a>';
141
-    }
141
+	}
142 142
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -59,17 +59,17 @@  discard block
 block discarded – undo
59 59
     public function searchBox(string $text, string $input_id, string $url): void
60 60
     {
61 61
         $this->setRequestParams();
62
-        if (! empty($this->orderby)) {
63
-            echo '<input type="hidden" name="orderby" value="' . esc_attr($this->orderby) . '" />';
62
+        if ( ! empty($this->orderby)) {
63
+            echo '<input type="hidden" name="orderby" value="'.esc_attr($this->orderby).'" />';
64 64
         }
65
-        if (! empty($this->order)) {
66
-            echo '<input type="hidden" name="order" value="' . esc_attr($this->order) . '" />';
65
+        if ( ! empty($this->order)) {
66
+            echo '<input type="hidden" name="order" value="'.esc_attr($this->order).'" />';
67 67
         }
68
-        if (! empty($this->post_mime_type)) {
69
-            echo '<input type="hidden" name="post_mime_type" value="' . esc_attr($this->post_mime_type) . '" />';
68
+        if ( ! empty($this->post_mime_type)) {
69
+            echo '<input type="hidden" name="post_mime_type" value="'.esc_attr($this->post_mime_type).'" />';
70 70
         }
71
-        if (! empty($this->detached)) {
72
-            echo '<input type="hidden" name="detached" value="' . esc_attr($this->detached) . '" />';
71
+        if ( ! empty($this->detached)) {
72
+            echo '<input type="hidden" name="detached" value="'.esc_attr($this->detached).'" />';
73 73
         }
74 74
         ?>
75 75
         <p class="search-box">
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
             />
82 82
             <?php submit_button($text, '', '', false, ['id' => 'search-submit']); ?>
83 83
             <?php
84
-            if (! empty($this->search_term)) {
84
+            if ( ! empty($this->search_term)) {
85 85
                 echo wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags());
86 86
             }
87 87
             ?>
@@ -120,7 +120,7 @@  discard block
 block discarded – undo
120 120
                        value='$filter_submit_btn_text'
121 121
                 />
122 122
                 <input type='hidden' id='ee-list-table-use-filters' name='use_filters' value='$use_filters' />
123
-                " . wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags()) . "
123
+                ".wp_kses($this->generateResetButton($url), AllowedTags::getAllowedTags())."
124 124
             </span>
125 125
         </div>";
126 126
     }
@@ -133,8 +133,8 @@  discard block
 block discarded – undo
133 133
     private function generateResetButton(string $url): string
134 134
     {
135 135
         return '<a class="ee-aria-tooltip button button--icon-only"
136
-            href="' . esc_url_raw($url) . '"
137
-            aria-label="' . esc_attr__('Reset Filters', 'event_espresso') . '"
136
+            href="' . esc_url_raw($url).'"
137
+            aria-label="' . esc_attr__('Reset Filters', 'event_espresso').'"
138 138
         >
139 139
             <span class="dashicons dashicons-update"></span>
140 140
         </a>';
Please login to merge, or discard this patch.
core/services/request/CurrentPage.php 2 patches
Indentation   +316 added lines, -316 removed lines patch added patch discarded remove patch
@@ -23,320 +23,320 @@
 block discarded – undo
23 23
  */
24 24
 class CurrentPage
25 25
 {
26
-    /**
27
-     * @var EE_CPT_Strategy
28
-     */
29
-    private $cpt_strategy;
30
-
31
-    /**
32
-     * @var bool
33
-     */
34
-    private $initialized;
35
-
36
-    /**
37
-     * @var bool
38
-     */
39
-    private $is_espresso_page;
40
-
41
-    /**
42
-     * @var int
43
-     */
44
-    private $post_id = 0;
45
-
46
-    /**
47
-     * @var string
48
-     */
49
-    private $post_name = '';
50
-
51
-    /**
52
-     * @var array
53
-     */
54
-    private $post_type = [];
55
-
56
-    /**
57
-     * @var RequestInterface $request
58
-     */
59
-    private $request;
60
-
61
-
62
-    /**
63
-     * CurrentPage constructor.
64
-     *
65
-     * @param EE_CPT_Strategy  $cpt_strategy
66
-     * @param RequestInterface $request
67
-     */
68
-    public function __construct(EE_CPT_Strategy $cpt_strategy, RequestInterface $request)
69
-    {
70
-        $this->cpt_strategy = $cpt_strategy;
71
-        $this->request      = $request;
72
-        $this->initialized  = is_admin();
73
-        // analyse the incoming WP request
74
-        add_action('parse_request', [$this, 'parseQueryVars'], 2, 1);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param WP|null $WP
80
-     * @return void
81
-     */
82
-    public function parseQueryVars(WP $WP = null)
83
-    {
84
-        if ($this->initialized) {
85
-            return;
86
-        }
87
-        // if somebody forgot to provide us with WP, that's ok because its global
88
-        if (! $WP instanceof WP) {
89
-            global $WP;
90
-        }
91
-        $this->post_id   = $this->getPostId($WP);
92
-        $this->post_name = $this->getPostName($WP);
93
-        $this->post_type = $this->getPostType($WP);
94
-        // true or false ? is this page being used by EE ?
95
-        $this->setEspressoPage();
96
-        remove_action('parse_request', [$this, 'parseRequest'], 2);
97
-        $this->initialized = true;
98
-    }
99
-
100
-
101
-    /**
102
-     * Just a helper method for getting the url for the displayed page.
103
-     *
104
-     * @param WP|null $WP
105
-     * @return string
106
-     */
107
-    public function getPermalink(WP $WP = null): string
108
-    {
109
-        $post_id = $this->post_id ?: $this->getPostId($WP);
110
-        if ($post_id) {
111
-            return get_permalink($post_id);
112
-        }
113
-        if (! $WP instanceof WP) {
114
-            global $WP;
115
-        }
116
-        if ($WP instanceof WP && $WP->request) {
117
-            return site_url($WP->request);
118
-        }
119
-        return esc_url_raw(site_url($_SERVER['REQUEST_URI']));
120
-    }
121
-
122
-
123
-    /**
124
-     * @return array
125
-     */
126
-    public function espressoPostType(): array
127
-    {
128
-        return array_filter(
129
-            $this->post_type,
130
-            function ($post_type) {
131
-                return strpos($post_type, 'espresso_') === 0;
132
-            }
133
-        );
134
-    }
135
-
136
-
137
-    /**
138
-     * pokes and prods the WP object query_vars in an attempt to shake out a page/post ID
139
-     *
140
-     * @param WP|null $WP $WP
141
-     * @return int
142
-     */
143
-    private function getPostId(WP $WP = null): ?int
144
-    {
145
-        $post_id = 0;
146
-        if ($WP instanceof WP) {
147
-            // look for the post ID in the aptly named 'p' query var
148
-            if (isset($WP->query_vars['p'])) {
149
-                $post_id = $WP->query_vars['p'];
150
-            }
151
-            // not a post? what about a page?
152
-            if (! $post_id && isset($WP->query_vars['page_id'])) {
153
-                $post_id = $WP->query_vars['page_id'];
154
-            }
155
-            // ok... maybe pretty permalinks are off and the ID is set in the raw request...
156
-            // but hasn't been processed yet ie: this method is being called too early :\
157
-            if (! $post_id && $WP->request !== null && is_numeric(basename($WP->request))) {
158
-                $post_id = basename($WP->request);
159
-            }
160
-        }
161
-        // none of the above? ok what about an explicit "post_id" URL parameter?
162
-        if (! $post_id && $this->request->requestParamIsSet('post_id')) {
163
-            $post_id = $this->request->getRequestParam('post_id', 0, DataType::INT);
164
-        }
165
-        return (int) $post_id;
166
-    }
167
-
168
-
169
-    /**
170
-     * similar to getPostId() above but attempts to obtain the "name" for the current page/post
171
-     *
172
-     * @param WP|null $WP $WP
173
-     * @return string|null
174
-     */
175
-    private function getPostName(WP $WP = null): ?string
176
-    {
177
-        global $wpdb;
178
-        $post_name = '';
179
-        if ($WP instanceof WP) {
180
-            // if this is a post, then is the post name set?
181
-            if (isset($WP->query_vars['name']) && ! empty($WP->query_vars['name'])) {
182
-                $post_name = is_array($WP->query_vars['name']) ? $WP->query_vars['name'][0] : $WP->query_vars['name'];
183
-            }
184
-            // what about the page name?
185
-            if (! $post_name && isset($WP->query_vars['pagename']) && ! empty($WP->query_vars['pagename'])) {
186
-                $post_name = is_array($WP->query_vars['pagename']) ? $WP->query_vars['pagename'][0]
187
-                    : $WP->query_vars['pagename'];
188
-            }
189
-            // this stinks but let's run a query to try and get the post name from the URL
190
-            // (assuming pretty permalinks are on)
191
-            if (! $post_name && ! empty($WP->request)) {
192
-                $possible_post_name = basename($WP->request);
193
-                if (! is_numeric($possible_post_name)) {
194
-                    $SQL                = "SELECT ID from {$wpdb->posts}";
195
-                    $SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
196
-                    $SQL                .= ' AND post_name=%s';
197
-                    $possible_post_name = $wpdb->get_var($wpdb->prepare($SQL, $possible_post_name));
198
-                    if ($possible_post_name) {
199
-                        $post_name = $possible_post_name;
200
-                    }
201
-                }
202
-            }
203
-        }
204
-        // ug... ok... nothing yet... but do we have a post ID?
205
-        // if so then... sigh... run a query to get the post name :\
206
-        if (! $post_name && $this->post_id) {
207
-            $SQL                = "SELECT post_name from {$wpdb->posts}";
208
-            $SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
209
-            $SQL                .= ' AND ID=%d';
210
-            $possible_post_name = $wpdb->get_var($wpdb->prepare($SQL, $this->post_id));
211
-            if ($possible_post_name) {
212
-                $post_name = $possible_post_name;
213
-            }
214
-        }
215
-        // still nothing? ok what about an explicit 'post_name' URL parameter?
216
-        if (! $post_name && $this->request->requestParamIsSet('post_name')) {
217
-            $post_name = $this->request->getRequestParam('post_name');
218
-        }
219
-        return $post_name;
220
-    }
221
-
222
-
223
-    /**
224
-     * also similar to getPostId() and getPostName() above but not as insane
225
-     *
226
-     * @param WP|null $WP $WP
227
-     * @return array
228
-     */
229
-    private function getPostType(WP $WP = null): array
230
-    {
231
-        $post_types = [];
232
-        if ($WP instanceof WP) {
233
-            $post_types = isset($WP->query_vars['post_type'])
234
-                ? (array) $WP->query_vars['post_type']
235
-                : [];
236
-        }
237
-        if (empty($post_types) && $this->request->requestParamIsSet('post_type')) {
238
-            $post_types = $this->request->getRequestParam('post_type', [], DataType::STRING, true);
239
-        }
240
-        return (array) $post_types;
241
-    }
242
-
243
-
244
-    /**
245
-     * if TRUE, then the current page is somehow utilizing EE logic
246
-     *
247
-     * @return bool
248
-     */
249
-    public function isEspressoPage(): bool
250
-    {
251
-        if ($this->is_espresso_page === null) {
252
-            $this->setEspressoPage();
253
-        }
254
-        return $this->is_espresso_page;
255
-    }
256
-
257
-
258
-    /**
259
-     * @return int
260
-     */
261
-    public function postId(): int
262
-    {
263
-        return $this->post_id;
264
-    }
265
-
266
-
267
-    /**
268
-     * @return string
269
-     */
270
-    public function postName(): string
271
-    {
272
-        return $this->post_name;
273
-    }
274
-
275
-
276
-    /**
277
-     * @return array
278
-     */
279
-    public function postType(): array
280
-    {
281
-        return $this->post_type;
282
-    }
283
-
284
-
285
-    /**
286
-     * for manually indicating the current page will utilize EE logic
287
-     *
288
-     * @param bool|int|string|null $value
289
-     * @return void
290
-     */
291
-    public function setEspressoPage($value = null)
292
-    {
293
-        $this->is_espresso_page = $value !== null
294
-            ? filter_var($value, FILTER_VALIDATE_BOOLEAN)
295
-            : $this->testForEspressoPage();
296
-    }
297
-
298
-
299
-    /**
300
-     * attempts to determine if the current page/post is an EE related page/post
301
-     * because it utilizes one of our CPT taxonomies, endpoints, or post types
302
-     *
303
-     * @return bool
304
-     */
305
-    private function testForEspressoPage(): bool
306
-    {
307
-        // in case it has already been set
308
-        if ($this->is_espresso_page) {
309
-            return true;
310
-        }
311
-        global $WP;
312
-        $espresso_CPT_taxonomies = $this->cpt_strategy->get_CPT_taxonomies();
313
-        if (is_array($espresso_CPT_taxonomies)) {
314
-            foreach ($espresso_CPT_taxonomies as $espresso_CPT_taxonomy => $details) {
315
-                if (isset($WP->query_vars, $WP->query_vars[ $espresso_CPT_taxonomy ])) {
316
-                    return true;
317
-                }
318
-            }
319
-        }
320
-        // load espresso CPT endpoints
321
-        $espresso_CPT_endpoints  = $this->cpt_strategy->get_CPT_endpoints();
322
-        $post_type_CPT_endpoints = array_flip($espresso_CPT_endpoints);
323
-        foreach ($this->post_type as $post_type) {
324
-            // was a post name passed ?
325
-            if (isset($post_type_CPT_endpoints[ $post_type ])) {
326
-                // kk we know this is an espresso page, but is it a specific post ?
327
-                if (! $this->post_name) {
328
-                    $espresso_post_type = $this->request->getRequestParam('post_type');
329
-                    // there's no specific post name set, so maybe it's one of our endpoints like www.domain.com/events
330
-                    // this essentially sets the post_name to "events" (or whatever EE CPT)
331
-                    $post_name = $post_type_CPT_endpoints[ $espresso_post_type ] ?? '';
332
-                    // if the post type matches one of ours then set the post name to the endpoint
333
-                    if ($post_name) {
334
-                        $this->post_name = $post_name;
335
-                    }
336
-                }
337
-                return true;
338
-            }
339
-        }
340
-        return false;
341
-    }
26
+	/**
27
+	 * @var EE_CPT_Strategy
28
+	 */
29
+	private $cpt_strategy;
30
+
31
+	/**
32
+	 * @var bool
33
+	 */
34
+	private $initialized;
35
+
36
+	/**
37
+	 * @var bool
38
+	 */
39
+	private $is_espresso_page;
40
+
41
+	/**
42
+	 * @var int
43
+	 */
44
+	private $post_id = 0;
45
+
46
+	/**
47
+	 * @var string
48
+	 */
49
+	private $post_name = '';
50
+
51
+	/**
52
+	 * @var array
53
+	 */
54
+	private $post_type = [];
55
+
56
+	/**
57
+	 * @var RequestInterface $request
58
+	 */
59
+	private $request;
60
+
61
+
62
+	/**
63
+	 * CurrentPage constructor.
64
+	 *
65
+	 * @param EE_CPT_Strategy  $cpt_strategy
66
+	 * @param RequestInterface $request
67
+	 */
68
+	public function __construct(EE_CPT_Strategy $cpt_strategy, RequestInterface $request)
69
+	{
70
+		$this->cpt_strategy = $cpt_strategy;
71
+		$this->request      = $request;
72
+		$this->initialized  = is_admin();
73
+		// analyse the incoming WP request
74
+		add_action('parse_request', [$this, 'parseQueryVars'], 2, 1);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param WP|null $WP
80
+	 * @return void
81
+	 */
82
+	public function parseQueryVars(WP $WP = null)
83
+	{
84
+		if ($this->initialized) {
85
+			return;
86
+		}
87
+		// if somebody forgot to provide us with WP, that's ok because its global
88
+		if (! $WP instanceof WP) {
89
+			global $WP;
90
+		}
91
+		$this->post_id   = $this->getPostId($WP);
92
+		$this->post_name = $this->getPostName($WP);
93
+		$this->post_type = $this->getPostType($WP);
94
+		// true or false ? is this page being used by EE ?
95
+		$this->setEspressoPage();
96
+		remove_action('parse_request', [$this, 'parseRequest'], 2);
97
+		$this->initialized = true;
98
+	}
99
+
100
+
101
+	/**
102
+	 * Just a helper method for getting the url for the displayed page.
103
+	 *
104
+	 * @param WP|null $WP
105
+	 * @return string
106
+	 */
107
+	public function getPermalink(WP $WP = null): string
108
+	{
109
+		$post_id = $this->post_id ?: $this->getPostId($WP);
110
+		if ($post_id) {
111
+			return get_permalink($post_id);
112
+		}
113
+		if (! $WP instanceof WP) {
114
+			global $WP;
115
+		}
116
+		if ($WP instanceof WP && $WP->request) {
117
+			return site_url($WP->request);
118
+		}
119
+		return esc_url_raw(site_url($_SERVER['REQUEST_URI']));
120
+	}
121
+
122
+
123
+	/**
124
+	 * @return array
125
+	 */
126
+	public function espressoPostType(): array
127
+	{
128
+		return array_filter(
129
+			$this->post_type,
130
+			function ($post_type) {
131
+				return strpos($post_type, 'espresso_') === 0;
132
+			}
133
+		);
134
+	}
135
+
136
+
137
+	/**
138
+	 * pokes and prods the WP object query_vars in an attempt to shake out a page/post ID
139
+	 *
140
+	 * @param WP|null $WP $WP
141
+	 * @return int
142
+	 */
143
+	private function getPostId(WP $WP = null): ?int
144
+	{
145
+		$post_id = 0;
146
+		if ($WP instanceof WP) {
147
+			// look for the post ID in the aptly named 'p' query var
148
+			if (isset($WP->query_vars['p'])) {
149
+				$post_id = $WP->query_vars['p'];
150
+			}
151
+			// not a post? what about a page?
152
+			if (! $post_id && isset($WP->query_vars['page_id'])) {
153
+				$post_id = $WP->query_vars['page_id'];
154
+			}
155
+			// ok... maybe pretty permalinks are off and the ID is set in the raw request...
156
+			// but hasn't been processed yet ie: this method is being called too early :\
157
+			if (! $post_id && $WP->request !== null && is_numeric(basename($WP->request))) {
158
+				$post_id = basename($WP->request);
159
+			}
160
+		}
161
+		// none of the above? ok what about an explicit "post_id" URL parameter?
162
+		if (! $post_id && $this->request->requestParamIsSet('post_id')) {
163
+			$post_id = $this->request->getRequestParam('post_id', 0, DataType::INT);
164
+		}
165
+		return (int) $post_id;
166
+	}
167
+
168
+
169
+	/**
170
+	 * similar to getPostId() above but attempts to obtain the "name" for the current page/post
171
+	 *
172
+	 * @param WP|null $WP $WP
173
+	 * @return string|null
174
+	 */
175
+	private function getPostName(WP $WP = null): ?string
176
+	{
177
+		global $wpdb;
178
+		$post_name = '';
179
+		if ($WP instanceof WP) {
180
+			// if this is a post, then is the post name set?
181
+			if (isset($WP->query_vars['name']) && ! empty($WP->query_vars['name'])) {
182
+				$post_name = is_array($WP->query_vars['name']) ? $WP->query_vars['name'][0] : $WP->query_vars['name'];
183
+			}
184
+			// what about the page name?
185
+			if (! $post_name && isset($WP->query_vars['pagename']) && ! empty($WP->query_vars['pagename'])) {
186
+				$post_name = is_array($WP->query_vars['pagename']) ? $WP->query_vars['pagename'][0]
187
+					: $WP->query_vars['pagename'];
188
+			}
189
+			// this stinks but let's run a query to try and get the post name from the URL
190
+			// (assuming pretty permalinks are on)
191
+			if (! $post_name && ! empty($WP->request)) {
192
+				$possible_post_name = basename($WP->request);
193
+				if (! is_numeric($possible_post_name)) {
194
+					$SQL                = "SELECT ID from {$wpdb->posts}";
195
+					$SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
196
+					$SQL                .= ' AND post_name=%s';
197
+					$possible_post_name = $wpdb->get_var($wpdb->prepare($SQL, $possible_post_name));
198
+					if ($possible_post_name) {
199
+						$post_name = $possible_post_name;
200
+					}
201
+				}
202
+			}
203
+		}
204
+		// ug... ok... nothing yet... but do we have a post ID?
205
+		// if so then... sigh... run a query to get the post name :\
206
+		if (! $post_name && $this->post_id) {
207
+			$SQL                = "SELECT post_name from {$wpdb->posts}";
208
+			$SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
209
+			$SQL                .= ' AND ID=%d';
210
+			$possible_post_name = $wpdb->get_var($wpdb->prepare($SQL, $this->post_id));
211
+			if ($possible_post_name) {
212
+				$post_name = $possible_post_name;
213
+			}
214
+		}
215
+		// still nothing? ok what about an explicit 'post_name' URL parameter?
216
+		if (! $post_name && $this->request->requestParamIsSet('post_name')) {
217
+			$post_name = $this->request->getRequestParam('post_name');
218
+		}
219
+		return $post_name;
220
+	}
221
+
222
+
223
+	/**
224
+	 * also similar to getPostId() and getPostName() above but not as insane
225
+	 *
226
+	 * @param WP|null $WP $WP
227
+	 * @return array
228
+	 */
229
+	private function getPostType(WP $WP = null): array
230
+	{
231
+		$post_types = [];
232
+		if ($WP instanceof WP) {
233
+			$post_types = isset($WP->query_vars['post_type'])
234
+				? (array) $WP->query_vars['post_type']
235
+				: [];
236
+		}
237
+		if (empty($post_types) && $this->request->requestParamIsSet('post_type')) {
238
+			$post_types = $this->request->getRequestParam('post_type', [], DataType::STRING, true);
239
+		}
240
+		return (array) $post_types;
241
+	}
242
+
243
+
244
+	/**
245
+	 * if TRUE, then the current page is somehow utilizing EE logic
246
+	 *
247
+	 * @return bool
248
+	 */
249
+	public function isEspressoPage(): bool
250
+	{
251
+		if ($this->is_espresso_page === null) {
252
+			$this->setEspressoPage();
253
+		}
254
+		return $this->is_espresso_page;
255
+	}
256
+
257
+
258
+	/**
259
+	 * @return int
260
+	 */
261
+	public function postId(): int
262
+	{
263
+		return $this->post_id;
264
+	}
265
+
266
+
267
+	/**
268
+	 * @return string
269
+	 */
270
+	public function postName(): string
271
+	{
272
+		return $this->post_name;
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return array
278
+	 */
279
+	public function postType(): array
280
+	{
281
+		return $this->post_type;
282
+	}
283
+
284
+
285
+	/**
286
+	 * for manually indicating the current page will utilize EE logic
287
+	 *
288
+	 * @param bool|int|string|null $value
289
+	 * @return void
290
+	 */
291
+	public function setEspressoPage($value = null)
292
+	{
293
+		$this->is_espresso_page = $value !== null
294
+			? filter_var($value, FILTER_VALIDATE_BOOLEAN)
295
+			: $this->testForEspressoPage();
296
+	}
297
+
298
+
299
+	/**
300
+	 * attempts to determine if the current page/post is an EE related page/post
301
+	 * because it utilizes one of our CPT taxonomies, endpoints, or post types
302
+	 *
303
+	 * @return bool
304
+	 */
305
+	private function testForEspressoPage(): bool
306
+	{
307
+		// in case it has already been set
308
+		if ($this->is_espresso_page) {
309
+			return true;
310
+		}
311
+		global $WP;
312
+		$espresso_CPT_taxonomies = $this->cpt_strategy->get_CPT_taxonomies();
313
+		if (is_array($espresso_CPT_taxonomies)) {
314
+			foreach ($espresso_CPT_taxonomies as $espresso_CPT_taxonomy => $details) {
315
+				if (isset($WP->query_vars, $WP->query_vars[ $espresso_CPT_taxonomy ])) {
316
+					return true;
317
+				}
318
+			}
319
+		}
320
+		// load espresso CPT endpoints
321
+		$espresso_CPT_endpoints  = $this->cpt_strategy->get_CPT_endpoints();
322
+		$post_type_CPT_endpoints = array_flip($espresso_CPT_endpoints);
323
+		foreach ($this->post_type as $post_type) {
324
+			// was a post name passed ?
325
+			if (isset($post_type_CPT_endpoints[ $post_type ])) {
326
+				// kk we know this is an espresso page, but is it a specific post ?
327
+				if (! $this->post_name) {
328
+					$espresso_post_type = $this->request->getRequestParam('post_type');
329
+					// there's no specific post name set, so maybe it's one of our endpoints like www.domain.com/events
330
+					// this essentially sets the post_name to "events" (or whatever EE CPT)
331
+					$post_name = $post_type_CPT_endpoints[ $espresso_post_type ] ?? '';
332
+					// if the post type matches one of ours then set the post name to the endpoint
333
+					if ($post_name) {
334
+						$this->post_name = $post_name;
335
+					}
336
+				}
337
+				return true;
338
+			}
339
+		}
340
+		return false;
341
+	}
342 342
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -85,7 +85,7 @@  discard block
 block discarded – undo
85 85
             return;
86 86
         }
87 87
         // if somebody forgot to provide us with WP, that's ok because its global
88
-        if (! $WP instanceof WP) {
88
+        if ( ! $WP instanceof WP) {
89 89
             global $WP;
90 90
         }
91 91
         $this->post_id   = $this->getPostId($WP);
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
         if ($post_id) {
111 111
             return get_permalink($post_id);
112 112
         }
113
-        if (! $WP instanceof WP) {
113
+        if ( ! $WP instanceof WP) {
114 114
             global $WP;
115 115
         }
116 116
         if ($WP instanceof WP && $WP->request) {
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
     {
128 128
         return array_filter(
129 129
             $this->post_type,
130
-            function ($post_type) {
130
+            function($post_type) {
131 131
                 return strpos($post_type, 'espresso_') === 0;
132 132
             }
133 133
         );
@@ -149,17 +149,17 @@  discard block
 block discarded – undo
149 149
                 $post_id = $WP->query_vars['p'];
150 150
             }
151 151
             // not a post? what about a page?
152
-            if (! $post_id && isset($WP->query_vars['page_id'])) {
152
+            if ( ! $post_id && isset($WP->query_vars['page_id'])) {
153 153
                 $post_id = $WP->query_vars['page_id'];
154 154
             }
155 155
             // ok... maybe pretty permalinks are off and the ID is set in the raw request...
156 156
             // but hasn't been processed yet ie: this method is being called too early :\
157
-            if (! $post_id && $WP->request !== null && is_numeric(basename($WP->request))) {
157
+            if ( ! $post_id && $WP->request !== null && is_numeric(basename($WP->request))) {
158 158
                 $post_id = basename($WP->request);
159 159
             }
160 160
         }
161 161
         // none of the above? ok what about an explicit "post_id" URL parameter?
162
-        if (! $post_id && $this->request->requestParamIsSet('post_id')) {
162
+        if ( ! $post_id && $this->request->requestParamIsSet('post_id')) {
163 163
             $post_id = $this->request->getRequestParam('post_id', 0, DataType::INT);
164 164
         }
165 165
         return (int) $post_id;
@@ -182,15 +182,15 @@  discard block
 block discarded – undo
182 182
                 $post_name = is_array($WP->query_vars['name']) ? $WP->query_vars['name'][0] : $WP->query_vars['name'];
183 183
             }
184 184
             // what about the page name?
185
-            if (! $post_name && isset($WP->query_vars['pagename']) && ! empty($WP->query_vars['pagename'])) {
185
+            if ( ! $post_name && isset($WP->query_vars['pagename']) && ! empty($WP->query_vars['pagename'])) {
186 186
                 $post_name = is_array($WP->query_vars['pagename']) ? $WP->query_vars['pagename'][0]
187 187
                     : $WP->query_vars['pagename'];
188 188
             }
189 189
             // this stinks but let's run a query to try and get the post name from the URL
190 190
             // (assuming pretty permalinks are on)
191
-            if (! $post_name && ! empty($WP->request)) {
191
+            if ( ! $post_name && ! empty($WP->request)) {
192 192
                 $possible_post_name = basename($WP->request);
193
-                if (! is_numeric($possible_post_name)) {
193
+                if ( ! is_numeric($possible_post_name)) {
194 194
                     $SQL                = "SELECT ID from {$wpdb->posts}";
195 195
                     $SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
196 196
                     $SQL                .= ' AND post_name=%s';
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
         }
204 204
         // ug... ok... nothing yet... but do we have a post ID?
205 205
         // if so then... sigh... run a query to get the post name :\
206
-        if (! $post_name && $this->post_id) {
206
+        if ( ! $post_name && $this->post_id) {
207 207
             $SQL                = "SELECT post_name from {$wpdb->posts}";
208 208
             $SQL                .= " WHERE post_status NOT IN ('auto-draft', 'inherit', 'trash')";
209 209
             $SQL                .= ' AND ID=%d';
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
             }
214 214
         }
215 215
         // still nothing? ok what about an explicit 'post_name' URL parameter?
216
-        if (! $post_name && $this->request->requestParamIsSet('post_name')) {
216
+        if ( ! $post_name && $this->request->requestParamIsSet('post_name')) {
217 217
             $post_name = $this->request->getRequestParam('post_name');
218 218
         }
219 219
         return $post_name;
@@ -312,7 +312,7 @@  discard block
 block discarded – undo
312 312
         $espresso_CPT_taxonomies = $this->cpt_strategy->get_CPT_taxonomies();
313 313
         if (is_array($espresso_CPT_taxonomies)) {
314 314
             foreach ($espresso_CPT_taxonomies as $espresso_CPT_taxonomy => $details) {
315
-                if (isset($WP->query_vars, $WP->query_vars[ $espresso_CPT_taxonomy ])) {
315
+                if (isset($WP->query_vars, $WP->query_vars[$espresso_CPT_taxonomy])) {
316 316
                     return true;
317 317
                 }
318 318
             }
@@ -322,13 +322,13 @@  discard block
 block discarded – undo
322 322
         $post_type_CPT_endpoints = array_flip($espresso_CPT_endpoints);
323 323
         foreach ($this->post_type as $post_type) {
324 324
             // was a post name passed ?
325
-            if (isset($post_type_CPT_endpoints[ $post_type ])) {
325
+            if (isset($post_type_CPT_endpoints[$post_type])) {
326 326
                 // kk we know this is an espresso page, but is it a specific post ?
327
-                if (! $this->post_name) {
327
+                if ( ! $this->post_name) {
328 328
                     $espresso_post_type = $this->request->getRequestParam('post_type');
329 329
                     // there's no specific post name set, so maybe it's one of our endpoints like www.domain.com/events
330 330
                     // this essentially sets the post_name to "events" (or whatever EE CPT)
331
-                    $post_name = $post_type_CPT_endpoints[ $espresso_post_type ] ?? '';
331
+                    $post_name = $post_type_CPT_endpoints[$espresso_post_type] ?? '';
332 332
                     // if the post type matches one of ours then set the post name to the endpoint
333 333
                     if ($post_name) {
334 334
                         $this->post_name = $post_name;
Please login to merge, or discard this patch.