Completed
Branch FET/reg-form-builder/main (e2c78f)
by
unknown
15:46 queued 13:27
created
core/admin/EE_Admin_Page.core.php 1 patch
Indentation   +4093 added lines, -4093 removed lines patch added patch discarded remove patch
@@ -18,4163 +18,4163 @@
 block discarded – undo
18 18
  */
19 19
 abstract class EE_Admin_Page extends EE_Base implements InterminableInterface
20 20
 {
21
-    /**
22
-     * @var EE_Admin_Config
23
-     */
24
-    protected $admin_config;
21
+	/**
22
+	 * @var EE_Admin_Config
23
+	 */
24
+	protected $admin_config;
25 25
 
26
-    /**
27
-     * @var LoaderInterface $loader
28
-     */
29
-    protected $loader;
26
+	/**
27
+	 * @var LoaderInterface $loader
28
+	 */
29
+	protected $loader;
30 30
 
31
-    // set in _init_page_props()
32
-    public $page_slug;
31
+	// set in _init_page_props()
32
+	public $page_slug;
33 33
 
34
-    public $page_label;
34
+	public $page_label;
35 35
 
36
-    public $page_folder;
36
+	public $page_folder;
37 37
 
38
-    // set in define_page_props()
39
-    protected $_admin_base_url;
38
+	// set in define_page_props()
39
+	protected $_admin_base_url;
40 40
 
41
-    protected $_admin_base_path;
41
+	protected $_admin_base_path;
42 42
 
43
-    protected $_admin_page_title;
43
+	protected $_admin_page_title;
44 44
 
45
-    protected $_labels;
45
+	protected $_labels;
46 46
 
47 47
 
48
-    // set early within EE_Admin_Init
49
-    protected $_wp_page_slug;
48
+	// set early within EE_Admin_Init
49
+	protected $_wp_page_slug;
50 50
 
51
-    // nav tabs
52
-    protected $_nav_tabs;
51
+	// nav tabs
52
+	protected $_nav_tabs;
53 53
 
54
-    protected $_default_nav_tab_name;
54
+	protected $_default_nav_tab_name;
55 55
 
56
-    /**
57
-     * @var array $_help_tour
58
-     */
59
-    protected $_help_tour = array();
56
+	/**
57
+	 * @var array $_help_tour
58
+	 */
59
+	protected $_help_tour = array();
60 60
 
61 61
 
62
-    // template variables (used by templates)
63
-    protected $_template_path;
62
+	// template variables (used by templates)
63
+	protected $_template_path;
64 64
 
65
-    protected $_column_template_path;
65
+	protected $_column_template_path;
66 66
 
67
-    /**
68
-     * @var array $_template_args
69
-     */
70
-    protected $_template_args = array();
67
+	/**
68
+	 * @var array $_template_args
69
+	 */
70
+	protected $_template_args = array();
71 71
 
72
-    /**
73
-     * this will hold the list table object for a given view.
74
-     *
75
-     * @var EE_Admin_List_Table $_list_table_object
76
-     */
77
-    protected $_list_table_object;
72
+	/**
73
+	 * this will hold the list table object for a given view.
74
+	 *
75
+	 * @var EE_Admin_List_Table $_list_table_object
76
+	 */
77
+	protected $_list_table_object;
78 78
 
79
-    // boolean
80
-    protected $_is_UI_request; // this starts at null so we can have no header routes progress through two states.
79
+	// boolean
80
+	protected $_is_UI_request; // this starts at null so we can have no header routes progress through two states.
81 81
 
82
-    protected $_routing;
82
+	protected $_routing;
83 83
 
84
-    // list table args
85
-    protected $_view;
84
+	// list table args
85
+	protected $_view;
86 86
 
87
-    protected $_views;
87
+	protected $_views;
88 88
 
89 89
 
90
-    // action => method pairs used for routing incoming requests
91
-    protected $_page_routes;
90
+	// action => method pairs used for routing incoming requests
91
+	protected $_page_routes;
92 92
 
93
-    /**
94
-     * @var array $_page_config
95
-     */
96
-    protected $_page_config;
93
+	/**
94
+	 * @var array $_page_config
95
+	 */
96
+	protected $_page_config;
97 97
 
98
-    /**
99
-     * the current page route and route config
100
-     *
101
-     * @var string $_route
102
-     */
103
-    protected $_route;
98
+	/**
99
+	 * the current page route and route config
100
+	 *
101
+	 * @var string $_route
102
+	 */
103
+	protected $_route;
104 104
 
105
-    /**
106
-     * @var string $_cpt_route
107
-     */
108
-    protected $_cpt_route;
105
+	/**
106
+	 * @var string $_cpt_route
107
+	 */
108
+	protected $_cpt_route;
109 109
 
110
-    /**
111
-     * @var array $_route_config
112
-     */
113
-    protected $_route_config;
110
+	/**
111
+	 * @var array $_route_config
112
+	 */
113
+	protected $_route_config;
114 114
 
115
-    /**
116
-     * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
117
-     * actions.
118
-     *
119
-     * @since 4.6.x
120
-     * @var array.
121
-     */
122
-    protected $_default_route_query_args;
115
+	/**
116
+	 * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
117
+	 * actions.
118
+	 *
119
+	 * @since 4.6.x
120
+	 * @var array.
121
+	 */
122
+	protected $_default_route_query_args;
123 123
 
124
-    // set via request page and action args.
125
-    protected $_current_page;
126
-
127
-    protected $_current_view;
128
-
129
-    protected $_current_page_view_url;
130
-
131
-    // sanitized request action (and nonce)
132
-
133
-    /**
134
-     * @var string $_req_action
135
-     */
136
-    protected $_req_action;
137
-
138
-    /**
139
-     * @var string $_req_nonce
140
-     */
141
-    protected $_req_nonce;
142
-
143
-    // search related
144
-    protected $_search_btn_label;
145
-
146
-    protected $_search_box_callback;
147
-
148
-    /**
149
-     * WP Current Screen object
150
-     *
151
-     * @var WP_Screen
152
-     */
153
-    protected $_current_screen;
154
-
155
-    // for holding EE_Admin_Hooks object when needed (set via set_hook_object())
156
-    protected $_hook_obj;
157
-
158
-    // for holding incoming request data
159
-    protected $_req_data = [];
160
-
161
-    // yes / no array for admin form fields
162
-    protected $_yes_no_values = array();
163
-
164
-    // some default things shared by all child classes
165
-    protected $_default_espresso_metaboxes;
166
-
167
-    /**
168
-     *    EE_Registry Object
169
-     *
170
-     * @var    EE_Registry
171
-     */
172
-    protected $EE;
173
-
174
-
175
-    /**
176
-     * This is just a property that flags whether the given route is a caffeinated route or not.
177
-     *
178
-     * @var boolean
179
-     */
180
-    protected $_is_caf = false;
181
-
182
-    /**
183
-     * whether or not initializePage() has run
184
-     *
185
-     * @var boolean
186
-     */
187
-    protected $initialized = false;
188
-
189
-
190
-    /**
191
-     * @Constructor
192
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
193
-     * @throws InvalidArgumentException
194
-     * @throws InvalidDataTypeException
195
-     * @throws InvalidInterfaceException
196
-     * @throws ReflectionException
197
-     */
198
-    public function __construct($routing = true)
199
-    {
200
-        $this->loader = LoaderFactory::getLoader();
201
-        $this->admin_config = $this->loader->getShared('EE_Admin_Config');
202
-        if (strpos($this->_get_dir(), 'caffeinated') !== false) {
203
-            $this->_is_caf = true;
204
-        }
205
-        $this->_yes_no_values = array(
206
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
207
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
208
-        );
209
-        // set the _req_data property.
210
-        $this->_req_data = array_merge($_GET, $_POST);
211
-        // routing enabled?
212
-        $this->_routing = $routing;
213
-    }
214
-
215
-
216
-    /**
217
-     * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
218
-     * for child classes that needed to set properties prior to these methods getting called,
219
-     * but also needed the parent class to have its construction completed as well.
220
-     * Bottom line is that constructors should ONLY be used for setting initial properties
221
-     * and any complex initialization logic should only run after instantiation is complete.
222
-     *
223
-     * This method gets called immediately after construction from within
224
-     *      EE_Admin_Page_Init::_initialize_admin_page()
225
-     *
226
-     * @throws EE_Error
227
-     * @throws InvalidArgumentException
228
-     * @throws InvalidDataTypeException
229
-     * @throws InvalidInterfaceException
230
-     * @throws ReflectionException
231
-     * @since $VID:$
232
-     */
233
-    public function initializePage()
234
-    {
235
-        if ($this->initialized) {
236
-            return;
237
-        }
238
-        // set initial page props (child method)
239
-        $this->_init_page_props();
240
-        // set global defaults
241
-        $this->_set_defaults();
242
-        // set early because incoming requests could be ajax related and we need to register those hooks.
243
-        $this->_global_ajax_hooks();
244
-        $this->_ajax_hooks();
245
-        // other_page_hooks have to be early too.
246
-        $this->_do_other_page_hooks();
247
-        // This just allows us to have extending classes do something specific
248
-        // before the parent constructor runs _page_setup().
249
-        if (method_exists($this, '_before_page_setup')) {
250
-            $this->_before_page_setup();
251
-        }
252
-        // set up page dependencies
253
-        $this->_page_setup();
254
-        $this->initialized = true;
255
-    }
256
-
257
-
258
-    /**
259
-     * _init_page_props
260
-     * Child classes use to set at least the following properties:
261
-     * $page_slug.
262
-     * $page_label.
263
-     *
264
-     * @abstract
265
-     * @return void
266
-     */
267
-    abstract protected function _init_page_props();
268
-
269
-
270
-    /**
271
-     * _ajax_hooks
272
-     * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
273
-     * Note: within the ajax callback methods.
274
-     *
275
-     * @abstract
276
-     * @return void
277
-     */
278
-    abstract protected function _ajax_hooks();
279
-
280
-
281
-    /**
282
-     * _define_page_props
283
-     * child classes define page properties in here.  Must include at least:
284
-     * $_admin_base_url = base_url for all admin pages
285
-     * $_admin_page_title = default admin_page_title for admin pages
286
-     * $_labels = array of default labels for various automatically generated elements:
287
-     *    array(
288
-     *        'buttons' => array(
289
-     *            'add' => esc_html__('label for add new button'),
290
-     *            'edit' => esc_html__('label for edit button'),
291
-     *            'delete' => esc_html__('label for delete button')
292
-     *            )
293
-     *        )
294
-     *
295
-     * @abstract
296
-     * @return void
297
-     */
298
-    abstract protected function _define_page_props();
299
-
300
-
301
-    /**
302
-     * _set_page_routes
303
-     * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
304
-     * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
305
-     * have a 'default' route. Here's the format
306
-     * $this->_page_routes = array(
307
-     *        'default' => array(
308
-     *            'func' => '_default_method_handling_route',
309
-     *            'args' => array('array','of','args'),
310
-     *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
311
-     *            ajax request, backend processing)
312
-     *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
313
-     *            headers route after.  The string you enter here should match the defined route reference for a
314
-     *            headers sent route.
315
-     *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
316
-     *            this route.
317
-     *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
318
-     *            checks).
319
-     *        ),
320
-     *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
321
-     *        handling method.
322
-     *        )
323
-     * )
324
-     *
325
-     * @abstract
326
-     * @return void
327
-     */
328
-    abstract protected function _set_page_routes();
329
-
330
-
331
-    /**
332
-     * _set_page_config
333
-     * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
334
-     * array corresponds to the page_route for the loaded page. Format:
335
-     * $this->_page_config = array(
336
-     *        'default' => array(
337
-     *            'labels' => array(
338
-     *                'buttons' => array(
339
-     *                    'add' => esc_html__('label for adding item'),
340
-     *                    'edit' => esc_html__('label for editing item'),
341
-     *                    'delete' => esc_html__('label for deleting item')
342
-     *                ),
343
-     *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
344
-     *            ), //optional an array of custom labels for various automatically generated elements to use on the
345
-     *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
346
-     *            _define_page_props() method
347
-     *            'nav' => array(
348
-     *                'label' => esc_html__('Label for Tab', 'event_espresso').
349
-     *                'url' => 'http://someurl', //automatically generated UNLESS you define
350
-     *                'css_class' => 'css-class', //automatically generated UNLESS you define
351
-     *                'order' => 10, //required to indicate tab position.
352
-     *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
353
-     *                displayed then add this parameter.
354
-     *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
355
-     *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
356
-     *            metaboxes set for eventespresso admin pages.
357
-     *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
358
-     *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
359
-     *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
360
-     *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
361
-     *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
362
-     *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
363
-     *            array indicates the max number of columns (4) and the default number of columns on page load (2).
364
-     *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
365
-     *            want to display.
366
-     *            'help_tabs' => array( //this is used for adding help tabs to a page
367
-     *                'tab_id' => array(
368
-     *                    'title' => 'tab_title',
369
-     *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
370
-     *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
371
-     *                    should match a file in the admin folder's "help_tabs" dir (ie..
372
-     *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
373
-     *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
374
-     *                    attempt to use the callback which should match the name of a method in the class
375
-     *                    ),
376
-     *                'tab2_id' => array(
377
-     *                    'title' => 'tab2 title',
378
-     *                    'filename' => 'file_name_2'
379
-     *                    'callback' => 'callback_method_for_content',
380
-     *                 ),
381
-     *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
382
-     *            help tab area on an admin page. @link
383
-     *            http://make.wordpress.org/core/2011/12/06/help-and-screen-api-changes-in-3-3/
384
-     *            'help_tour' => array(
385
-     *                'name_of_help_tour_class', //all help tours shoudl be a child class of EE_Help_Tour and located
386
-     *                in a folder for this admin page named "help_tours", a file name matching the key given here
387
-     *                (name_of_help_tour_class.class.php), and class matching key given here (name_of_help_tour_class)
388
-     *            ),
389
-     *            'require_nonce' => TRUE //this is used if you want to set a route to NOT require a nonce (default is
390
-     *            true if it isn't present).  To remove the requirement for a nonce check when this route is visited
391
-     *            just set
392
-     *            'require_nonce' to FALSE
393
-     *            )
394
-     * )
395
-     *
396
-     * @abstract
397
-     * @return void
398
-     */
399
-    abstract protected function _set_page_config();
400
-
401
-
402
-
403
-
404
-
405
-    /** end sample help_tour methods **/
406
-    /**
407
-     * _add_screen_options
408
-     * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
409
-     * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
410
-     * to a particular view.
411
-     *
412
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
413
-     *         see also WP_Screen object documents...
414
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
415
-     * @abstract
416
-     * @return void
417
-     */
418
-    abstract protected function _add_screen_options();
419
-
420
-
421
-    /**
422
-     * _add_feature_pointers
423
-     * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
424
-     * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
425
-     * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
426
-     * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
427
-     * extended) also see:
428
-     *
429
-     * @link   http://eamann.com/tech/wordpress-portland/
430
-     * @abstract
431
-     * @return void
432
-     */
433
-    abstract protected function _add_feature_pointers();
434
-
435
-
436
-    /**
437
-     * load_scripts_styles
438
-     * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
439
-     * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
440
-     * scripts/styles per view by putting them in a dynamic function in this format
441
-     * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
442
-     *
443
-     * @abstract
444
-     * @return void
445
-     */
446
-    abstract public function load_scripts_styles();
447
-
448
-
449
-    /**
450
-     * admin_init
451
-     * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
452
-     * all pages/views loaded by child class.
453
-     *
454
-     * @abstract
455
-     * @return void
456
-     */
457
-    abstract public function admin_init();
458
-
459
-
460
-    /**
461
-     * admin_notices
462
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
463
-     * all pages/views loaded by child class.
464
-     *
465
-     * @abstract
466
-     * @return void
467
-     */
468
-    abstract public function admin_notices();
469
-
470
-
471
-    /**
472
-     * admin_footer_scripts
473
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
474
-     * will apply to all pages/views loaded by child class.
475
-     *
476
-     * @return void
477
-     */
478
-    abstract public function admin_footer_scripts();
479
-
480
-
481
-    /**
482
-     * admin_footer
483
-     * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
484
-     * apply to all pages/views loaded by child class.
485
-     *
486
-     * @return void
487
-     */
488
-    public function admin_footer()
489
-    {
490
-    }
491
-
492
-
493
-    /**
494
-     * _global_ajax_hooks
495
-     * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
496
-     * Note: within the ajax callback methods.
497
-     *
498
-     * @abstract
499
-     * @return void
500
-     */
501
-    protected function _global_ajax_hooks()
502
-    {
503
-        // for lazy loading of metabox content
504
-        add_action('wp_ajax_espresso-ajax-content', array($this, 'ajax_metabox_content'), 10);
505
-
506
-        add_action(
507
-            'wp_ajax_espresso_hide_status_change_notice',
508
-            [$this, 'hideStatusChangeNotice']
509
-        );
510
-        add_action(
511
-            'wp_ajax_nopriv_espresso_hide_status_change_notice',
512
-            [$this, 'hideStatusChangeNotice']
513
-        );
514
-    }
515
-
516
-
517
-    public function ajax_metabox_content()
518
-    {
519
-        $contentid = isset($this->_req_data['contentid']) ? $this->_req_data['contentid'] : '';
520
-        $url = isset($this->_req_data['contenturl']) ? $this->_req_data['contenturl'] : '';
521
-        EE_Admin_Page::cached_rss_display($contentid, $url);
522
-        wp_die();
523
-    }
524
-
525
-
526
-    public function hideStatusChangeNotice()
527
-    {
528
-        $response = [];
529
-        try {
530
-            /** @var EventEspresso\core\admin\StatusChangeNotice $status_change_notice */
531
-            $status_change_notice = $this->loader->getShared('EventEspresso\core\admin\StatusChangeNotice');
532
-            $response['success'] = $status_change_notice->dismiss() > -1;
533
-        } catch (Exception $exception) {
534
-            $response['errors'] = $exception->getMessage();
535
-        }
536
-        echo wp_json_encode($response);
537
-        exit();
538
-    }
539
-
540
-
541
-    /**
542
-     * _page_setup
543
-     * Makes sure any things that need to be loaded early get handled.  We also escape early here if the page requested
544
-     * doesn't match the object.
545
-     *
546
-     * @final
547
-     * @return void
548
-     * @throws EE_Error
549
-     * @throws InvalidArgumentException
550
-     * @throws ReflectionException
551
-     * @throws InvalidDataTypeException
552
-     * @throws InvalidInterfaceException
553
-     */
554
-    final protected function _page_setup()
555
-    {
556
-        // requires?
557
-        // admin_init stuff - global - we're setting this REALLY early
558
-        // so if EE_Admin pages have to hook into other WP pages they can.
559
-        // But keep in mind, not everything is available from the EE_Admin Page object at this point.
560
-        add_action('admin_init', array($this, 'admin_init_global'), 5);
561
-        // next verify if we need to load anything...
562
-        $this->_current_page = ! empty($_GET['page']) ? sanitize_key($_GET['page']) : '';
563
-        $this->page_folder = strtolower(
564
-            str_replace(array('_Admin_Page', 'Extend_'), '', get_class($this))
565
-        );
566
-        global $ee_menu_slugs;
567
-        $ee_menu_slugs = (array) $ee_menu_slugs;
568
-        if (! defined('DOING_AJAX') && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))) {
569
-            return;
570
-        }
571
-        // becuz WP List tables have two duplicate select inputs for choosing bulk actions, we need to copy the action from the second to the first
572
-        if (isset($this->_req_data['action2']) && $this->_req_data['action'] === '-1') {
573
-            $this->_req_data['action'] = ! empty($this->_req_data['action2']) && $this->_req_data['action2'] !== '-1'
574
-                ? $this->_req_data['action2']
575
-                : $this->_req_data['action'];
576
-        }
577
-        // then set blank or -1 action values to 'default'
578
-        $this->_req_action = isset($this->_req_data['action'])
579
-                             && ! empty($this->_req_data['action'])
580
-                             && $this->_req_data['action'] !== '-1'
581
-            ? sanitize_key($this->_req_data['action'])
582
-            : 'default';
583
-        // if action is 'default' after the above BUT we have  'route' var set, then let's use the route as the action.
584
-        //  This covers cases where we're coming in from a list table that isn't on the default route.
585
-        $this->_req_action = $this->_req_action === 'default' && isset($this->_req_data['route'])
586
-            ? $this->_req_data['route'] : $this->_req_action;
587
-        // however if we are doing_ajax and we've got a 'route' set then that's what the req_action will be
588
-        $this->_req_action = defined('DOING_AJAX') && isset($this->_req_data['route'])
589
-            ? $this->_req_data['route']
590
-            : $this->_req_action;
591
-        $this->_current_view = $this->_req_action;
592
-        $this->_req_nonce = $this->_req_action . '_nonce';
593
-        $this->_define_page_props();
594
-        $this->_current_page_view_url = add_query_arg(
595
-            array('page' => $this->_current_page, 'action' => $this->_current_view),
596
-            $this->_admin_base_url
597
-        );
598
-        // default things
599
-        $this->_default_espresso_metaboxes = array(
600
-            '_espresso_news_post_box',
601
-            '_espresso_links_post_box',
602
-            '_espresso_ratings_request',
603
-            '_espresso_sponsors_post_box',
604
-        );
605
-        // set page configs
606
-        $this->_set_page_routes();
607
-        $this->_set_page_config();
608
-        // let's include any referrer data in our default_query_args for this route for "stickiness".
609
-        if (isset($this->_req_data['wp_referer'])) {
610
-            $this->_default_route_query_args['wp_referer'] = $this->_req_data['wp_referer'];
611
-        }
612
-        // for caffeinated and other extended functionality.
613
-        //  If there is a _extend_page_config method
614
-        // then let's run that to modify the all the various page configuration arrays
615
-        if (method_exists($this, '_extend_page_config')) {
616
-            $this->_extend_page_config();
617
-        }
618
-        // for CPT and other extended functionality.
619
-        // If there is an _extend_page_config_for_cpt
620
-        // then let's run that to modify all the various page configuration arrays.
621
-        if (method_exists($this, '_extend_page_config_for_cpt')) {
622
-            $this->_extend_page_config_for_cpt();
623
-        }
624
-        // filter routes and page_config so addons can add their stuff. Filtering done per class
625
-        $this->_page_routes = apply_filters(
626
-            'FHEE__' . get_class($this) . '__page_setup__page_routes',
627
-            $this->_page_routes,
628
-            $this
629
-        );
630
-        $this->_page_config = apply_filters(
631
-            'FHEE__' . get_class($this) . '__page_setup__page_config',
632
-            $this->_page_config,
633
-            $this
634
-        );
635
-        // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
636
-        // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
637
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
638
-            add_action(
639
-                'AHEE__EE_Admin_Page__route_admin_request',
640
-                array($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view),
641
-                10,
642
-                2
643
-            );
644
-        }
645
-        // next route only if routing enabled
646
-        if ($this->_routing && ! defined('DOING_AJAX')) {
647
-            $this->_verify_routes();
648
-            // next let's just check user_access and kill if no access
649
-            $this->check_user_access();
650
-            if ($this->_is_UI_request) {
651
-                // admin_init stuff - global, all views for this page class, specific view
652
-                add_action('admin_init', array($this, 'admin_init'), 10);
653
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
654
-                    add_action('admin_init', array($this, 'admin_init_' . $this->_current_view), 15);
655
-                }
656
-            } else {
657
-                // hijack regular WP loading and route admin request immediately
658
-                @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
659
-                $this->route_admin_request();
660
-            }
661
-        }
662
-    }
663
-
664
-
665
-    /**
666
-     * Provides a way for related child admin pages to load stuff on the loaded admin page.
667
-     *
668
-     * @return void
669
-     * @throws EE_Error
670
-     */
671
-    private function _do_other_page_hooks()
672
-    {
673
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, array());
674
-        foreach ($registered_pages as $page) {
675
-            // now let's setup the file name and class that should be present
676
-            $classname = str_replace('.class.php', '', $page);
677
-            // autoloaders should take care of loading file
678
-            if (! class_exists($classname)) {
679
-                $error_msg[] = sprintf(
680
-                    esc_html__(
681
-                        'Something went wrong with loading the %s admin hooks page.',
682
-                        'event_espresso'
683
-                    ),
684
-                    $page
685
-                );
686
-                $error_msg[] = $error_msg[0]
687
-                               . "\r\n"
688
-                               . sprintf(
689
-                                   esc_html__(
690
-                                       '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',
691
-                                       'event_espresso'
692
-                                   ),
693
-                                   $page,
694
-                                   '<br />',
695
-                                   '<strong>' . $classname . '</strong>'
696
-                               );
697
-                throw new EE_Error(implode('||', $error_msg));
698
-            }
699
-            // // notice we are passing the instance of this class to the hook object.
700
-            $this->loader->getShared($classname, [$this]);
701
-        }
702
-    }
703
-
704
-
705
-    /**
706
-     * @throws DomainException
707
-     * @throws EE_Error
708
-     * @throws InvalidArgumentException
709
-     * @throws InvalidDataTypeException
710
-     * @throws InvalidInterfaceException
711
-     * @throws ReflectionException
712
-     * @since $VID:$
713
-     */
714
-    public function load_page_dependencies()
715
-    {
716
-        try {
717
-            $this->_load_page_dependencies();
718
-        } catch (EE_Error $e) {
719
-            $e->get_error();
720
-        }
721
-    }
722
-
723
-
724
-    /**
725
-     * load_page_dependencies
726
-     * loads things specific to this page class when its loaded.  Really helps with efficiency.
727
-     *
728
-     * @return void
729
-     * @throws DomainException
730
-     * @throws EE_Error
731
-     * @throws InvalidArgumentException
732
-     * @throws InvalidDataTypeException
733
-     * @throws InvalidInterfaceException
734
-     * @throws ReflectionException
735
-     */
736
-    protected function _load_page_dependencies()
737
-    {
738
-        // let's set the current_screen and screen options to override what WP set
739
-        $this->_current_screen = get_current_screen();
740
-        // load admin_notices - global, page class, and view specific
741
-        add_action('admin_notices', array($this, 'admin_notices_global'), 5);
742
-        add_action('admin_notices', array($this, 'admin_notices'), 10);
743
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
744
-            add_action('admin_notices', array($this, 'admin_notices_' . $this->_current_view), 15);
745
-        }
746
-        // load network admin_notices - global, page class, and view specific
747
-        add_action('network_admin_notices', array($this, 'network_admin_notices_global'), 5);
748
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
749
-            add_action('network_admin_notices', array($this, 'network_admin_notices_' . $this->_current_view));
750
-        }
751
-        // this will save any per_page screen options if they are present
752
-        $this->_set_per_page_screen_options();
753
-        // setup list table properties
754
-        $this->_set_list_table();
755
-        // child classes can "register" a metabox to be automatically handled via the _page_config array property.
756
-        // However in some cases the metaboxes will need to be added within a route handling callback.
757
-        $this->_add_registered_meta_boxes();
758
-        $this->_add_screen_columns();
759
-        // add screen options - global, page child class, and view specific
760
-        $this->_add_global_screen_options();
761
-        $this->_add_screen_options();
762
-        $add_screen_options = "_add_screen_options_{$this->_current_view}";
763
-        if (method_exists($this, $add_screen_options)) {
764
-            $this->{$add_screen_options}();
765
-        }
766
-        // add help tab(s) and tours- set via page_config and qtips.
767
-        // $this->_add_help_tour();
768
-        $this->_add_help_tabs();
769
-        $this->_add_qtips();
770
-        // add feature_pointers - global, page child class, and view specific
771
-        $this->_add_feature_pointers();
772
-        $this->_add_global_feature_pointers();
773
-        $add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
774
-        if (method_exists($this, $add_feature_pointer)) {
775
-            $this->{$add_feature_pointer}();
776
-        }
777
-        // enqueue scripts/styles - global, page class, and view specific
778
-        add_action('admin_enqueue_scripts', array($this, 'load_global_scripts_styles'), 5);
779
-        add_action('admin_enqueue_scripts', array($this, 'load_scripts_styles'), 10);
780
-        if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
781
-            add_action('admin_enqueue_scripts', array($this, "load_scripts_styles_{$this->_current_view}"), 15);
782
-        }
783
-        add_action('admin_enqueue_scripts', array($this, 'admin_footer_scripts_eei18n_js_strings'), 100);
784
-        // admin_print_footer_scripts - global, page child class, and view specific.
785
-        // NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
786
-        // In most cases that's doing_it_wrong().  But adding hidden container elements etc.
787
-        // is a good use case. Notice the late priority we're giving these
788
-        add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts_global'), 99);
789
-        add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts'), 100);
790
-        if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
791
-            add_action('admin_print_footer_scripts', array($this, "admin_footer_scripts_{$this->_current_view}"), 101);
792
-        }
793
-        // admin footer scripts
794
-        add_action('admin_footer', array($this, 'admin_footer_global'), 99);
795
-        add_action('admin_footer', array($this, 'admin_footer'), 100);
796
-        if (method_exists($this, "admin_footer_{$this->_current_view}")) {
797
-            add_action('admin_footer', array($this, "admin_footer_{$this->_current_view}"), 101);
798
-        }
799
-        do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
800
-        // targeted hook
801
-        do_action(
802
-            "FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
803
-        );
804
-    }
805
-
806
-
807
-    /**
808
-     * _set_defaults
809
-     * This sets some global defaults for class properties.
810
-     */
811
-    private function _set_defaults()
812
-    {
813
-        $this->_current_screen = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
814
-        $this->_event = $this->_template_path = $this->_column_template_path = null;
815
-        $this->_nav_tabs = $this->_views = $this->_page_routes = array();
816
-        $this->_page_config = $this->_default_route_query_args = array();
817
-        $this->_default_nav_tab_name = 'overview';
818
-        // init template args
819
-        $this->_template_args = array(
820
-            'admin_page_header'  => '',
821
-            'admin_page_content' => '',
822
-            'post_body_content'  => '',
823
-            'before_list_table'  => '',
824
-            'after_list_table'   => '',
825
-        );
826
-    }
827
-
828
-
829
-    /**
830
-     * route_admin_request
831
-     *
832
-     * @see    _route_admin_request()
833
-     * @return exception|void error
834
-     * @throws InvalidArgumentException
835
-     * @throws InvalidInterfaceException
836
-     * @throws InvalidDataTypeException
837
-     * @throws EE_Error
838
-     * @throws ReflectionException
839
-     */
840
-    public function route_admin_request()
841
-    {
842
-        try {
843
-            $this->_route_admin_request();
844
-        } catch (EE_Error $e) {
845
-            $e->get_error();
846
-        }
847
-    }
848
-
849
-
850
-    public function set_wp_page_slug($wp_page_slug)
851
-    {
852
-        $this->_wp_page_slug = $wp_page_slug;
853
-        // if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
854
-        if (is_network_admin()) {
855
-            $this->_wp_page_slug .= '-network';
856
-        }
857
-    }
858
-
859
-
860
-    /**
861
-     * _verify_routes
862
-     * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
863
-     * we know if we need to drop out.
864
-     *
865
-     * @return bool
866
-     * @throws EE_Error
867
-     */
868
-    protected function _verify_routes()
869
-    {
870
-        if (! $this->_current_page && ! defined('DOING_AJAX')) {
871
-            return false;
872
-        }
873
-        $this->_route = false;
874
-        // check that the page_routes array is not empty
875
-        if (empty($this->_page_routes)) {
876
-            // user error msg
877
-            $error_msg = sprintf(
878
-                esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
879
-                $this->_admin_page_title
880
-            );
881
-            // developer error msg
882
-            $error_msg .= '||' . $error_msg
883
-                          . esc_html__(
884
-                              ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
885
-                              'event_espresso'
886
-                          );
887
-            throw new EE_Error($error_msg);
888
-        }
889
-        // and that the requested page route exists
890
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
891
-            $this->_route = $this->_page_routes[ $this->_req_action ];
892
-            $this->_route_config = isset($this->_page_config[ $this->_req_action ])
893
-                ? $this->_page_config[ $this->_req_action ] : array();
894
-        } else {
895
-            // user error msg
896
-            $error_msg = sprintf(
897
-                esc_html__(
898
-                    'The requested page route does not exist for the %s admin page.',
899
-                    'event_espresso'
900
-                ),
901
-                $this->_admin_page_title
902
-            );
903
-            // developer error msg
904
-            $error_msg .= '||' . $error_msg
905
-                          . sprintf(
906
-                              esc_html__(
907
-                                  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
908
-                                  'event_espresso'
909
-                              ),
910
-                              $this->_req_action
911
-                          );
912
-            throw new EE_Error($error_msg);
913
-        }
914
-        // and that a default route exists
915
-        if (! array_key_exists('default', $this->_page_routes)) {
916
-            // user error msg
917
-            $error_msg = sprintf(
918
-                esc_html__(
919
-                    'A default page route has not been set for the % admin page.',
920
-                    'event_espresso'
921
-                ),
922
-                $this->_admin_page_title
923
-            );
924
-            // developer error msg
925
-            $error_msg .= '||' . $error_msg
926
-                          . esc_html__(
927
-                              ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
928
-                              'event_espresso'
929
-                          );
930
-            throw new EE_Error($error_msg);
931
-        }
932
-
933
-        // first lets' catch if the UI request has EVER been set.
934
-        if ($this->_is_UI_request === null) {
935
-            // lets set if this is a UI request or not.
936
-            $this->_is_UI_request = ! isset($this->_req_data['noheader']) || $this->_req_data['noheader'] !== true;
937
-            // wait a minute... we might have a noheader in the route array
938
-            $this->_is_UI_request = is_array($this->_route)
939
-                                    && isset($this->_route['noheader'])
940
-                                    && $this->_route['noheader'] ? false : $this->_is_UI_request;
941
-        }
942
-        $this->_set_current_labels();
943
-        return true;
944
-    }
945
-
946
-
947
-    /**
948
-     * this method simply verifies a given route and makes sure its an actual route available for the loaded page
949
-     *
950
-     * @param  string $route the route name we're verifying
951
-     * @return mixed (bool|Exception)      we'll throw an exception if this isn't a valid route.
952
-     * @throws EE_Error
953
-     */
954
-    protected function _verify_route($route)
955
-    {
956
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
957
-            return true;
958
-        }
959
-        // user error msg
960
-        $error_msg = sprintf(
961
-            esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
962
-            $this->_admin_page_title
963
-        );
964
-        // developer error msg
965
-        $error_msg .= '||' . $error_msg
966
-                      . sprintf(
967
-                          esc_html__(
968
-                              ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
969
-                              'event_espresso'
970
-                          ),
971
-                          $route
972
-                      );
973
-        throw new EE_Error($error_msg);
974
-    }
975
-
976
-
977
-    /**
978
-     * perform nonce verification
979
-     * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
980
-     * using this method (and save retyping!)
981
-     *
982
-     * @param string $nonce     The nonce sent
983
-     * @param string $nonce_ref The nonce reference string (name0)
984
-     * @return void
985
-     * @throws EE_Error
986
-     * @throws InvalidArgumentException
987
-     * @throws InvalidDataTypeException
988
-     * @throws InvalidInterfaceException
989
-     */
990
-    protected function _verify_nonce($nonce, $nonce_ref)
991
-    {
992
-        // verify nonce against expected value
993
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
994
-            // these are not the droids you are looking for !!!
995
-            $msg = sprintf(
996
-                esc_html__('%sNonce Fail.%s', 'event_espresso'),
997
-                '<a href="http://www.youtube.com/watch?v=56_S0WeTkzs">',
998
-                '</a>'
999
-            );
1000
-            if (WP_DEBUG) {
1001
-                $msg .= "\n  "
1002
-                        . sprintf(
1003
-                            esc_html__(
1004
-                                'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1005
-                                'event_espresso'
1006
-                            ),
1007
-                            EE_Admin_Page::class
1008
-                        );
1009
-            }
1010
-            if (! defined('DOING_AJAX')) {
1011
-                wp_die($msg);
1012
-            } else {
1013
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1014
-                $this->_return_json();
1015
-            }
1016
-        }
1017
-    }
1018
-
1019
-
1020
-    /**
1021
-     * _route_admin_request()
1022
-     * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1023
-     * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1024
-     * in the page routes and then will try to load the corresponding method.
1025
-     *
1026
-     * @return void
1027
-     * @throws EE_Error
1028
-     * @throws InvalidArgumentException
1029
-     * @throws InvalidDataTypeException
1030
-     * @throws InvalidInterfaceException
1031
-     * @throws ReflectionException
1032
-     */
1033
-    protected function _route_admin_request()
1034
-    {
1035
-        if (! $this->_is_UI_request) {
1036
-            $this->_verify_routes();
1037
-        }
1038
-        $nonce_check = isset($this->_route_config['require_nonce'])
1039
-            ? $this->_route_config['require_nonce']
1040
-            : true;
1041
-        if ($this->_req_action !== 'default' && $nonce_check) {
1042
-            // set nonce from post data
1043
-            $nonce = isset($this->_req_data[ $this->_req_nonce ])
1044
-                ? sanitize_text_field($this->_req_data[ $this->_req_nonce ])
1045
-                : '';
1046
-            $this->_verify_nonce($nonce, $this->_req_nonce);
1047
-        }
1048
-        // set the nav_tabs array but ONLY if this is  UI_request
1049
-        if ($this->_is_UI_request) {
1050
-            $this->_set_nav_tabs();
1051
-        }
1052
-        // grab callback function
1053
-        $func = is_array($this->_route) && isset($this->_route['func']) ? $this->_route['func'] : $this->_route;
1054
-        // check if callback has args
1055
-        $args = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : array();
1056
-        $error_msg = '';
1057
-        // action right before calling route
1058
-        // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1059
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1060
-            do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1061
-        }
1062
-        // right before calling the route, let's remove _wp_http_referer from the
1063
-        // $_SERVER[REQUEST_URI] global (its now in _req_data for route processing).
1064
-        $_SERVER['REQUEST_URI'] = remove_query_arg(
1065
-            '_wp_http_referer',
1066
-            wp_unslash($_SERVER['REQUEST_URI'])
1067
-        );
1068
-        if (! empty($func)) {
1069
-            if (is_array($func)) {
1070
-                list($class, $method) = $func;
1071
-            } elseif (strpos($func, '::') !== false) {
1072
-                list($class, $method) = explode('::', $func);
1073
-            } else {
1074
-                $class = $this;
1075
-                $method = $func;
1076
-            }
1077
-            if (! (is_object($class) && $class === $this)) {
1078
-                // send along this admin page object for access by addons.
1079
-                $args['admin_page_object'] = $this;
1080
-            }
1081
-            // is it a method on a class that doesn't work?
1082
-            if (
1083
-                ((method_exists($class, $method)
1084
-                  && call_user_func_array(array($class, $method), $args) === false)
1085
-                 && (// is it a standalone function that doesn't work?
1086
-                     function_exists($method)
1087
-                     && call_user_func_array(
1088
-                         $func,
1089
-                         array_merge(array('admin_page_object' => $this), $args)
1090
-                     ) === false
1091
-                 )) || (// is it neither a class method NOR a standalone function?
1092
-                    ! function_exists($method)
1093
-                    && ! method_exists($class, $method)
1094
-                )
1095
-            ) {
1096
-                // user error msg
1097
-                $error_msg = esc_html__(
1098
-                    'An error occurred. The  requested page route could not be found.',
1099
-                    'event_espresso'
1100
-                );
1101
-                // developer error msg
1102
-                $error_msg .= '||';
1103
-                $error_msg .= sprintf(
1104
-                    esc_html__(
1105
-                        'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1106
-                        'event_espresso'
1107
-                    ),
1108
-                    $method
1109
-                );
1110
-            }
1111
-            if (! empty($error_msg)) {
1112
-                throw new EE_Error($error_msg);
1113
-            }
1114
-        }
1115
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1116
-        // then we need to reset the routing properties to the new route.
1117
-        // 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.
1118
-        if (
1119
-            $this->_is_UI_request === false
1120
-            && is_array($this->_route)
1121
-            && ! empty($this->_route['headers_sent_route'])
1122
-        ) {
1123
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1124
-        }
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     * This method just allows the resetting of page properties in the case where a no headers
1130
-     * route redirects to a headers route in its route config.
1131
-     *
1132
-     * @since   4.3.0
1133
-     * @param  string $new_route New (non header) route to redirect to.
1134
-     * @return   void
1135
-     * @throws ReflectionException
1136
-     * @throws InvalidArgumentException
1137
-     * @throws InvalidInterfaceException
1138
-     * @throws InvalidDataTypeException
1139
-     * @throws EE_Error
1140
-     */
1141
-    protected function _reset_routing_properties($new_route)
1142
-    {
1143
-        $this->_is_UI_request = true;
1144
-        // now we set the current route to whatever the headers_sent_route is set at
1145
-        $this->_req_data['action'] = $new_route;
1146
-        // rerun page setup
1147
-        $this->_page_setup();
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * _add_query_arg
1153
-     * adds nonce to array of arguments then calls WP add_query_arg function
1154
-     *(internally just uses EEH_URL's function with the same name)
1155
-     *
1156
-     * @param array  $args
1157
-     * @param string $url
1158
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1159
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1160
-     *                                        Example usage: If the current page is:
1161
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1162
-     *                                        &action=default&event_id=20&month_range=March%202015
1163
-     *                                        &_wpnonce=5467821
1164
-     *                                        and you call:
1165
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1166
-     *                                        array(
1167
-     *                                        'action' => 'resend_something',
1168
-     *                                        'page=>espresso_registrations'
1169
-     *                                        ),
1170
-     *                                        $some_url,
1171
-     *                                        true
1172
-     *                                        );
1173
-     *                                        It will produce a url in this structure:
1174
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1175
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1176
-     *                                        month_range]=March%202015
1177
-     * @param   bool $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1178
-     * @return string
1179
-     */
1180
-    public static function add_query_args_and_nonce(
1181
-        $args = array(),
1182
-        $url = '',
1183
-        $sticky = false,
1184
-        $exclude_nonce = false
1185
-    ) {
1186
-        // if there is a _wp_http_referer include the values from the request but only if sticky = true
1187
-        if ($sticky) {
1188
-            $request = $_REQUEST;
1189
-            unset($request['_wp_http_referer'], $request['wp_referer']);
1190
-            foreach ($request as $key => $value) {
1191
-                // do not add nonces
1192
-                if (strpos($key, 'nonce') !== false) {
1193
-                    continue;
1194
-                }
1195
-                $args[ 'wp_referer[' . $key . ']' ] = $value;
1196
-            }
1197
-        }
1198
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce);
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * This returns a generated link that will load the related help tab.
1204
-     *
1205
-     * @param  string $help_tab_id the id for the connected help tab
1206
-     * @param  string $icon_style  (optional) include css class for the style you want to use for the help icon.
1207
-     * @param  string $help_text   (optional) send help text you want to use for the link if default not to be used
1208
-     * @uses EEH_Template::get_help_tab_link()
1209
-     * @return string              generated link
1210
-     */
1211
-    protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1212
-    {
1213
-        return EEH_Template::get_help_tab_link(
1214
-            $help_tab_id,
1215
-            $this->page_slug,
1216
-            $this->_req_action,
1217
-            $icon_style,
1218
-            $help_text
1219
-        );
1220
-    }
1221
-
1222
-
1223
-    /**
1224
-     * _add_help_tabs
1225
-     * Note child classes define their help tabs within the page_config array.
1226
-     *
1227
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1228
-     * @return void
1229
-     * @throws DomainException
1230
-     * @throws EE_Error
1231
-     * @throws ReflectionException
1232
-     */
1233
-    protected function _add_help_tabs()
1234
-    {
1235
-        $tour_buttons = '';
1236
-        if (isset($this->_page_config[ $this->_req_action ])) {
1237
-            $config = $this->_page_config[ $this->_req_action ];
1238
-            // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1239
-            // is there a help tour for the current route?  if there is let's setup the tour buttons
1240
-            // if (isset($this->_help_tour[ $this->_req_action ])) {
1241
-            //     $tb = array();
1242
-            //     $tour_buttons = '<div class="ee-abs-container"><div class="ee-help-tour-restart-buttons">';
1243
-            //     foreach ($this->_help_tour['tours'] as $tour) {
1244
-            //         // if this is the end tour then we don't need to setup a button
1245
-            //         if ($tour instanceof EE_Help_Tour_final_stop || ! $tour instanceof EE_Help_Tour) {
1246
-            //             continue;
1247
-            //         }
1248
-            //         $tb[] = '<button id="trigger-tour-'
1249
-            //                 . $tour->get_slug()
1250
-            //                 . '" class="button-primary trigger-ee-help-tour">'
1251
-            //                 . $tour->get_label()
1252
-            //                 . '</button>';
1253
-            //     }
1254
-            //     $tour_buttons .= implode('<br />', $tb);
1255
-            //     $tour_buttons .= '</div></div>';
1256
-            // }
1257
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1258
-            if (is_array($config) && isset($config['help_sidebar'])) {
1259
-                // check that the callback given is valid
1260
-                if (! method_exists($this, $config['help_sidebar'])) {
1261
-                    throw new EE_Error(
1262
-                        sprintf(
1263
-                            esc_html__(
1264
-                                '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',
1265
-                                'event_espresso'
1266
-                            ),
1267
-                            $config['help_sidebar'],
1268
-                            get_class($this)
1269
-                        )
1270
-                    );
1271
-                }
1272
-                $content = apply_filters(
1273
-                    'FHEE__' . get_class($this) . '__add_help_tabs__help_sidebar',
1274
-                    $this->{$config['help_sidebar']}()
1275
-                );
1276
-                $content .= $tour_buttons; // add help tour buttons.
1277
-                // do we have any help tours setup?  Cause if we do we want to add the buttons
1278
-                $this->_current_screen->set_help_sidebar($content);
1279
-            }
1280
-            // if there ARE tour buttons...
1281
-            if (! empty($tour_buttons)) {
1282
-                // if we DON'T have config help sidebar then we'll just add the tour buttons to the sidebar.
1283
-                if (! isset($config['help_sidebar'])) {
1284
-                    $this->_current_screen->set_help_sidebar($tour_buttons);
1285
-                }
1286
-                // handle if no help_tabs are set so the sidebar will still show for the help tour buttons
1287
-                if (! isset($config['help_tabs'])) {
1288
-                    $_ht['id'] = $this->page_slug;
1289
-                    $_ht['title'] = esc_html__('Help Tours', 'event_espresso');
1290
-                    $_ht['content'] = '<p>'
1291
-                                      . esc_html__(
1292
-                                          'The buttons to the right allow you to start/restart any help tours available for this page',
1293
-                                          'event_espresso'
1294
-                                      ) . '</p>';
1295
-                    $this->_current_screen->add_help_tab($_ht);
1296
-                }
1297
-            }
1298
-            if (! isset($config['help_tabs'])) {
1299
-                return;
1300
-            } //no help tabs for this route
1301
-            foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1302
-                // we're here so there ARE help tabs!
1303
-                // make sure we've got what we need
1304
-                if (! isset($cfg['title'])) {
1305
-                    throw new EE_Error(
1306
-                        esc_html__(
1307
-                            'The _page_config array is not set up properly for help tabs.  It is missing a title',
1308
-                            'event_espresso'
1309
-                        )
1310
-                    );
1311
-                }
1312
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1313
-                    throw new EE_Error(
1314
-                        esc_html__(
1315
-                            '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',
1316
-                            'event_espresso'
1317
-                        )
1318
-                    );
1319
-                }
1320
-                // first priority goes to content.
1321
-                if (! empty($cfg['content'])) {
1322
-                    $content = ! empty($cfg['content']) ? $cfg['content'] : null;
1323
-                    // second priority goes to filename
1324
-                } elseif (! empty($cfg['filename'])) {
1325
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1326
-                    // 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)
1327
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1328
-                                                             . basename($this->_get_dir())
1329
-                                                             . '/help_tabs/'
1330
-                                                             . $cfg['filename']
1331
-                                                             . '.help_tab.php' : $file_path;
1332
-                    // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1333
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1334
-                        EE_Error::add_error(
1335
-                            sprintf(
1336
-                                esc_html__(
1337
-                                    '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',
1338
-                                    'event_espresso'
1339
-                                ),
1340
-                                $tab_id,
1341
-                                key($config),
1342
-                                $file_path
1343
-                            ),
1344
-                            __FILE__,
1345
-                            __FUNCTION__,
1346
-                            __LINE__
1347
-                        );
1348
-                        return;
1349
-                    }
1350
-                    $template_args['admin_page_obj'] = $this;
1351
-                    $content = EEH_Template::display_template(
1352
-                        $file_path,
1353
-                        $template_args,
1354
-                        true
1355
-                    );
1356
-                } else {
1357
-                    $content = '';
1358
-                }
1359
-                // check if callback is valid
1360
-                if (
1361
-                    empty($content) && (
1362
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1363
-                    )
1364
-                ) {
1365
-                    EE_Error::add_error(
1366
-                        sprintf(
1367
-                            esc_html__(
1368
-                                '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.',
1369
-                                'event_espresso'
1370
-                            ),
1371
-                            $cfg['title']
1372
-                        ),
1373
-                        __FILE__,
1374
-                        __FUNCTION__,
1375
-                        __LINE__
1376
-                    );
1377
-                    return;
1378
-                }
1379
-                // setup config array for help tab method
1380
-                $id = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1381
-                $_ht = array(
1382
-                    'id'       => $id,
1383
-                    'title'    => $cfg['title'],
1384
-                    'callback' => isset($cfg['callback']) && empty($content) ? array($this, $cfg['callback']) : null,
1385
-                    'content'  => $content,
1386
-                );
1387
-                $this->_current_screen->add_help_tab($_ht);
1388
-            }
1389
-        }
1390
-    }
1391
-
1392
-
1393
-    /**
1394
-     * This basically checks loaded $_page_config property to see if there are any help_tours defined.  "help_tours" is
1395
-     * an array with properties for setting up usage of the joyride plugin
1396
-     *
1397
-     * @link   http://zurb.com/playground/jquery-joyride-feature-tour-plugin
1398
-     * @see    instructions regarding the format and construction of the "help_tour" array element is found in the
1399
-     *         _set_page_config() comments
1400
-     * @return void
1401
-     * @throws EE_Error
1402
-     * @throws InvalidArgumentException
1403
-     * @throws InvalidDataTypeException
1404
-     * @throws InvalidInterfaceException
1405
-     * @throws ReflectionException
1406
-     */
1407
-    protected function _add_help_tour()
1408
-    {
1409
-        // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1410
-        // $tours = array();
1411
-        // $this->_help_tour = array();
1412
-        // // exit early if help tours are turned off globally
1413
-        // if ((defined('EE_DISABLE_HELP_TOURS') && EE_DISABLE_HELP_TOURS)
1414
-        //     || ! EE_Registry::instance()->CFG->admin->help_tour_activation
1415
-        // ) {
1416
-        //     return;
1417
-        // }
1418
-        // // loop through _page_config to find any help_tour defined
1419
-        // foreach ($this->_page_config as $route => $config) {
1420
-        //     // we're only going to set things up for this route
1421
-        //     if ($route !== $this->_req_action) {
1422
-        //         continue;
1423
-        //     }
1424
-        //     if (isset($config['help_tour'])) {
1425
-        //         foreach ($config['help_tour'] as $tour) {
1426
-        //             $file_path = $this->_get_dir() . '/help_tours/' . $tour . '.class.php';
1427
-        //             // let's see if we can get that file...
1428
-        //             // if not its possible this is a decaf route not set in caffeinated
1429
-        //             // so lets try and get the caffeinated equivalent
1430
-        //             $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1431
-        //                                                      . basename($this->_get_dir())
1432
-        //                                                      . '/help_tours/'
1433
-        //                                                      . $tour
1434
-        //                                                      . '.class.php' : $file_path;
1435
-        //             // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1436
-        //             if (! is_readable($file_path)) {
1437
-        //                 EE_Error::add_error(
1438
-        //                     sprintf(
1439
-        //                         esc_html__(
1440
-        //                             'The file path given for the help tour (%s) is not a valid path.  Please check that the string you set for the help tour on this route (%s) is the correct spelling',
1441
-        //                             'event_espresso'
1442
-        //                         ),
1443
-        //                         $file_path,
1444
-        //                         $tour
1445
-        //                     ),
1446
-        //                     __FILE__,
1447
-        //                     __FUNCTION__,
1448
-        //                     __LINE__
1449
-        //                 );
1450
-        //                 return;
1451
-        //             }
1452
-        //             require_once $file_path;
1453
-        //             if (! class_exists($tour)) {
1454
-        //                 $error_msg[] = sprintf(
1455
-        //                     esc_html__('Something went wrong with loading the %s Help Tour Class.', 'event_espresso'),
1456
-        //                     $tour
1457
-        //                 );
1458
-        //                 $error_msg[] = $error_msg[0] . "\r\n"
1459
-        //                                . sprintf(
1460
-        //                                    esc_html__(
1461
-        //                                        'There is no class in place for the %s help tour.%s Make sure you have <strong>%s</strong> defined in the "help_tour" array for the %s route of the % admin page.',
1462
-        //                                        'event_espresso'
1463
-        //                                    ),
1464
-        //                                    $tour,
1465
-        //                                    '<br />',
1466
-        //                                    $tour,
1467
-        //                                    $this->_req_action,
1468
-        //                                    get_class($this)
1469
-        //                                );
1470
-        //                 throw new EE_Error(implode('||', $error_msg));
1471
-        //             }
1472
-        //             $tour_obj = new $tour($this->_is_caf);
1473
-        //             $tours[] = $tour_obj;
1474
-        //             $this->_help_tour[ $route ][] = EEH_Template::help_tour_stops_generator($tour_obj);
1475
-        //         }
1476
-        //         // let's inject the end tour stop element common to all pages... this will only get seen once per machine.
1477
-        //         $end_stop_tour = new EE_Help_Tour_final_stop($this->_is_caf);
1478
-        //         $tours[] = $end_stop_tour;
1479
-        //         $this->_help_tour[ $route ][] = EEH_Template::help_tour_stops_generator($end_stop_tour);
1480
-        //     }
1481
-        // }
1482
-        //
1483
-        // if (! empty($tours)) {
1484
-        //     $this->_help_tour['tours'] = $tours;
1485
-        // }
1486
-        // // that's it!  Now that the $_help_tours property is set (or not)
1487
-        // // the scripts and html should be taken care of automatically.
1488
-        //
1489
-        // /**
1490
-        //  * Allow extending the help tours variable.
1491
-        //  *
1492
-        //  * @param Array $_help_tour The array containing all help tour information to be displayed.
1493
-        //  */
1494
-        // $this->_help_tour = apply_filters('FHEE__EE_Admin_Page___add_help_tour___help_tour', $this->_help_tour);
1495
-    }
1496
-
1497
-
1498
-    /**
1499
-     * This simply sets up any qtips that have been defined in the page config
1500
-     *
1501
-     * @return void
1502
-     * @throws ReflectionException
1503
-     * @throws EE_Error
1504
-     */
1505
-    protected function _add_qtips()
1506
-    {
1507
-        if (isset($this->_route_config['qtips'])) {
1508
-            $qtips = (array) $this->_route_config['qtips'];
1509
-            // load qtip loader
1510
-            $path = array(
1511
-                $this->_get_dir() . '/qtips/',
1512
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1513
-            );
1514
-            $qtip_loader = EEH_Qtip_Loader::instance();
1515
-            if ($qtip_loader instanceof EEH_Qtip_Loader) {
1516
-                $qtip_loader->register($qtips, $path);
1517
-            }
1518
-        }
1519
-    }
1520
-
1521
-
1522
-    /**
1523
-     * _set_nav_tabs
1524
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1525
-     * wish to add additional tabs or modify accordingly.
1526
-     *
1527
-     * @return void
1528
-     * @throws InvalidArgumentException
1529
-     * @throws InvalidInterfaceException
1530
-     * @throws InvalidDataTypeException
1531
-     */
1532
-    protected function _set_nav_tabs()
1533
-    {
1534
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1535
-        $i = 0;
1536
-        foreach ($this->_page_config as $slug => $config) {
1537
-            if (
1538
-                ! is_array($config)
1539
-                || (
1540
-                    is_array($config)
1541
-                    && (
1542
-                        (isset($config['nav']) && ! $config['nav'])
1543
-                        || ! isset($config['nav'])
1544
-                    )
1545
-                )
1546
-            ) {
1547
-                continue;
1548
-            }
1549
-            // no nav tab for this config
1550
-            // check for persistent flag
1551
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1552
-                // nav tab is only to appear when route requested.
1553
-                continue;
1554
-            }
1555
-            if (! $this->check_user_access($slug, true)) {
1556
-                // no nav tab because current user does not have access.
1557
-                continue;
1558
-            }
1559
-            $css_class = isset($config['css_class']) ? $config['css_class'] . ' ' : '';
1560
-            $this->_nav_tabs[ $slug ] = array(
1561
-                'url'       => isset($config['nav']['url'])
1562
-                    ? $config['nav']['url']
1563
-                    : EE_Admin_Page::add_query_args_and_nonce(
1564
-                        array('action' => $slug),
1565
-                        $this->_admin_base_url
1566
-                    ),
1567
-                'link_text' => isset($config['nav']['label'])
1568
-                    ? $config['nav']['label']
1569
-                    : ucwords(
1570
-                        str_replace('_', ' ', $slug)
1571
-                    ),
1572
-                'css_class' => $this->_req_action === $slug ? $css_class . 'nav-tab-active' : $css_class,
1573
-                'order'     => isset($config['nav']['order']) ? $config['nav']['order'] : $i,
1574
-            );
1575
-            $i++;
1576
-        }
1577
-        // if $this->_nav_tabs is empty then lets set the default
1578
-        if (empty($this->_nav_tabs)) {
1579
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = array(
1580
-                'url'       => $this->_admin_base_url,
1581
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1582
-                'css_class' => 'nav-tab-active',
1583
-                'order'     => 10,
1584
-            );
1585
-        }
1586
-        // now let's sort the tabs according to order
1587
-        usort($this->_nav_tabs, array($this, '_sort_nav_tabs'));
1588
-    }
1589
-
1590
-
1591
-    /**
1592
-     * _set_current_labels
1593
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1594
-     * property array
1595
-     *
1596
-     * @return void
1597
-     */
1598
-    private function _set_current_labels()
1599
-    {
1600
-        if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1601
-            foreach ($this->_route_config['labels'] as $label => $text) {
1602
-                if (is_array($text)) {
1603
-                    foreach ($text as $sublabel => $subtext) {
1604
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1605
-                    }
1606
-                } else {
1607
-                    $this->_labels[ $label ] = $text;
1608
-                }
1609
-            }
1610
-        }
1611
-    }
1612
-
1613
-
1614
-    /**
1615
-     *        verifies user access for this admin page
1616
-     *
1617
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1618
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1619
-     *                               return false if verify fail.
1620
-     * @return bool
1621
-     * @throws InvalidArgumentException
1622
-     * @throws InvalidDataTypeException
1623
-     * @throws InvalidInterfaceException
1624
-     */
1625
-    public function check_user_access($route_to_check = '', $verify_only = false)
1626
-    {
1627
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1628
-        $route_to_check = empty($route_to_check) ? $this->_req_action : $route_to_check;
1629
-        $capability = ! empty($route_to_check) && isset($this->_page_routes[ $route_to_check ])
1630
-                      && is_array(
1631
-                          $this->_page_routes[ $route_to_check ]
1632
-                      )
1633
-                      && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1634
-            ? $this->_page_routes[ $route_to_check ]['capability'] : null;
1635
-        if (empty($capability) && empty($route_to_check)) {
1636
-            $capability = is_array($this->_route) && empty($this->_route['capability']) ? 'manage_options'
1637
-                : $this->_route['capability'];
1638
-        } else {
1639
-            $capability = empty($capability) ? 'manage_options' : $capability;
1640
-        }
1641
-        $id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1642
-        if (
1643
-            ! defined('DOING_AJAX')
1644
-            && (
1645
-                ! function_exists('is_admin')
1646
-                || ! EE_Registry::instance()->CAP->current_user_can(
1647
-                    $capability,
1648
-                    $this->page_slug
1649
-                    . '_'
1650
-                    . $route_to_check,
1651
-                    $id
1652
-                )
1653
-            )
1654
-        ) {
1655
-            if ($verify_only) {
1656
-                return false;
1657
-            }
1658
-            if (is_user_logged_in()) {
1659
-                wp_die(__('You do not have access to this route.', 'event_espresso'));
1660
-            } else {
1661
-                return false;
1662
-            }
1663
-        }
1664
-        return true;
1665
-    }
1666
-
1667
-
1668
-    /**
1669
-     * admin_init_global
1670
-     * This runs all the code that we want executed within the WP admin_init hook.
1671
-     * This method executes for ALL EE Admin pages.
1672
-     *
1673
-     * @return void
1674
-     */
1675
-    public function admin_init_global()
1676
-    {
1677
-    }
1678
-
1679
-
1680
-    /**
1681
-     * wp_loaded_global
1682
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1683
-     * EE_Admin page and will execute on every EE Admin Page load
1684
-     *
1685
-     * @return void
1686
-     */
1687
-    public function wp_loaded()
1688
-    {
1689
-    }
1690
-
1691
-
1692
-    /**
1693
-     * admin_notices
1694
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1695
-     * ALL EE_Admin pages.
1696
-     *
1697
-     * @return void
1698
-     */
1699
-    public function admin_notices_global()
1700
-    {
1701
-        $this->_display_no_javascript_warning();
1702
-        $this->_display_espresso_notices();
1703
-    }
1704
-
1705
-
1706
-    public function network_admin_notices_global()
1707
-    {
1708
-        $this->_display_no_javascript_warning();
1709
-        $this->_display_espresso_notices();
1710
-    }
1711
-
1712
-
1713
-    /**
1714
-     * admin_footer_scripts_global
1715
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1716
-     * will apply on ALL EE_Admin pages.
1717
-     *
1718
-     * @return void
1719
-     */
1720
-    public function admin_footer_scripts_global()
1721
-    {
1722
-        $this->_add_admin_page_ajax_loading_img();
1723
-        $this->_add_admin_page_overlay();
1724
-        // if metaboxes are present we need to add the nonce field
1725
-        if (
1726
-            isset($this->_route_config['metaboxes'])
1727
-            || isset($this->_route_config['list_table'])
1728
-            || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1729
-        ) {
1730
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1731
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1732
-        }
1733
-    }
1734
-
1735
-
1736
-    /**
1737
-     * admin_footer_global
1738
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1739
-     * This particular method will apply on ALL EE_Admin Pages.
1740
-     *
1741
-     * @return void
1742
-     * @throws InvalidArgumentException
1743
-     * @throws InvalidDataTypeException
1744
-     * @throws InvalidInterfaceException
1745
-     */
1746
-    public function admin_footer_global()
1747
-    {
1748
-        // dialog container for dialog helper
1749
-        $d_cont = '<div class="ee-admin-dialog-container auto-hide hidden">' . "\n";
1750
-        $d_cont .= '<div class="ee-notices"></div>';
1751
-        $d_cont .= '<div class="ee-admin-dialog-container-inner-content"></div>';
1752
-        $d_cont .= '</div>';
1753
-        echo $d_cont;
1754
-        // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1755
-        // help tour stuff?
1756
-        // if (isset($this->_help_tour[ $this->_req_action ])) {
1757
-        //     echo implode('<br />', $this->_help_tour[ $this->_req_action ]);
1758
-        // }
1759
-        // current set timezone for timezone js
1760
-        echo '<span id="current_timezone" class="hidden">' . EEH_DTT_Helper::get_timezone() . '</span>';
1761
-    }
1762
-
1763
-
1764
-    /**
1765
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1766
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1767
-     * help popups then in your templates or your content you set "triggers" for the content using the
1768
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1769
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1770
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1771
-     * for the
1772
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1773
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1774
-     *    'help_trigger_id' => array(
1775
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1776
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1777
-     *    )
1778
-     * );
1779
-     * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1780
-     *
1781
-     * @param array $help_array
1782
-     * @param bool  $display
1783
-     * @return string content
1784
-     * @throws DomainException
1785
-     * @throws EE_Error
1786
-     */
1787
-    protected function _set_help_popup_content($help_array = array(), $display = false)
1788
-    {
1789
-        $content = '';
1790
-        $help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1791
-        // loop through the array and setup content
1792
-        foreach ($help_array as $trigger => $help) {
1793
-            // make sure the array is setup properly
1794
-            if (! isset($help['title'], $help['content'])) {
1795
-                throw new EE_Error(
1796
-                    esc_html__(
1797
-                        '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',
1798
-                        'event_espresso'
1799
-                    )
1800
-                );
1801
-            }
1802
-            // we're good so let'd setup the template vars and then assign parsed template content to our content.
1803
-            $template_args = array(
1804
-                'help_popup_id'      => $trigger,
1805
-                'help_popup_title'   => $help['title'],
1806
-                'help_popup_content' => $help['content'],
1807
-            );
1808
-            $content .= EEH_Template::display_template(
1809
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1810
-                $template_args,
1811
-                true
1812
-            );
1813
-        }
1814
-        if ($display) {
1815
-            echo $content;
1816
-            return '';
1817
-        }
1818
-        return $content;
1819
-    }
1820
-
1821
-
1822
-    /**
1823
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1824
-     *
1825
-     * @return array properly formatted array for help popup content
1826
-     * @throws EE_Error
1827
-     */
1828
-    private function _get_help_content()
1829
-    {
1830
-        // what is the method we're looking for?
1831
-        $method_name = '_help_popup_content_' . $this->_req_action;
1832
-        // if method doesn't exist let's get out.
1833
-        if (! method_exists($this, $method_name)) {
1834
-            return array();
1835
-        }
1836
-        // k we're good to go let's retrieve the help array
1837
-        $help_array = $this->{$method_name}();
1838
-        // make sure we've got an array!
1839
-        if (! is_array($help_array)) {
1840
-            throw new EE_Error(
1841
-                esc_html__(
1842
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1843
-                    'event_espresso'
1844
-                )
1845
-            );
1846
-        }
1847
-        return $help_array;
1848
-    }
1849
-
1850
-
1851
-    /**
1852
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1853
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1854
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1855
-     *
1856
-     * @param string  $trigger_id reference for retrieving the trigger content for the popup
1857
-     * @param boolean $display    if false then we return the trigger string
1858
-     * @param array   $dimensions an array of dimensions for the box (array(h,w))
1859
-     * @return string
1860
-     * @throws DomainException
1861
-     * @throws EE_Error
1862
-     */
1863
-    protected function _set_help_trigger($trigger_id, $display = true, $dimensions = array('400', '640'))
1864
-    {
1865
-        if (defined('DOING_AJAX')) {
1866
-            return '';
1867
-        }
1868
-        // 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
1869
-        $help_array = $this->_get_help_content();
1870
-        $help_content = '';
1871
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1872
-            $help_array[ $trigger_id ] = array(
1873
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1874
-                'content' => esc_html__(
1875
-                    '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.)',
1876
-                    'event_espresso'
1877
-                ),
1878
-            );
1879
-            $help_content = $this->_set_help_popup_content($help_array);
1880
-        }
1881
-        // let's setup the trigger
1882
-        $content = '<a class="ee-dialog" href="?height='
1883
-                   . $dimensions[0]
1884
-                   . '&width='
1885
-                   . $dimensions[1]
1886
-                   . '&inlineId='
1887
-                   . $trigger_id
1888
-                   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1889
-        $content .= $help_content;
1890
-        if ($display) {
1891
-            echo $content;
1892
-            return '';
1893
-        }
1894
-        return $content;
1895
-    }
1896
-
1897
-
1898
-    /**
1899
-     * _add_global_screen_options
1900
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1901
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1902
-     *
1903
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1904
-     *         see also WP_Screen object documents...
1905
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1906
-     * @abstract
1907
-     * @return void
1908
-     */
1909
-    private function _add_global_screen_options()
1910
-    {
1911
-    }
1912
-
1913
-
1914
-    /**
1915
-     * _add_global_feature_pointers
1916
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1917
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1918
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1919
-     *
1920
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1921
-     *         extended) also see:
1922
-     * @link   http://eamann.com/tech/wordpress-portland/
1923
-     * @abstract
1924
-     * @return void
1925
-     */
1926
-    private function _add_global_feature_pointers()
1927
-    {
1928
-    }
1929
-
1930
-
1931
-    /**
1932
-     * load_global_scripts_styles
1933
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1934
-     *
1935
-     * @return void
1936
-     * @throws EE_Error
1937
-     */
1938
-    public function load_global_scripts_styles()
1939
-    {
1940
-        // add debugging styles
1941
-        if (WP_DEBUG) {
1942
-            add_action('admin_head', array($this, 'add_xdebug_style'));
1943
-        }
1944
-        // taking care of metaboxes
1945
-        if (
1946
-            empty($this->_cpt_route)
1947
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1948
-        ) {
1949
-            wp_enqueue_script('dashboard');
1950
-        }
1951
-
1952
-        // LOCALIZED DATA
1953
-        // localize script for ajax lazy loading
1954
-        wp_localize_script(
1955
-            EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1956
-            'eeLazyLoadingContainers',
1957
-            apply_filters(
1958
-                'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1959
-                ['espresso_news_post_box_content']
1960
-            )
1961
-        );
1962
-        // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1963
-        // /**
1964
-        //  * help tour stuff
1965
-        //  */
1966
-        // if (! empty($this->_help_tour)) {
1967
-        //     // register the js for kicking things off
1968
-        //     wp_enqueue_script(
1969
-        //         'ee-help-tour',
1970
-        //         EE_ADMIN_URL . 'assets/ee-help-tour.js',
1971
-        //         array('jquery-joyride'),
1972
-        //         EVENT_ESPRESSO_VERSION,
1973
-        //         true
1974
-        //     );
1975
-        //     $tours = array();
1976
-        //     // setup tours for the js tour object
1977
-        //     foreach ($this->_help_tour['tours'] as $tour) {
1978
-        //         if ($tour instanceof EE_Help_Tour) {
1979
-        //             $tours[] = array(
1980
-        //                 'id'      => $tour->get_slug(),
1981
-        //                 'options' => $tour->get_options(),
1982
-        //             );
1983
-        //         }
1984
-        //     }
1985
-        //     wp_localize_script('ee-help-tour', 'EE_HELP_TOUR', array('tours' => $tours));
1986
-        //     // admin_footer_global will take care of making sure our help_tour skeleton gets printed via the info stored in $this->_help_tour
1987
-        // }
1988
-    }
1989
-
1990
-
1991
-    /**
1992
-     *        admin_footer_scripts_eei18n_js_strings
1993
-     *
1994
-     * @return        void
1995
-     */
1996
-    public function admin_footer_scripts_eei18n_js_strings()
1997
-    {
1998
-        EE_Registry::$i18n_js_strings['ajax_url'] = WP_AJAX_URL;
1999
-        EE_Registry::$i18n_js_strings['confirm_delete'] = esc_html__(
2000
-            '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!!!',
2001
-            'event_espresso'
2002
-        );
2003
-        EE_Registry::$i18n_js_strings['January'] = esc_html__('January', 'event_espresso');
2004
-        EE_Registry::$i18n_js_strings['February'] = esc_html__('February', 'event_espresso');
2005
-        EE_Registry::$i18n_js_strings['March'] = esc_html__('March', 'event_espresso');
2006
-        EE_Registry::$i18n_js_strings['April'] = esc_html__('April', 'event_espresso');
2007
-        EE_Registry::$i18n_js_strings['May'] = esc_html__('May', 'event_espresso');
2008
-        EE_Registry::$i18n_js_strings['June'] = esc_html__('June', 'event_espresso');
2009
-        EE_Registry::$i18n_js_strings['July'] = esc_html__('July', 'event_espresso');
2010
-        EE_Registry::$i18n_js_strings['August'] = esc_html__('August', 'event_espresso');
2011
-        EE_Registry::$i18n_js_strings['September'] = esc_html__('September', 'event_espresso');
2012
-        EE_Registry::$i18n_js_strings['October'] = esc_html__('October', 'event_espresso');
2013
-        EE_Registry::$i18n_js_strings['November'] = esc_html__('November', 'event_espresso');
2014
-        EE_Registry::$i18n_js_strings['December'] = esc_html__('December', 'event_espresso');
2015
-        EE_Registry::$i18n_js_strings['Jan'] = esc_html__('Jan', 'event_espresso');
2016
-        EE_Registry::$i18n_js_strings['Feb'] = esc_html__('Feb', 'event_espresso');
2017
-        EE_Registry::$i18n_js_strings['Mar'] = esc_html__('Mar', 'event_espresso');
2018
-        EE_Registry::$i18n_js_strings['Apr'] = esc_html__('Apr', 'event_espresso');
2019
-        EE_Registry::$i18n_js_strings['May'] = esc_html__('May', 'event_espresso');
2020
-        EE_Registry::$i18n_js_strings['Jun'] = esc_html__('Jun', 'event_espresso');
2021
-        EE_Registry::$i18n_js_strings['Jul'] = esc_html__('Jul', 'event_espresso');
2022
-        EE_Registry::$i18n_js_strings['Aug'] = esc_html__('Aug', 'event_espresso');
2023
-        EE_Registry::$i18n_js_strings['Sep'] = esc_html__('Sep', 'event_espresso');
2024
-        EE_Registry::$i18n_js_strings['Oct'] = esc_html__('Oct', 'event_espresso');
2025
-        EE_Registry::$i18n_js_strings['Nov'] = esc_html__('Nov', 'event_espresso');
2026
-        EE_Registry::$i18n_js_strings['Dec'] = esc_html__('Dec', 'event_espresso');
2027
-        EE_Registry::$i18n_js_strings['Sunday'] = esc_html__('Sunday', 'event_espresso');
2028
-        EE_Registry::$i18n_js_strings['Monday'] = esc_html__('Monday', 'event_espresso');
2029
-        EE_Registry::$i18n_js_strings['Tuesday'] = esc_html__('Tuesday', 'event_espresso');
2030
-        EE_Registry::$i18n_js_strings['Wednesday'] = esc_html__('Wednesday', 'event_espresso');
2031
-        EE_Registry::$i18n_js_strings['Thursday'] = esc_html__('Thursday', 'event_espresso');
2032
-        EE_Registry::$i18n_js_strings['Friday'] = esc_html__('Friday', 'event_espresso');
2033
-        EE_Registry::$i18n_js_strings['Saturday'] = esc_html__('Saturday', 'event_espresso');
2034
-        EE_Registry::$i18n_js_strings['Sun'] = esc_html__('Sun', 'event_espresso');
2035
-        EE_Registry::$i18n_js_strings['Mon'] = esc_html__('Mon', 'event_espresso');
2036
-        EE_Registry::$i18n_js_strings['Tue'] = esc_html__('Tue', 'event_espresso');
2037
-        EE_Registry::$i18n_js_strings['Wed'] = esc_html__('Wed', 'event_espresso');
2038
-        EE_Registry::$i18n_js_strings['Thu'] = esc_html__('Thu', 'event_espresso');
2039
-        EE_Registry::$i18n_js_strings['Fri'] = esc_html__('Fri', 'event_espresso');
2040
-        EE_Registry::$i18n_js_strings['Sat'] = esc_html__('Sat', 'event_espresso');
2041
-    }
2042
-
2043
-
2044
-    /**
2045
-     *        load enhanced xdebug styles for ppl with failing eyesight
2046
-     *
2047
-     * @return        void
2048
-     */
2049
-    public function add_xdebug_style()
2050
-    {
2051
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2052
-    }
2053
-
2054
-
2055
-    /************************/
2056
-    /** LIST TABLE METHODS **/
2057
-    /************************/
2058
-    /**
2059
-     * this sets up the list table if the current view requires it.
2060
-     *
2061
-     * @return void
2062
-     * @throws EE_Error
2063
-     * @throws InvalidArgumentException
2064
-     * @throws InvalidDataTypeException
2065
-     * @throws InvalidInterfaceException
2066
-     */
2067
-    protected function _set_list_table()
2068
-    {
2069
-        // first is this a list_table view?
2070
-        if (! isset($this->_route_config['list_table'])) {
2071
-            return;
2072
-        } //not a list_table view so get out.
2073
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
2074
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2075
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2076
-            // user error msg
2077
-            $error_msg = esc_html__(
2078
-                'An error occurred. The requested list table views could not be found.',
2079
-                'event_espresso'
2080
-            );
2081
-            // developer error msg
2082
-            $error_msg .= '||'
2083
-                          . sprintf(
2084
-                              esc_html__(
2085
-                                  '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.',
2086
-                                  'event_espresso'
2087
-                              ),
2088
-                              $this->_req_action,
2089
-                              $list_table_view
2090
-                          );
2091
-            throw new EE_Error($error_msg);
2092
-        }
2093
-        // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2094
-        $this->_views = apply_filters(
2095
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2096
-            $this->_views
2097
-        );
2098
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2099
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2100
-        $this->_set_list_table_view();
2101
-        $this->_set_list_table_object();
2102
-    }
2103
-
2104
-
2105
-    /**
2106
-     * set current view for List Table
2107
-     *
2108
-     * @return void
2109
-     */
2110
-    protected function _set_list_table_view()
2111
-    {
2112
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2113
-        // looking at active items or dumpster diving ?
2114
-        if (! isset($this->_req_data['status']) || ! array_key_exists($this->_req_data['status'], $this->_views)) {
2115
-            $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2116
-        } else {
2117
-            $this->_view = sanitize_key($this->_req_data['status']);
2118
-        }
2119
-    }
2120
-
2121
-
2122
-    /**
2123
-     * _set_list_table_object
2124
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2125
-     *
2126
-     * @throws InvalidInterfaceException
2127
-     * @throws InvalidArgumentException
2128
-     * @throws InvalidDataTypeException
2129
-     * @throws EE_Error
2130
-     * @throws InvalidInterfaceException
2131
-     */
2132
-    protected function _set_list_table_object()
2133
-    {
2134
-        if (isset($this->_route_config['list_table'])) {
2135
-            if (! class_exists($this->_route_config['list_table'])) {
2136
-                throw new EE_Error(
2137
-                    sprintf(
2138
-                        esc_html__(
2139
-                            '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.',
2140
-                            'event_espresso'
2141
-                        ),
2142
-                        $this->_route_config['list_table'],
2143
-                        get_class($this)
2144
-                    )
2145
-                );
2146
-            }
2147
-            $this->_list_table_object = $this->loader->getShared(
2148
-                $this->_route_config['list_table'],
2149
-                array($this)
2150
-            );
2151
-        }
2152
-    }
2153
-
2154
-
2155
-    /**
2156
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2157
-     *
2158
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2159
-     *                                                    urls.  The array should be indexed by the view it is being
2160
-     *                                                    added to.
2161
-     * @return array
2162
-     */
2163
-    public function get_list_table_view_RLs($extra_query_args = array())
2164
-    {
2165
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2166
-        if (empty($this->_views)) {
2167
-            $this->_views = array();
2168
-        }
2169
-        // cycle thru views
2170
-        foreach ($this->_views as $key => $view) {
2171
-            $query_args = array();
2172
-            // check for current view
2173
-            $this->_views[ $key ]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2174
-            $query_args['action'] = $this->_req_action;
2175
-            $query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2176
-            $query_args['status'] = $view['slug'];
2177
-            // merge any other arguments sent in.
2178
-            if (isset($extra_query_args[ $view['slug'] ])) {
2179
-                foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2180
-                    $query_args[] = $extra_query_arg;
2181
-                }
2182
-            }
2183
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2184
-        }
2185
-        return $this->_views;
2186
-    }
2187
-
2188
-
2189
-    /**
2190
-     * _entries_per_page_dropdown
2191
-     * generates a drop down box for selecting the number of visible rows in an admin page list table
2192
-     *
2193
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2194
-     *         WP does it.
2195
-     * @param int $max_entries total number of rows in the table
2196
-     * @return string
2197
-     */
2198
-    protected function _entries_per_page_dropdown($max_entries = 0)
2199
-    {
2200
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2201
-        $values = array(10, 25, 50, 100);
2202
-        $per_page = (! empty($this->_req_data['per_page'])) ? absint($this->_req_data['per_page']) : 10;
2203
-        if ($max_entries) {
2204
-            $values[] = $max_entries;
2205
-            sort($values);
2206
-        }
2207
-        $entries_per_page_dropdown = '
124
+	// set via request page and action args.
125
+	protected $_current_page;
126
+
127
+	protected $_current_view;
128
+
129
+	protected $_current_page_view_url;
130
+
131
+	// sanitized request action (and nonce)
132
+
133
+	/**
134
+	 * @var string $_req_action
135
+	 */
136
+	protected $_req_action;
137
+
138
+	/**
139
+	 * @var string $_req_nonce
140
+	 */
141
+	protected $_req_nonce;
142
+
143
+	// search related
144
+	protected $_search_btn_label;
145
+
146
+	protected $_search_box_callback;
147
+
148
+	/**
149
+	 * WP Current Screen object
150
+	 *
151
+	 * @var WP_Screen
152
+	 */
153
+	protected $_current_screen;
154
+
155
+	// for holding EE_Admin_Hooks object when needed (set via set_hook_object())
156
+	protected $_hook_obj;
157
+
158
+	// for holding incoming request data
159
+	protected $_req_data = [];
160
+
161
+	// yes / no array for admin form fields
162
+	protected $_yes_no_values = array();
163
+
164
+	// some default things shared by all child classes
165
+	protected $_default_espresso_metaboxes;
166
+
167
+	/**
168
+	 *    EE_Registry Object
169
+	 *
170
+	 * @var    EE_Registry
171
+	 */
172
+	protected $EE;
173
+
174
+
175
+	/**
176
+	 * This is just a property that flags whether the given route is a caffeinated route or not.
177
+	 *
178
+	 * @var boolean
179
+	 */
180
+	protected $_is_caf = false;
181
+
182
+	/**
183
+	 * whether or not initializePage() has run
184
+	 *
185
+	 * @var boolean
186
+	 */
187
+	protected $initialized = false;
188
+
189
+
190
+	/**
191
+	 * @Constructor
192
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
193
+	 * @throws InvalidArgumentException
194
+	 * @throws InvalidDataTypeException
195
+	 * @throws InvalidInterfaceException
196
+	 * @throws ReflectionException
197
+	 */
198
+	public function __construct($routing = true)
199
+	{
200
+		$this->loader = LoaderFactory::getLoader();
201
+		$this->admin_config = $this->loader->getShared('EE_Admin_Config');
202
+		if (strpos($this->_get_dir(), 'caffeinated') !== false) {
203
+			$this->_is_caf = true;
204
+		}
205
+		$this->_yes_no_values = array(
206
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
207
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
208
+		);
209
+		// set the _req_data property.
210
+		$this->_req_data = array_merge($_GET, $_POST);
211
+		// routing enabled?
212
+		$this->_routing = $routing;
213
+	}
214
+
215
+
216
+	/**
217
+	 * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
218
+	 * for child classes that needed to set properties prior to these methods getting called,
219
+	 * but also needed the parent class to have its construction completed as well.
220
+	 * Bottom line is that constructors should ONLY be used for setting initial properties
221
+	 * and any complex initialization logic should only run after instantiation is complete.
222
+	 *
223
+	 * This method gets called immediately after construction from within
224
+	 *      EE_Admin_Page_Init::_initialize_admin_page()
225
+	 *
226
+	 * @throws EE_Error
227
+	 * @throws InvalidArgumentException
228
+	 * @throws InvalidDataTypeException
229
+	 * @throws InvalidInterfaceException
230
+	 * @throws ReflectionException
231
+	 * @since $VID:$
232
+	 */
233
+	public function initializePage()
234
+	{
235
+		if ($this->initialized) {
236
+			return;
237
+		}
238
+		// set initial page props (child method)
239
+		$this->_init_page_props();
240
+		// set global defaults
241
+		$this->_set_defaults();
242
+		// set early because incoming requests could be ajax related and we need to register those hooks.
243
+		$this->_global_ajax_hooks();
244
+		$this->_ajax_hooks();
245
+		// other_page_hooks have to be early too.
246
+		$this->_do_other_page_hooks();
247
+		// This just allows us to have extending classes do something specific
248
+		// before the parent constructor runs _page_setup().
249
+		if (method_exists($this, '_before_page_setup')) {
250
+			$this->_before_page_setup();
251
+		}
252
+		// set up page dependencies
253
+		$this->_page_setup();
254
+		$this->initialized = true;
255
+	}
256
+
257
+
258
+	/**
259
+	 * _init_page_props
260
+	 * Child classes use to set at least the following properties:
261
+	 * $page_slug.
262
+	 * $page_label.
263
+	 *
264
+	 * @abstract
265
+	 * @return void
266
+	 */
267
+	abstract protected function _init_page_props();
268
+
269
+
270
+	/**
271
+	 * _ajax_hooks
272
+	 * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
273
+	 * Note: within the ajax callback methods.
274
+	 *
275
+	 * @abstract
276
+	 * @return void
277
+	 */
278
+	abstract protected function _ajax_hooks();
279
+
280
+
281
+	/**
282
+	 * _define_page_props
283
+	 * child classes define page properties in here.  Must include at least:
284
+	 * $_admin_base_url = base_url for all admin pages
285
+	 * $_admin_page_title = default admin_page_title for admin pages
286
+	 * $_labels = array of default labels for various automatically generated elements:
287
+	 *    array(
288
+	 *        'buttons' => array(
289
+	 *            'add' => esc_html__('label for add new button'),
290
+	 *            'edit' => esc_html__('label for edit button'),
291
+	 *            'delete' => esc_html__('label for delete button')
292
+	 *            )
293
+	 *        )
294
+	 *
295
+	 * @abstract
296
+	 * @return void
297
+	 */
298
+	abstract protected function _define_page_props();
299
+
300
+
301
+	/**
302
+	 * _set_page_routes
303
+	 * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
304
+	 * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
305
+	 * have a 'default' route. Here's the format
306
+	 * $this->_page_routes = array(
307
+	 *        'default' => array(
308
+	 *            'func' => '_default_method_handling_route',
309
+	 *            'args' => array('array','of','args'),
310
+	 *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
311
+	 *            ajax request, backend processing)
312
+	 *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
313
+	 *            headers route after.  The string you enter here should match the defined route reference for a
314
+	 *            headers sent route.
315
+	 *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
316
+	 *            this route.
317
+	 *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
318
+	 *            checks).
319
+	 *        ),
320
+	 *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
321
+	 *        handling method.
322
+	 *        )
323
+	 * )
324
+	 *
325
+	 * @abstract
326
+	 * @return void
327
+	 */
328
+	abstract protected function _set_page_routes();
329
+
330
+
331
+	/**
332
+	 * _set_page_config
333
+	 * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
334
+	 * array corresponds to the page_route for the loaded page. Format:
335
+	 * $this->_page_config = array(
336
+	 *        'default' => array(
337
+	 *            'labels' => array(
338
+	 *                'buttons' => array(
339
+	 *                    'add' => esc_html__('label for adding item'),
340
+	 *                    'edit' => esc_html__('label for editing item'),
341
+	 *                    'delete' => esc_html__('label for deleting item')
342
+	 *                ),
343
+	 *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
344
+	 *            ), //optional an array of custom labels for various automatically generated elements to use on the
345
+	 *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
346
+	 *            _define_page_props() method
347
+	 *            'nav' => array(
348
+	 *                'label' => esc_html__('Label for Tab', 'event_espresso').
349
+	 *                'url' => 'http://someurl', //automatically generated UNLESS you define
350
+	 *                'css_class' => 'css-class', //automatically generated UNLESS you define
351
+	 *                'order' => 10, //required to indicate tab position.
352
+	 *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
353
+	 *                displayed then add this parameter.
354
+	 *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
355
+	 *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
356
+	 *            metaboxes set for eventespresso admin pages.
357
+	 *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
358
+	 *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
359
+	 *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
360
+	 *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
361
+	 *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
362
+	 *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
363
+	 *            array indicates the max number of columns (4) and the default number of columns on page load (2).
364
+	 *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
365
+	 *            want to display.
366
+	 *            'help_tabs' => array( //this is used for adding help tabs to a page
367
+	 *                'tab_id' => array(
368
+	 *                    'title' => 'tab_title',
369
+	 *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
370
+	 *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
371
+	 *                    should match a file in the admin folder's "help_tabs" dir (ie..
372
+	 *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
373
+	 *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
374
+	 *                    attempt to use the callback which should match the name of a method in the class
375
+	 *                    ),
376
+	 *                'tab2_id' => array(
377
+	 *                    'title' => 'tab2 title',
378
+	 *                    'filename' => 'file_name_2'
379
+	 *                    'callback' => 'callback_method_for_content',
380
+	 *                 ),
381
+	 *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
382
+	 *            help tab area on an admin page. @link
383
+	 *            http://make.wordpress.org/core/2011/12/06/help-and-screen-api-changes-in-3-3/
384
+	 *            'help_tour' => array(
385
+	 *                'name_of_help_tour_class', //all help tours shoudl be a child class of EE_Help_Tour and located
386
+	 *                in a folder for this admin page named "help_tours", a file name matching the key given here
387
+	 *                (name_of_help_tour_class.class.php), and class matching key given here (name_of_help_tour_class)
388
+	 *            ),
389
+	 *            'require_nonce' => TRUE //this is used if you want to set a route to NOT require a nonce (default is
390
+	 *            true if it isn't present).  To remove the requirement for a nonce check when this route is visited
391
+	 *            just set
392
+	 *            'require_nonce' to FALSE
393
+	 *            )
394
+	 * )
395
+	 *
396
+	 * @abstract
397
+	 * @return void
398
+	 */
399
+	abstract protected function _set_page_config();
400
+
401
+
402
+
403
+
404
+
405
+	/** end sample help_tour methods **/
406
+	/**
407
+	 * _add_screen_options
408
+	 * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
409
+	 * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
410
+	 * to a particular view.
411
+	 *
412
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
413
+	 *         see also WP_Screen object documents...
414
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
415
+	 * @abstract
416
+	 * @return void
417
+	 */
418
+	abstract protected function _add_screen_options();
419
+
420
+
421
+	/**
422
+	 * _add_feature_pointers
423
+	 * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
424
+	 * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
425
+	 * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
426
+	 * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
427
+	 * extended) also see:
428
+	 *
429
+	 * @link   http://eamann.com/tech/wordpress-portland/
430
+	 * @abstract
431
+	 * @return void
432
+	 */
433
+	abstract protected function _add_feature_pointers();
434
+
435
+
436
+	/**
437
+	 * load_scripts_styles
438
+	 * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
439
+	 * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
440
+	 * scripts/styles per view by putting them in a dynamic function in this format
441
+	 * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
442
+	 *
443
+	 * @abstract
444
+	 * @return void
445
+	 */
446
+	abstract public function load_scripts_styles();
447
+
448
+
449
+	/**
450
+	 * admin_init
451
+	 * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
452
+	 * all pages/views loaded by child class.
453
+	 *
454
+	 * @abstract
455
+	 * @return void
456
+	 */
457
+	abstract public function admin_init();
458
+
459
+
460
+	/**
461
+	 * admin_notices
462
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
463
+	 * all pages/views loaded by child class.
464
+	 *
465
+	 * @abstract
466
+	 * @return void
467
+	 */
468
+	abstract public function admin_notices();
469
+
470
+
471
+	/**
472
+	 * admin_footer_scripts
473
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
474
+	 * will apply to all pages/views loaded by child class.
475
+	 *
476
+	 * @return void
477
+	 */
478
+	abstract public function admin_footer_scripts();
479
+
480
+
481
+	/**
482
+	 * admin_footer
483
+	 * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
484
+	 * apply to all pages/views loaded by child class.
485
+	 *
486
+	 * @return void
487
+	 */
488
+	public function admin_footer()
489
+	{
490
+	}
491
+
492
+
493
+	/**
494
+	 * _global_ajax_hooks
495
+	 * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
496
+	 * Note: within the ajax callback methods.
497
+	 *
498
+	 * @abstract
499
+	 * @return void
500
+	 */
501
+	protected function _global_ajax_hooks()
502
+	{
503
+		// for lazy loading of metabox content
504
+		add_action('wp_ajax_espresso-ajax-content', array($this, 'ajax_metabox_content'), 10);
505
+
506
+		add_action(
507
+			'wp_ajax_espresso_hide_status_change_notice',
508
+			[$this, 'hideStatusChangeNotice']
509
+		);
510
+		add_action(
511
+			'wp_ajax_nopriv_espresso_hide_status_change_notice',
512
+			[$this, 'hideStatusChangeNotice']
513
+		);
514
+	}
515
+
516
+
517
+	public function ajax_metabox_content()
518
+	{
519
+		$contentid = isset($this->_req_data['contentid']) ? $this->_req_data['contentid'] : '';
520
+		$url = isset($this->_req_data['contenturl']) ? $this->_req_data['contenturl'] : '';
521
+		EE_Admin_Page::cached_rss_display($contentid, $url);
522
+		wp_die();
523
+	}
524
+
525
+
526
+	public function hideStatusChangeNotice()
527
+	{
528
+		$response = [];
529
+		try {
530
+			/** @var EventEspresso\core\admin\StatusChangeNotice $status_change_notice */
531
+			$status_change_notice = $this->loader->getShared('EventEspresso\core\admin\StatusChangeNotice');
532
+			$response['success'] = $status_change_notice->dismiss() > -1;
533
+		} catch (Exception $exception) {
534
+			$response['errors'] = $exception->getMessage();
535
+		}
536
+		echo wp_json_encode($response);
537
+		exit();
538
+	}
539
+
540
+
541
+	/**
542
+	 * _page_setup
543
+	 * Makes sure any things that need to be loaded early get handled.  We also escape early here if the page requested
544
+	 * doesn't match the object.
545
+	 *
546
+	 * @final
547
+	 * @return void
548
+	 * @throws EE_Error
549
+	 * @throws InvalidArgumentException
550
+	 * @throws ReflectionException
551
+	 * @throws InvalidDataTypeException
552
+	 * @throws InvalidInterfaceException
553
+	 */
554
+	final protected function _page_setup()
555
+	{
556
+		// requires?
557
+		// admin_init stuff - global - we're setting this REALLY early
558
+		// so if EE_Admin pages have to hook into other WP pages they can.
559
+		// But keep in mind, not everything is available from the EE_Admin Page object at this point.
560
+		add_action('admin_init', array($this, 'admin_init_global'), 5);
561
+		// next verify if we need to load anything...
562
+		$this->_current_page = ! empty($_GET['page']) ? sanitize_key($_GET['page']) : '';
563
+		$this->page_folder = strtolower(
564
+			str_replace(array('_Admin_Page', 'Extend_'), '', get_class($this))
565
+		);
566
+		global $ee_menu_slugs;
567
+		$ee_menu_slugs = (array) $ee_menu_slugs;
568
+		if (! defined('DOING_AJAX') && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))) {
569
+			return;
570
+		}
571
+		// becuz WP List tables have two duplicate select inputs for choosing bulk actions, we need to copy the action from the second to the first
572
+		if (isset($this->_req_data['action2']) && $this->_req_data['action'] === '-1') {
573
+			$this->_req_data['action'] = ! empty($this->_req_data['action2']) && $this->_req_data['action2'] !== '-1'
574
+				? $this->_req_data['action2']
575
+				: $this->_req_data['action'];
576
+		}
577
+		// then set blank or -1 action values to 'default'
578
+		$this->_req_action = isset($this->_req_data['action'])
579
+							 && ! empty($this->_req_data['action'])
580
+							 && $this->_req_data['action'] !== '-1'
581
+			? sanitize_key($this->_req_data['action'])
582
+			: 'default';
583
+		// if action is 'default' after the above BUT we have  'route' var set, then let's use the route as the action.
584
+		//  This covers cases where we're coming in from a list table that isn't on the default route.
585
+		$this->_req_action = $this->_req_action === 'default' && isset($this->_req_data['route'])
586
+			? $this->_req_data['route'] : $this->_req_action;
587
+		// however if we are doing_ajax and we've got a 'route' set then that's what the req_action will be
588
+		$this->_req_action = defined('DOING_AJAX') && isset($this->_req_data['route'])
589
+			? $this->_req_data['route']
590
+			: $this->_req_action;
591
+		$this->_current_view = $this->_req_action;
592
+		$this->_req_nonce = $this->_req_action . '_nonce';
593
+		$this->_define_page_props();
594
+		$this->_current_page_view_url = add_query_arg(
595
+			array('page' => $this->_current_page, 'action' => $this->_current_view),
596
+			$this->_admin_base_url
597
+		);
598
+		// default things
599
+		$this->_default_espresso_metaboxes = array(
600
+			'_espresso_news_post_box',
601
+			'_espresso_links_post_box',
602
+			'_espresso_ratings_request',
603
+			'_espresso_sponsors_post_box',
604
+		);
605
+		// set page configs
606
+		$this->_set_page_routes();
607
+		$this->_set_page_config();
608
+		// let's include any referrer data in our default_query_args for this route for "stickiness".
609
+		if (isset($this->_req_data['wp_referer'])) {
610
+			$this->_default_route_query_args['wp_referer'] = $this->_req_data['wp_referer'];
611
+		}
612
+		// for caffeinated and other extended functionality.
613
+		//  If there is a _extend_page_config method
614
+		// then let's run that to modify the all the various page configuration arrays
615
+		if (method_exists($this, '_extend_page_config')) {
616
+			$this->_extend_page_config();
617
+		}
618
+		// for CPT and other extended functionality.
619
+		// If there is an _extend_page_config_for_cpt
620
+		// then let's run that to modify all the various page configuration arrays.
621
+		if (method_exists($this, '_extend_page_config_for_cpt')) {
622
+			$this->_extend_page_config_for_cpt();
623
+		}
624
+		// filter routes and page_config so addons can add their stuff. Filtering done per class
625
+		$this->_page_routes = apply_filters(
626
+			'FHEE__' . get_class($this) . '__page_setup__page_routes',
627
+			$this->_page_routes,
628
+			$this
629
+		);
630
+		$this->_page_config = apply_filters(
631
+			'FHEE__' . get_class($this) . '__page_setup__page_config',
632
+			$this->_page_config,
633
+			$this
634
+		);
635
+		// if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
636
+		// then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
637
+		if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
638
+			add_action(
639
+				'AHEE__EE_Admin_Page__route_admin_request',
640
+				array($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view),
641
+				10,
642
+				2
643
+			);
644
+		}
645
+		// next route only if routing enabled
646
+		if ($this->_routing && ! defined('DOING_AJAX')) {
647
+			$this->_verify_routes();
648
+			// next let's just check user_access and kill if no access
649
+			$this->check_user_access();
650
+			if ($this->_is_UI_request) {
651
+				// admin_init stuff - global, all views for this page class, specific view
652
+				add_action('admin_init', array($this, 'admin_init'), 10);
653
+				if (method_exists($this, 'admin_init_' . $this->_current_view)) {
654
+					add_action('admin_init', array($this, 'admin_init_' . $this->_current_view), 15);
655
+				}
656
+			} else {
657
+				// hijack regular WP loading and route admin request immediately
658
+				@ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
659
+				$this->route_admin_request();
660
+			}
661
+		}
662
+	}
663
+
664
+
665
+	/**
666
+	 * Provides a way for related child admin pages to load stuff on the loaded admin page.
667
+	 *
668
+	 * @return void
669
+	 * @throws EE_Error
670
+	 */
671
+	private function _do_other_page_hooks()
672
+	{
673
+		$registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, array());
674
+		foreach ($registered_pages as $page) {
675
+			// now let's setup the file name and class that should be present
676
+			$classname = str_replace('.class.php', '', $page);
677
+			// autoloaders should take care of loading file
678
+			if (! class_exists($classname)) {
679
+				$error_msg[] = sprintf(
680
+					esc_html__(
681
+						'Something went wrong with loading the %s admin hooks page.',
682
+						'event_espresso'
683
+					),
684
+					$page
685
+				);
686
+				$error_msg[] = $error_msg[0]
687
+							   . "\r\n"
688
+							   . sprintf(
689
+								   esc_html__(
690
+									   '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',
691
+									   'event_espresso'
692
+								   ),
693
+								   $page,
694
+								   '<br />',
695
+								   '<strong>' . $classname . '</strong>'
696
+							   );
697
+				throw new EE_Error(implode('||', $error_msg));
698
+			}
699
+			// // notice we are passing the instance of this class to the hook object.
700
+			$this->loader->getShared($classname, [$this]);
701
+		}
702
+	}
703
+
704
+
705
+	/**
706
+	 * @throws DomainException
707
+	 * @throws EE_Error
708
+	 * @throws InvalidArgumentException
709
+	 * @throws InvalidDataTypeException
710
+	 * @throws InvalidInterfaceException
711
+	 * @throws ReflectionException
712
+	 * @since $VID:$
713
+	 */
714
+	public function load_page_dependencies()
715
+	{
716
+		try {
717
+			$this->_load_page_dependencies();
718
+		} catch (EE_Error $e) {
719
+			$e->get_error();
720
+		}
721
+	}
722
+
723
+
724
+	/**
725
+	 * load_page_dependencies
726
+	 * loads things specific to this page class when its loaded.  Really helps with efficiency.
727
+	 *
728
+	 * @return void
729
+	 * @throws DomainException
730
+	 * @throws EE_Error
731
+	 * @throws InvalidArgumentException
732
+	 * @throws InvalidDataTypeException
733
+	 * @throws InvalidInterfaceException
734
+	 * @throws ReflectionException
735
+	 */
736
+	protected function _load_page_dependencies()
737
+	{
738
+		// let's set the current_screen and screen options to override what WP set
739
+		$this->_current_screen = get_current_screen();
740
+		// load admin_notices - global, page class, and view specific
741
+		add_action('admin_notices', array($this, 'admin_notices_global'), 5);
742
+		add_action('admin_notices', array($this, 'admin_notices'), 10);
743
+		if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
744
+			add_action('admin_notices', array($this, 'admin_notices_' . $this->_current_view), 15);
745
+		}
746
+		// load network admin_notices - global, page class, and view specific
747
+		add_action('network_admin_notices', array($this, 'network_admin_notices_global'), 5);
748
+		if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
749
+			add_action('network_admin_notices', array($this, 'network_admin_notices_' . $this->_current_view));
750
+		}
751
+		// this will save any per_page screen options if they are present
752
+		$this->_set_per_page_screen_options();
753
+		// setup list table properties
754
+		$this->_set_list_table();
755
+		// child classes can "register" a metabox to be automatically handled via the _page_config array property.
756
+		// However in some cases the metaboxes will need to be added within a route handling callback.
757
+		$this->_add_registered_meta_boxes();
758
+		$this->_add_screen_columns();
759
+		// add screen options - global, page child class, and view specific
760
+		$this->_add_global_screen_options();
761
+		$this->_add_screen_options();
762
+		$add_screen_options = "_add_screen_options_{$this->_current_view}";
763
+		if (method_exists($this, $add_screen_options)) {
764
+			$this->{$add_screen_options}();
765
+		}
766
+		// add help tab(s) and tours- set via page_config and qtips.
767
+		// $this->_add_help_tour();
768
+		$this->_add_help_tabs();
769
+		$this->_add_qtips();
770
+		// add feature_pointers - global, page child class, and view specific
771
+		$this->_add_feature_pointers();
772
+		$this->_add_global_feature_pointers();
773
+		$add_feature_pointer = "_add_feature_pointer_{$this->_current_view}";
774
+		if (method_exists($this, $add_feature_pointer)) {
775
+			$this->{$add_feature_pointer}();
776
+		}
777
+		// enqueue scripts/styles - global, page class, and view specific
778
+		add_action('admin_enqueue_scripts', array($this, 'load_global_scripts_styles'), 5);
779
+		add_action('admin_enqueue_scripts', array($this, 'load_scripts_styles'), 10);
780
+		if (method_exists($this, "load_scripts_styles_{$this->_current_view}")) {
781
+			add_action('admin_enqueue_scripts', array($this, "load_scripts_styles_{$this->_current_view}"), 15);
782
+		}
783
+		add_action('admin_enqueue_scripts', array($this, 'admin_footer_scripts_eei18n_js_strings'), 100);
784
+		// admin_print_footer_scripts - global, page child class, and view specific.
785
+		// NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
786
+		// In most cases that's doing_it_wrong().  But adding hidden container elements etc.
787
+		// is a good use case. Notice the late priority we're giving these
788
+		add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts_global'), 99);
789
+		add_action('admin_print_footer_scripts', array($this, 'admin_footer_scripts'), 100);
790
+		if (method_exists($this, "admin_footer_scripts_{$this->_current_view}")) {
791
+			add_action('admin_print_footer_scripts', array($this, "admin_footer_scripts_{$this->_current_view}"), 101);
792
+		}
793
+		// admin footer scripts
794
+		add_action('admin_footer', array($this, 'admin_footer_global'), 99);
795
+		add_action('admin_footer', array($this, 'admin_footer'), 100);
796
+		if (method_exists($this, "admin_footer_{$this->_current_view}")) {
797
+			add_action('admin_footer', array($this, "admin_footer_{$this->_current_view}"), 101);
798
+		}
799
+		do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
800
+		// targeted hook
801
+		do_action(
802
+			"FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__{$this->_req_action}"
803
+		);
804
+	}
805
+
806
+
807
+	/**
808
+	 * _set_defaults
809
+	 * This sets some global defaults for class properties.
810
+	 */
811
+	private function _set_defaults()
812
+	{
813
+		$this->_current_screen = $this->_admin_page_title = $this->_req_action = $this->_req_nonce = null;
814
+		$this->_event = $this->_template_path = $this->_column_template_path = null;
815
+		$this->_nav_tabs = $this->_views = $this->_page_routes = array();
816
+		$this->_page_config = $this->_default_route_query_args = array();
817
+		$this->_default_nav_tab_name = 'overview';
818
+		// init template args
819
+		$this->_template_args = array(
820
+			'admin_page_header'  => '',
821
+			'admin_page_content' => '',
822
+			'post_body_content'  => '',
823
+			'before_list_table'  => '',
824
+			'after_list_table'   => '',
825
+		);
826
+	}
827
+
828
+
829
+	/**
830
+	 * route_admin_request
831
+	 *
832
+	 * @see    _route_admin_request()
833
+	 * @return exception|void error
834
+	 * @throws InvalidArgumentException
835
+	 * @throws InvalidInterfaceException
836
+	 * @throws InvalidDataTypeException
837
+	 * @throws EE_Error
838
+	 * @throws ReflectionException
839
+	 */
840
+	public function route_admin_request()
841
+	{
842
+		try {
843
+			$this->_route_admin_request();
844
+		} catch (EE_Error $e) {
845
+			$e->get_error();
846
+		}
847
+	}
848
+
849
+
850
+	public function set_wp_page_slug($wp_page_slug)
851
+	{
852
+		$this->_wp_page_slug = $wp_page_slug;
853
+		// if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
854
+		if (is_network_admin()) {
855
+			$this->_wp_page_slug .= '-network';
856
+		}
857
+	}
858
+
859
+
860
+	/**
861
+	 * _verify_routes
862
+	 * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
863
+	 * we know if we need to drop out.
864
+	 *
865
+	 * @return bool
866
+	 * @throws EE_Error
867
+	 */
868
+	protected function _verify_routes()
869
+	{
870
+		if (! $this->_current_page && ! defined('DOING_AJAX')) {
871
+			return false;
872
+		}
873
+		$this->_route = false;
874
+		// check that the page_routes array is not empty
875
+		if (empty($this->_page_routes)) {
876
+			// user error msg
877
+			$error_msg = sprintf(
878
+				esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
879
+				$this->_admin_page_title
880
+			);
881
+			// developer error msg
882
+			$error_msg .= '||' . $error_msg
883
+						  . esc_html__(
884
+							  ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
885
+							  'event_espresso'
886
+						  );
887
+			throw new EE_Error($error_msg);
888
+		}
889
+		// and that the requested page route exists
890
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
891
+			$this->_route = $this->_page_routes[ $this->_req_action ];
892
+			$this->_route_config = isset($this->_page_config[ $this->_req_action ])
893
+				? $this->_page_config[ $this->_req_action ] : array();
894
+		} else {
895
+			// user error msg
896
+			$error_msg = sprintf(
897
+				esc_html__(
898
+					'The requested page route does not exist for the %s admin page.',
899
+					'event_espresso'
900
+				),
901
+				$this->_admin_page_title
902
+			);
903
+			// developer error msg
904
+			$error_msg .= '||' . $error_msg
905
+						  . sprintf(
906
+							  esc_html__(
907
+								  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
908
+								  'event_espresso'
909
+							  ),
910
+							  $this->_req_action
911
+						  );
912
+			throw new EE_Error($error_msg);
913
+		}
914
+		// and that a default route exists
915
+		if (! array_key_exists('default', $this->_page_routes)) {
916
+			// user error msg
917
+			$error_msg = sprintf(
918
+				esc_html__(
919
+					'A default page route has not been set for the % admin page.',
920
+					'event_espresso'
921
+				),
922
+				$this->_admin_page_title
923
+			);
924
+			// developer error msg
925
+			$error_msg .= '||' . $error_msg
926
+						  . esc_html__(
927
+							  ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
928
+							  'event_espresso'
929
+						  );
930
+			throw new EE_Error($error_msg);
931
+		}
932
+
933
+		// first lets' catch if the UI request has EVER been set.
934
+		if ($this->_is_UI_request === null) {
935
+			// lets set if this is a UI request or not.
936
+			$this->_is_UI_request = ! isset($this->_req_data['noheader']) || $this->_req_data['noheader'] !== true;
937
+			// wait a minute... we might have a noheader in the route array
938
+			$this->_is_UI_request = is_array($this->_route)
939
+									&& isset($this->_route['noheader'])
940
+									&& $this->_route['noheader'] ? false : $this->_is_UI_request;
941
+		}
942
+		$this->_set_current_labels();
943
+		return true;
944
+	}
945
+
946
+
947
+	/**
948
+	 * this method simply verifies a given route and makes sure its an actual route available for the loaded page
949
+	 *
950
+	 * @param  string $route the route name we're verifying
951
+	 * @return mixed (bool|Exception)      we'll throw an exception if this isn't a valid route.
952
+	 * @throws EE_Error
953
+	 */
954
+	protected function _verify_route($route)
955
+	{
956
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
957
+			return true;
958
+		}
959
+		// user error msg
960
+		$error_msg = sprintf(
961
+			esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
962
+			$this->_admin_page_title
963
+		);
964
+		// developer error msg
965
+		$error_msg .= '||' . $error_msg
966
+					  . sprintf(
967
+						  esc_html__(
968
+							  ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
969
+							  'event_espresso'
970
+						  ),
971
+						  $route
972
+					  );
973
+		throw new EE_Error($error_msg);
974
+	}
975
+
976
+
977
+	/**
978
+	 * perform nonce verification
979
+	 * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
980
+	 * using this method (and save retyping!)
981
+	 *
982
+	 * @param string $nonce     The nonce sent
983
+	 * @param string $nonce_ref The nonce reference string (name0)
984
+	 * @return void
985
+	 * @throws EE_Error
986
+	 * @throws InvalidArgumentException
987
+	 * @throws InvalidDataTypeException
988
+	 * @throws InvalidInterfaceException
989
+	 */
990
+	protected function _verify_nonce($nonce, $nonce_ref)
991
+	{
992
+		// verify nonce against expected value
993
+		if (! wp_verify_nonce($nonce, $nonce_ref)) {
994
+			// these are not the droids you are looking for !!!
995
+			$msg = sprintf(
996
+				esc_html__('%sNonce Fail.%s', 'event_espresso'),
997
+				'<a href="http://www.youtube.com/watch?v=56_S0WeTkzs">',
998
+				'</a>'
999
+			);
1000
+			if (WP_DEBUG) {
1001
+				$msg .= "\n  "
1002
+						. sprintf(
1003
+							esc_html__(
1004
+								'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1005
+								'event_espresso'
1006
+							),
1007
+							EE_Admin_Page::class
1008
+						);
1009
+			}
1010
+			if (! defined('DOING_AJAX')) {
1011
+				wp_die($msg);
1012
+			} else {
1013
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1014
+				$this->_return_json();
1015
+			}
1016
+		}
1017
+	}
1018
+
1019
+
1020
+	/**
1021
+	 * _route_admin_request()
1022
+	 * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1023
+	 * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1024
+	 * in the page routes and then will try to load the corresponding method.
1025
+	 *
1026
+	 * @return void
1027
+	 * @throws EE_Error
1028
+	 * @throws InvalidArgumentException
1029
+	 * @throws InvalidDataTypeException
1030
+	 * @throws InvalidInterfaceException
1031
+	 * @throws ReflectionException
1032
+	 */
1033
+	protected function _route_admin_request()
1034
+	{
1035
+		if (! $this->_is_UI_request) {
1036
+			$this->_verify_routes();
1037
+		}
1038
+		$nonce_check = isset($this->_route_config['require_nonce'])
1039
+			? $this->_route_config['require_nonce']
1040
+			: true;
1041
+		if ($this->_req_action !== 'default' && $nonce_check) {
1042
+			// set nonce from post data
1043
+			$nonce = isset($this->_req_data[ $this->_req_nonce ])
1044
+				? sanitize_text_field($this->_req_data[ $this->_req_nonce ])
1045
+				: '';
1046
+			$this->_verify_nonce($nonce, $this->_req_nonce);
1047
+		}
1048
+		// set the nav_tabs array but ONLY if this is  UI_request
1049
+		if ($this->_is_UI_request) {
1050
+			$this->_set_nav_tabs();
1051
+		}
1052
+		// grab callback function
1053
+		$func = is_array($this->_route) && isset($this->_route['func']) ? $this->_route['func'] : $this->_route;
1054
+		// check if callback has args
1055
+		$args = is_array($this->_route) && isset($this->_route['args']) ? $this->_route['args'] : array();
1056
+		$error_msg = '';
1057
+		// action right before calling route
1058
+		// (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1059
+		if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1060
+			do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1061
+		}
1062
+		// right before calling the route, let's remove _wp_http_referer from the
1063
+		// $_SERVER[REQUEST_URI] global (its now in _req_data for route processing).
1064
+		$_SERVER['REQUEST_URI'] = remove_query_arg(
1065
+			'_wp_http_referer',
1066
+			wp_unslash($_SERVER['REQUEST_URI'])
1067
+		);
1068
+		if (! empty($func)) {
1069
+			if (is_array($func)) {
1070
+				list($class, $method) = $func;
1071
+			} elseif (strpos($func, '::') !== false) {
1072
+				list($class, $method) = explode('::', $func);
1073
+			} else {
1074
+				$class = $this;
1075
+				$method = $func;
1076
+			}
1077
+			if (! (is_object($class) && $class === $this)) {
1078
+				// send along this admin page object for access by addons.
1079
+				$args['admin_page_object'] = $this;
1080
+			}
1081
+			// is it a method on a class that doesn't work?
1082
+			if (
1083
+				((method_exists($class, $method)
1084
+				  && call_user_func_array(array($class, $method), $args) === false)
1085
+				 && (// is it a standalone function that doesn't work?
1086
+					 function_exists($method)
1087
+					 && call_user_func_array(
1088
+						 $func,
1089
+						 array_merge(array('admin_page_object' => $this), $args)
1090
+					 ) === false
1091
+				 )) || (// is it neither a class method NOR a standalone function?
1092
+					! function_exists($method)
1093
+					&& ! method_exists($class, $method)
1094
+				)
1095
+			) {
1096
+				// user error msg
1097
+				$error_msg = esc_html__(
1098
+					'An error occurred. The  requested page route could not be found.',
1099
+					'event_espresso'
1100
+				);
1101
+				// developer error msg
1102
+				$error_msg .= '||';
1103
+				$error_msg .= sprintf(
1104
+					esc_html__(
1105
+						'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1106
+						'event_espresso'
1107
+					),
1108
+					$method
1109
+				);
1110
+			}
1111
+			if (! empty($error_msg)) {
1112
+				throw new EE_Error($error_msg);
1113
+			}
1114
+		}
1115
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1116
+		// then we need to reset the routing properties to the new route.
1117
+		// 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.
1118
+		if (
1119
+			$this->_is_UI_request === false
1120
+			&& is_array($this->_route)
1121
+			&& ! empty($this->_route['headers_sent_route'])
1122
+		) {
1123
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1124
+		}
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 * This method just allows the resetting of page properties in the case where a no headers
1130
+	 * route redirects to a headers route in its route config.
1131
+	 *
1132
+	 * @since   4.3.0
1133
+	 * @param  string $new_route New (non header) route to redirect to.
1134
+	 * @return   void
1135
+	 * @throws ReflectionException
1136
+	 * @throws InvalidArgumentException
1137
+	 * @throws InvalidInterfaceException
1138
+	 * @throws InvalidDataTypeException
1139
+	 * @throws EE_Error
1140
+	 */
1141
+	protected function _reset_routing_properties($new_route)
1142
+	{
1143
+		$this->_is_UI_request = true;
1144
+		// now we set the current route to whatever the headers_sent_route is set at
1145
+		$this->_req_data['action'] = $new_route;
1146
+		// rerun page setup
1147
+		$this->_page_setup();
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * _add_query_arg
1153
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1154
+	 *(internally just uses EEH_URL's function with the same name)
1155
+	 *
1156
+	 * @param array  $args
1157
+	 * @param string $url
1158
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1159
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1160
+	 *                                        Example usage: If the current page is:
1161
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1162
+	 *                                        &action=default&event_id=20&month_range=March%202015
1163
+	 *                                        &_wpnonce=5467821
1164
+	 *                                        and you call:
1165
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1166
+	 *                                        array(
1167
+	 *                                        'action' => 'resend_something',
1168
+	 *                                        'page=>espresso_registrations'
1169
+	 *                                        ),
1170
+	 *                                        $some_url,
1171
+	 *                                        true
1172
+	 *                                        );
1173
+	 *                                        It will produce a url in this structure:
1174
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1175
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1176
+	 *                                        month_range]=March%202015
1177
+	 * @param   bool $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1178
+	 * @return string
1179
+	 */
1180
+	public static function add_query_args_and_nonce(
1181
+		$args = array(),
1182
+		$url = '',
1183
+		$sticky = false,
1184
+		$exclude_nonce = false
1185
+	) {
1186
+		// if there is a _wp_http_referer include the values from the request but only if sticky = true
1187
+		if ($sticky) {
1188
+			$request = $_REQUEST;
1189
+			unset($request['_wp_http_referer'], $request['wp_referer']);
1190
+			foreach ($request as $key => $value) {
1191
+				// do not add nonces
1192
+				if (strpos($key, 'nonce') !== false) {
1193
+					continue;
1194
+				}
1195
+				$args[ 'wp_referer[' . $key . ']' ] = $value;
1196
+			}
1197
+		}
1198
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce);
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * This returns a generated link that will load the related help tab.
1204
+	 *
1205
+	 * @param  string $help_tab_id the id for the connected help tab
1206
+	 * @param  string $icon_style  (optional) include css class for the style you want to use for the help icon.
1207
+	 * @param  string $help_text   (optional) send help text you want to use for the link if default not to be used
1208
+	 * @uses EEH_Template::get_help_tab_link()
1209
+	 * @return string              generated link
1210
+	 */
1211
+	protected function _get_help_tab_link($help_tab_id, $icon_style = '', $help_text = '')
1212
+	{
1213
+		return EEH_Template::get_help_tab_link(
1214
+			$help_tab_id,
1215
+			$this->page_slug,
1216
+			$this->_req_action,
1217
+			$icon_style,
1218
+			$help_text
1219
+		);
1220
+	}
1221
+
1222
+
1223
+	/**
1224
+	 * _add_help_tabs
1225
+	 * Note child classes define their help tabs within the page_config array.
1226
+	 *
1227
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1228
+	 * @return void
1229
+	 * @throws DomainException
1230
+	 * @throws EE_Error
1231
+	 * @throws ReflectionException
1232
+	 */
1233
+	protected function _add_help_tabs()
1234
+	{
1235
+		$tour_buttons = '';
1236
+		if (isset($this->_page_config[ $this->_req_action ])) {
1237
+			$config = $this->_page_config[ $this->_req_action ];
1238
+			// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1239
+			// is there a help tour for the current route?  if there is let's setup the tour buttons
1240
+			// if (isset($this->_help_tour[ $this->_req_action ])) {
1241
+			//     $tb = array();
1242
+			//     $tour_buttons = '<div class="ee-abs-container"><div class="ee-help-tour-restart-buttons">';
1243
+			//     foreach ($this->_help_tour['tours'] as $tour) {
1244
+			//         // if this is the end tour then we don't need to setup a button
1245
+			//         if ($tour instanceof EE_Help_Tour_final_stop || ! $tour instanceof EE_Help_Tour) {
1246
+			//             continue;
1247
+			//         }
1248
+			//         $tb[] = '<button id="trigger-tour-'
1249
+			//                 . $tour->get_slug()
1250
+			//                 . '" class="button-primary trigger-ee-help-tour">'
1251
+			//                 . $tour->get_label()
1252
+			//                 . '</button>';
1253
+			//     }
1254
+			//     $tour_buttons .= implode('<br />', $tb);
1255
+			//     $tour_buttons .= '</div></div>';
1256
+			// }
1257
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1258
+			if (is_array($config) && isset($config['help_sidebar'])) {
1259
+				// check that the callback given is valid
1260
+				if (! method_exists($this, $config['help_sidebar'])) {
1261
+					throw new EE_Error(
1262
+						sprintf(
1263
+							esc_html__(
1264
+								'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',
1265
+								'event_espresso'
1266
+							),
1267
+							$config['help_sidebar'],
1268
+							get_class($this)
1269
+						)
1270
+					);
1271
+				}
1272
+				$content = apply_filters(
1273
+					'FHEE__' . get_class($this) . '__add_help_tabs__help_sidebar',
1274
+					$this->{$config['help_sidebar']}()
1275
+				);
1276
+				$content .= $tour_buttons; // add help tour buttons.
1277
+				// do we have any help tours setup?  Cause if we do we want to add the buttons
1278
+				$this->_current_screen->set_help_sidebar($content);
1279
+			}
1280
+			// if there ARE tour buttons...
1281
+			if (! empty($tour_buttons)) {
1282
+				// if we DON'T have config help sidebar then we'll just add the tour buttons to the sidebar.
1283
+				if (! isset($config['help_sidebar'])) {
1284
+					$this->_current_screen->set_help_sidebar($tour_buttons);
1285
+				}
1286
+				// handle if no help_tabs are set so the sidebar will still show for the help tour buttons
1287
+				if (! isset($config['help_tabs'])) {
1288
+					$_ht['id'] = $this->page_slug;
1289
+					$_ht['title'] = esc_html__('Help Tours', 'event_espresso');
1290
+					$_ht['content'] = '<p>'
1291
+									  . esc_html__(
1292
+										  'The buttons to the right allow you to start/restart any help tours available for this page',
1293
+										  'event_espresso'
1294
+									  ) . '</p>';
1295
+					$this->_current_screen->add_help_tab($_ht);
1296
+				}
1297
+			}
1298
+			if (! isset($config['help_tabs'])) {
1299
+				return;
1300
+			} //no help tabs for this route
1301
+			foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1302
+				// we're here so there ARE help tabs!
1303
+				// make sure we've got what we need
1304
+				if (! isset($cfg['title'])) {
1305
+					throw new EE_Error(
1306
+						esc_html__(
1307
+							'The _page_config array is not set up properly for help tabs.  It is missing a title',
1308
+							'event_espresso'
1309
+						)
1310
+					);
1311
+				}
1312
+				if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1313
+					throw new EE_Error(
1314
+						esc_html__(
1315
+							'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',
1316
+							'event_espresso'
1317
+						)
1318
+					);
1319
+				}
1320
+				// first priority goes to content.
1321
+				if (! empty($cfg['content'])) {
1322
+					$content = ! empty($cfg['content']) ? $cfg['content'] : null;
1323
+					// second priority goes to filename
1324
+				} elseif (! empty($cfg['filename'])) {
1325
+					$file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1326
+					// 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)
1327
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1328
+															 . basename($this->_get_dir())
1329
+															 . '/help_tabs/'
1330
+															 . $cfg['filename']
1331
+															 . '.help_tab.php' : $file_path;
1332
+					// if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1333
+					if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1334
+						EE_Error::add_error(
1335
+							sprintf(
1336
+								esc_html__(
1337
+									'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',
1338
+									'event_espresso'
1339
+								),
1340
+								$tab_id,
1341
+								key($config),
1342
+								$file_path
1343
+							),
1344
+							__FILE__,
1345
+							__FUNCTION__,
1346
+							__LINE__
1347
+						);
1348
+						return;
1349
+					}
1350
+					$template_args['admin_page_obj'] = $this;
1351
+					$content = EEH_Template::display_template(
1352
+						$file_path,
1353
+						$template_args,
1354
+						true
1355
+					);
1356
+				} else {
1357
+					$content = '';
1358
+				}
1359
+				// check if callback is valid
1360
+				if (
1361
+					empty($content) && (
1362
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1363
+					)
1364
+				) {
1365
+					EE_Error::add_error(
1366
+						sprintf(
1367
+							esc_html__(
1368
+								'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.',
1369
+								'event_espresso'
1370
+							),
1371
+							$cfg['title']
1372
+						),
1373
+						__FILE__,
1374
+						__FUNCTION__,
1375
+						__LINE__
1376
+					);
1377
+					return;
1378
+				}
1379
+				// setup config array for help tab method
1380
+				$id = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1381
+				$_ht = array(
1382
+					'id'       => $id,
1383
+					'title'    => $cfg['title'],
1384
+					'callback' => isset($cfg['callback']) && empty($content) ? array($this, $cfg['callback']) : null,
1385
+					'content'  => $content,
1386
+				);
1387
+				$this->_current_screen->add_help_tab($_ht);
1388
+			}
1389
+		}
1390
+	}
1391
+
1392
+
1393
+	/**
1394
+	 * This basically checks loaded $_page_config property to see if there are any help_tours defined.  "help_tours" is
1395
+	 * an array with properties for setting up usage of the joyride plugin
1396
+	 *
1397
+	 * @link   http://zurb.com/playground/jquery-joyride-feature-tour-plugin
1398
+	 * @see    instructions regarding the format and construction of the "help_tour" array element is found in the
1399
+	 *         _set_page_config() comments
1400
+	 * @return void
1401
+	 * @throws EE_Error
1402
+	 * @throws InvalidArgumentException
1403
+	 * @throws InvalidDataTypeException
1404
+	 * @throws InvalidInterfaceException
1405
+	 * @throws ReflectionException
1406
+	 */
1407
+	protected function _add_help_tour()
1408
+	{
1409
+		// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1410
+		// $tours = array();
1411
+		// $this->_help_tour = array();
1412
+		// // exit early if help tours are turned off globally
1413
+		// if ((defined('EE_DISABLE_HELP_TOURS') && EE_DISABLE_HELP_TOURS)
1414
+		//     || ! EE_Registry::instance()->CFG->admin->help_tour_activation
1415
+		// ) {
1416
+		//     return;
1417
+		// }
1418
+		// // loop through _page_config to find any help_tour defined
1419
+		// foreach ($this->_page_config as $route => $config) {
1420
+		//     // we're only going to set things up for this route
1421
+		//     if ($route !== $this->_req_action) {
1422
+		//         continue;
1423
+		//     }
1424
+		//     if (isset($config['help_tour'])) {
1425
+		//         foreach ($config['help_tour'] as $tour) {
1426
+		//             $file_path = $this->_get_dir() . '/help_tours/' . $tour . '.class.php';
1427
+		//             // let's see if we can get that file...
1428
+		//             // if not its possible this is a decaf route not set in caffeinated
1429
+		//             // so lets try and get the caffeinated equivalent
1430
+		//             $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1431
+		//                                                      . basename($this->_get_dir())
1432
+		//                                                      . '/help_tours/'
1433
+		//                                                      . $tour
1434
+		//                                                      . '.class.php' : $file_path;
1435
+		//             // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1436
+		//             if (! is_readable($file_path)) {
1437
+		//                 EE_Error::add_error(
1438
+		//                     sprintf(
1439
+		//                         esc_html__(
1440
+		//                             'The file path given for the help tour (%s) is not a valid path.  Please check that the string you set for the help tour on this route (%s) is the correct spelling',
1441
+		//                             'event_espresso'
1442
+		//                         ),
1443
+		//                         $file_path,
1444
+		//                         $tour
1445
+		//                     ),
1446
+		//                     __FILE__,
1447
+		//                     __FUNCTION__,
1448
+		//                     __LINE__
1449
+		//                 );
1450
+		//                 return;
1451
+		//             }
1452
+		//             require_once $file_path;
1453
+		//             if (! class_exists($tour)) {
1454
+		//                 $error_msg[] = sprintf(
1455
+		//                     esc_html__('Something went wrong with loading the %s Help Tour Class.', 'event_espresso'),
1456
+		//                     $tour
1457
+		//                 );
1458
+		//                 $error_msg[] = $error_msg[0] . "\r\n"
1459
+		//                                . sprintf(
1460
+		//                                    esc_html__(
1461
+		//                                        'There is no class in place for the %s help tour.%s Make sure you have <strong>%s</strong> defined in the "help_tour" array for the %s route of the % admin page.',
1462
+		//                                        'event_espresso'
1463
+		//                                    ),
1464
+		//                                    $tour,
1465
+		//                                    '<br />',
1466
+		//                                    $tour,
1467
+		//                                    $this->_req_action,
1468
+		//                                    get_class($this)
1469
+		//                                );
1470
+		//                 throw new EE_Error(implode('||', $error_msg));
1471
+		//             }
1472
+		//             $tour_obj = new $tour($this->_is_caf);
1473
+		//             $tours[] = $tour_obj;
1474
+		//             $this->_help_tour[ $route ][] = EEH_Template::help_tour_stops_generator($tour_obj);
1475
+		//         }
1476
+		//         // let's inject the end tour stop element common to all pages... this will only get seen once per machine.
1477
+		//         $end_stop_tour = new EE_Help_Tour_final_stop($this->_is_caf);
1478
+		//         $tours[] = $end_stop_tour;
1479
+		//         $this->_help_tour[ $route ][] = EEH_Template::help_tour_stops_generator($end_stop_tour);
1480
+		//     }
1481
+		// }
1482
+		//
1483
+		// if (! empty($tours)) {
1484
+		//     $this->_help_tour['tours'] = $tours;
1485
+		// }
1486
+		// // that's it!  Now that the $_help_tours property is set (or not)
1487
+		// // the scripts and html should be taken care of automatically.
1488
+		//
1489
+		// /**
1490
+		//  * Allow extending the help tours variable.
1491
+		//  *
1492
+		//  * @param Array $_help_tour The array containing all help tour information to be displayed.
1493
+		//  */
1494
+		// $this->_help_tour = apply_filters('FHEE__EE_Admin_Page___add_help_tour___help_tour', $this->_help_tour);
1495
+	}
1496
+
1497
+
1498
+	/**
1499
+	 * This simply sets up any qtips that have been defined in the page config
1500
+	 *
1501
+	 * @return void
1502
+	 * @throws ReflectionException
1503
+	 * @throws EE_Error
1504
+	 */
1505
+	protected function _add_qtips()
1506
+	{
1507
+		if (isset($this->_route_config['qtips'])) {
1508
+			$qtips = (array) $this->_route_config['qtips'];
1509
+			// load qtip loader
1510
+			$path = array(
1511
+				$this->_get_dir() . '/qtips/',
1512
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1513
+			);
1514
+			$qtip_loader = EEH_Qtip_Loader::instance();
1515
+			if ($qtip_loader instanceof EEH_Qtip_Loader) {
1516
+				$qtip_loader->register($qtips, $path);
1517
+			}
1518
+		}
1519
+	}
1520
+
1521
+
1522
+	/**
1523
+	 * _set_nav_tabs
1524
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1525
+	 * wish to add additional tabs or modify accordingly.
1526
+	 *
1527
+	 * @return void
1528
+	 * @throws InvalidArgumentException
1529
+	 * @throws InvalidInterfaceException
1530
+	 * @throws InvalidDataTypeException
1531
+	 */
1532
+	protected function _set_nav_tabs()
1533
+	{
1534
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1535
+		$i = 0;
1536
+		foreach ($this->_page_config as $slug => $config) {
1537
+			if (
1538
+				! is_array($config)
1539
+				|| (
1540
+					is_array($config)
1541
+					&& (
1542
+						(isset($config['nav']) && ! $config['nav'])
1543
+						|| ! isset($config['nav'])
1544
+					)
1545
+				)
1546
+			) {
1547
+				continue;
1548
+			}
1549
+			// no nav tab for this config
1550
+			// check for persistent flag
1551
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1552
+				// nav tab is only to appear when route requested.
1553
+				continue;
1554
+			}
1555
+			if (! $this->check_user_access($slug, true)) {
1556
+				// no nav tab because current user does not have access.
1557
+				continue;
1558
+			}
1559
+			$css_class = isset($config['css_class']) ? $config['css_class'] . ' ' : '';
1560
+			$this->_nav_tabs[ $slug ] = array(
1561
+				'url'       => isset($config['nav']['url'])
1562
+					? $config['nav']['url']
1563
+					: EE_Admin_Page::add_query_args_and_nonce(
1564
+						array('action' => $slug),
1565
+						$this->_admin_base_url
1566
+					),
1567
+				'link_text' => isset($config['nav']['label'])
1568
+					? $config['nav']['label']
1569
+					: ucwords(
1570
+						str_replace('_', ' ', $slug)
1571
+					),
1572
+				'css_class' => $this->_req_action === $slug ? $css_class . 'nav-tab-active' : $css_class,
1573
+				'order'     => isset($config['nav']['order']) ? $config['nav']['order'] : $i,
1574
+			);
1575
+			$i++;
1576
+		}
1577
+		// if $this->_nav_tabs is empty then lets set the default
1578
+		if (empty($this->_nav_tabs)) {
1579
+			$this->_nav_tabs[ $this->_default_nav_tab_name ] = array(
1580
+				'url'       => $this->_admin_base_url,
1581
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1582
+				'css_class' => 'nav-tab-active',
1583
+				'order'     => 10,
1584
+			);
1585
+		}
1586
+		// now let's sort the tabs according to order
1587
+		usort($this->_nav_tabs, array($this, '_sort_nav_tabs'));
1588
+	}
1589
+
1590
+
1591
+	/**
1592
+	 * _set_current_labels
1593
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1594
+	 * property array
1595
+	 *
1596
+	 * @return void
1597
+	 */
1598
+	private function _set_current_labels()
1599
+	{
1600
+		if (is_array($this->_route_config) && isset($this->_route_config['labels'])) {
1601
+			foreach ($this->_route_config['labels'] as $label => $text) {
1602
+				if (is_array($text)) {
1603
+					foreach ($text as $sublabel => $subtext) {
1604
+						$this->_labels[ $label ][ $sublabel ] = $subtext;
1605
+					}
1606
+				} else {
1607
+					$this->_labels[ $label ] = $text;
1608
+				}
1609
+			}
1610
+		}
1611
+	}
1612
+
1613
+
1614
+	/**
1615
+	 *        verifies user access for this admin page
1616
+	 *
1617
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1618
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1619
+	 *                               return false if verify fail.
1620
+	 * @return bool
1621
+	 * @throws InvalidArgumentException
1622
+	 * @throws InvalidDataTypeException
1623
+	 * @throws InvalidInterfaceException
1624
+	 */
1625
+	public function check_user_access($route_to_check = '', $verify_only = false)
1626
+	{
1627
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
1628
+		$route_to_check = empty($route_to_check) ? $this->_req_action : $route_to_check;
1629
+		$capability = ! empty($route_to_check) && isset($this->_page_routes[ $route_to_check ])
1630
+					  && is_array(
1631
+						  $this->_page_routes[ $route_to_check ]
1632
+					  )
1633
+					  && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1634
+			? $this->_page_routes[ $route_to_check ]['capability'] : null;
1635
+		if (empty($capability) && empty($route_to_check)) {
1636
+			$capability = is_array($this->_route) && empty($this->_route['capability']) ? 'manage_options'
1637
+				: $this->_route['capability'];
1638
+		} else {
1639
+			$capability = empty($capability) ? 'manage_options' : $capability;
1640
+		}
1641
+		$id = is_array($this->_route) && ! empty($this->_route['obj_id']) ? $this->_route['obj_id'] : 0;
1642
+		if (
1643
+			! defined('DOING_AJAX')
1644
+			&& (
1645
+				! function_exists('is_admin')
1646
+				|| ! EE_Registry::instance()->CAP->current_user_can(
1647
+					$capability,
1648
+					$this->page_slug
1649
+					. '_'
1650
+					. $route_to_check,
1651
+					$id
1652
+				)
1653
+			)
1654
+		) {
1655
+			if ($verify_only) {
1656
+				return false;
1657
+			}
1658
+			if (is_user_logged_in()) {
1659
+				wp_die(__('You do not have access to this route.', 'event_espresso'));
1660
+			} else {
1661
+				return false;
1662
+			}
1663
+		}
1664
+		return true;
1665
+	}
1666
+
1667
+
1668
+	/**
1669
+	 * admin_init_global
1670
+	 * This runs all the code that we want executed within the WP admin_init hook.
1671
+	 * This method executes for ALL EE Admin pages.
1672
+	 *
1673
+	 * @return void
1674
+	 */
1675
+	public function admin_init_global()
1676
+	{
1677
+	}
1678
+
1679
+
1680
+	/**
1681
+	 * wp_loaded_global
1682
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1683
+	 * EE_Admin page and will execute on every EE Admin Page load
1684
+	 *
1685
+	 * @return void
1686
+	 */
1687
+	public function wp_loaded()
1688
+	{
1689
+	}
1690
+
1691
+
1692
+	/**
1693
+	 * admin_notices
1694
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1695
+	 * ALL EE_Admin pages.
1696
+	 *
1697
+	 * @return void
1698
+	 */
1699
+	public function admin_notices_global()
1700
+	{
1701
+		$this->_display_no_javascript_warning();
1702
+		$this->_display_espresso_notices();
1703
+	}
1704
+
1705
+
1706
+	public function network_admin_notices_global()
1707
+	{
1708
+		$this->_display_no_javascript_warning();
1709
+		$this->_display_espresso_notices();
1710
+	}
1711
+
1712
+
1713
+	/**
1714
+	 * admin_footer_scripts_global
1715
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1716
+	 * will apply on ALL EE_Admin pages.
1717
+	 *
1718
+	 * @return void
1719
+	 */
1720
+	public function admin_footer_scripts_global()
1721
+	{
1722
+		$this->_add_admin_page_ajax_loading_img();
1723
+		$this->_add_admin_page_overlay();
1724
+		// if metaboxes are present we need to add the nonce field
1725
+		if (
1726
+			isset($this->_route_config['metaboxes'])
1727
+			|| isset($this->_route_config['list_table'])
1728
+			|| (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1729
+		) {
1730
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1731
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1732
+		}
1733
+	}
1734
+
1735
+
1736
+	/**
1737
+	 * admin_footer_global
1738
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1739
+	 * This particular method will apply on ALL EE_Admin Pages.
1740
+	 *
1741
+	 * @return void
1742
+	 * @throws InvalidArgumentException
1743
+	 * @throws InvalidDataTypeException
1744
+	 * @throws InvalidInterfaceException
1745
+	 */
1746
+	public function admin_footer_global()
1747
+	{
1748
+		// dialog container for dialog helper
1749
+		$d_cont = '<div class="ee-admin-dialog-container auto-hide hidden">' . "\n";
1750
+		$d_cont .= '<div class="ee-notices"></div>';
1751
+		$d_cont .= '<div class="ee-admin-dialog-container-inner-content"></div>';
1752
+		$d_cont .= '</div>';
1753
+		echo $d_cont;
1754
+		// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1755
+		// help tour stuff?
1756
+		// if (isset($this->_help_tour[ $this->_req_action ])) {
1757
+		//     echo implode('<br />', $this->_help_tour[ $this->_req_action ]);
1758
+		// }
1759
+		// current set timezone for timezone js
1760
+		echo '<span id="current_timezone" class="hidden">' . EEH_DTT_Helper::get_timezone() . '</span>';
1761
+	}
1762
+
1763
+
1764
+	/**
1765
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1766
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1767
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1768
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1769
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1770
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1771
+	 * for the
1772
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1773
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1774
+	 *    'help_trigger_id' => array(
1775
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1776
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1777
+	 *    )
1778
+	 * );
1779
+	 * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1780
+	 *
1781
+	 * @param array $help_array
1782
+	 * @param bool  $display
1783
+	 * @return string content
1784
+	 * @throws DomainException
1785
+	 * @throws EE_Error
1786
+	 */
1787
+	protected function _set_help_popup_content($help_array = array(), $display = false)
1788
+	{
1789
+		$content = '';
1790
+		$help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1791
+		// loop through the array and setup content
1792
+		foreach ($help_array as $trigger => $help) {
1793
+			// make sure the array is setup properly
1794
+			if (! isset($help['title'], $help['content'])) {
1795
+				throw new EE_Error(
1796
+					esc_html__(
1797
+						'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',
1798
+						'event_espresso'
1799
+					)
1800
+				);
1801
+			}
1802
+			// we're good so let'd setup the template vars and then assign parsed template content to our content.
1803
+			$template_args = array(
1804
+				'help_popup_id'      => $trigger,
1805
+				'help_popup_title'   => $help['title'],
1806
+				'help_popup_content' => $help['content'],
1807
+			);
1808
+			$content .= EEH_Template::display_template(
1809
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1810
+				$template_args,
1811
+				true
1812
+			);
1813
+		}
1814
+		if ($display) {
1815
+			echo $content;
1816
+			return '';
1817
+		}
1818
+		return $content;
1819
+	}
1820
+
1821
+
1822
+	/**
1823
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1824
+	 *
1825
+	 * @return array properly formatted array for help popup content
1826
+	 * @throws EE_Error
1827
+	 */
1828
+	private function _get_help_content()
1829
+	{
1830
+		// what is the method we're looking for?
1831
+		$method_name = '_help_popup_content_' . $this->_req_action;
1832
+		// if method doesn't exist let's get out.
1833
+		if (! method_exists($this, $method_name)) {
1834
+			return array();
1835
+		}
1836
+		// k we're good to go let's retrieve the help array
1837
+		$help_array = $this->{$method_name}();
1838
+		// make sure we've got an array!
1839
+		if (! is_array($help_array)) {
1840
+			throw new EE_Error(
1841
+				esc_html__(
1842
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1843
+					'event_espresso'
1844
+				)
1845
+			);
1846
+		}
1847
+		return $help_array;
1848
+	}
1849
+
1850
+
1851
+	/**
1852
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1853
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1854
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1855
+	 *
1856
+	 * @param string  $trigger_id reference for retrieving the trigger content for the popup
1857
+	 * @param boolean $display    if false then we return the trigger string
1858
+	 * @param array   $dimensions an array of dimensions for the box (array(h,w))
1859
+	 * @return string
1860
+	 * @throws DomainException
1861
+	 * @throws EE_Error
1862
+	 */
1863
+	protected function _set_help_trigger($trigger_id, $display = true, $dimensions = array('400', '640'))
1864
+	{
1865
+		if (defined('DOING_AJAX')) {
1866
+			return '';
1867
+		}
1868
+		// 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
1869
+		$help_array = $this->_get_help_content();
1870
+		$help_content = '';
1871
+		if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1872
+			$help_array[ $trigger_id ] = array(
1873
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1874
+				'content' => esc_html__(
1875
+					'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.)',
1876
+					'event_espresso'
1877
+				),
1878
+			);
1879
+			$help_content = $this->_set_help_popup_content($help_array);
1880
+		}
1881
+		// let's setup the trigger
1882
+		$content = '<a class="ee-dialog" href="?height='
1883
+				   . $dimensions[0]
1884
+				   . '&width='
1885
+				   . $dimensions[1]
1886
+				   . '&inlineId='
1887
+				   . $trigger_id
1888
+				   . '" target="_blank"><span class="question ee-help-popup-question"></span></a>';
1889
+		$content .= $help_content;
1890
+		if ($display) {
1891
+			echo $content;
1892
+			return '';
1893
+		}
1894
+		return $content;
1895
+	}
1896
+
1897
+
1898
+	/**
1899
+	 * _add_global_screen_options
1900
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1901
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1902
+	 *
1903
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1904
+	 *         see also WP_Screen object documents...
1905
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1906
+	 * @abstract
1907
+	 * @return void
1908
+	 */
1909
+	private function _add_global_screen_options()
1910
+	{
1911
+	}
1912
+
1913
+
1914
+	/**
1915
+	 * _add_global_feature_pointers
1916
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1917
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1918
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1919
+	 *
1920
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1921
+	 *         extended) also see:
1922
+	 * @link   http://eamann.com/tech/wordpress-portland/
1923
+	 * @abstract
1924
+	 * @return void
1925
+	 */
1926
+	private function _add_global_feature_pointers()
1927
+	{
1928
+	}
1929
+
1930
+
1931
+	/**
1932
+	 * load_global_scripts_styles
1933
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1934
+	 *
1935
+	 * @return void
1936
+	 * @throws EE_Error
1937
+	 */
1938
+	public function load_global_scripts_styles()
1939
+	{
1940
+		// add debugging styles
1941
+		if (WP_DEBUG) {
1942
+			add_action('admin_head', array($this, 'add_xdebug_style'));
1943
+		}
1944
+		// taking care of metaboxes
1945
+		if (
1946
+			empty($this->_cpt_route)
1947
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1948
+		) {
1949
+			wp_enqueue_script('dashboard');
1950
+		}
1951
+
1952
+		// LOCALIZED DATA
1953
+		// localize script for ajax lazy loading
1954
+		wp_localize_script(
1955
+			EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1956
+			'eeLazyLoadingContainers',
1957
+			apply_filters(
1958
+				'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1959
+				['espresso_news_post_box_content']
1960
+			)
1961
+		);
1962
+		// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
1963
+		// /**
1964
+		//  * help tour stuff
1965
+		//  */
1966
+		// if (! empty($this->_help_tour)) {
1967
+		//     // register the js for kicking things off
1968
+		//     wp_enqueue_script(
1969
+		//         'ee-help-tour',
1970
+		//         EE_ADMIN_URL . 'assets/ee-help-tour.js',
1971
+		//         array('jquery-joyride'),
1972
+		//         EVENT_ESPRESSO_VERSION,
1973
+		//         true
1974
+		//     );
1975
+		//     $tours = array();
1976
+		//     // setup tours for the js tour object
1977
+		//     foreach ($this->_help_tour['tours'] as $tour) {
1978
+		//         if ($tour instanceof EE_Help_Tour) {
1979
+		//             $tours[] = array(
1980
+		//                 'id'      => $tour->get_slug(),
1981
+		//                 'options' => $tour->get_options(),
1982
+		//             );
1983
+		//         }
1984
+		//     }
1985
+		//     wp_localize_script('ee-help-tour', 'EE_HELP_TOUR', array('tours' => $tours));
1986
+		//     // admin_footer_global will take care of making sure our help_tour skeleton gets printed via the info stored in $this->_help_tour
1987
+		// }
1988
+	}
1989
+
1990
+
1991
+	/**
1992
+	 *        admin_footer_scripts_eei18n_js_strings
1993
+	 *
1994
+	 * @return        void
1995
+	 */
1996
+	public function admin_footer_scripts_eei18n_js_strings()
1997
+	{
1998
+		EE_Registry::$i18n_js_strings['ajax_url'] = WP_AJAX_URL;
1999
+		EE_Registry::$i18n_js_strings['confirm_delete'] = esc_html__(
2000
+			'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!!!',
2001
+			'event_espresso'
2002
+		);
2003
+		EE_Registry::$i18n_js_strings['January'] = esc_html__('January', 'event_espresso');
2004
+		EE_Registry::$i18n_js_strings['February'] = esc_html__('February', 'event_espresso');
2005
+		EE_Registry::$i18n_js_strings['March'] = esc_html__('March', 'event_espresso');
2006
+		EE_Registry::$i18n_js_strings['April'] = esc_html__('April', 'event_espresso');
2007
+		EE_Registry::$i18n_js_strings['May'] = esc_html__('May', 'event_espresso');
2008
+		EE_Registry::$i18n_js_strings['June'] = esc_html__('June', 'event_espresso');
2009
+		EE_Registry::$i18n_js_strings['July'] = esc_html__('July', 'event_espresso');
2010
+		EE_Registry::$i18n_js_strings['August'] = esc_html__('August', 'event_espresso');
2011
+		EE_Registry::$i18n_js_strings['September'] = esc_html__('September', 'event_espresso');
2012
+		EE_Registry::$i18n_js_strings['October'] = esc_html__('October', 'event_espresso');
2013
+		EE_Registry::$i18n_js_strings['November'] = esc_html__('November', 'event_espresso');
2014
+		EE_Registry::$i18n_js_strings['December'] = esc_html__('December', 'event_espresso');
2015
+		EE_Registry::$i18n_js_strings['Jan'] = esc_html__('Jan', 'event_espresso');
2016
+		EE_Registry::$i18n_js_strings['Feb'] = esc_html__('Feb', 'event_espresso');
2017
+		EE_Registry::$i18n_js_strings['Mar'] = esc_html__('Mar', 'event_espresso');
2018
+		EE_Registry::$i18n_js_strings['Apr'] = esc_html__('Apr', 'event_espresso');
2019
+		EE_Registry::$i18n_js_strings['May'] = esc_html__('May', 'event_espresso');
2020
+		EE_Registry::$i18n_js_strings['Jun'] = esc_html__('Jun', 'event_espresso');
2021
+		EE_Registry::$i18n_js_strings['Jul'] = esc_html__('Jul', 'event_espresso');
2022
+		EE_Registry::$i18n_js_strings['Aug'] = esc_html__('Aug', 'event_espresso');
2023
+		EE_Registry::$i18n_js_strings['Sep'] = esc_html__('Sep', 'event_espresso');
2024
+		EE_Registry::$i18n_js_strings['Oct'] = esc_html__('Oct', 'event_espresso');
2025
+		EE_Registry::$i18n_js_strings['Nov'] = esc_html__('Nov', 'event_espresso');
2026
+		EE_Registry::$i18n_js_strings['Dec'] = esc_html__('Dec', 'event_espresso');
2027
+		EE_Registry::$i18n_js_strings['Sunday'] = esc_html__('Sunday', 'event_espresso');
2028
+		EE_Registry::$i18n_js_strings['Monday'] = esc_html__('Monday', 'event_espresso');
2029
+		EE_Registry::$i18n_js_strings['Tuesday'] = esc_html__('Tuesday', 'event_espresso');
2030
+		EE_Registry::$i18n_js_strings['Wednesday'] = esc_html__('Wednesday', 'event_espresso');
2031
+		EE_Registry::$i18n_js_strings['Thursday'] = esc_html__('Thursday', 'event_espresso');
2032
+		EE_Registry::$i18n_js_strings['Friday'] = esc_html__('Friday', 'event_espresso');
2033
+		EE_Registry::$i18n_js_strings['Saturday'] = esc_html__('Saturday', 'event_espresso');
2034
+		EE_Registry::$i18n_js_strings['Sun'] = esc_html__('Sun', 'event_espresso');
2035
+		EE_Registry::$i18n_js_strings['Mon'] = esc_html__('Mon', 'event_espresso');
2036
+		EE_Registry::$i18n_js_strings['Tue'] = esc_html__('Tue', 'event_espresso');
2037
+		EE_Registry::$i18n_js_strings['Wed'] = esc_html__('Wed', 'event_espresso');
2038
+		EE_Registry::$i18n_js_strings['Thu'] = esc_html__('Thu', 'event_espresso');
2039
+		EE_Registry::$i18n_js_strings['Fri'] = esc_html__('Fri', 'event_espresso');
2040
+		EE_Registry::$i18n_js_strings['Sat'] = esc_html__('Sat', 'event_espresso');
2041
+	}
2042
+
2043
+
2044
+	/**
2045
+	 *        load enhanced xdebug styles for ppl with failing eyesight
2046
+	 *
2047
+	 * @return        void
2048
+	 */
2049
+	public function add_xdebug_style()
2050
+	{
2051
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
2052
+	}
2053
+
2054
+
2055
+	/************************/
2056
+	/** LIST TABLE METHODS **/
2057
+	/************************/
2058
+	/**
2059
+	 * this sets up the list table if the current view requires it.
2060
+	 *
2061
+	 * @return void
2062
+	 * @throws EE_Error
2063
+	 * @throws InvalidArgumentException
2064
+	 * @throws InvalidDataTypeException
2065
+	 * @throws InvalidInterfaceException
2066
+	 */
2067
+	protected function _set_list_table()
2068
+	{
2069
+		// first is this a list_table view?
2070
+		if (! isset($this->_route_config['list_table'])) {
2071
+			return;
2072
+		} //not a list_table view so get out.
2073
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
2074
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
2075
+		if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2076
+			// user error msg
2077
+			$error_msg = esc_html__(
2078
+				'An error occurred. The requested list table views could not be found.',
2079
+				'event_espresso'
2080
+			);
2081
+			// developer error msg
2082
+			$error_msg .= '||'
2083
+						  . sprintf(
2084
+							  esc_html__(
2085
+								  '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.',
2086
+								  'event_espresso'
2087
+							  ),
2088
+							  $this->_req_action,
2089
+							  $list_table_view
2090
+						  );
2091
+			throw new EE_Error($error_msg);
2092
+		}
2093
+		// let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2094
+		$this->_views = apply_filters(
2095
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2096
+			$this->_views
2097
+		);
2098
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2099
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2100
+		$this->_set_list_table_view();
2101
+		$this->_set_list_table_object();
2102
+	}
2103
+
2104
+
2105
+	/**
2106
+	 * set current view for List Table
2107
+	 *
2108
+	 * @return void
2109
+	 */
2110
+	protected function _set_list_table_view()
2111
+	{
2112
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2113
+		// looking at active items or dumpster diving ?
2114
+		if (! isset($this->_req_data['status']) || ! array_key_exists($this->_req_data['status'], $this->_views)) {
2115
+			$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2116
+		} else {
2117
+			$this->_view = sanitize_key($this->_req_data['status']);
2118
+		}
2119
+	}
2120
+
2121
+
2122
+	/**
2123
+	 * _set_list_table_object
2124
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2125
+	 *
2126
+	 * @throws InvalidInterfaceException
2127
+	 * @throws InvalidArgumentException
2128
+	 * @throws InvalidDataTypeException
2129
+	 * @throws EE_Error
2130
+	 * @throws InvalidInterfaceException
2131
+	 */
2132
+	protected function _set_list_table_object()
2133
+	{
2134
+		if (isset($this->_route_config['list_table'])) {
2135
+			if (! class_exists($this->_route_config['list_table'])) {
2136
+				throw new EE_Error(
2137
+					sprintf(
2138
+						esc_html__(
2139
+							'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.',
2140
+							'event_espresso'
2141
+						),
2142
+						$this->_route_config['list_table'],
2143
+						get_class($this)
2144
+					)
2145
+				);
2146
+			}
2147
+			$this->_list_table_object = $this->loader->getShared(
2148
+				$this->_route_config['list_table'],
2149
+				array($this)
2150
+			);
2151
+		}
2152
+	}
2153
+
2154
+
2155
+	/**
2156
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2157
+	 *
2158
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2159
+	 *                                                    urls.  The array should be indexed by the view it is being
2160
+	 *                                                    added to.
2161
+	 * @return array
2162
+	 */
2163
+	public function get_list_table_view_RLs($extra_query_args = array())
2164
+	{
2165
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2166
+		if (empty($this->_views)) {
2167
+			$this->_views = array();
2168
+		}
2169
+		// cycle thru views
2170
+		foreach ($this->_views as $key => $view) {
2171
+			$query_args = array();
2172
+			// check for current view
2173
+			$this->_views[ $key ]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2174
+			$query_args['action'] = $this->_req_action;
2175
+			$query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2176
+			$query_args['status'] = $view['slug'];
2177
+			// merge any other arguments sent in.
2178
+			if (isset($extra_query_args[ $view['slug'] ])) {
2179
+				foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2180
+					$query_args[] = $extra_query_arg;
2181
+				}
2182
+			}
2183
+			$this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2184
+		}
2185
+		return $this->_views;
2186
+	}
2187
+
2188
+
2189
+	/**
2190
+	 * _entries_per_page_dropdown
2191
+	 * generates a drop down box for selecting the number of visible rows in an admin page list table
2192
+	 *
2193
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2194
+	 *         WP does it.
2195
+	 * @param int $max_entries total number of rows in the table
2196
+	 * @return string
2197
+	 */
2198
+	protected function _entries_per_page_dropdown($max_entries = 0)
2199
+	{
2200
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2201
+		$values = array(10, 25, 50, 100);
2202
+		$per_page = (! empty($this->_req_data['per_page'])) ? absint($this->_req_data['per_page']) : 10;
2203
+		if ($max_entries) {
2204
+			$values[] = $max_entries;
2205
+			sort($values);
2206
+		}
2207
+		$entries_per_page_dropdown = '
2208 2208
 			<div id="entries-per-page-dv" class="alignleft actions">
2209 2209
 				<label class="hide-if-no-js">
2210 2210
 					Show
2211 2211
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2212
-        foreach ($values as $value) {
2213
-            if ($value < $max_entries) {
2214
-                $selected = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2215
-                $entries_per_page_dropdown .= '
2212
+		foreach ($values as $value) {
2213
+			if ($value < $max_entries) {
2214
+				$selected = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2215
+				$entries_per_page_dropdown .= '
2216 2216
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2217
-            }
2218
-        }
2219
-        $selected = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2220
-        $entries_per_page_dropdown .= '
2217
+			}
2218
+		}
2219
+		$selected = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2220
+		$entries_per_page_dropdown .= '
2221 2221
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2222
-        $entries_per_page_dropdown .= '
2222
+		$entries_per_page_dropdown .= '
2223 2223
 					</select>
2224 2224
 					entries
2225 2225
 				</label>
2226 2226
 				<input id="entries-per-page-btn" class="button-secondary" type="submit" value="Go" >
2227 2227
 			</div>
2228 2228
 		';
2229
-        return $entries_per_page_dropdown;
2230
-    }
2231
-
2232
-
2233
-    /**
2234
-     *        _set_search_attributes
2235
-     *
2236
-     * @return        void
2237
-     */
2238
-    public function _set_search_attributes()
2239
-    {
2240
-        $this->_template_args['search']['btn_label'] = sprintf(
2241
-            esc_html__('Search %s', 'event_espresso'),
2242
-            empty($this->_search_btn_label) ? $this->page_label
2243
-                : $this->_search_btn_label
2244
-        );
2245
-        $this->_template_args['search']['callback'] = 'search_' . $this->page_slug;
2246
-    }
2247
-
2248
-
2249
-
2250
-    /*** END LIST TABLE METHODS **/
2251
-
2252
-
2253
-    /**
2254
-     * _add_registered_metaboxes
2255
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2256
-     *
2257
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2258
-     * @return void
2259
-     * @throws EE_Error
2260
-     */
2261
-    private function _add_registered_meta_boxes()
2262
-    {
2263
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2264
-        // we only add meta boxes if the page_route calls for it
2265
-        if (
2266
-            is_array($this->_route_config) && isset($this->_route_config['metaboxes'])
2267
-            && is_array(
2268
-                $this->_route_config['metaboxes']
2269
-            )
2270
-        ) {
2271
-            // this simply loops through the callbacks provided
2272
-            // and checks if there is a corresponding callback registered by the child
2273
-            // if there is then we go ahead and process the metabox loader.
2274
-            foreach ($this->_route_config['metaboxes'] as $metabox_callback) {
2275
-                // first check for Closures
2276
-                if ($metabox_callback instanceof Closure) {
2277
-                    $result = $metabox_callback();
2278
-                } elseif (is_array($metabox_callback) && isset($metabox_callback[0], $metabox_callback[1])) {
2279
-                    $result = call_user_func(array($metabox_callback[0], $metabox_callback[1]));
2280
-                } else {
2281
-                    $result = $this->{$metabox_callback}();
2282
-                }
2283
-                if ($result === false) {
2284
-                    // user error msg
2285
-                    $error_msg = esc_html__(
2286
-                        'An error occurred. The  requested metabox could not be found.',
2287
-                        'event_espresso'
2288
-                    );
2289
-                    // developer error msg
2290
-                    $error_msg .= '||'
2291
-                                  . sprintf(
2292
-                                      esc_html__(
2293
-                                          '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.',
2294
-                                          'event_espresso'
2295
-                                      ),
2296
-                                      $metabox_callback
2297
-                                  );
2298
-                    throw new EE_Error($error_msg);
2299
-                }
2300
-            }
2301
-        }
2302
-    }
2303
-
2304
-
2305
-    /**
2306
-     * _add_screen_columns
2307
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2308
-     * the dynamic column template and we'll setup the column options for the page.
2309
-     *
2310
-     * @return void
2311
-     */
2312
-    private function _add_screen_columns()
2313
-    {
2314
-        if (
2315
-            is_array($this->_route_config)
2316
-            && isset($this->_route_config['columns'])
2317
-            && is_array($this->_route_config['columns'])
2318
-            && count($this->_route_config['columns']) === 2
2319
-        ) {
2320
-            add_screen_option(
2321
-                'layout_columns',
2322
-                array(
2323
-                    'max'     => (int) $this->_route_config['columns'][0],
2324
-                    'default' => (int) $this->_route_config['columns'][1],
2325
-                )
2326
-            );
2327
-            $this->_template_args['num_columns'] = $this->_route_config['columns'][0];
2328
-            $screen_id = $this->_current_screen->id;
2329
-            $screen_columns = (int) get_user_option("screen_layout_{$screen_id}");
2330
-            $total_columns = ! empty($screen_columns)
2331
-                ? $screen_columns
2332
-                : $this->_route_config['columns'][1];
2333
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2334
-            $this->_template_args['current_page'] = $this->_wp_page_slug;
2335
-            $this->_template_args['screen'] = $this->_current_screen;
2336
-            $this->_column_template_path = EE_ADMIN_TEMPLATE
2337
-                                           . 'admin_details_metabox_column_wrapper.template.php';
2338
-            // finally if we don't have has_metaboxes set in the route config
2339
-            // let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2340
-            $this->_route_config['has_metaboxes'] = true;
2341
-        }
2342
-    }
2343
-
2344
-
2345
-
2346
-    /** GLOBALLY AVAILABLE METABOXES **/
2347
-
2348
-
2349
-    /**
2350
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2351
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2352
-     * these get loaded on.
2353
-     */
2354
-    private function _espresso_news_post_box()
2355
-    {
2356
-        $news_box_title = apply_filters(
2357
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2358
-            esc_html__('New @ Event Espresso', 'event_espresso')
2359
-        );
2360
-        add_meta_box(
2361
-            'espresso_news_post_box',
2362
-            $news_box_title,
2363
-            array(
2364
-                $this,
2365
-                'espresso_news_post_box',
2366
-            ),
2367
-            $this->_wp_page_slug,
2368
-            'side'
2369
-        );
2370
-    }
2371
-
2372
-
2373
-    /**
2374
-     * Code for setting up espresso ratings request metabox.
2375
-     */
2376
-    protected function _espresso_ratings_request()
2377
-    {
2378
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2379
-            return;
2380
-        }
2381
-        $ratings_box_title = apply_filters(
2382
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2383
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2384
-        );
2385
-        add_meta_box(
2386
-            'espresso_ratings_request',
2387
-            $ratings_box_title,
2388
-            array(
2389
-                $this,
2390
-                'espresso_ratings_request',
2391
-            ),
2392
-            $this->_wp_page_slug,
2393
-            'side'
2394
-        );
2395
-    }
2396
-
2397
-
2398
-    /**
2399
-     * Code for setting up espresso ratings request metabox content.
2400
-     *
2401
-     * @throws DomainException
2402
-     */
2403
-    public function espresso_ratings_request()
2404
-    {
2405
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2406
-    }
2407
-
2408
-
2409
-    public static function cached_rss_display($rss_id, $url)
2410
-    {
2411
-        $loading = '<p class="widget-loading hide-if-no-js">'
2412
-                   . __('Loading&#8230;', 'event_espresso')
2413
-                   . '</p><p class="hide-if-js">'
2414
-                   . esc_html__('This widget requires JavaScript.', 'event_espresso')
2415
-                   . '</p>';
2416
-        $pre = '<div class="espresso-rss-display">' . "\n\t";
2417
-        $pre .= '<span id="' . $rss_id . '_url" class="hidden">' . $url . '</span>';
2418
-        $post = '</div>' . "\n";
2419
-        $cache_key = 'ee_rss_' . md5($rss_id);
2420
-        $output = get_transient($cache_key);
2421
-        if ($output !== false) {
2422
-            echo $pre . $output . $post;
2423
-            return true;
2424
-        }
2425
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2426
-            echo $pre . $loading . $post;
2427
-            return false;
2428
-        }
2429
-        ob_start();
2430
-        wp_widget_rss_output($url, array('show_date' => 0, 'items' => 5));
2431
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2432
-        return true;
2433
-    }
2434
-
2435
-
2436
-    public function espresso_news_post_box()
2437
-    {
2438
-        ?>
2229
+		return $entries_per_page_dropdown;
2230
+	}
2231
+
2232
+
2233
+	/**
2234
+	 *        _set_search_attributes
2235
+	 *
2236
+	 * @return        void
2237
+	 */
2238
+	public function _set_search_attributes()
2239
+	{
2240
+		$this->_template_args['search']['btn_label'] = sprintf(
2241
+			esc_html__('Search %s', 'event_espresso'),
2242
+			empty($this->_search_btn_label) ? $this->page_label
2243
+				: $this->_search_btn_label
2244
+		);
2245
+		$this->_template_args['search']['callback'] = 'search_' . $this->page_slug;
2246
+	}
2247
+
2248
+
2249
+
2250
+	/*** END LIST TABLE METHODS **/
2251
+
2252
+
2253
+	/**
2254
+	 * _add_registered_metaboxes
2255
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2256
+	 *
2257
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2258
+	 * @return void
2259
+	 * @throws EE_Error
2260
+	 */
2261
+	private function _add_registered_meta_boxes()
2262
+	{
2263
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2264
+		// we only add meta boxes if the page_route calls for it
2265
+		if (
2266
+			is_array($this->_route_config) && isset($this->_route_config['metaboxes'])
2267
+			&& is_array(
2268
+				$this->_route_config['metaboxes']
2269
+			)
2270
+		) {
2271
+			// this simply loops through the callbacks provided
2272
+			// and checks if there is a corresponding callback registered by the child
2273
+			// if there is then we go ahead and process the metabox loader.
2274
+			foreach ($this->_route_config['metaboxes'] as $metabox_callback) {
2275
+				// first check for Closures
2276
+				if ($metabox_callback instanceof Closure) {
2277
+					$result = $metabox_callback();
2278
+				} elseif (is_array($metabox_callback) && isset($metabox_callback[0], $metabox_callback[1])) {
2279
+					$result = call_user_func(array($metabox_callback[0], $metabox_callback[1]));
2280
+				} else {
2281
+					$result = $this->{$metabox_callback}();
2282
+				}
2283
+				if ($result === false) {
2284
+					// user error msg
2285
+					$error_msg = esc_html__(
2286
+						'An error occurred. The  requested metabox could not be found.',
2287
+						'event_espresso'
2288
+					);
2289
+					// developer error msg
2290
+					$error_msg .= '||'
2291
+								  . sprintf(
2292
+									  esc_html__(
2293
+										  '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.',
2294
+										  'event_espresso'
2295
+									  ),
2296
+									  $metabox_callback
2297
+								  );
2298
+					throw new EE_Error($error_msg);
2299
+				}
2300
+			}
2301
+		}
2302
+	}
2303
+
2304
+
2305
+	/**
2306
+	 * _add_screen_columns
2307
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2308
+	 * the dynamic column template and we'll setup the column options for the page.
2309
+	 *
2310
+	 * @return void
2311
+	 */
2312
+	private function _add_screen_columns()
2313
+	{
2314
+		if (
2315
+			is_array($this->_route_config)
2316
+			&& isset($this->_route_config['columns'])
2317
+			&& is_array($this->_route_config['columns'])
2318
+			&& count($this->_route_config['columns']) === 2
2319
+		) {
2320
+			add_screen_option(
2321
+				'layout_columns',
2322
+				array(
2323
+					'max'     => (int) $this->_route_config['columns'][0],
2324
+					'default' => (int) $this->_route_config['columns'][1],
2325
+				)
2326
+			);
2327
+			$this->_template_args['num_columns'] = $this->_route_config['columns'][0];
2328
+			$screen_id = $this->_current_screen->id;
2329
+			$screen_columns = (int) get_user_option("screen_layout_{$screen_id}");
2330
+			$total_columns = ! empty($screen_columns)
2331
+				? $screen_columns
2332
+				: $this->_route_config['columns'][1];
2333
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2334
+			$this->_template_args['current_page'] = $this->_wp_page_slug;
2335
+			$this->_template_args['screen'] = $this->_current_screen;
2336
+			$this->_column_template_path = EE_ADMIN_TEMPLATE
2337
+										   . 'admin_details_metabox_column_wrapper.template.php';
2338
+			// finally if we don't have has_metaboxes set in the route config
2339
+			// let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2340
+			$this->_route_config['has_metaboxes'] = true;
2341
+		}
2342
+	}
2343
+
2344
+
2345
+
2346
+	/** GLOBALLY AVAILABLE METABOXES **/
2347
+
2348
+
2349
+	/**
2350
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2351
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2352
+	 * these get loaded on.
2353
+	 */
2354
+	private function _espresso_news_post_box()
2355
+	{
2356
+		$news_box_title = apply_filters(
2357
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2358
+			esc_html__('New @ Event Espresso', 'event_espresso')
2359
+		);
2360
+		add_meta_box(
2361
+			'espresso_news_post_box',
2362
+			$news_box_title,
2363
+			array(
2364
+				$this,
2365
+				'espresso_news_post_box',
2366
+			),
2367
+			$this->_wp_page_slug,
2368
+			'side'
2369
+		);
2370
+	}
2371
+
2372
+
2373
+	/**
2374
+	 * Code for setting up espresso ratings request metabox.
2375
+	 */
2376
+	protected function _espresso_ratings_request()
2377
+	{
2378
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2379
+			return;
2380
+		}
2381
+		$ratings_box_title = apply_filters(
2382
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2383
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2384
+		);
2385
+		add_meta_box(
2386
+			'espresso_ratings_request',
2387
+			$ratings_box_title,
2388
+			array(
2389
+				$this,
2390
+				'espresso_ratings_request',
2391
+			),
2392
+			$this->_wp_page_slug,
2393
+			'side'
2394
+		);
2395
+	}
2396
+
2397
+
2398
+	/**
2399
+	 * Code for setting up espresso ratings request metabox content.
2400
+	 *
2401
+	 * @throws DomainException
2402
+	 */
2403
+	public function espresso_ratings_request()
2404
+	{
2405
+		EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2406
+	}
2407
+
2408
+
2409
+	public static function cached_rss_display($rss_id, $url)
2410
+	{
2411
+		$loading = '<p class="widget-loading hide-if-no-js">'
2412
+				   . __('Loading&#8230;', 'event_espresso')
2413
+				   . '</p><p class="hide-if-js">'
2414
+				   . esc_html__('This widget requires JavaScript.', 'event_espresso')
2415
+				   . '</p>';
2416
+		$pre = '<div class="espresso-rss-display">' . "\n\t";
2417
+		$pre .= '<span id="' . $rss_id . '_url" class="hidden">' . $url . '</span>';
2418
+		$post = '</div>' . "\n";
2419
+		$cache_key = 'ee_rss_' . md5($rss_id);
2420
+		$output = get_transient($cache_key);
2421
+		if ($output !== false) {
2422
+			echo $pre . $output . $post;
2423
+			return true;
2424
+		}
2425
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2426
+			echo $pre . $loading . $post;
2427
+			return false;
2428
+		}
2429
+		ob_start();
2430
+		wp_widget_rss_output($url, array('show_date' => 0, 'items' => 5));
2431
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2432
+		return true;
2433
+	}
2434
+
2435
+
2436
+	public function espresso_news_post_box()
2437
+	{
2438
+		?>
2439 2439
         <div class="padding">
2440 2440
             <div id="espresso_news_post_box_content" class="infolinks">
2441 2441
                 <?php
2442
-                // Get RSS Feed(s)
2443
-                EE_Admin_Page::cached_rss_display(
2444
-                    'espresso_news_post_box_content',
2445
-                    urlencode(
2446
-                        apply_filters(
2447
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2448
-                            'http://eventespresso.com/feed/'
2449
-                        )
2450
-                    )
2451
-                );
2452
-                ?>
2442
+				// Get RSS Feed(s)
2443
+				EE_Admin_Page::cached_rss_display(
2444
+					'espresso_news_post_box_content',
2445
+					urlencode(
2446
+						apply_filters(
2447
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2448
+							'http://eventespresso.com/feed/'
2449
+						)
2450
+					)
2451
+				);
2452
+				?>
2453 2453
             </div>
2454 2454
             <?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2455 2455
         </div>
2456 2456
         <?php
2457
-    }
2458
-
2459
-
2460
-    private function _espresso_links_post_box()
2461
-    {
2462
-        // Hiding until we actually have content to put in here...
2463
-        // add_meta_box('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2464
-    }
2465
-
2466
-
2467
-    public function espresso_links_post_box()
2468
-    {
2469
-        // Hiding until we actually have content to put in here...
2470
-        // EEH_Template::display_template(
2471
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2472
-        // );
2473
-    }
2474
-
2475
-
2476
-    protected function _espresso_sponsors_post_box()
2477
-    {
2478
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2479
-            add_meta_box(
2480
-                'espresso_sponsors_post_box',
2481
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2482
-                array($this, 'espresso_sponsors_post_box'),
2483
-                $this->_wp_page_slug,
2484
-                'side'
2485
-            );
2486
-        }
2487
-    }
2488
-
2489
-
2490
-    public function espresso_sponsors_post_box()
2491
-    {
2492
-        EEH_Template::display_template(
2493
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2494
-        );
2495
-    }
2496
-
2497
-
2498
-    private function _publish_post_box()
2499
-    {
2500
-        $meta_box_ref = 'espresso_' . $this->page_slug . '_editor_overview';
2501
-        // if there is a array('label' => array('publishbox' => 'some title') ) present in the _page_config array
2502
-        // then we'll use that for the metabox label.
2503
-        // Otherwise we'll just use publish (publishbox itself could be an array of labels indexed by routes)
2504
-        if (! empty($this->_labels['publishbox'])) {
2505
-            $box_label = is_array($this->_labels['publishbox']) ? $this->_labels['publishbox'][ $this->_req_action ]
2506
-                : $this->_labels['publishbox'];
2507
-        } else {
2508
-            $box_label = esc_html__('Publish', 'event_espresso');
2509
-        }
2510
-        $box_label = apply_filters(
2511
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2512
-            $box_label,
2513
-            $this->_req_action,
2514
-            $this
2515
-        );
2516
-        add_meta_box(
2517
-            $meta_box_ref,
2518
-            $box_label,
2519
-            array($this, 'editor_overview'),
2520
-            $this->_current_screen->id,
2521
-            'side',
2522
-            'high'
2523
-        );
2524
-    }
2525
-
2526
-
2527
-    public function editor_overview()
2528
-    {
2529
-        // if we have extra content set let's add it in if not make sure its empty
2530
-        $this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2531
-            ? $this->_template_args['publish_box_extra_content']
2532
-            : '';
2533
-        echo EEH_Template::display_template(
2534
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2535
-            $this->_template_args,
2536
-            true
2537
-        );
2538
-    }
2539
-
2540
-
2541
-    /** end of globally available metaboxes section **/
2542
-
2543
-
2544
-    /**
2545
-     * Public wrapper for the protected method.  Allows plugins/addons to externally call the
2546
-     * protected method.
2547
-     *
2548
-     * @see   $this->_set_publish_post_box_vars for param details
2549
-     * @since 4.6.0
2550
-     * @param string $name
2551
-     * @param int    $id
2552
-     * @param bool   $delete
2553
-     * @param string $save_close_redirect_URL
2554
-     * @param bool   $both_btns
2555
-     * @throws EE_Error
2556
-     * @throws InvalidArgumentException
2557
-     * @throws InvalidDataTypeException
2558
-     * @throws InvalidInterfaceException
2559
-     */
2560
-    public function set_publish_post_box_vars(
2561
-        $name = '',
2562
-        $id = 0,
2563
-        $delete = false,
2564
-        $save_close_redirect_URL = '',
2565
-        $both_btns = true
2566
-    ) {
2567
-        $this->_set_publish_post_box_vars(
2568
-            $name,
2569
-            $id,
2570
-            $delete,
2571
-            $save_close_redirect_URL,
2572
-            $both_btns
2573
-        );
2574
-    }
2575
-
2576
-
2577
-    /**
2578
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2579
-     * Note: currently there is no validation for this.  However if you want the delete button, the
2580
-     * save, and save and close buttons to work properly, then you will want to include a
2581
-     * values for the name and id arguments.
2582
-     *
2583
-     * @todo  Add in validation for name/id arguments.
2584
-     * @param    string  $name                    key used for the action ID (i.e. event_id)
2585
-     * @param    int     $id                      id attached to the item published
2586
-     * @param    string  $delete                  page route callback for the delete action
2587
-     * @param    string  $save_close_redirect_URL custom URL to redirect to after Save & Close has been completed
2588
-     * @param    boolean $both_btns               whether to display BOTH the "Save & Close" and "Save" buttons or just
2589
-     *                                            the Save button
2590
-     * @throws EE_Error
2591
-     * @throws InvalidArgumentException
2592
-     * @throws InvalidDataTypeException
2593
-     * @throws InvalidInterfaceException
2594
-     */
2595
-    protected function _set_publish_post_box_vars(
2596
-        $name = '',
2597
-        $id = 0,
2598
-        $delete = '',
2599
-        $save_close_redirect_URL = '',
2600
-        $both_btns = true
2601
-    ) {
2602
-        // if Save & Close, use a custom redirect URL or default to the main page?
2603
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2604
-            ? $save_close_redirect_URL
2605
-            : $this->_admin_base_url;
2606
-        // create the Save & Close and Save buttons
2607
-        $this->_set_save_buttons($both_btns, array(), array(), $save_close_redirect_URL);
2608
-        // if we have extra content set let's add it in if not make sure its empty
2609
-        $this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2610
-            ? $this->_template_args['publish_box_extra_content']
2611
-            : '';
2612
-        if ($delete && ! empty($id)) {
2613
-            // make sure we have a default if just true is sent.
2614
-            $delete = ! empty($delete) ? $delete : 'delete';
2615
-            $delete_link_args = array($name => $id);
2616
-            $delete = $this->get_action_link_or_button(
2617
-                $delete,
2618
-                $delete,
2619
-                $delete_link_args,
2620
-                'submitdelete deletion'
2621
-            );
2622
-        }
2623
-        $this->_template_args['publish_delete_link'] = ! empty($id) ? $delete : '';
2624
-        if (! empty($name) && ! empty($id)) {
2625
-            $hidden_field_arr[ $name ] = array(
2626
-                'type'  => 'hidden',
2627
-                'value' => $id,
2628
-            );
2629
-            $hf = $this->_generate_admin_form_fields($hidden_field_arr, 'array');
2630
-        } else {
2631
-            $hf = '';
2632
-        }
2633
-        // add hidden field
2634
-        $this->_template_args['publish_hidden_fields'] = is_array($hf) && ! empty($name)
2635
-            ? $hf[ $name ]['field']
2636
-            : $hf;
2637
-    }
2638
-
2639
-
2640
-    /**
2641
-     * displays an error message to ppl who have javascript disabled
2642
-     *
2643
-     * @return void
2644
-     */
2645
-    private function _display_no_javascript_warning()
2646
-    {
2647
-        ?>
2457
+	}
2458
+
2459
+
2460
+	private function _espresso_links_post_box()
2461
+	{
2462
+		// Hiding until we actually have content to put in here...
2463
+		// add_meta_box('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2464
+	}
2465
+
2466
+
2467
+	public function espresso_links_post_box()
2468
+	{
2469
+		// Hiding until we actually have content to put in here...
2470
+		// EEH_Template::display_template(
2471
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2472
+		// );
2473
+	}
2474
+
2475
+
2476
+	protected function _espresso_sponsors_post_box()
2477
+	{
2478
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2479
+			add_meta_box(
2480
+				'espresso_sponsors_post_box',
2481
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2482
+				array($this, 'espresso_sponsors_post_box'),
2483
+				$this->_wp_page_slug,
2484
+				'side'
2485
+			);
2486
+		}
2487
+	}
2488
+
2489
+
2490
+	public function espresso_sponsors_post_box()
2491
+	{
2492
+		EEH_Template::display_template(
2493
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2494
+		);
2495
+	}
2496
+
2497
+
2498
+	private function _publish_post_box()
2499
+	{
2500
+		$meta_box_ref = 'espresso_' . $this->page_slug . '_editor_overview';
2501
+		// if there is a array('label' => array('publishbox' => 'some title') ) present in the _page_config array
2502
+		// then we'll use that for the metabox label.
2503
+		// Otherwise we'll just use publish (publishbox itself could be an array of labels indexed by routes)
2504
+		if (! empty($this->_labels['publishbox'])) {
2505
+			$box_label = is_array($this->_labels['publishbox']) ? $this->_labels['publishbox'][ $this->_req_action ]
2506
+				: $this->_labels['publishbox'];
2507
+		} else {
2508
+			$box_label = esc_html__('Publish', 'event_espresso');
2509
+		}
2510
+		$box_label = apply_filters(
2511
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2512
+			$box_label,
2513
+			$this->_req_action,
2514
+			$this
2515
+		);
2516
+		add_meta_box(
2517
+			$meta_box_ref,
2518
+			$box_label,
2519
+			array($this, 'editor_overview'),
2520
+			$this->_current_screen->id,
2521
+			'side',
2522
+			'high'
2523
+		);
2524
+	}
2525
+
2526
+
2527
+	public function editor_overview()
2528
+	{
2529
+		// if we have extra content set let's add it in if not make sure its empty
2530
+		$this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2531
+			? $this->_template_args['publish_box_extra_content']
2532
+			: '';
2533
+		echo EEH_Template::display_template(
2534
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2535
+			$this->_template_args,
2536
+			true
2537
+		);
2538
+	}
2539
+
2540
+
2541
+	/** end of globally available metaboxes section **/
2542
+
2543
+
2544
+	/**
2545
+	 * Public wrapper for the protected method.  Allows plugins/addons to externally call the
2546
+	 * protected method.
2547
+	 *
2548
+	 * @see   $this->_set_publish_post_box_vars for param details
2549
+	 * @since 4.6.0
2550
+	 * @param string $name
2551
+	 * @param int    $id
2552
+	 * @param bool   $delete
2553
+	 * @param string $save_close_redirect_URL
2554
+	 * @param bool   $both_btns
2555
+	 * @throws EE_Error
2556
+	 * @throws InvalidArgumentException
2557
+	 * @throws InvalidDataTypeException
2558
+	 * @throws InvalidInterfaceException
2559
+	 */
2560
+	public function set_publish_post_box_vars(
2561
+		$name = '',
2562
+		$id = 0,
2563
+		$delete = false,
2564
+		$save_close_redirect_URL = '',
2565
+		$both_btns = true
2566
+	) {
2567
+		$this->_set_publish_post_box_vars(
2568
+			$name,
2569
+			$id,
2570
+			$delete,
2571
+			$save_close_redirect_URL,
2572
+			$both_btns
2573
+		);
2574
+	}
2575
+
2576
+
2577
+	/**
2578
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2579
+	 * Note: currently there is no validation for this.  However if you want the delete button, the
2580
+	 * save, and save and close buttons to work properly, then you will want to include a
2581
+	 * values for the name and id arguments.
2582
+	 *
2583
+	 * @todo  Add in validation for name/id arguments.
2584
+	 * @param    string  $name                    key used for the action ID (i.e. event_id)
2585
+	 * @param    int     $id                      id attached to the item published
2586
+	 * @param    string  $delete                  page route callback for the delete action
2587
+	 * @param    string  $save_close_redirect_URL custom URL to redirect to after Save & Close has been completed
2588
+	 * @param    boolean $both_btns               whether to display BOTH the "Save & Close" and "Save" buttons or just
2589
+	 *                                            the Save button
2590
+	 * @throws EE_Error
2591
+	 * @throws InvalidArgumentException
2592
+	 * @throws InvalidDataTypeException
2593
+	 * @throws InvalidInterfaceException
2594
+	 */
2595
+	protected function _set_publish_post_box_vars(
2596
+		$name = '',
2597
+		$id = 0,
2598
+		$delete = '',
2599
+		$save_close_redirect_URL = '',
2600
+		$both_btns = true
2601
+	) {
2602
+		// if Save & Close, use a custom redirect URL or default to the main page?
2603
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2604
+			? $save_close_redirect_URL
2605
+			: $this->_admin_base_url;
2606
+		// create the Save & Close and Save buttons
2607
+		$this->_set_save_buttons($both_btns, array(), array(), $save_close_redirect_URL);
2608
+		// if we have extra content set let's add it in if not make sure its empty
2609
+		$this->_template_args['publish_box_extra_content'] = isset($this->_template_args['publish_box_extra_content'])
2610
+			? $this->_template_args['publish_box_extra_content']
2611
+			: '';
2612
+		if ($delete && ! empty($id)) {
2613
+			// make sure we have a default if just true is sent.
2614
+			$delete = ! empty($delete) ? $delete : 'delete';
2615
+			$delete_link_args = array($name => $id);
2616
+			$delete = $this->get_action_link_or_button(
2617
+				$delete,
2618
+				$delete,
2619
+				$delete_link_args,
2620
+				'submitdelete deletion'
2621
+			);
2622
+		}
2623
+		$this->_template_args['publish_delete_link'] = ! empty($id) ? $delete : '';
2624
+		if (! empty($name) && ! empty($id)) {
2625
+			$hidden_field_arr[ $name ] = array(
2626
+				'type'  => 'hidden',
2627
+				'value' => $id,
2628
+			);
2629
+			$hf = $this->_generate_admin_form_fields($hidden_field_arr, 'array');
2630
+		} else {
2631
+			$hf = '';
2632
+		}
2633
+		// add hidden field
2634
+		$this->_template_args['publish_hidden_fields'] = is_array($hf) && ! empty($name)
2635
+			? $hf[ $name ]['field']
2636
+			: $hf;
2637
+	}
2638
+
2639
+
2640
+	/**
2641
+	 * displays an error message to ppl who have javascript disabled
2642
+	 *
2643
+	 * @return void
2644
+	 */
2645
+	private function _display_no_javascript_warning()
2646
+	{
2647
+		?>
2648 2648
         <noscript>
2649 2649
             <div id="no-js-message" class="error">
2650 2650
                 <p style="font-size:1.3em;">
2651 2651
                     <span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2652 2652
                     <?php esc_html_e(
2653
-                        '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.',
2654
-                        'event_espresso'
2655
-                    ); ?>
2653
+						'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.',
2654
+						'event_espresso'
2655
+					); ?>
2656 2656
                 </p>
2657 2657
             </div>
2658 2658
         </noscript>
2659 2659
         <?php
2660
-    }
2661
-
2662
-
2663
-    /**
2664
-     * displays espresso success and/or error notices
2665
-     *
2666
-     * @return void
2667
-     */
2668
-    private function _display_espresso_notices()
2669
-    {
2670
-        $notices = $this->_get_transient(true);
2671
-        echo stripslashes($notices);
2672
-    }
2673
-
2674
-
2675
-    /**
2676
-     * spinny things pacify the masses
2677
-     *
2678
-     * @return void
2679
-     */
2680
-    protected function _add_admin_page_ajax_loading_img()
2681
-    {
2682
-        ?>
2660
+	}
2661
+
2662
+
2663
+	/**
2664
+	 * displays espresso success and/or error notices
2665
+	 *
2666
+	 * @return void
2667
+	 */
2668
+	private function _display_espresso_notices()
2669
+	{
2670
+		$notices = $this->_get_transient(true);
2671
+		echo stripslashes($notices);
2672
+	}
2673
+
2674
+
2675
+	/**
2676
+	 * spinny things pacify the masses
2677
+	 *
2678
+	 * @return void
2679
+	 */
2680
+	protected function _add_admin_page_ajax_loading_img()
2681
+	{
2682
+		?>
2683 2683
         <div id="espresso-ajax-loading" class="ajax-loading-grey">
2684 2684
             <span class="ee-spinner ee-spin"></span><span class="hidden"><?php
2685
-                esc_html_e('loading...', 'event_espresso'); ?></span>
2685
+				esc_html_e('loading...', 'event_espresso'); ?></span>
2686 2686
         </div>
2687 2687
         <?php
2688
-    }
2688
+	}
2689 2689
 
2690 2690
 
2691
-    /**
2692
-     * add admin page overlay for modal boxes
2693
-     *
2694
-     * @return void
2695
-     */
2696
-    protected function _add_admin_page_overlay()
2697
-    {
2698
-        ?>
2691
+	/**
2692
+	 * add admin page overlay for modal boxes
2693
+	 *
2694
+	 * @return void
2695
+	 */
2696
+	protected function _add_admin_page_overlay()
2697
+	{
2698
+		?>
2699 2699
         <div id="espresso-admin-page-overlay-dv" class=""></div>
2700 2700
         <?php
2701
-    }
2702
-
2703
-
2704
-    /**
2705
-     * facade for add_meta_box
2706
-     *
2707
-     * @param string  $action        where the metabox get's displayed
2708
-     * @param string  $title         Title of Metabox (output in metabox header)
2709
-     * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2710
-     *                               instead of the one created in here.
2711
-     * @param array   $callback_args an array of args supplied for the metabox
2712
-     * @param string  $column        what metabox column
2713
-     * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2714
-     * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2715
-     *                               created but just set our own callback for wp's add_meta_box.
2716
-     * @throws DomainException
2717
-     */
2718
-    public function _add_admin_page_meta_box(
2719
-        $action,
2720
-        $title,
2721
-        $callback,
2722
-        $callback_args,
2723
-        $column = 'normal',
2724
-        $priority = 'high',
2725
-        $create_func = true
2726
-    ) {
2727
-        do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2728
-        // 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.
2729
-        if (empty($callback_args) && $create_func) {
2730
-            $callback_args = array(
2731
-                'template_path' => $this->_template_path,
2732
-                'template_args' => $this->_template_args,
2733
-            );
2734
-        }
2735
-        // 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)
2736
-        $call_back_func = $create_func
2737
-            ? static function ($post, $metabox) {
2738
-                do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2739
-                echo EEH_Template::display_template(
2740
-                    $metabox['args']['template_path'],
2741
-                    $metabox['args']['template_args'],
2742
-                    true
2743
-                );
2744
-            }
2745
-            : $callback;
2746
-        add_meta_box(
2747
-            str_replace('_', '-', $action) . '-mbox',
2748
-            $title,
2749
-            $call_back_func,
2750
-            $this->_wp_page_slug,
2751
-            $column,
2752
-            $priority,
2753
-            $callback_args
2754
-        );
2755
-    }
2756
-
2757
-
2758
-    /**
2759
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2760
-     *
2761
-     * @throws DomainException
2762
-     * @throws EE_Error
2763
-     * @throws InvalidArgumentException
2764
-     * @throws InvalidDataTypeException
2765
-     * @throws InvalidInterfaceException
2766
-     */
2767
-    public function display_admin_page_with_metabox_columns()
2768
-    {
2769
-        $this->_template_args['post_body_content'] = $this->_template_args['admin_page_content'];
2770
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2771
-            $this->_column_template_path,
2772
-            $this->_template_args,
2773
-            true
2774
-        );
2775
-        // the final wrapper
2776
-        $this->admin_page_wrapper();
2777
-    }
2778
-
2779
-
2780
-    /**
2781
-     * generates  HTML wrapper for an admin details page
2782
-     *
2783
-     * @return void
2784
-     * @throws DomainException
2785
-     * @throws EE_Error
2786
-     * @throws InvalidArgumentException
2787
-     * @throws InvalidDataTypeException
2788
-     * @throws InvalidInterfaceException
2789
-     */
2790
-    public function display_admin_page_with_sidebar()
2791
-    {
2792
-        $this->_display_admin_page(true);
2793
-    }
2794
-
2795
-
2796
-    /**
2797
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2798
-     *
2799
-     * @return void
2800
-     * @throws DomainException
2801
-     * @throws EE_Error
2802
-     * @throws InvalidArgumentException
2803
-     * @throws InvalidDataTypeException
2804
-     * @throws InvalidInterfaceException
2805
-     */
2806
-    public function display_admin_page_with_no_sidebar()
2807
-    {
2808
-        $this->_display_admin_page();
2809
-    }
2810
-
2811
-
2812
-    /**
2813
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2814
-     *
2815
-     * @return void
2816
-     * @throws DomainException
2817
-     * @throws EE_Error
2818
-     * @throws InvalidArgumentException
2819
-     * @throws InvalidDataTypeException
2820
-     * @throws InvalidInterfaceException
2821
-     */
2822
-    public function display_about_admin_page()
2823
-    {
2824
-        $this->_display_admin_page(false, true);
2825
-    }
2826
-
2827
-
2828
-    /**
2829
-     * display_admin_page
2830
-     * contains the code for actually displaying an admin page
2831
-     *
2832
-     * @param boolean $sidebar true with sidebar, false without
2833
-     * @param boolean $about   use the about admin wrapper instead of the default.
2834
-     * @return void
2835
-     * @throws DomainException
2836
-     * @throws EE_Error
2837
-     * @throws InvalidArgumentException
2838
-     * @throws InvalidDataTypeException
2839
-     * @throws InvalidInterfaceException
2840
-     */
2841
-    private function _display_admin_page($sidebar = false, $about = false)
2842
-    {
2843
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2844
-        // custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2845
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2846
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2847
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2848
-        $this->_template_args['current_page'] = $this->_wp_page_slug;
2849
-        $this->_template_args['admin_page_wrapper_div_id'] = $this->_cpt_route
2850
-            ? 'poststuff'
2851
-            : 'espresso-default-admin';
2852
-        $template_path = $sidebar
2853
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2854
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2855
-        if (defined('DOING_AJAX') && DOING_AJAX) {
2856
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2857
-        }
2858
-        $template_path = ! empty($this->_column_template_path)
2859
-            ? $this->_column_template_path : $template_path;
2860
-        $this->_template_args['post_body_content'] = isset($this->_template_args['admin_page_content'])
2861
-            ? $this->_template_args['admin_page_content']
2862
-            : '';
2863
-        $this->_template_args['before_admin_page_content'] = isset($this->_template_args['before_admin_page_content'])
2864
-            ? $this->_template_args['before_admin_page_content']
2865
-            : '';
2866
-        $this->_template_args['after_admin_page_content'] = isset($this->_template_args['after_admin_page_content'])
2867
-            ? $this->_template_args['after_admin_page_content']
2868
-            : '';
2869
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2870
-            $template_path,
2871
-            $this->_template_args,
2872
-            true
2873
-        );
2874
-        // the final template wrapper
2875
-        $this->admin_page_wrapper($about);
2876
-    }
2877
-
2878
-
2879
-    /**
2880
-     * This is used to display caf preview pages.
2881
-     *
2882
-     * @since 4.3.2
2883
-     * @param string $utm_campaign_source what is the key used for google analytics link
2884
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2885
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2886
-     * @return void
2887
-     * @throws DomainException
2888
-     * @throws EE_Error
2889
-     * @throws InvalidArgumentException
2890
-     * @throws InvalidDataTypeException
2891
-     * @throws InvalidInterfaceException
2892
-     */
2893
-    public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2894
-    {
2895
-        // let's generate a default preview action button if there isn't one already present.
2896
-        $this->_labels['buttons']['buy_now'] = esc_html__(
2897
-            'Upgrade to Event Espresso 4 Right Now',
2898
-            'event_espresso'
2899
-        );
2900
-        $buy_now_url = add_query_arg(
2901
-            array(
2902
-                'ee_ver'       => 'ee4',
2903
-                'utm_source'   => 'ee4_plugin_admin',
2904
-                'utm_medium'   => 'link',
2905
-                'utm_campaign' => $utm_campaign_source,
2906
-                'utm_content'  => 'buy_now_button',
2907
-            ),
2908
-            'http://eventespresso.com/pricing/'
2909
-        );
2910
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2911
-            ? $this->get_action_link_or_button(
2912
-                '',
2913
-                'buy_now',
2914
-                array(),
2915
-                'button-primary button-large',
2916
-                $buy_now_url,
2917
-                true
2918
-            )
2919
-            : $this->_template_args['preview_action_button'];
2920
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2921
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2922
-            $this->_template_args,
2923
-            true
2924
-        );
2925
-        $this->_display_admin_page($display_sidebar);
2926
-    }
2927
-
2928
-
2929
-    /**
2930
-     * display_admin_list_table_page_with_sidebar
2931
-     * generates HTML wrapper for an admin_page with list_table
2932
-     *
2933
-     * @return void
2934
-     * @throws DomainException
2935
-     * @throws EE_Error
2936
-     * @throws InvalidArgumentException
2937
-     * @throws InvalidDataTypeException
2938
-     * @throws InvalidInterfaceException
2939
-     */
2940
-    public function display_admin_list_table_page_with_sidebar()
2941
-    {
2942
-        $this->_display_admin_list_table_page(true);
2943
-    }
2944
-
2945
-
2946
-    /**
2947
-     * display_admin_list_table_page_with_no_sidebar
2948
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2949
-     *
2950
-     * @return void
2951
-     * @throws DomainException
2952
-     * @throws EE_Error
2953
-     * @throws InvalidArgumentException
2954
-     * @throws InvalidDataTypeException
2955
-     * @throws InvalidInterfaceException
2956
-     */
2957
-    public function display_admin_list_table_page_with_no_sidebar()
2958
-    {
2959
-        $this->_display_admin_list_table_page();
2960
-    }
2961
-
2962
-
2963
-    /**
2964
-     * generates html wrapper for an admin_list_table page
2965
-     *
2966
-     * @param boolean $sidebar whether to display with sidebar or not.
2967
-     * @return void
2968
-     * @throws DomainException
2969
-     * @throws EE_Error
2970
-     * @throws InvalidArgumentException
2971
-     * @throws InvalidDataTypeException
2972
-     * @throws InvalidInterfaceException
2973
-     */
2974
-    private function _display_admin_list_table_page($sidebar = false)
2975
-    {
2976
-        // setup search attributes
2977
-        $this->_set_search_attributes();
2978
-        $this->_template_args['current_page'] = $this->_wp_page_slug;
2979
-        $template_path = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2980
-        $this->_template_args['table_url'] = defined('DOING_AJAX')
2981
-            ? add_query_arg(array('noheader' => 'true', 'route' => $this->_req_action), $this->_admin_base_url)
2982
-            : add_query_arg(array('route' => $this->_req_action), $this->_admin_base_url);
2983
-        $this->_template_args['list_table'] = $this->_list_table_object;
2984
-        $this->_template_args['current_route'] = $this->_req_action;
2985
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2986
-        $ajax_sorting_callback = $this->_list_table_object->get_ajax_sorting_callback();
2987
-        if (! empty($ajax_sorting_callback)) {
2988
-            $sortable_list_table_form_fields = wp_nonce_field(
2989
-                $ajax_sorting_callback . '_nonce',
2990
-                $ajax_sorting_callback . '_nonce',
2991
-                false,
2992
-                false
2993
-            );
2994
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2995
-                                                . $this->page_slug
2996
-                                                . '" />';
2997
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2998
-                                                . $ajax_sorting_callback
2999
-                                                . '" />';
3000
-        } else {
3001
-            $sortable_list_table_form_fields = '';
3002
-        }
3003
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3004
-        $hidden_form_fields = isset($this->_template_args['list_table_hidden_fields'])
3005
-            ? $this->_template_args['list_table_hidden_fields']
3006
-            : '';
3007
-        $nonce_ref = $this->_req_action . '_nonce';
3008
-        $hidden_form_fields .= '<input type="hidden" name="'
3009
-                               . $nonce_ref
3010
-                               . '" value="'
3011
-                               . wp_create_nonce($nonce_ref)
3012
-                               . '">';
3013
-        $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
3014
-        // display message about search results?
3015
-        $this->_template_args['before_list_table'] .= ! empty($this->_req_data['s'])
3016
-            ? '<p class="ee-search-results">' . sprintf(
3017
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3018
-                trim($this->_req_data['s'], '%')
3019
-            ) . '</p>'
3020
-            : '';
3021
-        // filter before_list_table template arg
3022
-        $this->_template_args['before_list_table'] = apply_filters(
3023
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3024
-            $this->_template_args['before_list_table'],
3025
-            $this->page_slug,
3026
-            $this->_req_data,
3027
-            $this->_req_action
3028
-        );
3029
-        // convert to array and filter again
3030
-        // arrays are easier to inject new items in a specific location,
3031
-        // but would not be backwards compatible, so we have to add a new filter
3032
-        $this->_template_args['before_list_table'] = implode(
3033
-            " \n",
3034
-            (array) apply_filters(
3035
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3036
-                (array) $this->_template_args['before_list_table'],
3037
-                $this->page_slug,
3038
-                $this->_req_data,
3039
-                $this->_req_action
3040
-            )
3041
-        );
3042
-        // filter after_list_table template arg
3043
-        $this->_template_args['after_list_table'] = apply_filters(
3044
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3045
-            $this->_template_args['after_list_table'],
3046
-            $this->page_slug,
3047
-            $this->_req_data,
3048
-            $this->_req_action
3049
-        );
3050
-        // convert to array and filter again
3051
-        // arrays are easier to inject new items in a specific location,
3052
-        // but would not be backwards compatible, so we have to add a new filter
3053
-        $this->_template_args['after_list_table'] = implode(
3054
-            " \n",
3055
-            (array) apply_filters(
3056
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3057
-                (array) $this->_template_args['after_list_table'],
3058
-                $this->page_slug,
3059
-                $this->_req_data,
3060
-                $this->_req_action
3061
-            )
3062
-        );
3063
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3064
-            $template_path,
3065
-            $this->_template_args,
3066
-            true
3067
-        );
3068
-        // the final template wrapper
3069
-        if ($sidebar) {
3070
-            $this->display_admin_page_with_sidebar();
3071
-        } else {
3072
-            $this->display_admin_page_with_no_sidebar();
3073
-        }
3074
-    }
3075
-
3076
-
3077
-    /**
3078
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3079
-     * html string for the legend.
3080
-     * $items are expected in an array in the following format:
3081
-     * $legend_items = array(
3082
-     *        'item_id' => array(
3083
-     *            'icon' => 'http://url_to_icon_being_described.png',
3084
-     *            'desc' => esc_html__('localized description of item');
3085
-     *        )
3086
-     * );
3087
-     *
3088
-     * @param  array $items see above for format of array
3089
-     * @return string html string of legend
3090
-     * @throws DomainException
3091
-     */
3092
-    protected function _display_legend($items)
3093
-    {
3094
-        $this->_template_args['items'] = apply_filters(
3095
-            'FHEE__EE_Admin_Page___display_legend__items',
3096
-            (array) $items,
3097
-            $this
3098
-        );
3099
-        /** @var EventEspresso\core\admin\StatusChangeNotice $status_change_notice */
3100
-        $status_change_notice = $this->loader->getShared('EventEspresso\core\admin\StatusChangeNotice');
3101
-        if (! $status_change_notice->isDismissed()) {
3102
-            $this->_template_args['status_change_notice'] = EEH_Template::display_template(
3103
-                EE_ADMIN_TEMPLATE . 'status_change_notice.template.php',
3104
-                [ 'context' => '__admin-legend', 'page_slug' => $this->page_slug ],
3105
-                true
3106
-            );
3107
-        }
3108
-        return EEH_Template::display_template(
3109
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3110
-            $this->_template_args,
3111
-            true
3112
-        );
3113
-    }
3114
-
3115
-
3116
-    /**
3117
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3118
-     * The returned json object is created from an array in the following format:
3119
-     * array(
3120
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3121
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3122
-     *  'notices' => '', // - contains any EE_Error formatted notices
3123
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3124
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3125
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3126
-     *  that might be included in here)
3127
-     * )
3128
-     * The json object is populated by whatever is set in the $_template_args property.
3129
-     *
3130
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3131
-     *                                 instead of displayed.
3132
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3133
-     * @return void
3134
-     * @throws EE_Error
3135
-     * @throws InvalidArgumentException
3136
-     * @throws InvalidDataTypeException
3137
-     * @throws InvalidInterfaceException
3138
-     */
3139
-    protected function _return_json($sticky_notices = false, $notices_arguments = array())
3140
-    {
3141
-        // make sure any EE_Error notices have been handled.
3142
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3143
-        $data = isset($this->_template_args['data']) ? $this->_template_args['data'] : array();
3144
-        unset($this->_template_args['data']);
3145
-        $json = array(
3146
-            'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3147
-            'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3148
-            'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3149
-            'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3150
-            'notices'   => EE_Error::get_notices(),
3151
-            'content'   => isset($this->_template_args['admin_page_content'])
3152
-                ? $this->_template_args['admin_page_content'] : '',
3153
-            'data'      => array_merge($data, array('template_args' => $this->_template_args)),
3154
-            'isEEajax'  => true
3155
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3156
-        );
3157
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3158
-        if (null === error_get_last() || ! headers_sent()) {
3159
-            header('Content-Type: application/json; charset=UTF-8');
3160
-        }
3161
-        echo wp_json_encode($json);
3162
-        exit();
3163
-    }
3164
-
3165
-
3166
-    /**
3167
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3168
-     *
3169
-     * @return void
3170
-     * @throws EE_Error
3171
-     * @throws InvalidArgumentException
3172
-     * @throws InvalidDataTypeException
3173
-     * @throws InvalidInterfaceException
3174
-     */
3175
-    public function return_json()
3176
-    {
3177
-        if (defined('DOING_AJAX') && DOING_AJAX) {
3178
-            $this->_return_json();
3179
-        } else {
3180
-            throw new EE_Error(
3181
-                sprintf(
3182
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3183
-                    __FUNCTION__
3184
-                )
3185
-            );
3186
-        }
3187
-    }
3188
-
3189
-
3190
-    /**
3191
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3192
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3193
-     *
3194
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3195
-     */
3196
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3197
-    {
3198
-        $this->_hook_obj = $hook_obj;
3199
-    }
3200
-
3201
-
3202
-    /**
3203
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3204
-     *
3205
-     * @param boolean $about whether to use the special about page wrapper or default.
3206
-     * @return void
3207
-     * @throws DomainException
3208
-     * @throws EE_Error
3209
-     * @throws InvalidArgumentException
3210
-     * @throws InvalidDataTypeException
3211
-     * @throws InvalidInterfaceException
3212
-     */
3213
-    public function admin_page_wrapper($about = false)
3214
-    {
3215
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3216
-        $this->_nav_tabs = $this->_get_main_nav_tabs();
3217
-        $this->_template_args['nav_tabs'] = $this->_nav_tabs;
3218
-        $this->_template_args['admin_page_title'] = $this->_admin_page_title;
3219
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3220
-            "FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3221
-            isset($this->_template_args['before_admin_page_content'])
3222
-                ? $this->_template_args['before_admin_page_content']
3223
-                : ''
3224
-        );
3225
-        $this->_template_args['after_admin_page_content'] = apply_filters(
3226
-            "FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3227
-            isset($this->_template_args['after_admin_page_content'])
3228
-                ? $this->_template_args['after_admin_page_content']
3229
-                : ''
3230
-        );
3231
-        $this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3232
-        // load settings page wrapper template
3233
-        $template_path = ! defined('DOING_AJAX')
3234
-            ? EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php'
3235
-            : EE_ADMIN_TEMPLATE
3236
-              . 'admin_wrapper_ajax.template.php';
3237
-        // about page?
3238
-        $template_path = $about
3239
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3240
-            : $template_path;
3241
-        if (defined('DOING_AJAX')) {
3242
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3243
-                $template_path,
3244
-                $this->_template_args,
3245
-                true
3246
-            );
3247
-            $this->_return_json();
3248
-        } else {
3249
-            EEH_Template::display_template($template_path, $this->_template_args);
3250
-        }
3251
-    }
3252
-
3253
-
3254
-    /**
3255
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3256
-     *
3257
-     * @return string html
3258
-     * @throws EE_Error
3259
-     */
3260
-    protected function _get_main_nav_tabs()
3261
-    {
3262
-        // let's generate the html using the EEH_Tabbed_Content helper.
3263
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3264
-        // (rather than setting in the page_routes array)
3265
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs);
3266
-    }
3267
-
3268
-
3269
-    /**
3270
-     *        sort nav tabs
3271
-     *
3272
-     * @param $a
3273
-     * @param $b
3274
-     * @return int
3275
-     */
3276
-    private function _sort_nav_tabs($a, $b)
3277
-    {
3278
-        if ($a['order'] === $b['order']) {
3279
-            return 0;
3280
-        }
3281
-        return ($a['order'] < $b['order']) ? -1 : 1;
3282
-    }
3283
-
3284
-
3285
-    /**
3286
-     *    generates HTML for the forms used on admin pages
3287
-     *
3288
-     * @param    array $input_vars - array of input field details
3289
-     * @param string   $generator  (options are 'string' or 'array', basically use this to indicate which generator to
3290
-     *                             use)
3291
-     * @param bool     $id
3292
-     * @return string
3293
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3294
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3295
-     */
3296
-    protected function _generate_admin_form_fields($input_vars = array(), $generator = 'string', $id = false)
3297
-    {
3298
-        return $generator === 'string'
3299
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3300
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3301
-    }
3302
-
3303
-
3304
-    /**
3305
-     * generates the "Save" and "Save & Close" buttons for edit forms
3306
-     *
3307
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3308
-     *                                   Close" button.
3309
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3310
-     *                                   'Save', [1] => 'save & close')
3311
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3312
-     *                                   via the "name" value in the button).  We can also use this to just dump
3313
-     *                                   default actions by submitting some other value.
3314
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3315
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3316
-     *                                   close (normal form handling).
3317
-     */
3318
-    protected function _set_save_buttons($both = true, $text = array(), $actions = array(), $referrer = null)
3319
-    {
3320
-        // make sure $text and $actions are in an array
3321
-        $text = (array) $text;
3322
-        $actions = (array) $actions;
3323
-        $referrer_url = empty($referrer)
3324
-            ? '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3325
-              . $_SERVER['REQUEST_URI']
3326
-              . '" />'
3327
-            : '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3328
-              . $referrer
3329
-              . '" />';
3330
-        $button_text = ! empty($text)
3331
-            ? $text
3332
-            : array(
3333
-                esc_html__('Save', 'event_espresso'),
3334
-                esc_html__('Save and Close', 'event_espresso'),
3335
-            );
3336
-        $default_names = array('save', 'save_and_close');
3337
-        // add in a hidden index for the current page (so save and close redirects properly)
3338
-        $this->_template_args['save_buttons'] = $referrer_url;
3339
-        foreach ($button_text as $key => $button) {
3340
-            $ref = $default_names[ $key ];
3341
-            $this->_template_args['save_buttons'] .= '<input type="submit" class="button-primary '
3342
-                                                     . $ref
3343
-                                                     . '" value="'
3344
-                                                     . $button
3345
-                                                     . '" name="'
3346
-                                                     . (! empty($actions) ? $actions[ $key ] : $ref)
3347
-                                                     . '" id="'
3348
-                                                     . $this->_current_view . '_' . $ref
3349
-                                                     . '" />';
3350
-            if (! $both) {
3351
-                break;
3352
-            }
3353
-        }
3354
-    }
3355
-
3356
-
3357
-    /**
3358
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3359
-     *
3360
-     * @see   $this->_set_add_edit_form_tags() for details on params
3361
-     * @since 4.6.0
3362
-     * @param string $route
3363
-     * @param array  $additional_hidden_fields
3364
-     */
3365
-    public function set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3366
-    {
3367
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3368
-    }
3369
-
3370
-
3371
-    /**
3372
-     * set form open and close tags on add/edit pages.
3373
-     *
3374
-     * @param string $route                    the route you want the form to direct to
3375
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3376
-     * @return void
3377
-     */
3378
-    protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3379
-    {
3380
-        if (empty($route)) {
3381
-            $user_msg = esc_html__(
3382
-                'An error occurred. No action was set for this page\'s form.',
3383
-                'event_espresso'
3384
-            );
3385
-            $dev_msg = $user_msg . "\n"
3386
-                       . sprintf(
3387
-                           esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3388
-                           __FUNCTION__,
3389
-                           EE_Admin_Page::class
3390
-                       );
3391
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3392
-        }
3393
-        // open form
3394
-        $this->_template_args['before_admin_page_content'] = '<form name="form" method="post" action="'
3395
-                                                             . $this->_admin_base_url
3396
-                                                             . '" id="'
3397
-                                                             . $route
3398
-                                                             . '_event_form" >';
3399
-        // add nonce
3400
-        $nonce = wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3401
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3402
-        // add REQUIRED form action
3403
-        $hidden_fields = array(
3404
-            'action' => array('type' => 'hidden', 'value' => $route),
3405
-        );
3406
-        // merge arrays
3407
-        $hidden_fields = is_array($additional_hidden_fields)
3408
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3409
-            : $hidden_fields;
3410
-        // generate form fields
3411
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3412
-        // add fields to form
3413
-        foreach ((array) $form_fields as $field_name => $form_field) {
3414
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3415
-        }
3416
-        // close form
3417
-        $this->_template_args['after_admin_page_content'] = '</form>';
3418
-    }
3419
-
3420
-
3421
-    /**
3422
-     * Public Wrapper for _redirect_after_action() method since its
3423
-     * discovered it would be useful for external code to have access.
3424
-     *
3425
-     * @param bool   $success
3426
-     * @param string $what
3427
-     * @param string $action_desc
3428
-     * @param array  $query_args
3429
-     * @param bool   $override_overwrite
3430
-     * @throws EE_Error
3431
-     * @throws InvalidArgumentException
3432
-     * @throws InvalidDataTypeException
3433
-     * @throws InvalidInterfaceException
3434
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3435
-     * @since 4.5.0
3436
-     */
3437
-    public function redirect_after_action(
3438
-        $success = false,
3439
-        $what = 'item',
3440
-        $action_desc = 'processed',
3441
-        $query_args = array(),
3442
-        $override_overwrite = false
3443
-    ) {
3444
-        $this->_redirect_after_action(
3445
-            $success,
3446
-            $what,
3447
-            $action_desc,
3448
-            $query_args,
3449
-            $override_overwrite
3450
-        );
3451
-    }
3452
-
3453
-
3454
-    /**
3455
-     * Helper method for merging existing request data with the returned redirect url.
3456
-     *
3457
-     * This is typically used for redirects after an action so that if the original view was a filtered view those
3458
-     * filters are still applied.
3459
-     *
3460
-     * @param array $new_route_data
3461
-     * @return array
3462
-     */
3463
-    protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data)
3464
-    {
3465
-        foreach ($this->_req_data as $ref => $value) {
3466
-            // unset nonces
3467
-            if (strpos($ref, 'nonce') !== false) {
3468
-                unset($this->_req_data[ $ref ]);
3469
-                continue;
3470
-            }
3471
-            // urlencode values.
3472
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3473
-            $this->_req_data[ $ref ] = $value;
3474
-        }
3475
-        return array_merge($this->_req_data, $new_route_data);
3476
-    }
3477
-
3478
-
3479
-    /**
3480
-     *    _redirect_after_action
3481
-     *
3482
-     * @param int    $success            - whether success was for two or more records, or just one, or none
3483
-     * @param string $what               - what the action was performed on
3484
-     * @param string $action_desc        - what was done ie: updated, deleted, etc
3485
-     * @param array  $query_args         - an array of query_args to be added to the URL to redirect to after the admin
3486
-     *                                   action is completed
3487
-     * @param BOOL   $override_overwrite by default all EE_Error::success messages are overwritten, this allows you to
3488
-     *                                   override this so that they show.
3489
-     * @return void
3490
-     * @throws EE_Error
3491
-     * @throws InvalidArgumentException
3492
-     * @throws InvalidDataTypeException
3493
-     * @throws InvalidInterfaceException
3494
-     */
3495
-    protected function _redirect_after_action(
3496
-        $success = 0,
3497
-        $what = 'item',
3498
-        $action_desc = 'processed',
3499
-        $query_args = array(),
3500
-        $override_overwrite = false
3501
-    ) {
3502
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3503
-        // class name for actions/filters.
3504
-        $classname = get_class($this);
3505
-        // set redirect url.
3506
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3507
-        // otherwise we go with whatever is set as the _admin_base_url
3508
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3509
-        $notices = EE_Error::get_notices(false);
3510
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3511
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3512
-            EE_Error::overwrite_success();
3513
-        }
3514
-        if (! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3515
-            // how many records affected ? more than one record ? or just one ?
3516
-            if ($success > 1) {
3517
-                // set plural msg
3518
-                EE_Error::add_success(
3519
-                    sprintf(
3520
-                        esc_html__('The "%s" have been successfully %s.', 'event_espresso'),
3521
-                        $what,
3522
-                        $action_desc
3523
-                    ),
3524
-                    __FILE__,
3525
-                    __FUNCTION__,
3526
-                    __LINE__
3527
-                );
3528
-            } elseif ($success === 1) {
3529
-                // set singular msg
3530
-                EE_Error::add_success(
3531
-                    sprintf(
3532
-                        esc_html__('The "%s" has been successfully %s.', 'event_espresso'),
3533
-                        $what,
3534
-                        $action_desc
3535
-                    ),
3536
-                    __FILE__,
3537
-                    __FUNCTION__,
3538
-                    __LINE__
3539
-                );
3540
-            }
3541
-        }
3542
-        // check that $query_args isn't something crazy
3543
-        if (! is_array($query_args)) {
3544
-            $query_args = array();
3545
-        }
3546
-        /**
3547
-         * Allow injecting actions before the query_args are modified for possible different
3548
-         * redirections on save and close actions
3549
-         *
3550
-         * @since 4.2.0
3551
-         * @param array $query_args       The original query_args array coming into the
3552
-         *                                method.
3553
-         */
3554
-        do_action(
3555
-            "AHEE__{$classname}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3556
-            $query_args
3557
-        );
3558
-        // calculate where we're going (if we have a "save and close" button pushed)
3559
-        if (isset($this->_req_data['save_and_close'], $this->_req_data['save_and_close_referrer'])) {
3560
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3561
-            $parsed_url = parse_url($this->_req_data['save_and_close_referrer']);
3562
-            // regenerate query args array from referrer URL
3563
-            parse_str($parsed_url['query'], $query_args);
3564
-            // correct page and action will be in the query args now
3565
-            $redirect_url = admin_url('admin.php');
3566
-        }
3567
-        // merge any default query_args set in _default_route_query_args property
3568
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3569
-            $args_to_merge = array();
3570
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3571
-                // is there a wp_referer array in our _default_route_query_args property?
3572
-                if ($query_param === 'wp_referer') {
3573
-                    $query_value = (array) $query_value;
3574
-                    foreach ($query_value as $reference => $value) {
3575
-                        if (strpos($reference, 'nonce') !== false) {
3576
-                            continue;
3577
-                        }
3578
-                        // finally we will override any arguments in the referer with
3579
-                        // what might be set on the _default_route_query_args array.
3580
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3581
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3582
-                        } else {
3583
-                            $args_to_merge[ $reference ] = urlencode($value);
3584
-                        }
3585
-                    }
3586
-                    continue;
3587
-                }
3588
-                $args_to_merge[ $query_param ] = $query_value;
3589
-            }
3590
-            // now let's merge these arguments but override with what was specifically sent in to the
3591
-            // redirect.
3592
-            $query_args = array_merge($args_to_merge, $query_args);
3593
-        }
3594
-        $this->_process_notices($query_args);
3595
-        // generate redirect url
3596
-        // if redirecting to anything other than the main page, add a nonce
3597
-        if (isset($query_args['action'])) {
3598
-            // manually generate wp_nonce and merge that with the query vars
3599
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3600
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3601
-        }
3602
-        // we're adding some hooks and filters in here for processing any things just before redirects
3603
-        // (example: an admin page has done an insert or update and we want to run something after that).
3604
-        do_action('AHEE_redirect_' . $classname . $this->_req_action, $query_args);
3605
-        $redirect_url = apply_filters(
3606
-            'FHEE_redirect_' . $classname . $this->_req_action,
3607
-            EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3608
-            $query_args
3609
-        );
3610
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3611
-        if (defined('DOING_AJAX')) {
3612
-            $default_data = array(
3613
-                'close'        => true,
3614
-                'redirect_url' => $redirect_url,
3615
-                'where'        => 'main',
3616
-                'what'         => 'append',
3617
-            );
3618
-            $this->_template_args['success'] = $success;
3619
-            $this->_template_args['data'] = ! empty($this->_template_args['data']) ? array_merge(
3620
-                $default_data,
3621
-                $this->_template_args['data']
3622
-            ) : $default_data;
3623
-            $this->_return_json();
3624
-        }
3625
-        wp_safe_redirect($redirect_url);
3626
-        exit();
3627
-    }
3628
-
3629
-
3630
-    /**
3631
-     * process any notices before redirecting (or returning ajax request)
3632
-     * This method sets the $this->_template_args['notices'] attribute;
3633
-     *
3634
-     * @param array $query_args         any query args that need to be used for notice transient ('action')
3635
-     * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3636
-     *                                  page_routes haven't been defined yet.
3637
-     * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3638
-     *                                  still save a transient for the notice.
3639
-     * @return void
3640
-     * @throws EE_Error
3641
-     * @throws InvalidArgumentException
3642
-     * @throws InvalidDataTypeException
3643
-     * @throws InvalidInterfaceException
3644
-     */
3645
-    protected function _process_notices($query_args = array(), $skip_route_verify = false, $sticky_notices = true)
3646
-    {
3647
-        // first let's set individual error properties if doing_ajax and the properties aren't already set.
3648
-        if (defined('DOING_AJAX') && DOING_AJAX) {
3649
-            $notices = EE_Error::get_notices(false);
3650
-            if (empty($this->_template_args['success'])) {
3651
-                $this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3652
-            }
3653
-            if (empty($this->_template_args['errors'])) {
3654
-                $this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3655
-            }
3656
-            if (empty($this->_template_args['attention'])) {
3657
-                $this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3658
-            }
3659
-        }
3660
-        $this->_template_args['notices'] = EE_Error::get_notices();
3661
-        // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3662
-        if (! defined('DOING_AJAX') || $sticky_notices) {
3663
-            $route = isset($query_args['action']) ? $query_args['action'] : 'default';
3664
-            $this->_add_transient(
3665
-                $route,
3666
-                $this->_template_args['notices'],
3667
-                true,
3668
-                $skip_route_verify
3669
-            );
3670
-        }
3671
-    }
3672
-
3673
-
3674
-    /**
3675
-     * get_action_link_or_button
3676
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3677
-     *
3678
-     * @param string $action        use this to indicate which action the url is generated with.
3679
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3680
-     *                              property.
3681
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3682
-     * @param string $class         Use this to give the class for the button. Defaults to 'button-primary'
3683
-     * @param string $base_url      If this is not provided
3684
-     *                              the _admin_base_url will be used as the default for the button base_url.
3685
-     *                              Otherwise this value will be used.
3686
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3687
-     * @return string
3688
-     * @throws InvalidArgumentException
3689
-     * @throws InvalidInterfaceException
3690
-     * @throws InvalidDataTypeException
3691
-     * @throws EE_Error
3692
-     */
3693
-    public function get_action_link_or_button(
3694
-        $action,
3695
-        $type = 'add',
3696
-        $extra_request = array(),
3697
-        $class = 'button-primary',
3698
-        $base_url = '',
3699
-        $exclude_nonce = false
3700
-    ) {
3701
-        // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3702
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3703
-            throw new EE_Error(
3704
-                sprintf(
3705
-                    esc_html__(
3706
-                        'There is no page route for given action for the button.  This action was given: %s',
3707
-                        'event_espresso'
3708
-                    ),
3709
-                    $action
3710
-                )
3711
-            );
3712
-        }
3713
-        if (! isset($this->_labels['buttons'][ $type ])) {
3714
-            throw new EE_Error(
3715
-                sprintf(
3716
-                    __(
3717
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3718
-                        'event_espresso'
3719
-                    ),
3720
-                    $type
3721
-                )
3722
-            );
3723
-        }
3724
-        // finally check user access for this button.
3725
-        $has_access = $this->check_user_access($action, true);
3726
-        if (! $has_access) {
3727
-            return '';
3728
-        }
3729
-        $_base_url = ! $base_url ? $this->_admin_base_url : $base_url;
3730
-        $query_args = array(
3731
-            'action' => $action,
3732
-        );
3733
-        // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3734
-        if (! empty($extra_request)) {
3735
-            $query_args = array_merge($extra_request, $query_args);
3736
-        }
3737
-        $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3738
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3739
-    }
3740
-
3741
-
3742
-    /**
3743
-     * _per_page_screen_option
3744
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3745
-     *
3746
-     * @return void
3747
-     * @throws InvalidArgumentException
3748
-     * @throws InvalidInterfaceException
3749
-     * @throws InvalidDataTypeException
3750
-     */
3751
-    protected function _per_page_screen_option()
3752
-    {
3753
-        $option = 'per_page';
3754
-        $args = array(
3755
-            'label'   => apply_filters(
3756
-                'FHEE__EE_Admin_Page___per_page_screen_options___label',
3757
-                $this->_admin_page_title,
3758
-                $this
3759
-            ),
3760
-            'default' => (int) apply_filters(
3761
-                'FHEE__EE_Admin_Page___per_page_screen_options__default',
3762
-                20
3763
-            ),
3764
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3765
-        );
3766
-        // ONLY add the screen option if the user has access to it.
3767
-        if ($this->check_user_access($this->_current_view, true)) {
3768
-            add_screen_option($option, $args);
3769
-        }
3770
-    }
3771
-
3772
-
3773
-    /**
3774
-     * set_per_page_screen_option
3775
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3776
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3777
-     * admin_menu.
3778
-     *
3779
-     * @return void
3780
-     */
3781
-    private function _set_per_page_screen_options()
3782
-    {
3783
-        if (isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options'])) {
3784
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3785
-            if (! $user = wp_get_current_user()) {
3786
-                return;
3787
-            }
3788
-            $option = $_POST['wp_screen_options']['option'];
3789
-            $value = $_POST['wp_screen_options']['value'];
3790
-            if ($option !== sanitize_key($option)) {
3791
-                return;
3792
-            }
3793
-            $map_option = $option;
3794
-            $option = str_replace('-', '_', $option);
3795
-            switch ($map_option) {
3796
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3797
-                    $value = (int) $value;
3798
-                    $max_value = apply_filters(
3799
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3800
-                        999,
3801
-                        $this->_current_page,
3802
-                        $this->_current_view
3803
-                    );
3804
-                    if ($value < 1) {
3805
-                        return;
3806
-                    }
3807
-                    $value = min($value, $max_value);
3808
-                    break;
3809
-                default:
3810
-                    $value = apply_filters(
3811
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3812
-                        false,
3813
-                        $option,
3814
-                        $value
3815
-                    );
3816
-                    if (false === $value) {
3817
-                        return;
3818
-                    }
3819
-                    break;
3820
-            }
3821
-            update_user_meta($user->ID, $option, $value);
3822
-            wp_safe_redirect(remove_query_arg(array('pagenum', 'apage', 'paged'), wp_get_referer()));
3823
-            exit;
3824
-        }
3825
-    }
3826
-
3827
-
3828
-    /**
3829
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3830
-     *
3831
-     * @param array $data array that will be assigned to template args.
3832
-     */
3833
-    public function set_template_args($data)
3834
-    {
3835
-        $this->_template_args = array_merge($this->_template_args, (array) $data);
3836
-    }
3837
-
3838
-
3839
-    /**
3840
-     * This makes available the WP transient system for temporarily moving data between routes
3841
-     *
3842
-     * @param string $route             the route that should receive the transient
3843
-     * @param array  $data              the data that gets sent
3844
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3845
-     *                                  normal route transient.
3846
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3847
-     *                                  when we are adding a transient before page_routes have been defined.
3848
-     * @return void
3849
-     * @throws EE_Error
3850
-     */
3851
-    protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3852
-    {
3853
-        $user_id = get_current_user_id();
3854
-        if (! $skip_route_verify) {
3855
-            $this->_verify_route($route);
3856
-        }
3857
-        // now let's set the string for what kind of transient we're setting
3858
-        $transient = $notices
3859
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3860
-            : 'rte_tx_' . $route . '_' . $user_id;
3861
-        $data = $notices ? array('notices' => $data) : $data;
3862
-        // is there already a transient for this route?  If there is then let's ADD to that transient
3863
-        $existing = is_multisite() && is_network_admin()
3864
-            ? get_site_transient($transient)
3865
-            : get_transient($transient);
3866
-        if ($existing) {
3867
-            $data = array_merge((array) $data, (array) $existing);
3868
-        }
3869
-        if (is_multisite() && is_network_admin()) {
3870
-            set_site_transient($transient, $data, 8);
3871
-        } else {
3872
-            set_transient($transient, $data, 8);
3873
-        }
3874
-    }
3875
-
3876
-
3877
-    /**
3878
-     * this retrieves the temporary transient that has been set for moving data between routes.
3879
-     *
3880
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3881
-     * @param string $route
3882
-     * @return mixed data
3883
-     */
3884
-    protected function _get_transient($notices = false, $route = '')
3885
-    {
3886
-        $user_id = get_current_user_id();
3887
-        $route = ! $route ? $this->_req_action : $route;
3888
-        $transient = $notices
3889
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3890
-            : 'rte_tx_' . $route . '_' . $user_id;
3891
-        $data = is_multisite() && is_network_admin()
3892
-            ? get_site_transient($transient)
3893
-            : get_transient($transient);
3894
-        // delete transient after retrieval (just in case it hasn't expired);
3895
-        if (is_multisite() && is_network_admin()) {
3896
-            delete_site_transient($transient);
3897
-        } else {
3898
-            delete_transient($transient);
3899
-        }
3900
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3901
-    }
3902
-
3903
-
3904
-    /**
3905
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3906
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3907
-     * default route callback on the EE_Admin page you want it run.)
3908
-     *
3909
-     * @return void
3910
-     */
3911
-    protected function _transient_garbage_collection()
3912
-    {
3913
-        global $wpdb;
3914
-        // retrieve all existing transients
3915
-        $query = "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3916
-        if ($results = $wpdb->get_results($query)) {
3917
-            foreach ($results as $result) {
3918
-                $transient = str_replace('_transient_', '', $result->option_name);
3919
-                get_transient($transient);
3920
-                if (is_multisite() && is_network_admin()) {
3921
-                    get_site_transient($transient);
3922
-                }
3923
-            }
3924
-        }
3925
-    }
3926
-
3927
-
3928
-    /**
3929
-     * get_view
3930
-     *
3931
-     * @return string content of _view property
3932
-     */
3933
-    public function get_view()
3934
-    {
3935
-        return $this->_view;
3936
-    }
3937
-
3938
-
3939
-    /**
3940
-     * getter for the protected $_views property
3941
-     *
3942
-     * @return array
3943
-     */
3944
-    public function get_views()
3945
-    {
3946
-        return $this->_views;
3947
-    }
3948
-
3949
-
3950
-    /**
3951
-     * get_current_page
3952
-     *
3953
-     * @return string _current_page property value
3954
-     */
3955
-    public function get_current_page()
3956
-    {
3957
-        return $this->_current_page;
3958
-    }
3959
-
3960
-
3961
-    /**
3962
-     * get_current_view
3963
-     *
3964
-     * @return string _current_view property value
3965
-     */
3966
-    public function get_current_view()
3967
-    {
3968
-        return $this->_current_view;
3969
-    }
3970
-
3971
-
3972
-    /**
3973
-     * get_current_screen
3974
-     *
3975
-     * @return object The current WP_Screen object
3976
-     */
3977
-    public function get_current_screen()
3978
-    {
3979
-        return $this->_current_screen;
3980
-    }
3981
-
3982
-
3983
-    /**
3984
-     * get_current_page_view_url
3985
-     *
3986
-     * @return string This returns the url for the current_page_view.
3987
-     */
3988
-    public function get_current_page_view_url()
3989
-    {
3990
-        return $this->_current_page_view_url;
3991
-    }
3992
-
3993
-
3994
-    /**
3995
-     * just returns the _req_data property
3996
-     *
3997
-     * @return array
3998
-     */
3999
-    public function get_request_data()
4000
-    {
4001
-        return $this->_req_data;
4002
-    }
4003
-
4004
-
4005
-    /**
4006
-     * returns the _req_data protected property
4007
-     *
4008
-     * @return string
4009
-     */
4010
-    public function get_req_action()
4011
-    {
4012
-        return $this->_req_action;
4013
-    }
4014
-
4015
-
4016
-    /**
4017
-     * @return bool  value of $_is_caf property
4018
-     */
4019
-    public function is_caf()
4020
-    {
4021
-        return $this->_is_caf;
4022
-    }
4023
-
4024
-
4025
-    /**
4026
-     * @return mixed
4027
-     */
4028
-    public function default_espresso_metaboxes()
4029
-    {
4030
-        return $this->_default_espresso_metaboxes;
4031
-    }
4032
-
4033
-
4034
-    /**
4035
-     * @return mixed
4036
-     */
4037
-    public function admin_base_url()
4038
-    {
4039
-        return $this->_admin_base_url;
4040
-    }
4041
-
4042
-
4043
-    /**
4044
-     * @return mixed
4045
-     */
4046
-    public function wp_page_slug()
4047
-    {
4048
-        return $this->_wp_page_slug;
4049
-    }
4050
-
4051
-
4052
-    /**
4053
-     * updates  espresso configuration settings
4054
-     *
4055
-     * @param string                   $tab
4056
-     * @param EE_Config_Base|EE_Config $config
4057
-     * @param string                   $file file where error occurred
4058
-     * @param string                   $func function  where error occurred
4059
-     * @param string                   $line line no where error occurred
4060
-     * @return boolean
4061
-     */
4062
-    protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4063
-    {
4064
-        // remove any options that are NOT going to be saved with the config settings.
4065
-        if (isset($config->core->ee_ueip_optin)) {
4066
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4067
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4068
-            update_option('ee_ueip_has_notified', true);
4069
-        }
4070
-        // and save it (note we're also doing the network save here)
4071
-        $net_saved = is_main_site() ? EE_Network_Config::instance()->update_config(false, false) : true;
4072
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4073
-        if ($config_saved && $net_saved) {
4074
-            EE_Error::add_success(sprintf(__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4075
-            return true;
4076
-        }
4077
-        EE_Error::add_error(sprintf(__('The "%s" were not updated.', 'event_espresso'), $tab), $file, $func, $line);
4078
-        return false;
4079
-    }
4080
-
4081
-
4082
-    /**
4083
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4084
-     *
4085
-     * @return array
4086
-     */
4087
-    public function get_yes_no_values()
4088
-    {
4089
-        return $this->_yes_no_values;
4090
-    }
4091
-
4092
-
4093
-    /**
4094
-     * @return string
4095
-     * @throws ReflectionException
4096
-     * @since $VID:$
4097
-     */
4098
-    protected function _get_dir()
4099
-    {
4100
-        $reflector = new ReflectionClass(get_class($this));
4101
-        return dirname($reflector->getFileName());
4102
-    }
4103
-
4104
-
4105
-    /**
4106
-     * A helper for getting a "next link".
4107
-     *
4108
-     * @param string $url   The url to link to
4109
-     * @param string $class The class to use.
4110
-     * @return string
4111
-     */
4112
-    protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4113
-    {
4114
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4115
-    }
4116
-
4117
-
4118
-    /**
4119
-     * A helper for getting a "previous link".
4120
-     *
4121
-     * @param string $url   The url to link to
4122
-     * @param string $class The class to use.
4123
-     * @return string
4124
-     */
4125
-    protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4126
-    {
4127
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4128
-    }
4129
-
4130
-
4131
-
4132
-
4133
-
4134
-
4135
-
4136
-    // below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4137
-
4138
-
4139
-    /**
4140
-     * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4141
-     * 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
4142
-     * _req_data array.
4143
-     *
4144
-     * @return bool success/fail
4145
-     * @throws EE_Error
4146
-     * @throws InvalidArgumentException
4147
-     * @throws ReflectionException
4148
-     * @throws InvalidDataTypeException
4149
-     * @throws InvalidInterfaceException
4150
-     */
4151
-    protected function _process_resend_registration()
4152
-    {
4153
-        $this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4154
-        do_action(
4155
-            'AHEE__EE_Admin_Page___process_resend_registration',
4156
-            $this->_template_args['success'],
4157
-            $this->_req_data
4158
-        );
4159
-        return $this->_template_args['success'];
4160
-    }
4161
-
4162
-
4163
-    /**
4164
-     * This automatically processes any payment message notifications when manual payment has been applied.
4165
-     *
4166
-     * @param EE_Payment $payment
4167
-     * @return bool success/fail
4168
-     */
4169
-    protected function _process_payment_notification(EE_Payment $payment)
4170
-    {
4171
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4172
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4173
-        $this->_template_args['success'] = apply_filters(
4174
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4175
-            false,
4176
-            $payment
4177
-        );
4178
-        return $this->_template_args['success'];
4179
-    }
2701
+	}
2702
+
2703
+
2704
+	/**
2705
+	 * facade for add_meta_box
2706
+	 *
2707
+	 * @param string  $action        where the metabox get's displayed
2708
+	 * @param string  $title         Title of Metabox (output in metabox header)
2709
+	 * @param string  $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2710
+	 *                               instead of the one created in here.
2711
+	 * @param array   $callback_args an array of args supplied for the metabox
2712
+	 * @param string  $column        what metabox column
2713
+	 * @param string  $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2714
+	 * @param boolean $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2715
+	 *                               created but just set our own callback for wp's add_meta_box.
2716
+	 * @throws DomainException
2717
+	 */
2718
+	public function _add_admin_page_meta_box(
2719
+		$action,
2720
+		$title,
2721
+		$callback,
2722
+		$callback_args,
2723
+		$column = 'normal',
2724
+		$priority = 'high',
2725
+		$create_func = true
2726
+	) {
2727
+		do_action('AHEE_log', __FILE__, __FUNCTION__, $callback);
2728
+		// 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.
2729
+		if (empty($callback_args) && $create_func) {
2730
+			$callback_args = array(
2731
+				'template_path' => $this->_template_path,
2732
+				'template_args' => $this->_template_args,
2733
+			);
2734
+		}
2735
+		// 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)
2736
+		$call_back_func = $create_func
2737
+			? static function ($post, $metabox) {
2738
+				do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2739
+				echo EEH_Template::display_template(
2740
+					$metabox['args']['template_path'],
2741
+					$metabox['args']['template_args'],
2742
+					true
2743
+				);
2744
+			}
2745
+			: $callback;
2746
+		add_meta_box(
2747
+			str_replace('_', '-', $action) . '-mbox',
2748
+			$title,
2749
+			$call_back_func,
2750
+			$this->_wp_page_slug,
2751
+			$column,
2752
+			$priority,
2753
+			$callback_args
2754
+		);
2755
+	}
2756
+
2757
+
2758
+	/**
2759
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2760
+	 *
2761
+	 * @throws DomainException
2762
+	 * @throws EE_Error
2763
+	 * @throws InvalidArgumentException
2764
+	 * @throws InvalidDataTypeException
2765
+	 * @throws InvalidInterfaceException
2766
+	 */
2767
+	public function display_admin_page_with_metabox_columns()
2768
+	{
2769
+		$this->_template_args['post_body_content'] = $this->_template_args['admin_page_content'];
2770
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2771
+			$this->_column_template_path,
2772
+			$this->_template_args,
2773
+			true
2774
+		);
2775
+		// the final wrapper
2776
+		$this->admin_page_wrapper();
2777
+	}
2778
+
2779
+
2780
+	/**
2781
+	 * generates  HTML wrapper for an admin details page
2782
+	 *
2783
+	 * @return void
2784
+	 * @throws DomainException
2785
+	 * @throws EE_Error
2786
+	 * @throws InvalidArgumentException
2787
+	 * @throws InvalidDataTypeException
2788
+	 * @throws InvalidInterfaceException
2789
+	 */
2790
+	public function display_admin_page_with_sidebar()
2791
+	{
2792
+		$this->_display_admin_page(true);
2793
+	}
2794
+
2795
+
2796
+	/**
2797
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2798
+	 *
2799
+	 * @return void
2800
+	 * @throws DomainException
2801
+	 * @throws EE_Error
2802
+	 * @throws InvalidArgumentException
2803
+	 * @throws InvalidDataTypeException
2804
+	 * @throws InvalidInterfaceException
2805
+	 */
2806
+	public function display_admin_page_with_no_sidebar()
2807
+	{
2808
+		$this->_display_admin_page();
2809
+	}
2810
+
2811
+
2812
+	/**
2813
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2814
+	 *
2815
+	 * @return void
2816
+	 * @throws DomainException
2817
+	 * @throws EE_Error
2818
+	 * @throws InvalidArgumentException
2819
+	 * @throws InvalidDataTypeException
2820
+	 * @throws InvalidInterfaceException
2821
+	 */
2822
+	public function display_about_admin_page()
2823
+	{
2824
+		$this->_display_admin_page(false, true);
2825
+	}
2826
+
2827
+
2828
+	/**
2829
+	 * display_admin_page
2830
+	 * contains the code for actually displaying an admin page
2831
+	 *
2832
+	 * @param boolean $sidebar true with sidebar, false without
2833
+	 * @param boolean $about   use the about admin wrapper instead of the default.
2834
+	 * @return void
2835
+	 * @throws DomainException
2836
+	 * @throws EE_Error
2837
+	 * @throws InvalidArgumentException
2838
+	 * @throws InvalidDataTypeException
2839
+	 * @throws InvalidInterfaceException
2840
+	 */
2841
+	private function _display_admin_page($sidebar = false, $about = false)
2842
+	{
2843
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2844
+		// custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2845
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2846
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2847
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2848
+		$this->_template_args['current_page'] = $this->_wp_page_slug;
2849
+		$this->_template_args['admin_page_wrapper_div_id'] = $this->_cpt_route
2850
+			? 'poststuff'
2851
+			: 'espresso-default-admin';
2852
+		$template_path = $sidebar
2853
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2854
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2855
+		if (defined('DOING_AJAX') && DOING_AJAX) {
2856
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2857
+		}
2858
+		$template_path = ! empty($this->_column_template_path)
2859
+			? $this->_column_template_path : $template_path;
2860
+		$this->_template_args['post_body_content'] = isset($this->_template_args['admin_page_content'])
2861
+			? $this->_template_args['admin_page_content']
2862
+			: '';
2863
+		$this->_template_args['before_admin_page_content'] = isset($this->_template_args['before_admin_page_content'])
2864
+			? $this->_template_args['before_admin_page_content']
2865
+			: '';
2866
+		$this->_template_args['after_admin_page_content'] = isset($this->_template_args['after_admin_page_content'])
2867
+			? $this->_template_args['after_admin_page_content']
2868
+			: '';
2869
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2870
+			$template_path,
2871
+			$this->_template_args,
2872
+			true
2873
+		);
2874
+		// the final template wrapper
2875
+		$this->admin_page_wrapper($about);
2876
+	}
2877
+
2878
+
2879
+	/**
2880
+	 * This is used to display caf preview pages.
2881
+	 *
2882
+	 * @since 4.3.2
2883
+	 * @param string $utm_campaign_source what is the key used for google analytics link
2884
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2885
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2886
+	 * @return void
2887
+	 * @throws DomainException
2888
+	 * @throws EE_Error
2889
+	 * @throws InvalidArgumentException
2890
+	 * @throws InvalidDataTypeException
2891
+	 * @throws InvalidInterfaceException
2892
+	 */
2893
+	public function display_admin_caf_preview_page($utm_campaign_source = '', $display_sidebar = true)
2894
+	{
2895
+		// let's generate a default preview action button if there isn't one already present.
2896
+		$this->_labels['buttons']['buy_now'] = esc_html__(
2897
+			'Upgrade to Event Espresso 4 Right Now',
2898
+			'event_espresso'
2899
+		);
2900
+		$buy_now_url = add_query_arg(
2901
+			array(
2902
+				'ee_ver'       => 'ee4',
2903
+				'utm_source'   => 'ee4_plugin_admin',
2904
+				'utm_medium'   => 'link',
2905
+				'utm_campaign' => $utm_campaign_source,
2906
+				'utm_content'  => 'buy_now_button',
2907
+			),
2908
+			'http://eventespresso.com/pricing/'
2909
+		);
2910
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2911
+			? $this->get_action_link_or_button(
2912
+				'',
2913
+				'buy_now',
2914
+				array(),
2915
+				'button-primary button-large',
2916
+				$buy_now_url,
2917
+				true
2918
+			)
2919
+			: $this->_template_args['preview_action_button'];
2920
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2921
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2922
+			$this->_template_args,
2923
+			true
2924
+		);
2925
+		$this->_display_admin_page($display_sidebar);
2926
+	}
2927
+
2928
+
2929
+	/**
2930
+	 * display_admin_list_table_page_with_sidebar
2931
+	 * generates HTML wrapper for an admin_page with list_table
2932
+	 *
2933
+	 * @return void
2934
+	 * @throws DomainException
2935
+	 * @throws EE_Error
2936
+	 * @throws InvalidArgumentException
2937
+	 * @throws InvalidDataTypeException
2938
+	 * @throws InvalidInterfaceException
2939
+	 */
2940
+	public function display_admin_list_table_page_with_sidebar()
2941
+	{
2942
+		$this->_display_admin_list_table_page(true);
2943
+	}
2944
+
2945
+
2946
+	/**
2947
+	 * display_admin_list_table_page_with_no_sidebar
2948
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2949
+	 *
2950
+	 * @return void
2951
+	 * @throws DomainException
2952
+	 * @throws EE_Error
2953
+	 * @throws InvalidArgumentException
2954
+	 * @throws InvalidDataTypeException
2955
+	 * @throws InvalidInterfaceException
2956
+	 */
2957
+	public function display_admin_list_table_page_with_no_sidebar()
2958
+	{
2959
+		$this->_display_admin_list_table_page();
2960
+	}
2961
+
2962
+
2963
+	/**
2964
+	 * generates html wrapper for an admin_list_table page
2965
+	 *
2966
+	 * @param boolean $sidebar whether to display with sidebar or not.
2967
+	 * @return void
2968
+	 * @throws DomainException
2969
+	 * @throws EE_Error
2970
+	 * @throws InvalidArgumentException
2971
+	 * @throws InvalidDataTypeException
2972
+	 * @throws InvalidInterfaceException
2973
+	 */
2974
+	private function _display_admin_list_table_page($sidebar = false)
2975
+	{
2976
+		// setup search attributes
2977
+		$this->_set_search_attributes();
2978
+		$this->_template_args['current_page'] = $this->_wp_page_slug;
2979
+		$template_path = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2980
+		$this->_template_args['table_url'] = defined('DOING_AJAX')
2981
+			? add_query_arg(array('noheader' => 'true', 'route' => $this->_req_action), $this->_admin_base_url)
2982
+			: add_query_arg(array('route' => $this->_req_action), $this->_admin_base_url);
2983
+		$this->_template_args['list_table'] = $this->_list_table_object;
2984
+		$this->_template_args['current_route'] = $this->_req_action;
2985
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2986
+		$ajax_sorting_callback = $this->_list_table_object->get_ajax_sorting_callback();
2987
+		if (! empty($ajax_sorting_callback)) {
2988
+			$sortable_list_table_form_fields = wp_nonce_field(
2989
+				$ajax_sorting_callback . '_nonce',
2990
+				$ajax_sorting_callback . '_nonce',
2991
+				false,
2992
+				false
2993
+			);
2994
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2995
+												. $this->page_slug
2996
+												. '" />';
2997
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2998
+												. $ajax_sorting_callback
2999
+												. '" />';
3000
+		} else {
3001
+			$sortable_list_table_form_fields = '';
3002
+		}
3003
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
3004
+		$hidden_form_fields = isset($this->_template_args['list_table_hidden_fields'])
3005
+			? $this->_template_args['list_table_hidden_fields']
3006
+			: '';
3007
+		$nonce_ref = $this->_req_action . '_nonce';
3008
+		$hidden_form_fields .= '<input type="hidden" name="'
3009
+							   . $nonce_ref
3010
+							   . '" value="'
3011
+							   . wp_create_nonce($nonce_ref)
3012
+							   . '">';
3013
+		$this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
3014
+		// display message about search results?
3015
+		$this->_template_args['before_list_table'] .= ! empty($this->_req_data['s'])
3016
+			? '<p class="ee-search-results">' . sprintf(
3017
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
3018
+				trim($this->_req_data['s'], '%')
3019
+			) . '</p>'
3020
+			: '';
3021
+		// filter before_list_table template arg
3022
+		$this->_template_args['before_list_table'] = apply_filters(
3023
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
3024
+			$this->_template_args['before_list_table'],
3025
+			$this->page_slug,
3026
+			$this->_req_data,
3027
+			$this->_req_action
3028
+		);
3029
+		// convert to array and filter again
3030
+		// arrays are easier to inject new items in a specific location,
3031
+		// but would not be backwards compatible, so we have to add a new filter
3032
+		$this->_template_args['before_list_table'] = implode(
3033
+			" \n",
3034
+			(array) apply_filters(
3035
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
3036
+				(array) $this->_template_args['before_list_table'],
3037
+				$this->page_slug,
3038
+				$this->_req_data,
3039
+				$this->_req_action
3040
+			)
3041
+		);
3042
+		// filter after_list_table template arg
3043
+		$this->_template_args['after_list_table'] = apply_filters(
3044
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3045
+			$this->_template_args['after_list_table'],
3046
+			$this->page_slug,
3047
+			$this->_req_data,
3048
+			$this->_req_action
3049
+		);
3050
+		// convert to array and filter again
3051
+		// arrays are easier to inject new items in a specific location,
3052
+		// but would not be backwards compatible, so we have to add a new filter
3053
+		$this->_template_args['after_list_table'] = implode(
3054
+			" \n",
3055
+			(array) apply_filters(
3056
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3057
+				(array) $this->_template_args['after_list_table'],
3058
+				$this->page_slug,
3059
+				$this->_req_data,
3060
+				$this->_req_action
3061
+			)
3062
+		);
3063
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3064
+			$template_path,
3065
+			$this->_template_args,
3066
+			true
3067
+		);
3068
+		// the final template wrapper
3069
+		if ($sidebar) {
3070
+			$this->display_admin_page_with_sidebar();
3071
+		} else {
3072
+			$this->display_admin_page_with_no_sidebar();
3073
+		}
3074
+	}
3075
+
3076
+
3077
+	/**
3078
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3079
+	 * html string for the legend.
3080
+	 * $items are expected in an array in the following format:
3081
+	 * $legend_items = array(
3082
+	 *        'item_id' => array(
3083
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3084
+	 *            'desc' => esc_html__('localized description of item');
3085
+	 *        )
3086
+	 * );
3087
+	 *
3088
+	 * @param  array $items see above for format of array
3089
+	 * @return string html string of legend
3090
+	 * @throws DomainException
3091
+	 */
3092
+	protected function _display_legend($items)
3093
+	{
3094
+		$this->_template_args['items'] = apply_filters(
3095
+			'FHEE__EE_Admin_Page___display_legend__items',
3096
+			(array) $items,
3097
+			$this
3098
+		);
3099
+		/** @var EventEspresso\core\admin\StatusChangeNotice $status_change_notice */
3100
+		$status_change_notice = $this->loader->getShared('EventEspresso\core\admin\StatusChangeNotice');
3101
+		if (! $status_change_notice->isDismissed()) {
3102
+			$this->_template_args['status_change_notice'] = EEH_Template::display_template(
3103
+				EE_ADMIN_TEMPLATE . 'status_change_notice.template.php',
3104
+				[ 'context' => '__admin-legend', 'page_slug' => $this->page_slug ],
3105
+				true
3106
+			);
3107
+		}
3108
+		return EEH_Template::display_template(
3109
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3110
+			$this->_template_args,
3111
+			true
3112
+		);
3113
+	}
3114
+
3115
+
3116
+	/**
3117
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3118
+	 * The returned json object is created from an array in the following format:
3119
+	 * array(
3120
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3121
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3122
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3123
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3124
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3125
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3126
+	 *  that might be included in here)
3127
+	 * )
3128
+	 * The json object is populated by whatever is set in the $_template_args property.
3129
+	 *
3130
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3131
+	 *                                 instead of displayed.
3132
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3133
+	 * @return void
3134
+	 * @throws EE_Error
3135
+	 * @throws InvalidArgumentException
3136
+	 * @throws InvalidDataTypeException
3137
+	 * @throws InvalidInterfaceException
3138
+	 */
3139
+	protected function _return_json($sticky_notices = false, $notices_arguments = array())
3140
+	{
3141
+		// make sure any EE_Error notices have been handled.
3142
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3143
+		$data = isset($this->_template_args['data']) ? $this->_template_args['data'] : array();
3144
+		unset($this->_template_args['data']);
3145
+		$json = array(
3146
+			'error'     => isset($this->_template_args['error']) ? $this->_template_args['error'] : false,
3147
+			'success'   => isset($this->_template_args['success']) ? $this->_template_args['success'] : false,
3148
+			'errors'    => isset($this->_template_args['errors']) ? $this->_template_args['errors'] : false,
3149
+			'attention' => isset($this->_template_args['attention']) ? $this->_template_args['attention'] : false,
3150
+			'notices'   => EE_Error::get_notices(),
3151
+			'content'   => isset($this->_template_args['admin_page_content'])
3152
+				? $this->_template_args['admin_page_content'] : '',
3153
+			'data'      => array_merge($data, array('template_args' => $this->_template_args)),
3154
+			'isEEajax'  => true
3155
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3156
+		);
3157
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3158
+		if (null === error_get_last() || ! headers_sent()) {
3159
+			header('Content-Type: application/json; charset=UTF-8');
3160
+		}
3161
+		echo wp_json_encode($json);
3162
+		exit();
3163
+	}
3164
+
3165
+
3166
+	/**
3167
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3168
+	 *
3169
+	 * @return void
3170
+	 * @throws EE_Error
3171
+	 * @throws InvalidArgumentException
3172
+	 * @throws InvalidDataTypeException
3173
+	 * @throws InvalidInterfaceException
3174
+	 */
3175
+	public function return_json()
3176
+	{
3177
+		if (defined('DOING_AJAX') && DOING_AJAX) {
3178
+			$this->_return_json();
3179
+		} else {
3180
+			throw new EE_Error(
3181
+				sprintf(
3182
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3183
+					__FUNCTION__
3184
+				)
3185
+			);
3186
+		}
3187
+	}
3188
+
3189
+
3190
+	/**
3191
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3192
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3193
+	 *
3194
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3195
+	 */
3196
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3197
+	{
3198
+		$this->_hook_obj = $hook_obj;
3199
+	}
3200
+
3201
+
3202
+	/**
3203
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3204
+	 *
3205
+	 * @param boolean $about whether to use the special about page wrapper or default.
3206
+	 * @return void
3207
+	 * @throws DomainException
3208
+	 * @throws EE_Error
3209
+	 * @throws InvalidArgumentException
3210
+	 * @throws InvalidDataTypeException
3211
+	 * @throws InvalidInterfaceException
3212
+	 */
3213
+	public function admin_page_wrapper($about = false)
3214
+	{
3215
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3216
+		$this->_nav_tabs = $this->_get_main_nav_tabs();
3217
+		$this->_template_args['nav_tabs'] = $this->_nav_tabs;
3218
+		$this->_template_args['admin_page_title'] = $this->_admin_page_title;
3219
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3220
+			"FHEE_before_admin_page_content{$this->_current_page}{$this->_current_view}",
3221
+			isset($this->_template_args['before_admin_page_content'])
3222
+				? $this->_template_args['before_admin_page_content']
3223
+				: ''
3224
+		);
3225
+		$this->_template_args['after_admin_page_content'] = apply_filters(
3226
+			"FHEE_after_admin_page_content{$this->_current_page}{$this->_current_view}",
3227
+			isset($this->_template_args['after_admin_page_content'])
3228
+				? $this->_template_args['after_admin_page_content']
3229
+				: ''
3230
+		);
3231
+		$this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3232
+		// load settings page wrapper template
3233
+		$template_path = ! defined('DOING_AJAX')
3234
+			? EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php'
3235
+			: EE_ADMIN_TEMPLATE
3236
+			  . 'admin_wrapper_ajax.template.php';
3237
+		// about page?
3238
+		$template_path = $about
3239
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3240
+			: $template_path;
3241
+		if (defined('DOING_AJAX')) {
3242
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3243
+				$template_path,
3244
+				$this->_template_args,
3245
+				true
3246
+			);
3247
+			$this->_return_json();
3248
+		} else {
3249
+			EEH_Template::display_template($template_path, $this->_template_args);
3250
+		}
3251
+	}
3252
+
3253
+
3254
+	/**
3255
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3256
+	 *
3257
+	 * @return string html
3258
+	 * @throws EE_Error
3259
+	 */
3260
+	protected function _get_main_nav_tabs()
3261
+	{
3262
+		// let's generate the html using the EEH_Tabbed_Content helper.
3263
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3264
+		// (rather than setting in the page_routes array)
3265
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs);
3266
+	}
3267
+
3268
+
3269
+	/**
3270
+	 *        sort nav tabs
3271
+	 *
3272
+	 * @param $a
3273
+	 * @param $b
3274
+	 * @return int
3275
+	 */
3276
+	private function _sort_nav_tabs($a, $b)
3277
+	{
3278
+		if ($a['order'] === $b['order']) {
3279
+			return 0;
3280
+		}
3281
+		return ($a['order'] < $b['order']) ? -1 : 1;
3282
+	}
3283
+
3284
+
3285
+	/**
3286
+	 *    generates HTML for the forms used on admin pages
3287
+	 *
3288
+	 * @param    array $input_vars - array of input field details
3289
+	 * @param string   $generator  (options are 'string' or 'array', basically use this to indicate which generator to
3290
+	 *                             use)
3291
+	 * @param bool     $id
3292
+	 * @return string
3293
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3294
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3295
+	 */
3296
+	protected function _generate_admin_form_fields($input_vars = array(), $generator = 'string', $id = false)
3297
+	{
3298
+		return $generator === 'string'
3299
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3300
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3301
+	}
3302
+
3303
+
3304
+	/**
3305
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3306
+	 *
3307
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3308
+	 *                                   Close" button.
3309
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3310
+	 *                                   'Save', [1] => 'save & close')
3311
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3312
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3313
+	 *                                   default actions by submitting some other value.
3314
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3315
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3316
+	 *                                   close (normal form handling).
3317
+	 */
3318
+	protected function _set_save_buttons($both = true, $text = array(), $actions = array(), $referrer = null)
3319
+	{
3320
+		// make sure $text and $actions are in an array
3321
+		$text = (array) $text;
3322
+		$actions = (array) $actions;
3323
+		$referrer_url = empty($referrer)
3324
+			? '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3325
+			  . $_SERVER['REQUEST_URI']
3326
+			  . '" />'
3327
+			: '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3328
+			  . $referrer
3329
+			  . '" />';
3330
+		$button_text = ! empty($text)
3331
+			? $text
3332
+			: array(
3333
+				esc_html__('Save', 'event_espresso'),
3334
+				esc_html__('Save and Close', 'event_espresso'),
3335
+			);
3336
+		$default_names = array('save', 'save_and_close');
3337
+		// add in a hidden index for the current page (so save and close redirects properly)
3338
+		$this->_template_args['save_buttons'] = $referrer_url;
3339
+		foreach ($button_text as $key => $button) {
3340
+			$ref = $default_names[ $key ];
3341
+			$this->_template_args['save_buttons'] .= '<input type="submit" class="button-primary '
3342
+													 . $ref
3343
+													 . '" value="'
3344
+													 . $button
3345
+													 . '" name="'
3346
+													 . (! empty($actions) ? $actions[ $key ] : $ref)
3347
+													 . '" id="'
3348
+													 . $this->_current_view . '_' . $ref
3349
+													 . '" />';
3350
+			if (! $both) {
3351
+				break;
3352
+			}
3353
+		}
3354
+	}
3355
+
3356
+
3357
+	/**
3358
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3359
+	 *
3360
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3361
+	 * @since 4.6.0
3362
+	 * @param string $route
3363
+	 * @param array  $additional_hidden_fields
3364
+	 */
3365
+	public function set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3366
+	{
3367
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3368
+	}
3369
+
3370
+
3371
+	/**
3372
+	 * set form open and close tags on add/edit pages.
3373
+	 *
3374
+	 * @param string $route                    the route you want the form to direct to
3375
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3376
+	 * @return void
3377
+	 */
3378
+	protected function _set_add_edit_form_tags($route = '', $additional_hidden_fields = array())
3379
+	{
3380
+		if (empty($route)) {
3381
+			$user_msg = esc_html__(
3382
+				'An error occurred. No action was set for this page\'s form.',
3383
+				'event_espresso'
3384
+			);
3385
+			$dev_msg = $user_msg . "\n"
3386
+					   . sprintf(
3387
+						   esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3388
+						   __FUNCTION__,
3389
+						   EE_Admin_Page::class
3390
+					   );
3391
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3392
+		}
3393
+		// open form
3394
+		$this->_template_args['before_admin_page_content'] = '<form name="form" method="post" action="'
3395
+															 . $this->_admin_base_url
3396
+															 . '" id="'
3397
+															 . $route
3398
+															 . '_event_form" >';
3399
+		// add nonce
3400
+		$nonce = wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3401
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3402
+		// add REQUIRED form action
3403
+		$hidden_fields = array(
3404
+			'action' => array('type' => 'hidden', 'value' => $route),
3405
+		);
3406
+		// merge arrays
3407
+		$hidden_fields = is_array($additional_hidden_fields)
3408
+			? array_merge($hidden_fields, $additional_hidden_fields)
3409
+			: $hidden_fields;
3410
+		// generate form fields
3411
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3412
+		// add fields to form
3413
+		foreach ((array) $form_fields as $field_name => $form_field) {
3414
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3415
+		}
3416
+		// close form
3417
+		$this->_template_args['after_admin_page_content'] = '</form>';
3418
+	}
3419
+
3420
+
3421
+	/**
3422
+	 * Public Wrapper for _redirect_after_action() method since its
3423
+	 * discovered it would be useful for external code to have access.
3424
+	 *
3425
+	 * @param bool   $success
3426
+	 * @param string $what
3427
+	 * @param string $action_desc
3428
+	 * @param array  $query_args
3429
+	 * @param bool   $override_overwrite
3430
+	 * @throws EE_Error
3431
+	 * @throws InvalidArgumentException
3432
+	 * @throws InvalidDataTypeException
3433
+	 * @throws InvalidInterfaceException
3434
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3435
+	 * @since 4.5.0
3436
+	 */
3437
+	public function redirect_after_action(
3438
+		$success = false,
3439
+		$what = 'item',
3440
+		$action_desc = 'processed',
3441
+		$query_args = array(),
3442
+		$override_overwrite = false
3443
+	) {
3444
+		$this->_redirect_after_action(
3445
+			$success,
3446
+			$what,
3447
+			$action_desc,
3448
+			$query_args,
3449
+			$override_overwrite
3450
+		);
3451
+	}
3452
+
3453
+
3454
+	/**
3455
+	 * Helper method for merging existing request data with the returned redirect url.
3456
+	 *
3457
+	 * This is typically used for redirects after an action so that if the original view was a filtered view those
3458
+	 * filters are still applied.
3459
+	 *
3460
+	 * @param array $new_route_data
3461
+	 * @return array
3462
+	 */
3463
+	protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data)
3464
+	{
3465
+		foreach ($this->_req_data as $ref => $value) {
3466
+			// unset nonces
3467
+			if (strpos($ref, 'nonce') !== false) {
3468
+				unset($this->_req_data[ $ref ]);
3469
+				continue;
3470
+			}
3471
+			// urlencode values.
3472
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3473
+			$this->_req_data[ $ref ] = $value;
3474
+		}
3475
+		return array_merge($this->_req_data, $new_route_data);
3476
+	}
3477
+
3478
+
3479
+	/**
3480
+	 *    _redirect_after_action
3481
+	 *
3482
+	 * @param int    $success            - whether success was for two or more records, or just one, or none
3483
+	 * @param string $what               - what the action was performed on
3484
+	 * @param string $action_desc        - what was done ie: updated, deleted, etc
3485
+	 * @param array  $query_args         - an array of query_args to be added to the URL to redirect to after the admin
3486
+	 *                                   action is completed
3487
+	 * @param BOOL   $override_overwrite by default all EE_Error::success messages are overwritten, this allows you to
3488
+	 *                                   override this so that they show.
3489
+	 * @return void
3490
+	 * @throws EE_Error
3491
+	 * @throws InvalidArgumentException
3492
+	 * @throws InvalidDataTypeException
3493
+	 * @throws InvalidInterfaceException
3494
+	 */
3495
+	protected function _redirect_after_action(
3496
+		$success = 0,
3497
+		$what = 'item',
3498
+		$action_desc = 'processed',
3499
+		$query_args = array(),
3500
+		$override_overwrite = false
3501
+	) {
3502
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3503
+		// class name for actions/filters.
3504
+		$classname = get_class($this);
3505
+		// set redirect url.
3506
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3507
+		// otherwise we go with whatever is set as the _admin_base_url
3508
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3509
+		$notices = EE_Error::get_notices(false);
3510
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3511
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3512
+			EE_Error::overwrite_success();
3513
+		}
3514
+		if (! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3515
+			// how many records affected ? more than one record ? or just one ?
3516
+			if ($success > 1) {
3517
+				// set plural msg
3518
+				EE_Error::add_success(
3519
+					sprintf(
3520
+						esc_html__('The "%s" have been successfully %s.', 'event_espresso'),
3521
+						$what,
3522
+						$action_desc
3523
+					),
3524
+					__FILE__,
3525
+					__FUNCTION__,
3526
+					__LINE__
3527
+				);
3528
+			} elseif ($success === 1) {
3529
+				// set singular msg
3530
+				EE_Error::add_success(
3531
+					sprintf(
3532
+						esc_html__('The "%s" has been successfully %s.', 'event_espresso'),
3533
+						$what,
3534
+						$action_desc
3535
+					),
3536
+					__FILE__,
3537
+					__FUNCTION__,
3538
+					__LINE__
3539
+				);
3540
+			}
3541
+		}
3542
+		// check that $query_args isn't something crazy
3543
+		if (! is_array($query_args)) {
3544
+			$query_args = array();
3545
+		}
3546
+		/**
3547
+		 * Allow injecting actions before the query_args are modified for possible different
3548
+		 * redirections on save and close actions
3549
+		 *
3550
+		 * @since 4.2.0
3551
+		 * @param array $query_args       The original query_args array coming into the
3552
+		 *                                method.
3553
+		 */
3554
+		do_action(
3555
+			"AHEE__{$classname}___redirect_after_action__before_redirect_modification_{$this->_req_action}",
3556
+			$query_args
3557
+		);
3558
+		// calculate where we're going (if we have a "save and close" button pushed)
3559
+		if (isset($this->_req_data['save_and_close'], $this->_req_data['save_and_close_referrer'])) {
3560
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3561
+			$parsed_url = parse_url($this->_req_data['save_and_close_referrer']);
3562
+			// regenerate query args array from referrer URL
3563
+			parse_str($parsed_url['query'], $query_args);
3564
+			// correct page and action will be in the query args now
3565
+			$redirect_url = admin_url('admin.php');
3566
+		}
3567
+		// merge any default query_args set in _default_route_query_args property
3568
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3569
+			$args_to_merge = array();
3570
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3571
+				// is there a wp_referer array in our _default_route_query_args property?
3572
+				if ($query_param === 'wp_referer') {
3573
+					$query_value = (array) $query_value;
3574
+					foreach ($query_value as $reference => $value) {
3575
+						if (strpos($reference, 'nonce') !== false) {
3576
+							continue;
3577
+						}
3578
+						// finally we will override any arguments in the referer with
3579
+						// what might be set on the _default_route_query_args array.
3580
+						if (isset($this->_default_route_query_args[ $reference ])) {
3581
+							$args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3582
+						} else {
3583
+							$args_to_merge[ $reference ] = urlencode($value);
3584
+						}
3585
+					}
3586
+					continue;
3587
+				}
3588
+				$args_to_merge[ $query_param ] = $query_value;
3589
+			}
3590
+			// now let's merge these arguments but override with what was specifically sent in to the
3591
+			// redirect.
3592
+			$query_args = array_merge($args_to_merge, $query_args);
3593
+		}
3594
+		$this->_process_notices($query_args);
3595
+		// generate redirect url
3596
+		// if redirecting to anything other than the main page, add a nonce
3597
+		if (isset($query_args['action'])) {
3598
+			// manually generate wp_nonce and merge that with the query vars
3599
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3600
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3601
+		}
3602
+		// we're adding some hooks and filters in here for processing any things just before redirects
3603
+		// (example: an admin page has done an insert or update and we want to run something after that).
3604
+		do_action('AHEE_redirect_' . $classname . $this->_req_action, $query_args);
3605
+		$redirect_url = apply_filters(
3606
+			'FHEE_redirect_' . $classname . $this->_req_action,
3607
+			EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3608
+			$query_args
3609
+		);
3610
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3611
+		if (defined('DOING_AJAX')) {
3612
+			$default_data = array(
3613
+				'close'        => true,
3614
+				'redirect_url' => $redirect_url,
3615
+				'where'        => 'main',
3616
+				'what'         => 'append',
3617
+			);
3618
+			$this->_template_args['success'] = $success;
3619
+			$this->_template_args['data'] = ! empty($this->_template_args['data']) ? array_merge(
3620
+				$default_data,
3621
+				$this->_template_args['data']
3622
+			) : $default_data;
3623
+			$this->_return_json();
3624
+		}
3625
+		wp_safe_redirect($redirect_url);
3626
+		exit();
3627
+	}
3628
+
3629
+
3630
+	/**
3631
+	 * process any notices before redirecting (or returning ajax request)
3632
+	 * This method sets the $this->_template_args['notices'] attribute;
3633
+	 *
3634
+	 * @param array $query_args         any query args that need to be used for notice transient ('action')
3635
+	 * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3636
+	 *                                  page_routes haven't been defined yet.
3637
+	 * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3638
+	 *                                  still save a transient for the notice.
3639
+	 * @return void
3640
+	 * @throws EE_Error
3641
+	 * @throws InvalidArgumentException
3642
+	 * @throws InvalidDataTypeException
3643
+	 * @throws InvalidInterfaceException
3644
+	 */
3645
+	protected function _process_notices($query_args = array(), $skip_route_verify = false, $sticky_notices = true)
3646
+	{
3647
+		// first let's set individual error properties if doing_ajax and the properties aren't already set.
3648
+		if (defined('DOING_AJAX') && DOING_AJAX) {
3649
+			$notices = EE_Error::get_notices(false);
3650
+			if (empty($this->_template_args['success'])) {
3651
+				$this->_template_args['success'] = isset($notices['success']) ? $notices['success'] : false;
3652
+			}
3653
+			if (empty($this->_template_args['errors'])) {
3654
+				$this->_template_args['errors'] = isset($notices['errors']) ? $notices['errors'] : false;
3655
+			}
3656
+			if (empty($this->_template_args['attention'])) {
3657
+				$this->_template_args['attention'] = isset($notices['attention']) ? $notices['attention'] : false;
3658
+			}
3659
+		}
3660
+		$this->_template_args['notices'] = EE_Error::get_notices();
3661
+		// IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3662
+		if (! defined('DOING_AJAX') || $sticky_notices) {
3663
+			$route = isset($query_args['action']) ? $query_args['action'] : 'default';
3664
+			$this->_add_transient(
3665
+				$route,
3666
+				$this->_template_args['notices'],
3667
+				true,
3668
+				$skip_route_verify
3669
+			);
3670
+		}
3671
+	}
3672
+
3673
+
3674
+	/**
3675
+	 * get_action_link_or_button
3676
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3677
+	 *
3678
+	 * @param string $action        use this to indicate which action the url is generated with.
3679
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3680
+	 *                              property.
3681
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3682
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button-primary'
3683
+	 * @param string $base_url      If this is not provided
3684
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3685
+	 *                              Otherwise this value will be used.
3686
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3687
+	 * @return string
3688
+	 * @throws InvalidArgumentException
3689
+	 * @throws InvalidInterfaceException
3690
+	 * @throws InvalidDataTypeException
3691
+	 * @throws EE_Error
3692
+	 */
3693
+	public function get_action_link_or_button(
3694
+		$action,
3695
+		$type = 'add',
3696
+		$extra_request = array(),
3697
+		$class = 'button-primary',
3698
+		$base_url = '',
3699
+		$exclude_nonce = false
3700
+	) {
3701
+		// first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3702
+		if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3703
+			throw new EE_Error(
3704
+				sprintf(
3705
+					esc_html__(
3706
+						'There is no page route for given action for the button.  This action was given: %s',
3707
+						'event_espresso'
3708
+					),
3709
+					$action
3710
+				)
3711
+			);
3712
+		}
3713
+		if (! isset($this->_labels['buttons'][ $type ])) {
3714
+			throw new EE_Error(
3715
+				sprintf(
3716
+					__(
3717
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3718
+						'event_espresso'
3719
+					),
3720
+					$type
3721
+				)
3722
+			);
3723
+		}
3724
+		// finally check user access for this button.
3725
+		$has_access = $this->check_user_access($action, true);
3726
+		if (! $has_access) {
3727
+			return '';
3728
+		}
3729
+		$_base_url = ! $base_url ? $this->_admin_base_url : $base_url;
3730
+		$query_args = array(
3731
+			'action' => $action,
3732
+		);
3733
+		// merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3734
+		if (! empty($extra_request)) {
3735
+			$query_args = array_merge($extra_request, $query_args);
3736
+		}
3737
+		$url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3738
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3739
+	}
3740
+
3741
+
3742
+	/**
3743
+	 * _per_page_screen_option
3744
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3745
+	 *
3746
+	 * @return void
3747
+	 * @throws InvalidArgumentException
3748
+	 * @throws InvalidInterfaceException
3749
+	 * @throws InvalidDataTypeException
3750
+	 */
3751
+	protected function _per_page_screen_option()
3752
+	{
3753
+		$option = 'per_page';
3754
+		$args = array(
3755
+			'label'   => apply_filters(
3756
+				'FHEE__EE_Admin_Page___per_page_screen_options___label',
3757
+				$this->_admin_page_title,
3758
+				$this
3759
+			),
3760
+			'default' => (int) apply_filters(
3761
+				'FHEE__EE_Admin_Page___per_page_screen_options__default',
3762
+				20
3763
+			),
3764
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3765
+		);
3766
+		// ONLY add the screen option if the user has access to it.
3767
+		if ($this->check_user_access($this->_current_view, true)) {
3768
+			add_screen_option($option, $args);
3769
+		}
3770
+	}
3771
+
3772
+
3773
+	/**
3774
+	 * set_per_page_screen_option
3775
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3776
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3777
+	 * admin_menu.
3778
+	 *
3779
+	 * @return void
3780
+	 */
3781
+	private function _set_per_page_screen_options()
3782
+	{
3783
+		if (isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options'])) {
3784
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3785
+			if (! $user = wp_get_current_user()) {
3786
+				return;
3787
+			}
3788
+			$option = $_POST['wp_screen_options']['option'];
3789
+			$value = $_POST['wp_screen_options']['value'];
3790
+			if ($option !== sanitize_key($option)) {
3791
+				return;
3792
+			}
3793
+			$map_option = $option;
3794
+			$option = str_replace('-', '_', $option);
3795
+			switch ($map_option) {
3796
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3797
+					$value = (int) $value;
3798
+					$max_value = apply_filters(
3799
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3800
+						999,
3801
+						$this->_current_page,
3802
+						$this->_current_view
3803
+					);
3804
+					if ($value < 1) {
3805
+						return;
3806
+					}
3807
+					$value = min($value, $max_value);
3808
+					break;
3809
+				default:
3810
+					$value = apply_filters(
3811
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3812
+						false,
3813
+						$option,
3814
+						$value
3815
+					);
3816
+					if (false === $value) {
3817
+						return;
3818
+					}
3819
+					break;
3820
+			}
3821
+			update_user_meta($user->ID, $option, $value);
3822
+			wp_safe_redirect(remove_query_arg(array('pagenum', 'apage', 'paged'), wp_get_referer()));
3823
+			exit;
3824
+		}
3825
+	}
3826
+
3827
+
3828
+	/**
3829
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3830
+	 *
3831
+	 * @param array $data array that will be assigned to template args.
3832
+	 */
3833
+	public function set_template_args($data)
3834
+	{
3835
+		$this->_template_args = array_merge($this->_template_args, (array) $data);
3836
+	}
3837
+
3838
+
3839
+	/**
3840
+	 * This makes available the WP transient system for temporarily moving data between routes
3841
+	 *
3842
+	 * @param string $route             the route that should receive the transient
3843
+	 * @param array  $data              the data that gets sent
3844
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3845
+	 *                                  normal route transient.
3846
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3847
+	 *                                  when we are adding a transient before page_routes have been defined.
3848
+	 * @return void
3849
+	 * @throws EE_Error
3850
+	 */
3851
+	protected function _add_transient($route, $data, $notices = false, $skip_route_verify = false)
3852
+	{
3853
+		$user_id = get_current_user_id();
3854
+		if (! $skip_route_verify) {
3855
+			$this->_verify_route($route);
3856
+		}
3857
+		// now let's set the string for what kind of transient we're setting
3858
+		$transient = $notices
3859
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3860
+			: 'rte_tx_' . $route . '_' . $user_id;
3861
+		$data = $notices ? array('notices' => $data) : $data;
3862
+		// is there already a transient for this route?  If there is then let's ADD to that transient
3863
+		$existing = is_multisite() && is_network_admin()
3864
+			? get_site_transient($transient)
3865
+			: get_transient($transient);
3866
+		if ($existing) {
3867
+			$data = array_merge((array) $data, (array) $existing);
3868
+		}
3869
+		if (is_multisite() && is_network_admin()) {
3870
+			set_site_transient($transient, $data, 8);
3871
+		} else {
3872
+			set_transient($transient, $data, 8);
3873
+		}
3874
+	}
3875
+
3876
+
3877
+	/**
3878
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3879
+	 *
3880
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3881
+	 * @param string $route
3882
+	 * @return mixed data
3883
+	 */
3884
+	protected function _get_transient($notices = false, $route = '')
3885
+	{
3886
+		$user_id = get_current_user_id();
3887
+		$route = ! $route ? $this->_req_action : $route;
3888
+		$transient = $notices
3889
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3890
+			: 'rte_tx_' . $route . '_' . $user_id;
3891
+		$data = is_multisite() && is_network_admin()
3892
+			? get_site_transient($transient)
3893
+			: get_transient($transient);
3894
+		// delete transient after retrieval (just in case it hasn't expired);
3895
+		if (is_multisite() && is_network_admin()) {
3896
+			delete_site_transient($transient);
3897
+		} else {
3898
+			delete_transient($transient);
3899
+		}
3900
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3901
+	}
3902
+
3903
+
3904
+	/**
3905
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3906
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3907
+	 * default route callback on the EE_Admin page you want it run.)
3908
+	 *
3909
+	 * @return void
3910
+	 */
3911
+	protected function _transient_garbage_collection()
3912
+	{
3913
+		global $wpdb;
3914
+		// retrieve all existing transients
3915
+		$query = "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3916
+		if ($results = $wpdb->get_results($query)) {
3917
+			foreach ($results as $result) {
3918
+				$transient = str_replace('_transient_', '', $result->option_name);
3919
+				get_transient($transient);
3920
+				if (is_multisite() && is_network_admin()) {
3921
+					get_site_transient($transient);
3922
+				}
3923
+			}
3924
+		}
3925
+	}
3926
+
3927
+
3928
+	/**
3929
+	 * get_view
3930
+	 *
3931
+	 * @return string content of _view property
3932
+	 */
3933
+	public function get_view()
3934
+	{
3935
+		return $this->_view;
3936
+	}
3937
+
3938
+
3939
+	/**
3940
+	 * getter for the protected $_views property
3941
+	 *
3942
+	 * @return array
3943
+	 */
3944
+	public function get_views()
3945
+	{
3946
+		return $this->_views;
3947
+	}
3948
+
3949
+
3950
+	/**
3951
+	 * get_current_page
3952
+	 *
3953
+	 * @return string _current_page property value
3954
+	 */
3955
+	public function get_current_page()
3956
+	{
3957
+		return $this->_current_page;
3958
+	}
3959
+
3960
+
3961
+	/**
3962
+	 * get_current_view
3963
+	 *
3964
+	 * @return string _current_view property value
3965
+	 */
3966
+	public function get_current_view()
3967
+	{
3968
+		return $this->_current_view;
3969
+	}
3970
+
3971
+
3972
+	/**
3973
+	 * get_current_screen
3974
+	 *
3975
+	 * @return object The current WP_Screen object
3976
+	 */
3977
+	public function get_current_screen()
3978
+	{
3979
+		return $this->_current_screen;
3980
+	}
3981
+
3982
+
3983
+	/**
3984
+	 * get_current_page_view_url
3985
+	 *
3986
+	 * @return string This returns the url for the current_page_view.
3987
+	 */
3988
+	public function get_current_page_view_url()
3989
+	{
3990
+		return $this->_current_page_view_url;
3991
+	}
3992
+
3993
+
3994
+	/**
3995
+	 * just returns the _req_data property
3996
+	 *
3997
+	 * @return array
3998
+	 */
3999
+	public function get_request_data()
4000
+	{
4001
+		return $this->_req_data;
4002
+	}
4003
+
4004
+
4005
+	/**
4006
+	 * returns the _req_data protected property
4007
+	 *
4008
+	 * @return string
4009
+	 */
4010
+	public function get_req_action()
4011
+	{
4012
+		return $this->_req_action;
4013
+	}
4014
+
4015
+
4016
+	/**
4017
+	 * @return bool  value of $_is_caf property
4018
+	 */
4019
+	public function is_caf()
4020
+	{
4021
+		return $this->_is_caf;
4022
+	}
4023
+
4024
+
4025
+	/**
4026
+	 * @return mixed
4027
+	 */
4028
+	public function default_espresso_metaboxes()
4029
+	{
4030
+		return $this->_default_espresso_metaboxes;
4031
+	}
4032
+
4033
+
4034
+	/**
4035
+	 * @return mixed
4036
+	 */
4037
+	public function admin_base_url()
4038
+	{
4039
+		return $this->_admin_base_url;
4040
+	}
4041
+
4042
+
4043
+	/**
4044
+	 * @return mixed
4045
+	 */
4046
+	public function wp_page_slug()
4047
+	{
4048
+		return $this->_wp_page_slug;
4049
+	}
4050
+
4051
+
4052
+	/**
4053
+	 * updates  espresso configuration settings
4054
+	 *
4055
+	 * @param string                   $tab
4056
+	 * @param EE_Config_Base|EE_Config $config
4057
+	 * @param string                   $file file where error occurred
4058
+	 * @param string                   $func function  where error occurred
4059
+	 * @param string                   $line line no where error occurred
4060
+	 * @return boolean
4061
+	 */
4062
+	protected function _update_espresso_configuration($tab, $config, $file = '', $func = '', $line = '')
4063
+	{
4064
+		// remove any options that are NOT going to be saved with the config settings.
4065
+		if (isset($config->core->ee_ueip_optin)) {
4066
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4067
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4068
+			update_option('ee_ueip_has_notified', true);
4069
+		}
4070
+		// and save it (note we're also doing the network save here)
4071
+		$net_saved = is_main_site() ? EE_Network_Config::instance()->update_config(false, false) : true;
4072
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4073
+		if ($config_saved && $net_saved) {
4074
+			EE_Error::add_success(sprintf(__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4075
+			return true;
4076
+		}
4077
+		EE_Error::add_error(sprintf(__('The "%s" were not updated.', 'event_espresso'), $tab), $file, $func, $line);
4078
+		return false;
4079
+	}
4080
+
4081
+
4082
+	/**
4083
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4084
+	 *
4085
+	 * @return array
4086
+	 */
4087
+	public function get_yes_no_values()
4088
+	{
4089
+		return $this->_yes_no_values;
4090
+	}
4091
+
4092
+
4093
+	/**
4094
+	 * @return string
4095
+	 * @throws ReflectionException
4096
+	 * @since $VID:$
4097
+	 */
4098
+	protected function _get_dir()
4099
+	{
4100
+		$reflector = new ReflectionClass(get_class($this));
4101
+		return dirname($reflector->getFileName());
4102
+	}
4103
+
4104
+
4105
+	/**
4106
+	 * A helper for getting a "next link".
4107
+	 *
4108
+	 * @param string $url   The url to link to
4109
+	 * @param string $class The class to use.
4110
+	 * @return string
4111
+	 */
4112
+	protected function _next_link($url, $class = 'dashicons dashicons-arrow-right')
4113
+	{
4114
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4115
+	}
4116
+
4117
+
4118
+	/**
4119
+	 * A helper for getting a "previous link".
4120
+	 *
4121
+	 * @param string $url   The url to link to
4122
+	 * @param string $class The class to use.
4123
+	 * @return string
4124
+	 */
4125
+	protected function _previous_link($url, $class = 'dashicons dashicons-arrow-left')
4126
+	{
4127
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4128
+	}
4129
+
4130
+
4131
+
4132
+
4133
+
4134
+
4135
+
4136
+	// below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4137
+
4138
+
4139
+	/**
4140
+	 * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4141
+	 * 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
4142
+	 * _req_data array.
4143
+	 *
4144
+	 * @return bool success/fail
4145
+	 * @throws EE_Error
4146
+	 * @throws InvalidArgumentException
4147
+	 * @throws ReflectionException
4148
+	 * @throws InvalidDataTypeException
4149
+	 * @throws InvalidInterfaceException
4150
+	 */
4151
+	protected function _process_resend_registration()
4152
+	{
4153
+		$this->_template_args['success'] = EED_Messages::process_resend($this->_req_data);
4154
+		do_action(
4155
+			'AHEE__EE_Admin_Page___process_resend_registration',
4156
+			$this->_template_args['success'],
4157
+			$this->_req_data
4158
+		);
4159
+		return $this->_template_args['success'];
4160
+	}
4161
+
4162
+
4163
+	/**
4164
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4165
+	 *
4166
+	 * @param EE_Payment $payment
4167
+	 * @return bool success/fail
4168
+	 */
4169
+	protected function _process_payment_notification(EE_Payment $payment)
4170
+	{
4171
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4172
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4173
+		$this->_template_args['success'] = apply_filters(
4174
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4175
+			false,
4176
+			$payment
4177
+		);
4178
+		return $this->_template_args['success'];
4179
+	}
4180 4180
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Init.core.php 2 patches
Indentation   +451 added lines, -451 removed lines patch added patch discarded remove patch
@@ -17,455 +17,455 @@
 block discarded – undo
17 17
 abstract class EE_Admin_Page_Init extends EE_Base
18 18
 {
19 19
 
20
-    /**
21
-     * @var LoaderInterface $loader
22
-     */
23
-    protected $loader;
24
-
25
-    // identity properties (set in _set_defaults and _set_init_properties)
26
-    public $label;
27
-
28
-    /**
29
-     * Menu map has a capability.  However, this allows admin pages to have separate capability requirements for menus
30
-     * and accessing pages.  If capability is NOT set, then it defaults to the menu_map capability.
31
-     *
32
-     * @var string
33
-     */
34
-    public $capability;
35
-
36
-
37
-    /**
38
-     * This holds the menu map object for this admin page.
39
-     *
40
-     * @var EE_Admin_Page_Menu_Map
41
-     */
42
-    protected $_menu_map;
43
-
44
-    /**
45
-     * deprecated
46
-     */
47
-    public $menu_label;
48
-    public $menu_slug;
49
-
50
-
51
-    // set in _set_defaults
52
-    protected $_folder_name;
53
-    protected $_folder_path;
54
-    protected $_file_name;
55
-    public $hook_file;
56
-    protected $_wp_page_slug;
57
-    protected $_routing;
58
-
59
-
60
-    /**
61
-     * This holds the page object.
62
-     *
63
-     * @var EE_Admin_Page
64
-     */
65
-    protected $_loaded_page_object;
66
-
67
-
68
-    // for caf
69
-    protected $_files_hooked;
70
-    protected $_hook_paths;
71
-
72
-    // load_page?
73
-    private $_load_page;
74
-
75
-
76
-    /**
77
-     * @throws InvalidArgumentException
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     */
81
-    public function __construct()
82
-    {
83
-        $this->loader = LoaderFactory::getLoader();
84
-        // set global defaults
85
-        $this->_set_defaults();
86
-        // set properties that are always available with objects.
87
-        $this->_set_init_properties();
88
-        // global styles/scripts across all wp admin pages
89
-        add_action('admin_enqueue_scripts', array($this, 'load_wp_global_scripts_styles'), 5);
90
-        // load initial stuff.
91
-        $this->_set_file_and_folder_name();
92
-        $this->_set_menu_map();
93
-        if (empty($this->_menu_map) || is_array($this->_menu_map)) {
94
-            EE_Error::doing_it_wrong(
95
-                get_class($this) . '::$_menu_map',
96
-                sprintf(
97
-                    __(
98
-                        'The EE4 addon with the class %s is setting up the _menu_map property incorrectly for this version of EE core.  Please see Admin_Page_Init class examples in core for the new way of setting this property up.',
99
-                        'event_espresso'
100
-                    ),
101
-                    get_class($this)
102
-                ),
103
-                '4.4.0'
104
-            );
105
-            return;
106
-        }
107
-        // set default capability
108
-        $this->_set_capability();
109
-    }
110
-
111
-
112
-    /**
113
-     * _set_init_properties
114
-     * Child classes use to set the following properties:
115
-     * $label
116
-     *
117
-     * @abstract
118
-     * @access protected
119
-     * @return void
120
-     */
121
-    abstract protected function _set_init_properties();
122
-
123
-
124
-    /**
125
-     * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of
126
-     * EE_Admin_Page_Menu_Map.  Their menu can either be EE_Admin_Page_Main_Menu or EE_Admin_Page_Sub_Menu.
127
-     *
128
-     * @since 4.4.0
129
-     * @ return void.
130
-     */
131
-    protected function _set_menu_map()
132
-    {
133
-        return array();
134
-    }
135
-
136
-
137
-    /**
138
-     * returns the menu map for this admin page
139
-     *
140
-     * @since 4.4.0
141
-     * @return EE_Admin_Page_Menu_Map
142
-     */
143
-    public function get_menu_map()
144
-    {
145
-        return $this->_menu_map;
146
-    }
147
-
148
-
149
-    /**
150
-     * This loads scripts and styles for the EE_Admin system
151
-     * that must be available on ALL WP admin pages (i.e. EE_menu items)
152
-     *
153
-     * @return void
154
-     */
155
-    public function load_wp_global_scripts_styles()
156
-    {
157
-        wp_register_style(
158
-            'espresso_menu',
159
-            EE_ADMIN_URL . 'assets/admin-menu-styles.css',
160
-            array('dashicons'),
161
-            EVENT_ESPRESSO_VERSION
162
-        );
163
-        wp_enqueue_style('espresso_menu');
164
-    }
165
-
166
-
167
-    /**
168
-     * this sets default properties (might be overridden in _set_init_properties);
169
-     *
170
-     * @access private
171
-     * @return  void
172
-     */
173
-    private function _set_defaults()
174
-    {
175
-        $this->_file_name = $this->_folder_name = $this->_wp_page_slug = $this->capability = null;
176
-        $this->_routing = true;
177
-        $this->_load_page = false;
178
-        $this->_files_hooked = $this->_hook_paths = array();
179
-        // menu_map
180
-        $this->_menu_map = $this->get_menu_map();
181
-    }
182
-
183
-
184
-    protected function _set_capability()
185
-    {
186
-        $capability = empty($this->capability) ? $this->_menu_map->capability : $this->capability;
187
-        $this->capability = apply_filters('FHEE_' . $this->_menu_map->menu_slug . '_capability', $capability);
188
-    }
189
-
190
-
191
-    /**
192
-     * initialize_admin_page
193
-     * This method is what executes the loading of the specific page class for the given dir_name as called by the
194
-     * EE_Admin_Init class.
195
-     *
196
-     * @access  public
197
-     * @return void
198
-     * @throws EE_Error
199
-     * @throws InvalidArgumentException
200
-     * @throws InvalidDataTypeException
201
-     * @throws InvalidInterfaceException
202
-     * @throws ReflectionException
203
-     * @uses    _initialize_admin_page()
204
-     */
205
-    public function initialize_admin_page()
206
-    {
207
-        // let's check user access first
208
-        $this->_check_user_access();
209
-        if (! is_object($this->_loaded_page_object)) {
210
-            return;
211
-        }
212
-        $this->_loaded_page_object->route_admin_request();
213
-    }
214
-
215
-
216
-    /**
217
-     * @param string $wp_page_slug
218
-     * @throws EE_Error
219
-     * @since $VID:$
220
-     */
221
-    public function set_page_dependencies($wp_page_slug)
222
-    {
223
-        if (! $this->_load_page) {
224
-            return;
225
-        }
226
-        if (! is_object($this->_loaded_page_object)) {
227
-            $msg[] = __(
228
-                'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
229
-                'event_espresso'
230
-            );
231
-            $msg[] = $msg[0] . "\r\n"
232
-                     . sprintf(
233
-                         __(
234
-                             'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
235
-                             'event_espresso'
236
-                         ),
237
-                         $this->_file_name,
238
-                         $this->_file_name,
239
-                         $this->_folder_path . $this->_file_name,
240
-                         $this->_menu_map->menu_slug
241
-                     );
242
-            throw new EE_Error(implode('||', $msg));
243
-        }
244
-        $this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
245
-        $page_hook = 'load-' . $wp_page_slug;
246
-        // hook into page load hook so all page specific stuff get's loaded.
247
-        if (! empty($wp_page_slug)) {
248
-            add_action($page_hook, array($this->_loaded_page_object, 'load_page_dependencies'));
249
-        }
250
-    }
251
-
252
-
253
-    /**
254
-     * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run
255
-     * before the load-page... hook. Note, the page loads are happening around the wp_init hook.
256
-     *
257
-     * @return void
258
-     * @throws EE_Error
259
-     * @throws InvalidArgumentException
260
-     * @throws InvalidDataTypeException
261
-     * @throws InvalidInterfaceException
262
-     * @throws ReflectionException
263
-     */
264
-    public function do_initial_loads()
265
-    {
266
-        // no loading or initializing if menu map is setup incorrectly.
267
-        if (empty($this->_menu_map) || is_array($this->_menu_map)) {
268
-            return;
269
-        }
270
-        $this->_initialize_admin_page();
271
-    }
272
-
273
-
274
-    /**
275
-     * all we're doing here is setting the $_file_name property for later use.
276
-     *
277
-     * @access private
278
-     * @return void
279
-     */
280
-    private function _set_file_and_folder_name()
281
-    {
282
-        $bt = debug_backtrace();
283
-        // for more reliable determination of folder name
284
-        // we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this).  Why?  Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins)
285
-        $class = get_class($this);
286
-        foreach ($bt as $index => $values) {
287
-            if (isset($values['class']) && $values['class'] === $class) {
288
-                $file_index = $index - 1;
289
-                $this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
290
-                if (! empty($this->_folder_name)) {
291
-                    break;
292
-                }
293
-            }
294
-        }
295
-        $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
296
-        $this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name);
297
-        $this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name));
298
-        $this->_file_name = str_replace(' ', '_', $this->_file_name);
299
-    }
300
-
301
-
302
-    /**
303
-     * This automatically checks if we have a hook class in the loaded child directory.  If we DO then we will register
304
-     * it with the appropriate pages.  That way all we have to do is make sure the file is named correctly and
305
-     * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do:
306
-     * events_Messages_Hooks.class.php
307
-     *
308
-     * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks
309
-     *                     files/classes
310
-     * @return array
311
-     */
312
-    public function register_hooks($extend = false)
313
-    {
314
-
315
-        // get a list of files in the directory that have the "Hook" in their name an
316
-        // if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property.  Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf.
317
-        if ($extend) {
318
-            $hook_files_glob_path = apply_filters(
319
-                'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend',
320
-                EE_CORE_CAF_ADMIN_EXTEND
321
-                . $this->_folder_name
322
-                . '/*'
323
-                . $this->_file_name
324
-                . '_Hooks_Extend.class.php'
325
-            );
326
-            $this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend);
327
-        }
328
-        // loop through decaf folders
329
-        $hook_files_glob_path = apply_filters(
330
-            'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
331
-            $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
332
-        );
333
-        $this->_hook_paths = array_merge(
334
-            $this->_register_hook_files($hook_files_glob_path),
335
-            $this->_hook_paths
336
-        );  // making sure any extended hook paths are later in the array than the core hook paths!
337
-        return $this->_hook_paths;
338
-    }
339
-
340
-
341
-    protected function _register_hook_files($hook_files_glob_path, $extend = false)
342
-    {
343
-        $hook_paths = array();
344
-        if ($hook_files = glob($hook_files_glob_path)) {
345
-            if (empty($hook_files)) {
346
-                return array();
347
-            }
348
-            foreach ($hook_files as $file) {
349
-                // lets get the linked admin.
350
-                $hook_file = $extend ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
351
-                    : str_replace($this->_folder_path, '', $file);
352
-                $replace = $extend
353
-                    ? '_' . $this->_file_name . '_Hooks_Extend.class.php'
354
-                    : '_'
355
-                      . $this->_file_name
356
-                      . '_Hooks.class.php';
357
-                $rel_admin = str_replace($replace, '', $hook_file);
358
-                $rel_admin = strtolower($rel_admin);
359
-                $hook_paths[] = $file;
360
-                // make sure we haven't already got a hook setup for this page path
361
-                if (in_array($rel_admin, $this->_files_hooked, true)) {
362
-                    continue;
363
-                }
364
-                $this->hook_file = $hook_file;
365
-                $rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin;
366
-                add_filter($rel_admin_hook, array($this, 'load_admin_hook'));
367
-                $this->_files_hooked[] = $rel_admin;
368
-            }
369
-        }
370
-        return $hook_paths;
371
-    }
372
-
373
-
374
-    public function load_admin_hook($registered_pages)
375
-    {
376
-        $this->hook_file;
377
-        $hook_file = (array) $this->hook_file;
378
-        return array_merge($hook_file, $registered_pages);
379
-    }
380
-
381
-
382
-    /**
383
-     * _initialize_admin_page
384
-     *
385
-     * @throws EE_Error
386
-     * @throws InvalidArgumentException
387
-     * @throws InvalidDataTypeException
388
-     * @throws InvalidInterfaceException
389
-     * @throws ReflectionException
390
-     * @see  initialize_admin_page() for info
391
-     */
392
-    protected function _initialize_admin_page()
393
-    {
394
-        // just check we're on right page and if not get out
395
-        if ((! isset($_REQUEST['page']) || $_REQUEST['page'] !== $this->_menu_map->menu_slug) && $this->_routing) {
396
-            return;
397
-        }
398
-        $this->_load_page = true;
399
-
400
-        // we don't need to do a page_request check here because it's only called via WP menu system.
401
-        $admin_page = $this->_file_name . '_Admin_Page';
402
-        $hook_suffix = $this->_menu_map->menu_slug . '_' . $admin_page;
403
-        $admin_page = apply_filters(
404
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$hook_suffix}",
405
-            $admin_page
406
-        );
407
-        // define requested admin page class name then load the file and instantiate
408
-        $path_to_file = str_replace(array('\\', '/'), '/', $this->_folder_path . $admin_page . '.core.php');
409
-        $path_to_file = apply_filters(
410
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$hook_suffix}",
411
-            $path_to_file
412
-        );
413
-        // so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php,
414
-        // the filter would be FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
415
-        if (is_readable($path_to_file)) {
416
-            // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
417
-            do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
418
-            do_action(
419
-                'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_' . $this->_menu_map->menu_slug
420
-            );
421
-            require_once($path_to_file);
422
-            $this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]);
423
-            $this->_loaded_page_object->initializePage();
424
-        }
425
-        do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
426
-        do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_' . $this->_menu_map->menu_slug);
427
-    }
428
-
429
-
430
-    public function get_admin_page_name()
431
-    {
432
-        return $this->_file_name . '_Admin_Page';
433
-    }
434
-
435
-
436
-    /**
437
-     * @return mixed
438
-     */
439
-    public function loaded_page_object()
440
-    {
441
-        return $this->_loaded_page_object;
442
-    }
443
-
444
-
445
-    // public function set_autoloaders($className)
446
-    // {
447
-    //     $dir_ref = array(
448
-    //         $this->_folder_path => array('core', 'class'),
449
-    //     );
450
-    //     EEH_Autoloader::try_autoload($dir_ref, $className);
451
-    // }
452
-    /**
453
-     * _check_user_access
454
-     * verifies user access for this admin page.  If no user access is available then let's gracefully exit with a
455
-     * WordPress die message.
456
-     *
457
-     * @return bool true if pass (or admin) wp_die if fail
458
-     */
459
-    private function _check_user_access()
460
-    {
461
-        if (
462
-            ! EE_Registry::instance()->CAP->current_user_can(
463
-                $this->_menu_map->capability,
464
-                $this->_menu_map->menu_slug
465
-            )
466
-        ) {
467
-            wp_die(__('You don\'t have access to this page.', 'event_espresso'), '', array('back_link' => true));
468
-        }
469
-        return true;
470
-    }
20
+	/**
21
+	 * @var LoaderInterface $loader
22
+	 */
23
+	protected $loader;
24
+
25
+	// identity properties (set in _set_defaults and _set_init_properties)
26
+	public $label;
27
+
28
+	/**
29
+	 * Menu map has a capability.  However, this allows admin pages to have separate capability requirements for menus
30
+	 * and accessing pages.  If capability is NOT set, then it defaults to the menu_map capability.
31
+	 *
32
+	 * @var string
33
+	 */
34
+	public $capability;
35
+
36
+
37
+	/**
38
+	 * This holds the menu map object for this admin page.
39
+	 *
40
+	 * @var EE_Admin_Page_Menu_Map
41
+	 */
42
+	protected $_menu_map;
43
+
44
+	/**
45
+	 * deprecated
46
+	 */
47
+	public $menu_label;
48
+	public $menu_slug;
49
+
50
+
51
+	// set in _set_defaults
52
+	protected $_folder_name;
53
+	protected $_folder_path;
54
+	protected $_file_name;
55
+	public $hook_file;
56
+	protected $_wp_page_slug;
57
+	protected $_routing;
58
+
59
+
60
+	/**
61
+	 * This holds the page object.
62
+	 *
63
+	 * @var EE_Admin_Page
64
+	 */
65
+	protected $_loaded_page_object;
66
+
67
+
68
+	// for caf
69
+	protected $_files_hooked;
70
+	protected $_hook_paths;
71
+
72
+	// load_page?
73
+	private $_load_page;
74
+
75
+
76
+	/**
77
+	 * @throws InvalidArgumentException
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 */
81
+	public function __construct()
82
+	{
83
+		$this->loader = LoaderFactory::getLoader();
84
+		// set global defaults
85
+		$this->_set_defaults();
86
+		// set properties that are always available with objects.
87
+		$this->_set_init_properties();
88
+		// global styles/scripts across all wp admin pages
89
+		add_action('admin_enqueue_scripts', array($this, 'load_wp_global_scripts_styles'), 5);
90
+		// load initial stuff.
91
+		$this->_set_file_and_folder_name();
92
+		$this->_set_menu_map();
93
+		if (empty($this->_menu_map) || is_array($this->_menu_map)) {
94
+			EE_Error::doing_it_wrong(
95
+				get_class($this) . '::$_menu_map',
96
+				sprintf(
97
+					__(
98
+						'The EE4 addon with the class %s is setting up the _menu_map property incorrectly for this version of EE core.  Please see Admin_Page_Init class examples in core for the new way of setting this property up.',
99
+						'event_espresso'
100
+					),
101
+					get_class($this)
102
+				),
103
+				'4.4.0'
104
+			);
105
+			return;
106
+		}
107
+		// set default capability
108
+		$this->_set_capability();
109
+	}
110
+
111
+
112
+	/**
113
+	 * _set_init_properties
114
+	 * Child classes use to set the following properties:
115
+	 * $label
116
+	 *
117
+	 * @abstract
118
+	 * @access protected
119
+	 * @return void
120
+	 */
121
+	abstract protected function _set_init_properties();
122
+
123
+
124
+	/**
125
+	 * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of
126
+	 * EE_Admin_Page_Menu_Map.  Their menu can either be EE_Admin_Page_Main_Menu or EE_Admin_Page_Sub_Menu.
127
+	 *
128
+	 * @since 4.4.0
129
+	 * @ return void.
130
+	 */
131
+	protected function _set_menu_map()
132
+	{
133
+		return array();
134
+	}
135
+
136
+
137
+	/**
138
+	 * returns the menu map for this admin page
139
+	 *
140
+	 * @since 4.4.0
141
+	 * @return EE_Admin_Page_Menu_Map
142
+	 */
143
+	public function get_menu_map()
144
+	{
145
+		return $this->_menu_map;
146
+	}
147
+
148
+
149
+	/**
150
+	 * This loads scripts and styles for the EE_Admin system
151
+	 * that must be available on ALL WP admin pages (i.e. EE_menu items)
152
+	 *
153
+	 * @return void
154
+	 */
155
+	public function load_wp_global_scripts_styles()
156
+	{
157
+		wp_register_style(
158
+			'espresso_menu',
159
+			EE_ADMIN_URL . 'assets/admin-menu-styles.css',
160
+			array('dashicons'),
161
+			EVENT_ESPRESSO_VERSION
162
+		);
163
+		wp_enqueue_style('espresso_menu');
164
+	}
165
+
166
+
167
+	/**
168
+	 * this sets default properties (might be overridden in _set_init_properties);
169
+	 *
170
+	 * @access private
171
+	 * @return  void
172
+	 */
173
+	private function _set_defaults()
174
+	{
175
+		$this->_file_name = $this->_folder_name = $this->_wp_page_slug = $this->capability = null;
176
+		$this->_routing = true;
177
+		$this->_load_page = false;
178
+		$this->_files_hooked = $this->_hook_paths = array();
179
+		// menu_map
180
+		$this->_menu_map = $this->get_menu_map();
181
+	}
182
+
183
+
184
+	protected function _set_capability()
185
+	{
186
+		$capability = empty($this->capability) ? $this->_menu_map->capability : $this->capability;
187
+		$this->capability = apply_filters('FHEE_' . $this->_menu_map->menu_slug . '_capability', $capability);
188
+	}
189
+
190
+
191
+	/**
192
+	 * initialize_admin_page
193
+	 * This method is what executes the loading of the specific page class for the given dir_name as called by the
194
+	 * EE_Admin_Init class.
195
+	 *
196
+	 * @access  public
197
+	 * @return void
198
+	 * @throws EE_Error
199
+	 * @throws InvalidArgumentException
200
+	 * @throws InvalidDataTypeException
201
+	 * @throws InvalidInterfaceException
202
+	 * @throws ReflectionException
203
+	 * @uses    _initialize_admin_page()
204
+	 */
205
+	public function initialize_admin_page()
206
+	{
207
+		// let's check user access first
208
+		$this->_check_user_access();
209
+		if (! is_object($this->_loaded_page_object)) {
210
+			return;
211
+		}
212
+		$this->_loaded_page_object->route_admin_request();
213
+	}
214
+
215
+
216
+	/**
217
+	 * @param string $wp_page_slug
218
+	 * @throws EE_Error
219
+	 * @since $VID:$
220
+	 */
221
+	public function set_page_dependencies($wp_page_slug)
222
+	{
223
+		if (! $this->_load_page) {
224
+			return;
225
+		}
226
+		if (! is_object($this->_loaded_page_object)) {
227
+			$msg[] = __(
228
+				'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
229
+				'event_espresso'
230
+			);
231
+			$msg[] = $msg[0] . "\r\n"
232
+					 . sprintf(
233
+						 __(
234
+							 'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
235
+							 'event_espresso'
236
+						 ),
237
+						 $this->_file_name,
238
+						 $this->_file_name,
239
+						 $this->_folder_path . $this->_file_name,
240
+						 $this->_menu_map->menu_slug
241
+					 );
242
+			throw new EE_Error(implode('||', $msg));
243
+		}
244
+		$this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
245
+		$page_hook = 'load-' . $wp_page_slug;
246
+		// hook into page load hook so all page specific stuff get's loaded.
247
+		if (! empty($wp_page_slug)) {
248
+			add_action($page_hook, array($this->_loaded_page_object, 'load_page_dependencies'));
249
+		}
250
+	}
251
+
252
+
253
+	/**
254
+	 * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run
255
+	 * before the load-page... hook. Note, the page loads are happening around the wp_init hook.
256
+	 *
257
+	 * @return void
258
+	 * @throws EE_Error
259
+	 * @throws InvalidArgumentException
260
+	 * @throws InvalidDataTypeException
261
+	 * @throws InvalidInterfaceException
262
+	 * @throws ReflectionException
263
+	 */
264
+	public function do_initial_loads()
265
+	{
266
+		// no loading or initializing if menu map is setup incorrectly.
267
+		if (empty($this->_menu_map) || is_array($this->_menu_map)) {
268
+			return;
269
+		}
270
+		$this->_initialize_admin_page();
271
+	}
272
+
273
+
274
+	/**
275
+	 * all we're doing here is setting the $_file_name property for later use.
276
+	 *
277
+	 * @access private
278
+	 * @return void
279
+	 */
280
+	private function _set_file_and_folder_name()
281
+	{
282
+		$bt = debug_backtrace();
283
+		// for more reliable determination of folder name
284
+		// we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this).  Why?  Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins)
285
+		$class = get_class($this);
286
+		foreach ($bt as $index => $values) {
287
+			if (isset($values['class']) && $values['class'] === $class) {
288
+				$file_index = $index - 1;
289
+				$this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
290
+				if (! empty($this->_folder_name)) {
291
+					break;
292
+				}
293
+			}
294
+		}
295
+		$this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
296
+		$this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name);
297
+		$this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name));
298
+		$this->_file_name = str_replace(' ', '_', $this->_file_name);
299
+	}
300
+
301
+
302
+	/**
303
+	 * This automatically checks if we have a hook class in the loaded child directory.  If we DO then we will register
304
+	 * it with the appropriate pages.  That way all we have to do is make sure the file is named correctly and
305
+	 * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do:
306
+	 * events_Messages_Hooks.class.php
307
+	 *
308
+	 * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks
309
+	 *                     files/classes
310
+	 * @return array
311
+	 */
312
+	public function register_hooks($extend = false)
313
+	{
314
+
315
+		// get a list of files in the directory that have the "Hook" in their name an
316
+		// if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property.  Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf.
317
+		if ($extend) {
318
+			$hook_files_glob_path = apply_filters(
319
+				'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend',
320
+				EE_CORE_CAF_ADMIN_EXTEND
321
+				. $this->_folder_name
322
+				. '/*'
323
+				. $this->_file_name
324
+				. '_Hooks_Extend.class.php'
325
+			);
326
+			$this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend);
327
+		}
328
+		// loop through decaf folders
329
+		$hook_files_glob_path = apply_filters(
330
+			'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
331
+			$this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
332
+		);
333
+		$this->_hook_paths = array_merge(
334
+			$this->_register_hook_files($hook_files_glob_path),
335
+			$this->_hook_paths
336
+		);  // making sure any extended hook paths are later in the array than the core hook paths!
337
+		return $this->_hook_paths;
338
+	}
339
+
340
+
341
+	protected function _register_hook_files($hook_files_glob_path, $extend = false)
342
+	{
343
+		$hook_paths = array();
344
+		if ($hook_files = glob($hook_files_glob_path)) {
345
+			if (empty($hook_files)) {
346
+				return array();
347
+			}
348
+			foreach ($hook_files as $file) {
349
+				// lets get the linked admin.
350
+				$hook_file = $extend ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
351
+					: str_replace($this->_folder_path, '', $file);
352
+				$replace = $extend
353
+					? '_' . $this->_file_name . '_Hooks_Extend.class.php'
354
+					: '_'
355
+					  . $this->_file_name
356
+					  . '_Hooks.class.php';
357
+				$rel_admin = str_replace($replace, '', $hook_file);
358
+				$rel_admin = strtolower($rel_admin);
359
+				$hook_paths[] = $file;
360
+				// make sure we haven't already got a hook setup for this page path
361
+				if (in_array($rel_admin, $this->_files_hooked, true)) {
362
+					continue;
363
+				}
364
+				$this->hook_file = $hook_file;
365
+				$rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin;
366
+				add_filter($rel_admin_hook, array($this, 'load_admin_hook'));
367
+				$this->_files_hooked[] = $rel_admin;
368
+			}
369
+		}
370
+		return $hook_paths;
371
+	}
372
+
373
+
374
+	public function load_admin_hook($registered_pages)
375
+	{
376
+		$this->hook_file;
377
+		$hook_file = (array) $this->hook_file;
378
+		return array_merge($hook_file, $registered_pages);
379
+	}
380
+
381
+
382
+	/**
383
+	 * _initialize_admin_page
384
+	 *
385
+	 * @throws EE_Error
386
+	 * @throws InvalidArgumentException
387
+	 * @throws InvalidDataTypeException
388
+	 * @throws InvalidInterfaceException
389
+	 * @throws ReflectionException
390
+	 * @see  initialize_admin_page() for info
391
+	 */
392
+	protected function _initialize_admin_page()
393
+	{
394
+		// just check we're on right page and if not get out
395
+		if ((! isset($_REQUEST['page']) || $_REQUEST['page'] !== $this->_menu_map->menu_slug) && $this->_routing) {
396
+			return;
397
+		}
398
+		$this->_load_page = true;
399
+
400
+		// we don't need to do a page_request check here because it's only called via WP menu system.
401
+		$admin_page = $this->_file_name . '_Admin_Page';
402
+		$hook_suffix = $this->_menu_map->menu_slug . '_' . $admin_page;
403
+		$admin_page = apply_filters(
404
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$hook_suffix}",
405
+			$admin_page
406
+		);
407
+		// define requested admin page class name then load the file and instantiate
408
+		$path_to_file = str_replace(array('\\', '/'), '/', $this->_folder_path . $admin_page . '.core.php');
409
+		$path_to_file = apply_filters(
410
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$hook_suffix}",
411
+			$path_to_file
412
+		);
413
+		// so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php,
414
+		// the filter would be FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
415
+		if (is_readable($path_to_file)) {
416
+			// This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
417
+			do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
418
+			do_action(
419
+				'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_' . $this->_menu_map->menu_slug
420
+			);
421
+			require_once($path_to_file);
422
+			$this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]);
423
+			$this->_loaded_page_object->initializePage();
424
+		}
425
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
426
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_' . $this->_menu_map->menu_slug);
427
+	}
428
+
429
+
430
+	public function get_admin_page_name()
431
+	{
432
+		return $this->_file_name . '_Admin_Page';
433
+	}
434
+
435
+
436
+	/**
437
+	 * @return mixed
438
+	 */
439
+	public function loaded_page_object()
440
+	{
441
+		return $this->_loaded_page_object;
442
+	}
443
+
444
+
445
+	// public function set_autoloaders($className)
446
+	// {
447
+	//     $dir_ref = array(
448
+	//         $this->_folder_path => array('core', 'class'),
449
+	//     );
450
+	//     EEH_Autoloader::try_autoload($dir_ref, $className);
451
+	// }
452
+	/**
453
+	 * _check_user_access
454
+	 * verifies user access for this admin page.  If no user access is available then let's gracefully exit with a
455
+	 * WordPress die message.
456
+	 *
457
+	 * @return bool true if pass (or admin) wp_die if fail
458
+	 */
459
+	private function _check_user_access()
460
+	{
461
+		if (
462
+			! EE_Registry::instance()->CAP->current_user_can(
463
+				$this->_menu_map->capability,
464
+				$this->_menu_map->menu_slug
465
+			)
466
+		) {
467
+			wp_die(__('You don\'t have access to this page.', 'event_espresso'), '', array('back_link' => true));
468
+		}
469
+		return true;
470
+	}
471 471
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
         $this->_set_menu_map();
93 93
         if (empty($this->_menu_map) || is_array($this->_menu_map)) {
94 94
             EE_Error::doing_it_wrong(
95
-                get_class($this) . '::$_menu_map',
95
+                get_class($this).'::$_menu_map',
96 96
                 sprintf(
97 97
                     __(
98 98
                         'The EE4 addon with the class %s is setting up the _menu_map property incorrectly for this version of EE core.  Please see Admin_Page_Init class examples in core for the new way of setting this property up.',
@@ -156,7 +156,7 @@  discard block
 block discarded – undo
156 156
     {
157 157
         wp_register_style(
158 158
             'espresso_menu',
159
-            EE_ADMIN_URL . 'assets/admin-menu-styles.css',
159
+            EE_ADMIN_URL.'assets/admin-menu-styles.css',
160 160
             array('dashicons'),
161 161
             EVENT_ESPRESSO_VERSION
162 162
         );
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
     protected function _set_capability()
185 185
     {
186 186
         $capability = empty($this->capability) ? $this->_menu_map->capability : $this->capability;
187
-        $this->capability = apply_filters('FHEE_' . $this->_menu_map->menu_slug . '_capability', $capability);
187
+        $this->capability = apply_filters('FHEE_'.$this->_menu_map->menu_slug.'_capability', $capability);
188 188
     }
189 189
 
190 190
 
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
     {
207 207
         // let's check user access first
208 208
         $this->_check_user_access();
209
-        if (! is_object($this->_loaded_page_object)) {
209
+        if ( ! is_object($this->_loaded_page_object)) {
210 210
             return;
211 211
         }
212 212
         $this->_loaded_page_object->route_admin_request();
@@ -220,15 +220,15 @@  discard block
 block discarded – undo
220 220
      */
221 221
     public function set_page_dependencies($wp_page_slug)
222 222
     {
223
-        if (! $this->_load_page) {
223
+        if ( ! $this->_load_page) {
224 224
             return;
225 225
         }
226
-        if (! is_object($this->_loaded_page_object)) {
226
+        if ( ! is_object($this->_loaded_page_object)) {
227 227
             $msg[] = __(
228 228
                 'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
229 229
                 'event_espresso'
230 230
             );
231
-            $msg[] = $msg[0] . "\r\n"
231
+            $msg[] = $msg[0]."\r\n"
232 232
                      . sprintf(
233 233
                          __(
234 234
                              'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
@@ -236,15 +236,15 @@  discard block
 block discarded – undo
236 236
                          ),
237 237
                          $this->_file_name,
238 238
                          $this->_file_name,
239
-                         $this->_folder_path . $this->_file_name,
239
+                         $this->_folder_path.$this->_file_name,
240 240
                          $this->_menu_map->menu_slug
241 241
                      );
242 242
             throw new EE_Error(implode('||', $msg));
243 243
         }
244 244
         $this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
245
-        $page_hook = 'load-' . $wp_page_slug;
245
+        $page_hook = 'load-'.$wp_page_slug;
246 246
         // hook into page load hook so all page specific stuff get's loaded.
247
-        if (! empty($wp_page_slug)) {
247
+        if ( ! empty($wp_page_slug)) {
248 248
             add_action($page_hook, array($this->_loaded_page_object, 'load_page_dependencies'));
249 249
         }
250 250
     }
@@ -286,13 +286,13 @@  discard block
 block discarded – undo
286 286
         foreach ($bt as $index => $values) {
287 287
             if (isset($values['class']) && $values['class'] === $class) {
288 288
                 $file_index = $index - 1;
289
-                $this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
290
-                if (! empty($this->_folder_name)) {
289
+                $this->_folder_name = basename(dirname($bt[$file_index]['file']));
290
+                if ( ! empty($this->_folder_name)) {
291 291
                     break;
292 292
                 }
293 293
             }
294 294
         }
295
-        $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
295
+        $this->_folder_path = EE_ADMIN_PAGES.$this->_folder_name.'/';
296 296
         $this->_file_name = preg_replace('/^ee/', 'EE', $this->_folder_name);
297 297
         $this->_file_name = ucwords(str_replace('_', ' ', $this->_file_name));
298 298
         $this->_file_name = str_replace(' ', '_', $this->_file_name);
@@ -328,12 +328,12 @@  discard block
 block discarded – undo
328 328
         // loop through decaf folders
329 329
         $hook_files_glob_path = apply_filters(
330 330
             'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
331
-            $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
331
+            $this->_folder_path.'*'.$this->_file_name.'_Hooks.class.php'
332 332
         );
333 333
         $this->_hook_paths = array_merge(
334 334
             $this->_register_hook_files($hook_files_glob_path),
335 335
             $this->_hook_paths
336
-        );  // making sure any extended hook paths are later in the array than the core hook paths!
336
+        ); // making sure any extended hook paths are later in the array than the core hook paths!
337 337
         return $this->_hook_paths;
338 338
     }
339 339
 
@@ -347,10 +347,10 @@  discard block
 block discarded – undo
347 347
             }
348 348
             foreach ($hook_files as $file) {
349 349
                 // lets get the linked admin.
350
-                $hook_file = $extend ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
350
+                $hook_file = $extend ? str_replace(EE_CORE_CAF_ADMIN_EXTEND.$this->_folder_name.'/', '', $file)
351 351
                     : str_replace($this->_folder_path, '', $file);
352 352
                 $replace = $extend
353
-                    ? '_' . $this->_file_name . '_Hooks_Extend.class.php'
353
+                    ? '_'.$this->_file_name.'_Hooks_Extend.class.php'
354 354
                     : '_'
355 355
                       . $this->_file_name
356 356
                       . '_Hooks.class.php';
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
                     continue;
363 363
                 }
364 364
                 $this->hook_file = $hook_file;
365
-                $rel_admin_hook = 'FHEE_do_other_page_hooks_' . $rel_admin;
365
+                $rel_admin_hook = 'FHEE_do_other_page_hooks_'.$rel_admin;
366 366
                 add_filter($rel_admin_hook, array($this, 'load_admin_hook'));
367 367
                 $this->_files_hooked[] = $rel_admin;
368 368
             }
@@ -392,20 +392,20 @@  discard block
 block discarded – undo
392 392
     protected function _initialize_admin_page()
393 393
     {
394 394
         // just check we're on right page and if not get out
395
-        if ((! isset($_REQUEST['page']) || $_REQUEST['page'] !== $this->_menu_map->menu_slug) && $this->_routing) {
395
+        if (( ! isset($_REQUEST['page']) || $_REQUEST['page'] !== $this->_menu_map->menu_slug) && $this->_routing) {
396 396
             return;
397 397
         }
398 398
         $this->_load_page = true;
399 399
 
400 400
         // we don't need to do a page_request check here because it's only called via WP menu system.
401
-        $admin_page = $this->_file_name . '_Admin_Page';
402
-        $hook_suffix = $this->_menu_map->menu_slug . '_' . $admin_page;
401
+        $admin_page = $this->_file_name.'_Admin_Page';
402
+        $hook_suffix = $this->_menu_map->menu_slug.'_'.$admin_page;
403 403
         $admin_page = apply_filters(
404 404
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__{$hook_suffix}",
405 405
             $admin_page
406 406
         );
407 407
         // define requested admin page class name then load the file and instantiate
408
-        $path_to_file = str_replace(array('\\', '/'), '/', $this->_folder_path . $admin_page . '.core.php');
408
+        $path_to_file = str_replace(array('\\', '/'), '/', $this->_folder_path.$admin_page.'.core.php');
409 409
         $path_to_file = apply_filters(
410 410
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__{$hook_suffix}",
411 411
             $path_to_file
@@ -416,20 +416,20 @@  discard block
 block discarded – undo
416 416
             // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
417 417
             do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
418 418
             do_action(
419
-                'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_' . $this->_menu_map->menu_slug
419
+                'AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_'.$this->_menu_map->menu_slug
420 420
             );
421 421
             require_once($path_to_file);
422 422
             $this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]);
423 423
             $this->_loaded_page_object->initializePage();
424 424
         }
425 425
         do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
426
-        do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_' . $this->_menu_map->menu_slug);
426
+        do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_'.$this->_menu_map->menu_slug);
427 427
     }
428 428
 
429 429
 
430 430
     public function get_admin_page_name()
431 431
     {
432
-        return $this->_file_name . '_Admin_Page';
432
+        return $this->_file_name.'_Admin_Page';
433 433
     }
434 434
 
435 435
 
Please login to merge, or discard this patch.
core/db_models/EEM_Event.model.php 1 patch
Indentation   +920 added lines, -920 removed lines patch added patch discarded remove patch
@@ -14,924 +14,924 @@
 block discarded – undo
14 14
 class EEM_Event extends EEM_CPT_Base
15 15
 {
16 16
 
17
-    /**
18
-     * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
19
-     * event
20
-     */
21
-    const sold_out = 'sold_out';
22
-
23
-    /**
24
-     * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
25
-     * date)
26
-     */
27
-    const postponed = 'postponed';
28
-
29
-    /**
30
-     * constant used by status(), indicating that the event will no longer occur
31
-     */
32
-    const cancelled = 'cancelled';
33
-
34
-
35
-    /**
36
-     * @var string
37
-     */
38
-    protected static $_default_reg_status;
39
-
40
-
41
-    /**
42
-     * This is the default for the additional limit field.
43
-     * @var int
44
-     */
45
-    protected static $_default_additional_limit = 10;
46
-
47
-
48
-    /**
49
-     * private instance of the Event object
50
-     *
51
-     * @var EEM_Event
52
-     */
53
-    protected static $_instance;
54
-
55
-
56
-    /**
57
-     * Adds a relationship to Term_Taxonomy for each CPT_Base
58
-     *
59
-     * @param string $timezone
60
-     * @throws EE_Error
61
-     * @throws ReflectionException
62
-     */
63
-    protected function __construct($timezone = null)
64
-    {
65
-        EE_Registry::instance()->load_model('Registration');
66
-        $this->singular_item = esc_html__('Event', 'event_espresso');
67
-        $this->plural_item = esc_html__('Events', 'event_espresso');
68
-        // to remove Cancelled events from the frontend, copy the following filter to your functions.php file
69
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
70
-        // to remove Postponed events from the frontend, copy the following filter to your functions.php file
71
-        // add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
72
-        // to remove Sold Out events from the frontend, copy the following filter to your functions.php file
73
-        //  add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
74
-        $this->_custom_stati = apply_filters(
75
-            'AFEE__EEM_Event__construct___custom_stati',
76
-            array(
77
-                EEM_Event::cancelled => array(
78
-                    'label'  => esc_html__('Cancelled', 'event_espresso'),
79
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
80
-                ),
81
-                EEM_Event::postponed => array(
82
-                    'label'  => esc_html__('Postponed', 'event_espresso'),
83
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
84
-                ),
85
-                EEM_Event::sold_out  => array(
86
-                    'label'  => esc_html__('Sold Out', 'event_espresso'),
87
-                    'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
88
-                ),
89
-            )
90
-        );
91
-        self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
92
-            : self::$_default_reg_status;
93
-        $this->_tables = array(
94
-            'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
95
-            'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
96
-        );
97
-        $this->_fields = array(
98
-            'Event_CPT'  => array(
99
-                'EVT_ID'         => new EE_Primary_Key_Int_Field(
100
-                    'ID',
101
-                    esc_html__('Post ID for Event', 'event_espresso')
102
-                ),
103
-                'EVT_name'       => new EE_Plain_Text_Field(
104
-                    'post_title',
105
-                    esc_html__('Event Name', 'event_espresso'),
106
-                    false,
107
-                    ''
108
-                ),
109
-                'EVT_desc'       => new EE_Post_Content_Field(
110
-                    'post_content',
111
-                    esc_html__('Event Description', 'event_espresso'),
112
-                    false,
113
-                    ''
114
-                ),
115
-                'EVT_slug'       => new EE_Slug_Field(
116
-                    'post_name',
117
-                    esc_html__('Event Slug', 'event_espresso'),
118
-                    false,
119
-                    ''
120
-                ),
121
-                'EVT_created'    => new EE_Datetime_Field(
122
-                    'post_date',
123
-                    esc_html__('Date/Time Event Created', 'event_espresso'),
124
-                    false,
125
-                    EE_Datetime_Field::now
126
-                ),
127
-                'EVT_short_desc' => new EE_Simple_HTML_Field(
128
-                    'post_excerpt',
129
-                    esc_html__('Event Short Description', 'event_espresso'),
130
-                    false,
131
-                    ''
132
-                ),
133
-                'EVT_modified'   => new EE_Datetime_Field(
134
-                    'post_modified',
135
-                    esc_html__('Date/Time Event Modified', 'event_espresso'),
136
-                    false,
137
-                    EE_Datetime_Field::now
138
-                ),
139
-                'EVT_wp_user'    => new EE_WP_User_Field(
140
-                    'post_author',
141
-                    esc_html__('Event Creator ID', 'event_espresso'),
142
-                    false
143
-                ),
144
-                'parent'         => new EE_Integer_Field(
145
-                    'post_parent',
146
-                    esc_html__('Event Parent ID', 'event_espresso'),
147
-                    false,
148
-                    0
149
-                ),
150
-                'EVT_order'      => new EE_Integer_Field(
151
-                    'menu_order',
152
-                    esc_html__('Event Menu Order', 'event_espresso'),
153
-                    false,
154
-                    1
155
-                ),
156
-                'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
157
-                // EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
158
-                'status'         => new EE_WP_Post_Status_Field(
159
-                    'post_status',
160
-                    esc_html__('Event Status', 'event_espresso'),
161
-                    false,
162
-                    'draft',
163
-                    $this->_custom_stati
164
-                ),
165
-                'password' => new EE_Password_Field(
166
-                    'post_password',
167
-                    __('Password', 'event_espresso'),
168
-                    false,
169
-                    '',
170
-                    array(
171
-                        'EVT_desc',
172
-                        'EVT_short_desc',
173
-                        'EVT_display_desc',
174
-                        'EVT_display_ticket_selector',
175
-                        'EVT_visible_on',
176
-                        'EVT_additional_limit',
177
-                        'EVT_default_registration_status',
178
-                        'EVT_member_only',
179
-                        'EVT_phone',
180
-                        'EVT_allow_overflow',
181
-                        'EVT_timezone_string',
182
-                        'EVT_external_URL',
183
-                        'EVT_donations'
184
-                    )
185
-                )
186
-            ),
187
-            'Event_Meta' => array(
188
-                'EVTM_ID'                         => new EE_DB_Only_Float_Field(
189
-                    'EVTM_ID',
190
-                    esc_html__('Event Meta Row ID', 'event_espresso'),
191
-                    false
192
-                ),
193
-                'EVT_ID_fk'                       => new EE_DB_Only_Int_Field(
194
-                    'EVT_ID',
195
-                    esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'),
196
-                    false
197
-                ),
198
-                'EVT_display_desc'                => new EE_Boolean_Field(
199
-                    'EVT_display_desc',
200
-                    esc_html__('Display Description Flag', 'event_espresso'),
201
-                    false,
202
-                    true
203
-                ),
204
-                'EVT_display_ticket_selector'     => new EE_Boolean_Field(
205
-                    'EVT_display_ticket_selector',
206
-                    esc_html__('Display Ticket Selector Flag', 'event_espresso'),
207
-                    false,
208
-                    true
209
-                ),
210
-                'EVT_visible_on'                  => new EE_Datetime_Field(
211
-                    'EVT_visible_on',
212
-                    esc_html__('Event Visible Date', 'event_espresso'),
213
-                    true,
214
-                    EE_Datetime_Field::now
215
-                ),
216
-                'EVT_additional_limit'            => new EE_Integer_Field(
217
-                    'EVT_additional_limit',
218
-                    esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
219
-                    true,
220
-                    self::$_default_additional_limit
221
-                ),
222
-                'EVT_default_registration_status' => new EE_Enum_Text_Field(
223
-                    'EVT_default_registration_status',
224
-                    esc_html__('Default Registration Status on this Event', 'event_espresso'),
225
-                    false,
226
-                    EEM_Event::$_default_reg_status,
227
-                    EEM_Registration::reg_status_array()
228
-                ),
229
-                'EVT_member_only'                 => new EE_Boolean_Field(
230
-                    'EVT_member_only',
231
-                    esc_html__('Member-Only Event Flag', 'event_espresso'),
232
-                    false,
233
-                    false
234
-                ),
235
-                'EVT_phone'                       => new EE_Plain_Text_Field(
236
-                    'EVT_phone',
237
-                    esc_html__('Event Phone Number', 'event_espresso'),
238
-                    false,
239
-                    ''
240
-                ),
241
-                'EVT_allow_overflow'              => new EE_Boolean_Field(
242
-                    'EVT_allow_overflow',
243
-                    esc_html__('Allow Overflow on Event', 'event_espresso'),
244
-                    false,
245
-                    false
246
-                ),
247
-                'EVT_timezone_string'             => new EE_Plain_Text_Field(
248
-                    'EVT_timezone_string',
249
-                    esc_html__('Timezone (name) for Event times', 'event_espresso'),
250
-                    false,
251
-                    ''
252
-                ),
253
-                'EVT_external_URL'                => new EE_Plain_Text_Field(
254
-                    'EVT_external_URL',
255
-                    esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'),
256
-                    true
257
-                ),
258
-                'EVT_donations'                   => new EE_Boolean_Field(
259
-                    'EVT_donations',
260
-                    esc_html__('Accept Donations?', 'event_espresso'),
261
-                    false,
262
-                    false
263
-                ),
264
-                'FSC_UUID'                        => new EE_Foreign_Key_String_Field(
265
-                    'FSC_UUID',
266
-                    esc_html__('Registration Form UUID (universally unique identifier)', 'event_espresso'),
267
-                    true,
268
-                    null,
269
-                    'Form_Section',
270
-                    false
271
-                ),
272
-            ),
273
-        );
274
-        $this->_model_relations = array(
275
-            'Attendee'               => new EE_HABTM_Relation('Registration'),
276
-            'Datetime'               => new EE_Has_Many_Relation(),
277
-            'Event_Question_Group'   => new EE_Has_Many_Relation(),
278
-            'Form_Section'           => new EE_Belongs_To_Relation(),
279
-            'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
280
-            'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
281
-            'Registration'           => new EE_Has_Many_Relation(),
282
-            'Term_Relationship'      => new EE_Has_Many_Relation(),
283
-            'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
284
-            'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
285
-            'WP_User'                => new EE_Belongs_To_Relation(),
286
-        );
287
-        // this model is generally available for reading
288
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
289
-        $this->model_chain_to_password = '';
290
-        parent::__construct($timezone);
291
-    }
292
-
293
-
294
-    /**
295
-     * @param string $default_reg_status
296
-     * @throws EE_Error
297
-     * @throws EE_Error
298
-     */
299
-    public static function set_default_reg_status($default_reg_status)
300
-    {
301
-        self::$_default_reg_status = $default_reg_status;
302
-        // if EEM_Event has already been instantiated,
303
-        // then we need to reset the `EVT_default_reg_status` field to use the new default.
304
-        if (self::$_instance instanceof EEM_Event) {
305
-            $default_reg_status = new EE_Enum_Text_Field(
306
-                'EVT_default_registration_status',
307
-                esc_html__('Default Registration Status on this Event', 'event_espresso'),
308
-                false,
309
-                $default_reg_status,
310
-                EEM_Registration::reg_status_array()
311
-            );
312
-            $default_reg_status->_construct_finalize(
313
-                'Event_Meta',
314
-                'EVT_default_registration_status',
315
-                'EEM_Event'
316
-            );
317
-            self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
318
-        }
319
-    }
320
-
321
-
322
-    /**
323
-     * Used to override the default for the additional limit field.
324
-     * @param $additional_limit
325
-     */
326
-    public static function set_default_additional_limit($additional_limit)
327
-    {
328
-        self::$_default_additional_limit = (int) $additional_limit;
329
-        if (self::$_instance instanceof EEM_Event) {
330
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
331
-                'EVT_additional_limit',
332
-                __('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
333
-                true,
334
-                self::$_default_additional_limit
335
-            );
336
-            self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
337
-                'Event_Meta',
338
-                'EVT_additional_limit',
339
-                'EEM_Event'
340
-            );
341
-        }
342
-    }
343
-
344
-
345
-    /**
346
-     * Return what is currently set as the default additional limit for the event.
347
-     * @return int
348
-     */
349
-    public static function get_default_additional_limit()
350
-    {
351
-        return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
352
-    }
353
-
354
-
355
-    /**
356
-     * get_question_groups
357
-     *
358
-     * @return array
359
-     * @throws EE_Error
360
-     * @throws ReflectionException
361
-     */
362
-    public function get_all_question_groups()
363
-    {
364
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
365
-            array(
366
-                array('QSG_deleted' => false),
367
-                'order_by' => array('QSG_order' => 'ASC'),
368
-            )
369
-        );
370
-    }
371
-
372
-
373
-    /**
374
-     * get_question_groups
375
-     *
376
-     * @param int $EVT_ID
377
-     * @return array|bool
378
-     * @throws EE_Error
379
-     * @throws ReflectionException
380
-     */
381
-    public function get_all_event_question_groups($EVT_ID = 0)
382
-    {
383
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
384
-            EE_Error::add_error(
385
-                esc_html__(
386
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
387
-                    'event_espresso'
388
-                ),
389
-                __FILE__,
390
-                __FUNCTION__,
391
-                __LINE__
392
-            );
393
-            return false;
394
-        }
395
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
396
-            array(
397
-                array('EVT_ID' => $EVT_ID),
398
-            )
399
-        );
400
-    }
401
-
402
-
403
-    /**
404
-     * get_question_groups
405
-     *
406
-     * @param int $EVT_ID
407
-     * @param boolean $for_primary_attendee
408
-     * @return array|bool
409
-     * @throws EE_Error
410
-     * @throws InvalidArgumentException
411
-     * @throws ReflectionException
412
-     * @throws InvalidDataTypeException
413
-     * @throws InvalidInterfaceException
414
-     */
415
-    public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
416
-    {
417
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
418
-            EE_Error::add_error(
419
-                esc_html__(
420
-                    // @codingStandardsIgnoreStart
421
-                    'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
422
-                    // @codingStandardsIgnoreEnd
423
-                    'event_espresso'
424
-                ),
425
-                __FILE__,
426
-                __FUNCTION__,
427
-                __LINE__
428
-            );
429
-            return false;
430
-        }
431
-        $query_params = [
432
-            [
433
-                'EVT_ID' => $EVT_ID,
434
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary_attendee) => true
435
-            ]
436
-        ];
437
-        if ($for_primary_attendee) {
438
-            $query_params[0]['EQG_primary'] = true;
439
-        } else {
440
-            $query_params[0]['EQG_additional'] = true;
441
-        }
442
-        return EE_Registry::instance()->load_model('Event_Question_Group')->get_all($query_params);
443
-    }
444
-
445
-
446
-    /**
447
-     * get_question_groups
448
-     *
449
-     * @param int $EVT_ID
450
-     * @param EE_Registration $registration
451
-     * @return array|bool
452
-     * @throws EE_Error
453
-     * @throws InvalidArgumentException
454
-     * @throws InvalidDataTypeException
455
-     * @throws InvalidInterfaceException
456
-     * @throws ReflectionException
457
-     */
458
-    public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
459
-    {
460
-        if (! isset($EVT_ID) || ! absint($EVT_ID)) {
461
-            EE_Error::add_error(
462
-                esc_html__(
463
-                    'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
464
-                    'event_espresso'
465
-                ),
466
-                __FILE__,
467
-                __FUNCTION__,
468
-                __LINE__
469
-            );
470
-            return false;
471
-        }
472
-        return EE_Registry::instance()->load_model('Question_Group')->get_all(
473
-            [
474
-                [
475
-                    'Event_Question_Group.EVT_ID'      => $EVT_ID,
476
-                    'Event_Question_Group.'
477
-                        . EEM_Event_Question_Group::instance()->fieldNameForContext(
478
-                            $registration->is_primary_registrant()
479
-                        ) => true
480
-                ],
481
-                'order_by' => ['QSG_order' => 'ASC'],
482
-            ]
483
-        );
484
-    }
485
-
486
-
487
-    /**
488
-     * get_question_target_db_column
489
-     *
490
-     * @param string $QSG_IDs csv list of $QSG IDs
491
-     * @return array|bool
492
-     * @throws EE_Error
493
-     * @throws ReflectionException
494
-     */
495
-    public function get_questions_in_groups($QSG_IDs = '')
496
-    {
497
-        if (empty($QSG_IDs)) {
498
-            EE_Error::add_error(
499
-                esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
500
-                __FILE__,
501
-                __FUNCTION__,
502
-                __LINE__
503
-            );
504
-            return false;
505
-        }
506
-        return EE_Registry::instance()->load_model('Question')->get_all(
507
-            array(
508
-                array(
509
-                    'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
510
-                    'QST_deleted'           => false,
511
-                    'QST_admin_only'        => is_admin(),
512
-                ),
513
-                'order_by' => 'QST_order',
514
-            )
515
-        );
516
-    }
517
-
518
-
519
-    /**
520
-     * get_options_for_question
521
-     *
522
-     * @param string $QST_IDs csv list of $QST IDs
523
-     * @return array|bool
524
-     * @throws EE_Error
525
-     * @throws ReflectionException
526
-     */
527
-    public function get_options_for_question($QST_IDs)
528
-    {
529
-        if (empty($QST_IDs)) {
530
-            EE_Error::add_error(
531
-                esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
532
-                __FILE__,
533
-                __FUNCTION__,
534
-                __LINE__
535
-            );
536
-            return false;
537
-        }
538
-        return EE_Registry::instance()->load_model('Question_Option')->get_all(
539
-            array(
540
-                array(
541
-                    'Question.QST_ID' => array('IN', $QST_IDs),
542
-                    'QSO_deleted'     => false,
543
-                ),
544
-                'order_by' => 'QSO_ID',
545
-            )
546
-        );
547
-    }
548
-
549
-
550
-    /**
551
-     * Gets all events that are published
552
-     * and have event start time earlier than now and an event end time later than now
553
-     *
554
-     * @param array $query_params  An array of query params to further filter on
555
-     *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
556
-     * @param bool  $count         whether to return the count or not (default FALSE)
557
-     * @return EE_Event[]|int
558
-     * @throws EE_Error
559
-     * @throws ReflectionException
560
-     */
561
-    public function get_active_events($query_params, $count = false)
562
-    {
563
-        if (array_key_exists(0, $query_params)) {
564
-            $where_params = $query_params[0];
565
-            unset($query_params[0]);
566
-        } else {
567
-            $where_params = array();
568
-        }
569
-        // if we have count make sure we don't include group by
570
-        if ($count && isset($query_params['group_by'])) {
571
-            unset($query_params['group_by']);
572
-        }
573
-        // let's add specific query_params for active_events
574
-        // keep in mind this will override any sent status in the query AND any date queries.
575
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
576
-        // if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
577
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
578
-            $where_params['Datetime.DTT_EVT_start******'] = array(
579
-                '<',
580
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
581
-            );
582
-        } else {
583
-            $where_params['Datetime.DTT_EVT_start'] = array(
584
-                '<',
585
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
586
-            );
587
-        }
588
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
589
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
590
-                '>',
591
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
592
-            );
593
-        } else {
594
-            $where_params['Datetime.DTT_EVT_end'] = array(
595
-                '>',
596
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
597
-            );
598
-        }
599
-        $query_params[0] = $where_params;
600
-        // don't use $query_params with count()
601
-        // because we don't want to include additional query clauses like "GROUP BY"
602
-        return $count
603
-            ? $this->count(array($where_params), 'EVT_ID', true)
604
-            : $this->get_all($query_params);
605
-    }
606
-
607
-
608
-    /**
609
-     * get all events that are published and have an event start time later than now
610
-     *
611
-     * @param array $query_params  An array of query params to further filter on
612
-     *                             (Note that status and DTT_EVT_start will be overridden)
613
-     * @param bool  $count         whether to return the count or not (default FALSE)
614
-     * @return EE_Event[]|int
615
-     * @throws EE_Error
616
-     * @throws ReflectionException
617
-     */
618
-    public function get_upcoming_events($query_params, $count = false)
619
-    {
620
-        if (array_key_exists(0, $query_params)) {
621
-            $where_params = $query_params[0];
622
-            unset($query_params[0]);
623
-        } else {
624
-            $where_params = array();
625
-        }
626
-        // if we have count make sure we don't include group by
627
-        if ($count && isset($query_params['group_by'])) {
628
-            unset($query_params['group_by']);
629
-        }
630
-        // let's add specific query_params for active_events
631
-        // keep in mind this will override any sent status in the query AND any date queries.
632
-        // we need to pull events with a status of publish and sold_out
633
-        $event_status = array('publish', EEM_Event::sold_out);
634
-        // check if the user can read private events and if so add the 'private status to the were params'
635
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_upcoming_events')) {
636
-            $event_status[] = 'private';
637
-        }
638
-        $where_params['status'] = array('IN', $event_status);
639
-        // if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
640
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
641
-            $where_params['Datetime.DTT_EVT_start*****'] = array(
642
-                '>',
643
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
644
-            );
645
-        } else {
646
-            $where_params['Datetime.DTT_EVT_start'] = array(
647
-                '>',
648
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
649
-            );
650
-        }
651
-        $query_params[0] = $where_params;
652
-        // don't use $query_params with count()
653
-        // because we don't want to include additional query clauses like "GROUP BY"
654
-        return $count
655
-            ? $this->count(array($where_params), 'EVT_ID', true)
656
-            : $this->get_all($query_params);
657
-    }
658
-
659
-
660
-    /**
661
-     * Gets all events that are published
662
-     * and have an event end time later than now
663
-     *
664
-     * @param array $query_params  An array of query params to further filter on
665
-     *                             (note that status and DTT_EVT_end will be overridden)
666
-     * @param bool  $count         whether to return the count or not (default FALSE)
667
-     * @return EE_Event[]|int
668
-     * @throws EE_Error
669
-     * @throws ReflectionException
670
-     */
671
-    public function get_active_and_upcoming_events($query_params, $count = false)
672
-    {
673
-        if (array_key_exists(0, $query_params)) {
674
-            $where_params = $query_params[0];
675
-            unset($query_params[0]);
676
-        } else {
677
-            $where_params = array();
678
-        }
679
-        // if we have count make sure we don't include group by
680
-        if ($count && isset($query_params['group_by'])) {
681
-            unset($query_params['group_by']);
682
-        }
683
-        // let's add specific query_params for active_events
684
-        // keep in mind this will override any sent status in the query AND any date queries.
685
-        $where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
686
-        // add where params for DTT_EVT_end
687
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
688
-            $where_params['Datetime.DTT_EVT_end*****'] = array(
689
-                '>',
690
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
691
-            );
692
-        } else {
693
-            $where_params['Datetime.DTT_EVT_end'] = array(
694
-                '>',
695
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
696
-            );
697
-        }
698
-        $query_params[0] = $where_params;
699
-        // don't use $query_params with count()
700
-        // because we don't want to include additional query clauses like "GROUP BY"
701
-        return $count
702
-            ? $this->count(array($where_params), 'EVT_ID', true)
703
-            : $this->get_all($query_params);
704
-    }
705
-
706
-
707
-    /**
708
-     * This only returns events that are expired.
709
-     * They may still be published but all their datetimes have expired.
710
-     *
711
-     * @param array $query_params  An array of query params to further filter on
712
-     *                             (note that status and DTT_EVT_end will be overridden)
713
-     * @param bool  $count         whether to return the count or not (default FALSE)
714
-     * @return EE_Event[]|int
715
-     * @throws EE_Error
716
-     * @throws ReflectionException
717
-     */
718
-    public function get_expired_events($query_params, $count = false)
719
-    {
720
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
721
-        // if we have count make sure we don't include group by
722
-        if ($count && isset($query_params['group_by'])) {
723
-            unset($query_params['group_by']);
724
-        }
725
-        // let's add specific query_params for active_events
726
-        // keep in mind this will override any sent status in the query AND any date queries.
727
-        if (isset($where_params['status'])) {
728
-            unset($where_params['status']);
729
-        }
730
-        $exclude_query = $query_params;
731
-        if (isset($exclude_query[0])) {
732
-            unset($exclude_query[0]);
733
-        }
734
-        $exclude_query[0] = array(
735
-            'Datetime.DTT_EVT_end' => array(
736
-                '>',
737
-                EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
738
-            ),
739
-        );
740
-        // first get all events that have datetimes where its not expired.
741
-        $event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
742
-        $event_ids = array_keys($event_ids);
743
-        // if we have any additional query_params, let's add them to the 'AND' condition
744
-        $and_condition = array(
745
-            'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
746
-            'EVT_ID'               => array('NOT IN', $event_ids),
747
-        );
748
-        if (isset($where_params['OR'])) {
749
-            $and_condition['OR'] = $where_params['OR'];
750
-            unset($where_params['OR']);
751
-        }
752
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
753
-            $and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
754
-            unset($where_params['Datetime.DTT_EVT_end']);
755
-        }
756
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
757
-            $and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
758
-            unset($where_params['Datetime.DTT_EVT_start']);
759
-        }
760
-        // merge remaining $where params with the and conditions.
761
-        $where_params['AND'] = array_merge($and_condition, $where_params);
762
-        $query_params[0] = $where_params;
763
-        // don't use $query_params with count()
764
-        // because we don't want to include additional query clauses like "GROUP BY"
765
-        return $count
766
-            ? $this->count(array($where_params), 'EVT_ID', true)
767
-            : $this->get_all($query_params);
768
-    }
769
-
770
-
771
-
772
-    /**
773
-     * This basically just returns the events that do not have the publish status.
774
-     *
775
-     * @param  array   $query_params An array of query params to further filter on
776
-     *                               (note that status will be overwritten)
777
-     * @param  boolean $count        whether to return the count or not (default FALSE)
778
-     * @return EE_Event[]|int
779
-     * @throws EE_Error
780
-     */
781
-    public function get_inactive_events($query_params, $count = false)
782
-    {
783
-        $where_params = isset($query_params[0]) ? $query_params[0] : array();
784
-        // let's add in specific query_params for inactive events.
785
-        if (isset($where_params['status'])) {
786
-            unset($where_params['status']);
787
-        }
788
-        // if we have count make sure we don't include group by
789
-        if ($count && isset($query_params['group_by'])) {
790
-            unset($query_params['group_by']);
791
-        }
792
-        // if we have any additional query_params, let's add them to the 'AND' condition
793
-        $where_params['AND']['status'] = array('!=', 'publish');
794
-        if (isset($where_params['OR'])) {
795
-            $where_params['AND']['OR'] = $where_params['OR'];
796
-            unset($where_params['OR']);
797
-        }
798
-        if (isset($where_params['Datetime.DTT_EVT_end'])) {
799
-            $where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
800
-            unset($where_params['Datetime.DTT_EVT_end']);
801
-        }
802
-        if (isset($where_params['Datetime.DTT_EVT_start'])) {
803
-            $where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
804
-            unset($where_params['Datetime.DTT_EVT_start']);
805
-        }
806
-        $query_params[0] = $where_params;
807
-        // don't use $query_params with count()
808
-        // because we don't want to include additional query clauses like "GROUP BY"
809
-        return $count
810
-            ? $this->count(array($where_params), 'EVT_ID', true)
811
-            : $this->get_all($query_params);
812
-    }
813
-
814
-
815
-    /**
816
-     * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
817
-     * because we don't want to override any existing global default prices but instead insert NEW prices that get
818
-     * attached to the event. See parent for param descriptions
819
-     *
820
-     * @param        $id_or_obj
821
-     * @param        $other_model_id_or_obj
822
-     * @param string $relationName
823
-     * @param array  $where_query
824
-     * @return EE_Base_Class
825
-     * @throws EE_Error
826
-     * @throws ReflectionException
827
-     */
828
-    public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
829
-    {
830
-        if ($relationName === 'Price') {
831
-            // let's get the PRC object for the given ID to make sure that we aren't dealing with a default
832
-            $prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
833
-            // if EVT_ID = 0, then this is a default
834
-            if ((int) $prc_chk->get('EVT_ID') === 0) {
835
-                // let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
836
-                $prc_chk->set('PRC_ID', 0);
837
-            }
838
-            // run parent
839
-            return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
840
-        }
841
-        // otherwise carry on as normal
842
-        return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
843
-    }
844
-
845
-
846
-
847
-    /******************** DEPRECATED METHODS ********************/
848
-
849
-
850
-    /**
851
-     * _get_question_target_db_column
852
-     *
853
-     * @param EE_Registration $registration    (so existing answers for registration are included)
854
-     * @param int             $EVT_ID          so all question groups are included for event (not just answers from
855
-     *                                         registration).
856
-     * @return    array
857
-     * @throws ReflectionException
858
-     * @throws EE_Error*@deprecated as of 4.8.32.rc.001. Instead consider using
859
-     *                                         EE_Registration_Custom_Questions_Form located in
860
-     *                                         admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
861
-     * @access     public
862
-     */
863
-    public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
864
-    {
865
-        if (empty($EVT_ID)) {
866
-            throw new EE_Error(__(
867
-                'An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
868
-                'event_espresso'
869
-            ));
870
-        }
871
-        $questions = array();
872
-        // get all question groups for event
873
-        $qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
874
-        if (! empty($qgs)) {
875
-            foreach ($qgs as $qg) {
876
-                $qsts = $qg->questions();
877
-                $questions[ $qg->ID() ] = $qg->model_field_array();
878
-                $questions[ $qg->ID() ]['QSG_questions'] = array();
879
-                foreach ($qsts as $qst) {
880
-                    if ($qst->is_system_question()) {
881
-                        continue;
882
-                    }
883
-                    $answer = EEM_Answer::instance()->get_one(array(
884
-                        array(
885
-                            'QST_ID' => $qst->ID(),
886
-                            'REG_ID' => $registration->ID(),
887
-                        ),
888
-                    ));
889
-                    $answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
890
-                    $qst_name = $qstn_id = $qst->ID();
891
-                    $ans_id = $answer->ID();
892
-                    $qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
893
-                    $input_name = '';
894
-                    $input_id = sanitize_key($qst->display_text());
895
-                    $input_class = '';
896
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ] = $qst->model_field_array();
897
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn'
898
-                                                                                           . $input_name
899
-                                                                                           . $qst_name;
900
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
901
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
902
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
903
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
904
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
905
-                    // leave responses as-is, don't convert stuff into html entities please!
906
-                    $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['htmlentities'] = false;
907
-                    if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
908
-                        $QSOs = $qst->options(true, $answer->value());
909
-                        if (is_array($QSOs)) {
910
-                            foreach ($QSOs as $QSO_ID => $QSO) {
911
-                                $questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
912
-                            }
913
-                        }
914
-                    }
915
-                }
916
-            }
917
-        }
918
-        return $questions;
919
-    }
920
-
921
-
922
-    /**
923
-     * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
924
-     *                             or an stdClass where each property is the name of a column,
925
-     * @return EE_Base_Class
926
-     * @throws EE_Error
927
-     */
928
-    public function instantiate_class_from_array_or_object($cols_n_values)
929
-    {
930
-        $classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
931
-        if ($classInstance instanceof EE_Event) {
932
-            // events have their timezone defined in the DB, so use it immediately
933
-            $this->set_timezone($classInstance->get_timezone());
934
-        }
935
-        return $classInstance;
936
-    }
17
+	/**
18
+	 * constant used by status(), indicating that no more tickets can be purchased for any of the datetimes for the
19
+	 * event
20
+	 */
21
+	const sold_out = 'sold_out';
22
+
23
+	/**
24
+	 * constant used by status(), indicating that upcoming event dates have been postponed (may be pushed to a later
25
+	 * date)
26
+	 */
27
+	const postponed = 'postponed';
28
+
29
+	/**
30
+	 * constant used by status(), indicating that the event will no longer occur
31
+	 */
32
+	const cancelled = 'cancelled';
33
+
34
+
35
+	/**
36
+	 * @var string
37
+	 */
38
+	protected static $_default_reg_status;
39
+
40
+
41
+	/**
42
+	 * This is the default for the additional limit field.
43
+	 * @var int
44
+	 */
45
+	protected static $_default_additional_limit = 10;
46
+
47
+
48
+	/**
49
+	 * private instance of the Event object
50
+	 *
51
+	 * @var EEM_Event
52
+	 */
53
+	protected static $_instance;
54
+
55
+
56
+	/**
57
+	 * Adds a relationship to Term_Taxonomy for each CPT_Base
58
+	 *
59
+	 * @param string $timezone
60
+	 * @throws EE_Error
61
+	 * @throws ReflectionException
62
+	 */
63
+	protected function __construct($timezone = null)
64
+	{
65
+		EE_Registry::instance()->load_model('Registration');
66
+		$this->singular_item = esc_html__('Event', 'event_espresso');
67
+		$this->plural_item = esc_html__('Events', 'event_espresso');
68
+		// to remove Cancelled events from the frontend, copy the following filter to your functions.php file
69
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__cancelled__Public', '__return_false' );
70
+		// to remove Postponed events from the frontend, copy the following filter to your functions.php file
71
+		// add_filter( 'AFEE__EEM_Event__construct___custom_stati__postponed__Public', '__return_false' );
72
+		// to remove Sold Out events from the frontend, copy the following filter to your functions.php file
73
+		//  add_filter( 'AFEE__EEM_Event__construct___custom_stati__sold_out__Public', '__return_false' );
74
+		$this->_custom_stati = apply_filters(
75
+			'AFEE__EEM_Event__construct___custom_stati',
76
+			array(
77
+				EEM_Event::cancelled => array(
78
+					'label'  => esc_html__('Cancelled', 'event_espresso'),
79
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__cancelled__Public', true),
80
+				),
81
+				EEM_Event::postponed => array(
82
+					'label'  => esc_html__('Postponed', 'event_espresso'),
83
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__postponed__Public', true),
84
+				),
85
+				EEM_Event::sold_out  => array(
86
+					'label'  => esc_html__('Sold Out', 'event_espresso'),
87
+					'public' => apply_filters('AFEE__EEM_Event__construct___custom_stati__sold_out__Public', true),
88
+				),
89
+			)
90
+		);
91
+		self::$_default_reg_status = empty(self::$_default_reg_status) ? EEM_Registration::status_id_pending_payment
92
+			: self::$_default_reg_status;
93
+		$this->_tables = array(
94
+			'Event_CPT'  => new EE_Primary_Table('posts', 'ID'),
95
+			'Event_Meta' => new EE_Secondary_Table('esp_event_meta', 'EVTM_ID', 'EVT_ID'),
96
+		);
97
+		$this->_fields = array(
98
+			'Event_CPT'  => array(
99
+				'EVT_ID'         => new EE_Primary_Key_Int_Field(
100
+					'ID',
101
+					esc_html__('Post ID for Event', 'event_espresso')
102
+				),
103
+				'EVT_name'       => new EE_Plain_Text_Field(
104
+					'post_title',
105
+					esc_html__('Event Name', 'event_espresso'),
106
+					false,
107
+					''
108
+				),
109
+				'EVT_desc'       => new EE_Post_Content_Field(
110
+					'post_content',
111
+					esc_html__('Event Description', 'event_espresso'),
112
+					false,
113
+					''
114
+				),
115
+				'EVT_slug'       => new EE_Slug_Field(
116
+					'post_name',
117
+					esc_html__('Event Slug', 'event_espresso'),
118
+					false,
119
+					''
120
+				),
121
+				'EVT_created'    => new EE_Datetime_Field(
122
+					'post_date',
123
+					esc_html__('Date/Time Event Created', 'event_espresso'),
124
+					false,
125
+					EE_Datetime_Field::now
126
+				),
127
+				'EVT_short_desc' => new EE_Simple_HTML_Field(
128
+					'post_excerpt',
129
+					esc_html__('Event Short Description', 'event_espresso'),
130
+					false,
131
+					''
132
+				),
133
+				'EVT_modified'   => new EE_Datetime_Field(
134
+					'post_modified',
135
+					esc_html__('Date/Time Event Modified', 'event_espresso'),
136
+					false,
137
+					EE_Datetime_Field::now
138
+				),
139
+				'EVT_wp_user'    => new EE_WP_User_Field(
140
+					'post_author',
141
+					esc_html__('Event Creator ID', 'event_espresso'),
142
+					false
143
+				),
144
+				'parent'         => new EE_Integer_Field(
145
+					'post_parent',
146
+					esc_html__('Event Parent ID', 'event_espresso'),
147
+					false,
148
+					0
149
+				),
150
+				'EVT_order'      => new EE_Integer_Field(
151
+					'menu_order',
152
+					esc_html__('Event Menu Order', 'event_espresso'),
153
+					false,
154
+					1
155
+				),
156
+				'post_type'      => new EE_WP_Post_Type_Field('espresso_events'),
157
+				// EE_Plain_Text_Field( 'post_type', esc_html__( 'Event Post Type', 'event_espresso' ), FALSE, 'espresso_events' ),
158
+				'status'         => new EE_WP_Post_Status_Field(
159
+					'post_status',
160
+					esc_html__('Event Status', 'event_espresso'),
161
+					false,
162
+					'draft',
163
+					$this->_custom_stati
164
+				),
165
+				'password' => new EE_Password_Field(
166
+					'post_password',
167
+					__('Password', 'event_espresso'),
168
+					false,
169
+					'',
170
+					array(
171
+						'EVT_desc',
172
+						'EVT_short_desc',
173
+						'EVT_display_desc',
174
+						'EVT_display_ticket_selector',
175
+						'EVT_visible_on',
176
+						'EVT_additional_limit',
177
+						'EVT_default_registration_status',
178
+						'EVT_member_only',
179
+						'EVT_phone',
180
+						'EVT_allow_overflow',
181
+						'EVT_timezone_string',
182
+						'EVT_external_URL',
183
+						'EVT_donations'
184
+					)
185
+				)
186
+			),
187
+			'Event_Meta' => array(
188
+				'EVTM_ID'                         => new EE_DB_Only_Float_Field(
189
+					'EVTM_ID',
190
+					esc_html__('Event Meta Row ID', 'event_espresso'),
191
+					false
192
+				),
193
+				'EVT_ID_fk'                       => new EE_DB_Only_Int_Field(
194
+					'EVT_ID',
195
+					esc_html__('Foreign key to Event ID from Event Meta table', 'event_espresso'),
196
+					false
197
+				),
198
+				'EVT_display_desc'                => new EE_Boolean_Field(
199
+					'EVT_display_desc',
200
+					esc_html__('Display Description Flag', 'event_espresso'),
201
+					false,
202
+					true
203
+				),
204
+				'EVT_display_ticket_selector'     => new EE_Boolean_Field(
205
+					'EVT_display_ticket_selector',
206
+					esc_html__('Display Ticket Selector Flag', 'event_espresso'),
207
+					false,
208
+					true
209
+				),
210
+				'EVT_visible_on'                  => new EE_Datetime_Field(
211
+					'EVT_visible_on',
212
+					esc_html__('Event Visible Date', 'event_espresso'),
213
+					true,
214
+					EE_Datetime_Field::now
215
+				),
216
+				'EVT_additional_limit'            => new EE_Integer_Field(
217
+					'EVT_additional_limit',
218
+					esc_html__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
219
+					true,
220
+					self::$_default_additional_limit
221
+				),
222
+				'EVT_default_registration_status' => new EE_Enum_Text_Field(
223
+					'EVT_default_registration_status',
224
+					esc_html__('Default Registration Status on this Event', 'event_espresso'),
225
+					false,
226
+					EEM_Event::$_default_reg_status,
227
+					EEM_Registration::reg_status_array()
228
+				),
229
+				'EVT_member_only'                 => new EE_Boolean_Field(
230
+					'EVT_member_only',
231
+					esc_html__('Member-Only Event Flag', 'event_espresso'),
232
+					false,
233
+					false
234
+				),
235
+				'EVT_phone'                       => new EE_Plain_Text_Field(
236
+					'EVT_phone',
237
+					esc_html__('Event Phone Number', 'event_espresso'),
238
+					false,
239
+					''
240
+				),
241
+				'EVT_allow_overflow'              => new EE_Boolean_Field(
242
+					'EVT_allow_overflow',
243
+					esc_html__('Allow Overflow on Event', 'event_espresso'),
244
+					false,
245
+					false
246
+				),
247
+				'EVT_timezone_string'             => new EE_Plain_Text_Field(
248
+					'EVT_timezone_string',
249
+					esc_html__('Timezone (name) for Event times', 'event_espresso'),
250
+					false,
251
+					''
252
+				),
253
+				'EVT_external_URL'                => new EE_Plain_Text_Field(
254
+					'EVT_external_URL',
255
+					esc_html__('URL of Event Page if hosted elsewhere', 'event_espresso'),
256
+					true
257
+				),
258
+				'EVT_donations'                   => new EE_Boolean_Field(
259
+					'EVT_donations',
260
+					esc_html__('Accept Donations?', 'event_espresso'),
261
+					false,
262
+					false
263
+				),
264
+				'FSC_UUID'                        => new EE_Foreign_Key_String_Field(
265
+					'FSC_UUID',
266
+					esc_html__('Registration Form UUID (universally unique identifier)', 'event_espresso'),
267
+					true,
268
+					null,
269
+					'Form_Section',
270
+					false
271
+				),
272
+			),
273
+		);
274
+		$this->_model_relations = array(
275
+			'Attendee'               => new EE_HABTM_Relation('Registration'),
276
+			'Datetime'               => new EE_Has_Many_Relation(),
277
+			'Event_Question_Group'   => new EE_Has_Many_Relation(),
278
+			'Form_Section'           => new EE_Belongs_To_Relation(),
279
+			'Message_Template_Group' => new EE_HABTM_Relation('Event_Message_Template'),
280
+			'Question_Group'         => new EE_HABTM_Relation('Event_Question_Group'),
281
+			'Registration'           => new EE_Has_Many_Relation(),
282
+			'Term_Relationship'      => new EE_Has_Many_Relation(),
283
+			'Term_Taxonomy'          => new EE_HABTM_Relation('Term_Relationship'),
284
+			'Venue'                  => new EE_HABTM_Relation('Event_Venue'),
285
+			'WP_User'                => new EE_Belongs_To_Relation(),
286
+		);
287
+		// this model is generally available for reading
288
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
289
+		$this->model_chain_to_password = '';
290
+		parent::__construct($timezone);
291
+	}
292
+
293
+
294
+	/**
295
+	 * @param string $default_reg_status
296
+	 * @throws EE_Error
297
+	 * @throws EE_Error
298
+	 */
299
+	public static function set_default_reg_status($default_reg_status)
300
+	{
301
+		self::$_default_reg_status = $default_reg_status;
302
+		// if EEM_Event has already been instantiated,
303
+		// then we need to reset the `EVT_default_reg_status` field to use the new default.
304
+		if (self::$_instance instanceof EEM_Event) {
305
+			$default_reg_status = new EE_Enum_Text_Field(
306
+				'EVT_default_registration_status',
307
+				esc_html__('Default Registration Status on this Event', 'event_espresso'),
308
+				false,
309
+				$default_reg_status,
310
+				EEM_Registration::reg_status_array()
311
+			);
312
+			$default_reg_status->_construct_finalize(
313
+				'Event_Meta',
314
+				'EVT_default_registration_status',
315
+				'EEM_Event'
316
+			);
317
+			self::$_instance->_fields['Event_Meta']['EVT_default_registration_status'] = $default_reg_status;
318
+		}
319
+	}
320
+
321
+
322
+	/**
323
+	 * Used to override the default for the additional limit field.
324
+	 * @param $additional_limit
325
+	 */
326
+	public static function set_default_additional_limit($additional_limit)
327
+	{
328
+		self::$_default_additional_limit = (int) $additional_limit;
329
+		if (self::$_instance instanceof EEM_Event) {
330
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit'] = new EE_Integer_Field(
331
+				'EVT_additional_limit',
332
+				__('Limit of Additional Registrations on Same Transaction', 'event_espresso'),
333
+				true,
334
+				self::$_default_additional_limit
335
+			);
336
+			self::$_instance->_fields['Event_Meta']['EVT_additional_limit']->_construct_finalize(
337
+				'Event_Meta',
338
+				'EVT_additional_limit',
339
+				'EEM_Event'
340
+			);
341
+		}
342
+	}
343
+
344
+
345
+	/**
346
+	 * Return what is currently set as the default additional limit for the event.
347
+	 * @return int
348
+	 */
349
+	public static function get_default_additional_limit()
350
+	{
351
+		return apply_filters('FHEE__EEM_Event__get_default_additional_limit', self::$_default_additional_limit);
352
+	}
353
+
354
+
355
+	/**
356
+	 * get_question_groups
357
+	 *
358
+	 * @return array
359
+	 * @throws EE_Error
360
+	 * @throws ReflectionException
361
+	 */
362
+	public function get_all_question_groups()
363
+	{
364
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
365
+			array(
366
+				array('QSG_deleted' => false),
367
+				'order_by' => array('QSG_order' => 'ASC'),
368
+			)
369
+		);
370
+	}
371
+
372
+
373
+	/**
374
+	 * get_question_groups
375
+	 *
376
+	 * @param int $EVT_ID
377
+	 * @return array|bool
378
+	 * @throws EE_Error
379
+	 * @throws ReflectionException
380
+	 */
381
+	public function get_all_event_question_groups($EVT_ID = 0)
382
+	{
383
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
384
+			EE_Error::add_error(
385
+				esc_html__(
386
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
387
+					'event_espresso'
388
+				),
389
+				__FILE__,
390
+				__FUNCTION__,
391
+				__LINE__
392
+			);
393
+			return false;
394
+		}
395
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all(
396
+			array(
397
+				array('EVT_ID' => $EVT_ID),
398
+			)
399
+		);
400
+	}
401
+
402
+
403
+	/**
404
+	 * get_question_groups
405
+	 *
406
+	 * @param int $EVT_ID
407
+	 * @param boolean $for_primary_attendee
408
+	 * @return array|bool
409
+	 * @throws EE_Error
410
+	 * @throws InvalidArgumentException
411
+	 * @throws ReflectionException
412
+	 * @throws InvalidDataTypeException
413
+	 * @throws InvalidInterfaceException
414
+	 */
415
+	public function get_event_question_groups($EVT_ID = 0, $for_primary_attendee = true)
416
+	{
417
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
418
+			EE_Error::add_error(
419
+				esc_html__(
420
+					// @codingStandardsIgnoreStart
421
+					'An error occurred. No Event Question Groups could be retrieved because an Event ID was not received.',
422
+					// @codingStandardsIgnoreEnd
423
+					'event_espresso'
424
+				),
425
+				__FILE__,
426
+				__FUNCTION__,
427
+				__LINE__
428
+			);
429
+			return false;
430
+		}
431
+		$query_params = [
432
+			[
433
+				'EVT_ID' => $EVT_ID,
434
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary_attendee) => true
435
+			]
436
+		];
437
+		if ($for_primary_attendee) {
438
+			$query_params[0]['EQG_primary'] = true;
439
+		} else {
440
+			$query_params[0]['EQG_additional'] = true;
441
+		}
442
+		return EE_Registry::instance()->load_model('Event_Question_Group')->get_all($query_params);
443
+	}
444
+
445
+
446
+	/**
447
+	 * get_question_groups
448
+	 *
449
+	 * @param int $EVT_ID
450
+	 * @param EE_Registration $registration
451
+	 * @return array|bool
452
+	 * @throws EE_Error
453
+	 * @throws InvalidArgumentException
454
+	 * @throws InvalidDataTypeException
455
+	 * @throws InvalidInterfaceException
456
+	 * @throws ReflectionException
457
+	 */
458
+	public function get_question_groups_for_event($EVT_ID = 0, EE_Registration $registration)
459
+	{
460
+		if (! isset($EVT_ID) || ! absint($EVT_ID)) {
461
+			EE_Error::add_error(
462
+				esc_html__(
463
+					'An error occurred. No Question Groups could be retrieved because an Event ID was not received.',
464
+					'event_espresso'
465
+				),
466
+				__FILE__,
467
+				__FUNCTION__,
468
+				__LINE__
469
+			);
470
+			return false;
471
+		}
472
+		return EE_Registry::instance()->load_model('Question_Group')->get_all(
473
+			[
474
+				[
475
+					'Event_Question_Group.EVT_ID'      => $EVT_ID,
476
+					'Event_Question_Group.'
477
+						. EEM_Event_Question_Group::instance()->fieldNameForContext(
478
+							$registration->is_primary_registrant()
479
+						) => true
480
+				],
481
+				'order_by' => ['QSG_order' => 'ASC'],
482
+			]
483
+		);
484
+	}
485
+
486
+
487
+	/**
488
+	 * get_question_target_db_column
489
+	 *
490
+	 * @param string $QSG_IDs csv list of $QSG IDs
491
+	 * @return array|bool
492
+	 * @throws EE_Error
493
+	 * @throws ReflectionException
494
+	 */
495
+	public function get_questions_in_groups($QSG_IDs = '')
496
+	{
497
+		if (empty($QSG_IDs)) {
498
+			EE_Error::add_error(
499
+				esc_html__('An error occurred. No Question Group IDs were received.', 'event_espresso'),
500
+				__FILE__,
501
+				__FUNCTION__,
502
+				__LINE__
503
+			);
504
+			return false;
505
+		}
506
+		return EE_Registry::instance()->load_model('Question')->get_all(
507
+			array(
508
+				array(
509
+					'Question_Group.QSG_ID' => array('IN', $QSG_IDs),
510
+					'QST_deleted'           => false,
511
+					'QST_admin_only'        => is_admin(),
512
+				),
513
+				'order_by' => 'QST_order',
514
+			)
515
+		);
516
+	}
517
+
518
+
519
+	/**
520
+	 * get_options_for_question
521
+	 *
522
+	 * @param string $QST_IDs csv list of $QST IDs
523
+	 * @return array|bool
524
+	 * @throws EE_Error
525
+	 * @throws ReflectionException
526
+	 */
527
+	public function get_options_for_question($QST_IDs)
528
+	{
529
+		if (empty($QST_IDs)) {
530
+			EE_Error::add_error(
531
+				esc_html__('An error occurred. No Question IDs were received.', 'event_espresso'),
532
+				__FILE__,
533
+				__FUNCTION__,
534
+				__LINE__
535
+			);
536
+			return false;
537
+		}
538
+		return EE_Registry::instance()->load_model('Question_Option')->get_all(
539
+			array(
540
+				array(
541
+					'Question.QST_ID' => array('IN', $QST_IDs),
542
+					'QSO_deleted'     => false,
543
+				),
544
+				'order_by' => 'QSO_ID',
545
+			)
546
+		);
547
+	}
548
+
549
+
550
+	/**
551
+	 * Gets all events that are published
552
+	 * and have event start time earlier than now and an event end time later than now
553
+	 *
554
+	 * @param array $query_params  An array of query params to further filter on
555
+	 *                             (note that status and DTT_EVT_start and DTT_EVT_end will be overridden)
556
+	 * @param bool  $count         whether to return the count or not (default FALSE)
557
+	 * @return EE_Event[]|int
558
+	 * @throws EE_Error
559
+	 * @throws ReflectionException
560
+	 */
561
+	public function get_active_events($query_params, $count = false)
562
+	{
563
+		if (array_key_exists(0, $query_params)) {
564
+			$where_params = $query_params[0];
565
+			unset($query_params[0]);
566
+		} else {
567
+			$where_params = array();
568
+		}
569
+		// if we have count make sure we don't include group by
570
+		if ($count && isset($query_params['group_by'])) {
571
+			unset($query_params['group_by']);
572
+		}
573
+		// let's add specific query_params for active_events
574
+		// keep in mind this will override any sent status in the query AND any date queries.
575
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
576
+		// if already have where params for DTT_EVT_start or DTT_EVT_end then append these conditions
577
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
578
+			$where_params['Datetime.DTT_EVT_start******'] = array(
579
+				'<',
580
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
581
+			);
582
+		} else {
583
+			$where_params['Datetime.DTT_EVT_start'] = array(
584
+				'<',
585
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
586
+			);
587
+		}
588
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
589
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
590
+				'>',
591
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
592
+			);
593
+		} else {
594
+			$where_params['Datetime.DTT_EVT_end'] = array(
595
+				'>',
596
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
597
+			);
598
+		}
599
+		$query_params[0] = $where_params;
600
+		// don't use $query_params with count()
601
+		// because we don't want to include additional query clauses like "GROUP BY"
602
+		return $count
603
+			? $this->count(array($where_params), 'EVT_ID', true)
604
+			: $this->get_all($query_params);
605
+	}
606
+
607
+
608
+	/**
609
+	 * get all events that are published and have an event start time later than now
610
+	 *
611
+	 * @param array $query_params  An array of query params to further filter on
612
+	 *                             (Note that status and DTT_EVT_start will be overridden)
613
+	 * @param bool  $count         whether to return the count or not (default FALSE)
614
+	 * @return EE_Event[]|int
615
+	 * @throws EE_Error
616
+	 * @throws ReflectionException
617
+	 */
618
+	public function get_upcoming_events($query_params, $count = false)
619
+	{
620
+		if (array_key_exists(0, $query_params)) {
621
+			$where_params = $query_params[0];
622
+			unset($query_params[0]);
623
+		} else {
624
+			$where_params = array();
625
+		}
626
+		// if we have count make sure we don't include group by
627
+		if ($count && isset($query_params['group_by'])) {
628
+			unset($query_params['group_by']);
629
+		}
630
+		// let's add specific query_params for active_events
631
+		// keep in mind this will override any sent status in the query AND any date queries.
632
+		// we need to pull events with a status of publish and sold_out
633
+		$event_status = array('publish', EEM_Event::sold_out);
634
+		// check if the user can read private events and if so add the 'private status to the were params'
635
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_private_events', 'get_upcoming_events')) {
636
+			$event_status[] = 'private';
637
+		}
638
+		$where_params['status'] = array('IN', $event_status);
639
+		// if there are already query_params matching DTT_EVT_start then we need to modify that to add them.
640
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
641
+			$where_params['Datetime.DTT_EVT_start*****'] = array(
642
+				'>',
643
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
644
+			);
645
+		} else {
646
+			$where_params['Datetime.DTT_EVT_start'] = array(
647
+				'>',
648
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_start'),
649
+			);
650
+		}
651
+		$query_params[0] = $where_params;
652
+		// don't use $query_params with count()
653
+		// because we don't want to include additional query clauses like "GROUP BY"
654
+		return $count
655
+			? $this->count(array($where_params), 'EVT_ID', true)
656
+			: $this->get_all($query_params);
657
+	}
658
+
659
+
660
+	/**
661
+	 * Gets all events that are published
662
+	 * and have an event end time later than now
663
+	 *
664
+	 * @param array $query_params  An array of query params to further filter on
665
+	 *                             (note that status and DTT_EVT_end will be overridden)
666
+	 * @param bool  $count         whether to return the count or not (default FALSE)
667
+	 * @return EE_Event[]|int
668
+	 * @throws EE_Error
669
+	 * @throws ReflectionException
670
+	 */
671
+	public function get_active_and_upcoming_events($query_params, $count = false)
672
+	{
673
+		if (array_key_exists(0, $query_params)) {
674
+			$where_params = $query_params[0];
675
+			unset($query_params[0]);
676
+		} else {
677
+			$where_params = array();
678
+		}
679
+		// if we have count make sure we don't include group by
680
+		if ($count && isset($query_params['group_by'])) {
681
+			unset($query_params['group_by']);
682
+		}
683
+		// let's add specific query_params for active_events
684
+		// keep in mind this will override any sent status in the query AND any date queries.
685
+		$where_params['status'] = array('IN', array('publish', EEM_Event::sold_out));
686
+		// add where params for DTT_EVT_end
687
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
688
+			$where_params['Datetime.DTT_EVT_end*****'] = array(
689
+				'>',
690
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
691
+			);
692
+		} else {
693
+			$where_params['Datetime.DTT_EVT_end'] = array(
694
+				'>',
695
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
696
+			);
697
+		}
698
+		$query_params[0] = $where_params;
699
+		// don't use $query_params with count()
700
+		// because we don't want to include additional query clauses like "GROUP BY"
701
+		return $count
702
+			? $this->count(array($where_params), 'EVT_ID', true)
703
+			: $this->get_all($query_params);
704
+	}
705
+
706
+
707
+	/**
708
+	 * This only returns events that are expired.
709
+	 * They may still be published but all their datetimes have expired.
710
+	 *
711
+	 * @param array $query_params  An array of query params to further filter on
712
+	 *                             (note that status and DTT_EVT_end will be overridden)
713
+	 * @param bool  $count         whether to return the count or not (default FALSE)
714
+	 * @return EE_Event[]|int
715
+	 * @throws EE_Error
716
+	 * @throws ReflectionException
717
+	 */
718
+	public function get_expired_events($query_params, $count = false)
719
+	{
720
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
721
+		// if we have count make sure we don't include group by
722
+		if ($count && isset($query_params['group_by'])) {
723
+			unset($query_params['group_by']);
724
+		}
725
+		// let's add specific query_params for active_events
726
+		// keep in mind this will override any sent status in the query AND any date queries.
727
+		if (isset($where_params['status'])) {
728
+			unset($where_params['status']);
729
+		}
730
+		$exclude_query = $query_params;
731
+		if (isset($exclude_query[0])) {
732
+			unset($exclude_query[0]);
733
+		}
734
+		$exclude_query[0] = array(
735
+			'Datetime.DTT_EVT_end' => array(
736
+				'>',
737
+				EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end'),
738
+			),
739
+		);
740
+		// first get all events that have datetimes where its not expired.
741
+		$event_ids = $this->_get_all_wpdb_results($exclude_query, OBJECT_K, 'Event_CPT.ID');
742
+		$event_ids = array_keys($event_ids);
743
+		// if we have any additional query_params, let's add them to the 'AND' condition
744
+		$and_condition = array(
745
+			'Datetime.DTT_EVT_end' => array('<', EEM_Datetime::instance()->current_time_for_query('DTT_EVT_end')),
746
+			'EVT_ID'               => array('NOT IN', $event_ids),
747
+		);
748
+		if (isset($where_params['OR'])) {
749
+			$and_condition['OR'] = $where_params['OR'];
750
+			unset($where_params['OR']);
751
+		}
752
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
753
+			$and_condition['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
754
+			unset($where_params['Datetime.DTT_EVT_end']);
755
+		}
756
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
757
+			$and_condition['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
758
+			unset($where_params['Datetime.DTT_EVT_start']);
759
+		}
760
+		// merge remaining $where params with the and conditions.
761
+		$where_params['AND'] = array_merge($and_condition, $where_params);
762
+		$query_params[0] = $where_params;
763
+		// don't use $query_params with count()
764
+		// because we don't want to include additional query clauses like "GROUP BY"
765
+		return $count
766
+			? $this->count(array($where_params), 'EVT_ID', true)
767
+			: $this->get_all($query_params);
768
+	}
769
+
770
+
771
+
772
+	/**
773
+	 * This basically just returns the events that do not have the publish status.
774
+	 *
775
+	 * @param  array   $query_params An array of query params to further filter on
776
+	 *                               (note that status will be overwritten)
777
+	 * @param  boolean $count        whether to return the count or not (default FALSE)
778
+	 * @return EE_Event[]|int
779
+	 * @throws EE_Error
780
+	 */
781
+	public function get_inactive_events($query_params, $count = false)
782
+	{
783
+		$where_params = isset($query_params[0]) ? $query_params[0] : array();
784
+		// let's add in specific query_params for inactive events.
785
+		if (isset($where_params['status'])) {
786
+			unset($where_params['status']);
787
+		}
788
+		// if we have count make sure we don't include group by
789
+		if ($count && isset($query_params['group_by'])) {
790
+			unset($query_params['group_by']);
791
+		}
792
+		// if we have any additional query_params, let's add them to the 'AND' condition
793
+		$where_params['AND']['status'] = array('!=', 'publish');
794
+		if (isset($where_params['OR'])) {
795
+			$where_params['AND']['OR'] = $where_params['OR'];
796
+			unset($where_params['OR']);
797
+		}
798
+		if (isset($where_params['Datetime.DTT_EVT_end'])) {
799
+			$where_params['AND']['Datetime.DTT_EVT_end****'] = $where_params['Datetime.DTT_EVT_end'];
800
+			unset($where_params['Datetime.DTT_EVT_end']);
801
+		}
802
+		if (isset($where_params['Datetime.DTT_EVT_start'])) {
803
+			$where_params['AND']['Datetime.DTT_EVT_start'] = $where_params['Datetime.DTT_EVT_start'];
804
+			unset($where_params['Datetime.DTT_EVT_start']);
805
+		}
806
+		$query_params[0] = $where_params;
807
+		// don't use $query_params with count()
808
+		// because we don't want to include additional query clauses like "GROUP BY"
809
+		return $count
810
+			? $this->count(array($where_params), 'EVT_ID', true)
811
+			: $this->get_all($query_params);
812
+	}
813
+
814
+
815
+	/**
816
+	 * This is just injecting into the parent add_relationship_to so we do special handling on price relationships
817
+	 * because we don't want to override any existing global default prices but instead insert NEW prices that get
818
+	 * attached to the event. See parent for param descriptions
819
+	 *
820
+	 * @param        $id_or_obj
821
+	 * @param        $other_model_id_or_obj
822
+	 * @param string $relationName
823
+	 * @param array  $where_query
824
+	 * @return EE_Base_Class
825
+	 * @throws EE_Error
826
+	 * @throws ReflectionException
827
+	 */
828
+	public function add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query = array())
829
+	{
830
+		if ($relationName === 'Price') {
831
+			// let's get the PRC object for the given ID to make sure that we aren't dealing with a default
832
+			$prc_chk = $this->get_related_model_obj($relationName)->ensure_is_obj($other_model_id_or_obj);
833
+			// if EVT_ID = 0, then this is a default
834
+			if ((int) $prc_chk->get('EVT_ID') === 0) {
835
+				// let's set the prc_id as 0 so we force an insert on the add_relation_to carried out by relation
836
+				$prc_chk->set('PRC_ID', 0);
837
+			}
838
+			// run parent
839
+			return parent::add_relationship_to($id_or_obj, $prc_chk, $relationName, $where_query);
840
+		}
841
+		// otherwise carry on as normal
842
+		return parent::add_relationship_to($id_or_obj, $other_model_id_or_obj, $relationName, $where_query);
843
+	}
844
+
845
+
846
+
847
+	/******************** DEPRECATED METHODS ********************/
848
+
849
+
850
+	/**
851
+	 * _get_question_target_db_column
852
+	 *
853
+	 * @param EE_Registration $registration    (so existing answers for registration are included)
854
+	 * @param int             $EVT_ID          so all question groups are included for event (not just answers from
855
+	 *                                         registration).
856
+	 * @return    array
857
+	 * @throws ReflectionException
858
+	 * @throws EE_Error*@deprecated as of 4.8.32.rc.001. Instead consider using
859
+	 *                                         EE_Registration_Custom_Questions_Form located in
860
+	 *                                         admin_pages/registrations/form_sections/EE_Registration_Custom_Questions_Form.form.php
861
+	 * @access     public
862
+	 */
863
+	public function assemble_array_of_groups_questions_and_options(EE_Registration $registration, $EVT_ID = 0)
864
+	{
865
+		if (empty($EVT_ID)) {
866
+			throw new EE_Error(__(
867
+				'An error occurred. No EVT_ID is included.  Needed to know which question groups to retrieve.',
868
+				'event_espresso'
869
+			));
870
+		}
871
+		$questions = array();
872
+		// get all question groups for event
873
+		$qgs = $this->get_question_groups_for_event($EVT_ID, $registration);
874
+		if (! empty($qgs)) {
875
+			foreach ($qgs as $qg) {
876
+				$qsts = $qg->questions();
877
+				$questions[ $qg->ID() ] = $qg->model_field_array();
878
+				$questions[ $qg->ID() ]['QSG_questions'] = array();
879
+				foreach ($qsts as $qst) {
880
+					if ($qst->is_system_question()) {
881
+						continue;
882
+					}
883
+					$answer = EEM_Answer::instance()->get_one(array(
884
+						array(
885
+							'QST_ID' => $qst->ID(),
886
+							'REG_ID' => $registration->ID(),
887
+						),
888
+					));
889
+					$answer = $answer instanceof EE_Answer ? $answer : EEM_Answer::instance()->create_default_object();
890
+					$qst_name = $qstn_id = $qst->ID();
891
+					$ans_id = $answer->ID();
892
+					$qst_name = ! empty($ans_id) ? '[' . $qst_name . '][' . $ans_id . ']' : '[' . $qst_name . ']';
893
+					$input_name = '';
894
+					$input_id = sanitize_key($qst->display_text());
895
+					$input_class = '';
896
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ] = $qst->model_field_array();
897
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_name'] = 'qstn'
898
+																						   . $input_name
899
+																						   . $qst_name;
900
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_id'] = $input_id . '-' . $qstn_id;
901
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_input_class'] = $input_class;
902
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'] = array();
903
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['qst_obj'] = $qst;
904
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['ans_obj'] = $answer;
905
+					// leave responses as-is, don't convert stuff into html entities please!
906
+					$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['htmlentities'] = false;
907
+					if ($qst->type() == 'RADIO_BTN' || $qst->type() == 'CHECKBOX' || $qst->type() == 'DROPDOWN') {
908
+						$QSOs = $qst->options(true, $answer->value());
909
+						if (is_array($QSOs)) {
910
+							foreach ($QSOs as $QSO_ID => $QSO) {
911
+								$questions[ $qg->ID() ]['QSG_questions'][ $qst->ID() ]['QST_options'][ $QSO_ID ] = $QSO->model_field_array();
912
+							}
913
+						}
914
+					}
915
+				}
916
+			}
917
+		}
918
+		return $questions;
919
+	}
920
+
921
+
922
+	/**
923
+	 * @param mixed $cols_n_values either an array of where each key is the name of a field, and the value is its value
924
+	 *                             or an stdClass where each property is the name of a column,
925
+	 * @return EE_Base_Class
926
+	 * @throws EE_Error
927
+	 */
928
+	public function instantiate_class_from_array_or_object($cols_n_values)
929
+	{
930
+		$classInstance = parent::instantiate_class_from_array_or_object($cols_n_values);
931
+		if ($classInstance instanceof EE_Event) {
932
+			// events have their timezone defined in the DB, so use it immediately
933
+			$this->set_timezone($classInstance->get_timezone());
934
+		}
935
+		return $classInstance;
936
+	}
937 937
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Form_Element.model.php 1 patch
Indentation   +217 added lines, -217 removed lines patch added patch discarded remove patch
@@ -28,237 +28,237 @@
 block discarded – undo
28 28
 class EEM_Form_Element extends EEM_Base
29 29
 {
30 30
 
31
-    /**
32
-     * @var EEM_Form_Element
33
-     */
34
-    protected static $_instance;
31
+	/**
32
+	 * @var EEM_Form_Element
33
+	 */
34
+	protected static $_instance;
35 35
 
36
-    /**
37
-     * @var RequestInterface
38
-     */
39
-    private $request;
36
+	/**
37
+	 * @var RequestInterface
38
+	 */
39
+	private $request;
40 40
 
41
-    /**
42
-     * @var InputTypes
43
-     */
44
-    private $input_types;
41
+	/**
42
+	 * @var InputTypes
43
+	 */
44
+	private $input_types;
45 45
 
46 46
 
47
-    /**
48
-     * EEM_Form_Element constructor.
49
-     *
50
-     * @param FormStatus  $form_status
51
-     * @param InputTypes  $input_types
52
-     * @param string|null $timezone
53
-     * @throws EE_Error
54
-     */
55
-    protected function __construct(FormStatus $form_status, InputTypes $input_types, ?string $timezone)
56
-    {
57
-        $this->input_types   = $input_types;
58
-        $this->singular_item = esc_html__('Form Element', 'event_espresso');
59
-        $this->plural_item   = esc_html__('Form Elements', 'event_espresso');
47
+	/**
48
+	 * EEM_Form_Element constructor.
49
+	 *
50
+	 * @param FormStatus  $form_status
51
+	 * @param InputTypes  $input_types
52
+	 * @param string|null $timezone
53
+	 * @throws EE_Error
54
+	 */
55
+	protected function __construct(FormStatus $form_status, InputTypes $input_types, ?string $timezone)
56
+	{
57
+		$this->input_types   = $input_types;
58
+		$this->singular_item = esc_html__('Form Element', 'event_espresso');
59
+		$this->plural_item   = esc_html__('Form Elements', 'event_espresso');
60 60
 
61
-        $this->_tables          = [
62
-            'Form_Element' => new EE_Primary_Table('esp_form_element', 'FIN_UUID'),
63
-        ];
64
-        $this->_fields          = [
65
-            'Form_Element' => [
66
-                'FIN_UUID'      => new EE_Primary_Key_String_Field(
67
-                    'FIN_UUID',
68
-                    esc_html__('Form Element UUID (universally unique identifier)', 'event_espresso')
69
-                ),
70
-                'FSC_UUID' => new EE_Foreign_Key_String_Field(
71
-                    'FSC_UUID',
72
-                    esc_html__('UUID of parent form section this form input belongs to.', 'event_espresso'),
73
-                    false,
74
-                    null,
75
-                    ['Form_Section'],
76
-                    false
77
-                ),
78
-                'FIN_adminOnly' => new EE_Boolean_Field(
79
-                    'FIN_adminOnly',
80
-                    esc_html__(
81
-                        'Whether or not input is only displayed in the admin. If false, input will appear in public forms',
82
-                        'event_espresso'
83
-                    ),
84
-                    false,
85
-                    false
86
-                ),
87
-                'FIN_attributes' => new EE_JSON_Field(
88
-                    'FIN_attributes',
89
-                    esc_html__(
90
-                        'JSON string of HTML attributes such as class, max, min, placeholder, type, etc.',
91
-                        'event_espresso'
92
-                    ),
93
-                    true,
94
-                    '{}'
95
-                ),
96
-                'FIN_helpText' => new EE_JSON_Field(
97
-                    'FIN_helpText',
98
-                    esc_html__(
99
-                        'JSON string of properties pertaining to any help text required for an input.',
100
-                        'event_espresso'
101
-                    ),
102
-                    true,
103
-                    '{}'
104
-                ),
105
-                'FIN_label' => new EE_JSON_Field(
106
-                    'FIN_label',
107
-                    esc_html__(
108
-                        'JSON string of properties pertaining to an element\'s label.',
109
-                        'event_espresso'
110
-                    ),
111
-                    true,
112
-                    '{}'
113
-                ),
114
-                'FIN_mapsTo'     => new EE_Plain_Text_Field(
115
-                    'FIN_mapsTo',
116
-                    esc_html__(
117
-                        'Model and Fields name that this element maps to; ex: Attendee.email',
118
-                        'event_espresso'
119
-                    ),
120
-                    true,
121
-                    null
122
-                ),
123
-                'FIN_options'     => new EE_JSON_Field(
124
-                    'FIN_options',
125
-                    esc_html__(
126
-                        'JSON string of options for ENUM type inputs like checkboxes, radio buttons, select inputs, etc.',
127
-                        'event_espresso'
128
-                    ),
129
-                    true,
130
-                    '[]'
131
-                ),
132
-                'FIN_order'     => new EE_Integer_Field(
133
-                    'FIN_order',
134
-                    esc_html__('Order in which form input appears in a form.', 'event_espresso'),
135
-                    false,
136
-                    0
137
-                ),
138
-                'FIN_required' => new EE_JSON_Field(
139
-                    'FIN_required',
140
-                    esc_html__(
141
-                        'properties pertaining to an input\'s required status and the validation text to display.',
142
-                        'event_espresso'
143
-                    ),
144
-                    false,
145
-                    false
146
-                ),
147
-                'FIN_status'    => new EE_Enum_Text_Field(
148
-                    'FIN_status',
149
-                    esc_html(
150
-                        sprintf(
151
-                            /* translators: 1 class name */
152
-                            __(
153
-                                'Whether form element is active, archived, trashed, or used as a default on new forms. Values correspond to the %1$s class constants.',
154
-                                'event_espresso'
155
-                            ),
156
-                            'EventEspresso\core\services\form\meta\FormStatus'
157
-                        )
158
-                    ),
159
-                    false,
160
-                    FormStatus::ACTIVE,
161
-                    $form_status->validStatusOptions()
162
-                ),
163
-                'FIN_type'    => new EE_Enum_Text_Field(
164
-                    'FIN_type',
165
-                    esc_html__('Form element type.', 'event_espresso'),
166
-                    false,
167
-                    null,
168
-                    $input_types->validTypeOptions()
169
-                ),
170
-                'FIN_wpUser'    => new EE_WP_User_Field(
171
-                    'FIN_wpUser',
172
-                    esc_html__('ID of the WP User that created this form input.', 'event_espresso'),
173
-                    false
174
-                ),
175
-            ],
176
-        ];
61
+		$this->_tables          = [
62
+			'Form_Element' => new EE_Primary_Table('esp_form_element', 'FIN_UUID'),
63
+		];
64
+		$this->_fields          = [
65
+			'Form_Element' => [
66
+				'FIN_UUID'      => new EE_Primary_Key_String_Field(
67
+					'FIN_UUID',
68
+					esc_html__('Form Element UUID (universally unique identifier)', 'event_espresso')
69
+				),
70
+				'FSC_UUID' => new EE_Foreign_Key_String_Field(
71
+					'FSC_UUID',
72
+					esc_html__('UUID of parent form section this form input belongs to.', 'event_espresso'),
73
+					false,
74
+					null,
75
+					['Form_Section'],
76
+					false
77
+				),
78
+				'FIN_adminOnly' => new EE_Boolean_Field(
79
+					'FIN_adminOnly',
80
+					esc_html__(
81
+						'Whether or not input is only displayed in the admin. If false, input will appear in public forms',
82
+						'event_espresso'
83
+					),
84
+					false,
85
+					false
86
+				),
87
+				'FIN_attributes' => new EE_JSON_Field(
88
+					'FIN_attributes',
89
+					esc_html__(
90
+						'JSON string of HTML attributes such as class, max, min, placeholder, type, etc.',
91
+						'event_espresso'
92
+					),
93
+					true,
94
+					'{}'
95
+				),
96
+				'FIN_helpText' => new EE_JSON_Field(
97
+					'FIN_helpText',
98
+					esc_html__(
99
+						'JSON string of properties pertaining to any help text required for an input.',
100
+						'event_espresso'
101
+					),
102
+					true,
103
+					'{}'
104
+				),
105
+				'FIN_label' => new EE_JSON_Field(
106
+					'FIN_label',
107
+					esc_html__(
108
+						'JSON string of properties pertaining to an element\'s label.',
109
+						'event_espresso'
110
+					),
111
+					true,
112
+					'{}'
113
+				),
114
+				'FIN_mapsTo'     => new EE_Plain_Text_Field(
115
+					'FIN_mapsTo',
116
+					esc_html__(
117
+						'Model and Fields name that this element maps to; ex: Attendee.email',
118
+						'event_espresso'
119
+					),
120
+					true,
121
+					null
122
+				),
123
+				'FIN_options'     => new EE_JSON_Field(
124
+					'FIN_options',
125
+					esc_html__(
126
+						'JSON string of options for ENUM type inputs like checkboxes, radio buttons, select inputs, etc.',
127
+						'event_espresso'
128
+					),
129
+					true,
130
+					'[]'
131
+				),
132
+				'FIN_order'     => new EE_Integer_Field(
133
+					'FIN_order',
134
+					esc_html__('Order in which form input appears in a form.', 'event_espresso'),
135
+					false,
136
+					0
137
+				),
138
+				'FIN_required' => new EE_JSON_Field(
139
+					'FIN_required',
140
+					esc_html__(
141
+						'properties pertaining to an input\'s required status and the validation text to display.',
142
+						'event_espresso'
143
+					),
144
+					false,
145
+					false
146
+				),
147
+				'FIN_status'    => new EE_Enum_Text_Field(
148
+					'FIN_status',
149
+					esc_html(
150
+						sprintf(
151
+							/* translators: 1 class name */
152
+							__(
153
+								'Whether form element is active, archived, trashed, or used as a default on new forms. Values correspond to the %1$s class constants.',
154
+								'event_espresso'
155
+							),
156
+							'EventEspresso\core\services\form\meta\FormStatus'
157
+						)
158
+					),
159
+					false,
160
+					FormStatus::ACTIVE,
161
+					$form_status->validStatusOptions()
162
+				),
163
+				'FIN_type'    => new EE_Enum_Text_Field(
164
+					'FIN_type',
165
+					esc_html__('Form element type.', 'event_espresso'),
166
+					false,
167
+					null,
168
+					$input_types->validTypeOptions()
169
+				),
170
+				'FIN_wpUser'    => new EE_WP_User_Field(
171
+					'FIN_wpUser',
172
+					esc_html__('ID of the WP User that created this form input.', 'event_espresso'),
173
+					false
174
+				),
175
+			],
176
+		];
177 177
 
178
-        $this->_model_relations = [
179
-            'Form_Section' => new EE_Belongs_To_Relation(),
180
-            'WP_User'      => new EE_Belongs_To_Relation(),
181
-        ];
182
-        // this model is generally available for reading
183
-        $this->_cap_restriction_generators = [
184
-            EEM_Base::caps_read       => new EE_Restriction_Generator_Public(),
185
-            EEM_Base::caps_read_admin => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
186
-            EEM_Base::caps_edit       => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
187
-            EEM_Base::caps_delete     => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
188
-        ];
189
-        parent::__construct($timezone);
190
-        $this->request = $this->getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
191
-    }
178
+		$this->_model_relations = [
179
+			'Form_Section' => new EE_Belongs_To_Relation(),
180
+			'WP_User'      => new EE_Belongs_To_Relation(),
181
+		];
182
+		// this model is generally available for reading
183
+		$this->_cap_restriction_generators = [
184
+			EEM_Base::caps_read       => new EE_Restriction_Generator_Public(),
185
+			EEM_Base::caps_read_admin => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
186
+			EEM_Base::caps_edit       => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
187
+			EEM_Base::caps_delete     => new EE_Restriction_Generator_Reg_Form('FIN_applies_to'),
188
+		];
189
+		parent::__construct($timezone);
190
+		$this->request = $this->getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
191
+	}
192 192
 
193 193
 
194
-    /**
195
-     * @param array $query_params
196
-     * @return array
197
-     */
198
-    private function addDefaultWhereConditions(array $query_params): array
199
-    {
200
-        // might need to add a way to identify GQL requests for admin domains
201
-        $admin_request                            = $this->request->isAdmin() || $this->request->isAdminAjax();
202
-        $query_params['default_where_conditions'] = $admin_request
203
-            ? EEM_Base::default_where_conditions_none
204
-            : EEM_Base::default_where_conditions_all;
205
-        return $query_params;
206
-    }
194
+	/**
195
+	 * @param array $query_params
196
+	 * @return array
197
+	 */
198
+	private function addDefaultWhereConditions(array $query_params): array
199
+	{
200
+		// might need to add a way to identify GQL requests for admin domains
201
+		$admin_request                            = $this->request->isAdmin() || $this->request->isAdminAjax();
202
+		$query_params['default_where_conditions'] = $admin_request
203
+			? EEM_Base::default_where_conditions_none
204
+			: EEM_Base::default_where_conditions_all;
205
+		return $query_params;
206
+	}
207 207
 
208 208
 
209
-    /**
210
-     * form inputs should always be sorted in ascending order via the FIN_order field
211
-     *
212
-     * @param array $query_params
213
-     * @return array
214
-     */
215
-    private function addOrderByQueryParams(array $query_params): array
216
-    {
217
-        $query_params['order_by'] = ['FIN_order' => 'ASC'];
218
-        return $query_params;
219
-    }
209
+	/**
210
+	 * form inputs should always be sorted in ascending order via the FIN_order field
211
+	 *
212
+	 * @param array $query_params
213
+	 * @return array
214
+	 */
215
+	private function addOrderByQueryParams(array $query_params): array
216
+	{
217
+		$query_params['order_by'] = ['FIN_order' => 'ASC'];
218
+		return $query_params;
219
+	}
220 220
 
221 221
 
222
-    /**
223
-     * @param EE_Form_Section $form_section
224
-     * @param EE_Form_Element[] $all_form_elements
225
-     * @return EE_Form_Element[]
226
-     * @throws EE_Error
227
-     * @throws ReflectionException
228
-     */
229
-    public function filterFormElementsForFormSection(EE_Form_Section $form_section, array $all_form_elements): array
230
-    {
231
-        return array_filter($all_form_elements, $form_section->formElementFilter());
232
-    }
222
+	/**
223
+	 * @param EE_Form_Section $form_section
224
+	 * @param EE_Form_Element[] $all_form_elements
225
+	 * @return EE_Form_Element[]
226
+	 * @throws EE_Error
227
+	 * @throws ReflectionException
228
+	 */
229
+	public function filterFormElementsForFormSection(EE_Form_Section $form_section, array $all_form_elements): array
230
+	{
231
+		return array_filter($all_form_elements, $form_section->formElementFilter());
232
+	}
233 233
 
234 234
 
235
-    /**
236
-     * @param EE_Form_Section[] $form_sections
237
-     * @return EE_Form_Element[]
238
-     * @throws EE_Error
239
-     * @throws ReflectionException
240
-     */
241
-    public function getAllFormElementsForFormSections(array $form_sections): array
242
-    {
243
-        $FSC_UUIDs = [];
244
-        foreach ($form_sections as $form_section) {
245
-            if ($form_section instanceof EE_Form_Section) {
246
-                $FSC_UUIDs[] = $form_section->UUID();
247
-            }
248
-        }
249
-        $where_params = ['FSC_UUID' => ['IN', $FSC_UUIDs]];
250
-        $query_params = $this->addDefaultWhereConditions([$where_params]);
251
-        $query_params = $this->addOrderByQueryParams($query_params);
252
-        return $this->get_all($query_params);
253
-    }
235
+	/**
236
+	 * @param EE_Form_Section[] $form_sections
237
+	 * @return EE_Form_Element[]
238
+	 * @throws EE_Error
239
+	 * @throws ReflectionException
240
+	 */
241
+	public function getAllFormElementsForFormSections(array $form_sections): array
242
+	{
243
+		$FSC_UUIDs = [];
244
+		foreach ($form_sections as $form_section) {
245
+			if ($form_section instanceof EE_Form_Section) {
246
+				$FSC_UUIDs[] = $form_section->UUID();
247
+			}
248
+		}
249
+		$where_params = ['FSC_UUID' => ['IN', $FSC_UUIDs]];
250
+		$query_params = $this->addDefaultWhereConditions([$where_params]);
251
+		$query_params = $this->addOrderByQueryParams($query_params);
252
+		return $this->get_all($query_params);
253
+	}
254 254
 
255 255
 
256
-    /**
257
-     * @param bool $constants_only
258
-     * @return array
259
-     */
260
-    public function validTypeOptions(bool $constants_only = false): array
261
-    {
262
-        return $this->input_types->validTypeOptions($constants_only);
263
-    }
256
+	/**
257
+	 * @param bool $constants_only
258
+	 * @return array
259
+	 */
260
+	public function validTypeOptions(bool $constants_only = false): array
261
+	{
262
+		return $this->input_types->validTypeOptions($constants_only);
263
+	}
264 264
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Form_Submission.model.php 1 patch
Indentation   +114 added lines, -114 removed lines patch added patch discarded remove patch
@@ -11,130 +11,130 @@
 block discarded – undo
11 11
  */
12 12
 class EEM_Form_Submission extends EEM_Base
13 13
 {
14
-    /**
15
-     * @var EEM_Form_Submission
16
-     */
17
-    protected static $_instance;
14
+	/**
15
+	 * @var EEM_Form_Submission
16
+	 */
17
+	protected static $_instance;
18 18
 
19
-    /**
20
-     * @var RequestInterface
21
-     */
22
-    private $request;
19
+	/**
20
+	 * @var RequestInterface
21
+	 */
22
+	private $request;
23 23
 
24 24
 
25
-    /**
26
-     * EEM_Form_Submission constructor.
27
-     *
28
-     * @param string|null $timezone
29
-     * @throws EE_Error
30
-     */
31
-    protected function __construct(?string $timezone)
32
-    {
33
-        $this->singular_item = esc_html__('Form Submission', 'event_espresso');
34
-        $this->plural_item   = esc_html__('Form Submissions', 'event_espresso');
25
+	/**
26
+	 * EEM_Form_Submission constructor.
27
+	 *
28
+	 * @param string|null $timezone
29
+	 * @throws EE_Error
30
+	 */
31
+	protected function __construct(?string $timezone)
32
+	{
33
+		$this->singular_item = esc_html__('Form Submission', 'event_espresso');
34
+		$this->plural_item   = esc_html__('Form Submissions', 'event_espresso');
35 35
 
36
-        $this->_tables          = [
37
-            'Form_Submission' => new EE_Primary_Table('esp_form_submission', 'FSB_UUID'),
38
-        ];
39
-        $this->_fields          = [
40
-            'Form_Submission' => [
41
-                'FSB_UUID'      => new EE_Primary_Key_String_Field(
42
-                    'FSB_UUID',
43
-                    esc_html__('Form Submission UUID (universally unique identifier)', 'event_espresso')
44
-                ),
45
-                'FSC_UUID'      => new EE_Foreign_Key_String_Field(
46
-                    'FSC_UUID',
47
-                    esc_html__('Form Section UUID (universally unique identifier)', 'event_espresso'),
48
-                    false,
49
-                    '',
50
-                    'Form_Section',
51
-                    false
52
-                ),
53
-                'TXN_ID'        => new EE_Foreign_Key_Int_Field(
54
-                    'TXN_ID',
55
-                    esc_html__('Transaction ID', 'event_espresso'),
56
-                    false,
57
-                    0,
58
-                    'Transaction'
59
-                ),
60
-                'FSB_data'      => new EE_JSON_Field(
61
-                    'FSB_data',
62
-                    esc_html__('Serialized form submission data', 'event_espresso'),
63
-                    true,
64
-                    null
65
-                ),
66
-                'FSB_submitted' => new EE_Datetime_Field(
67
-                    'FSB_submitted',
68
-                    esc_html__('Form submission timestamp', 'event_espresso'),
69
-                    false,
70
-                    EE_Datetime_Field::now,
71
-                    $timezone
72
-                ),
73
-            ],
74
-        ];
75
-        $this->_model_relations = [
76
-            'Form_Section' => new EE_Belongs_To_Relation(),
77
-            'Transaction'  => new EE_Belongs_To_Relation(),
78
-        ];
79
-        parent::__construct($timezone);
80
-        $this->request = $this->getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
81
-    }
36
+		$this->_tables          = [
37
+			'Form_Submission' => new EE_Primary_Table('esp_form_submission', 'FSB_UUID'),
38
+		];
39
+		$this->_fields          = [
40
+			'Form_Submission' => [
41
+				'FSB_UUID'      => new EE_Primary_Key_String_Field(
42
+					'FSB_UUID',
43
+					esc_html__('Form Submission UUID (universally unique identifier)', 'event_espresso')
44
+				),
45
+				'FSC_UUID'      => new EE_Foreign_Key_String_Field(
46
+					'FSC_UUID',
47
+					esc_html__('Form Section UUID (universally unique identifier)', 'event_espresso'),
48
+					false,
49
+					'',
50
+					'Form_Section',
51
+					false
52
+				),
53
+				'TXN_ID'        => new EE_Foreign_Key_Int_Field(
54
+					'TXN_ID',
55
+					esc_html__('Transaction ID', 'event_espresso'),
56
+					false,
57
+					0,
58
+					'Transaction'
59
+				),
60
+				'FSB_data'      => new EE_JSON_Field(
61
+					'FSB_data',
62
+					esc_html__('Serialized form submission data', 'event_espresso'),
63
+					true,
64
+					null
65
+				),
66
+				'FSB_submitted' => new EE_Datetime_Field(
67
+					'FSB_submitted',
68
+					esc_html__('Form submission timestamp', 'event_espresso'),
69
+					false,
70
+					EE_Datetime_Field::now,
71
+					$timezone
72
+				),
73
+			],
74
+		];
75
+		$this->_model_relations = [
76
+			'Form_Section' => new EE_Belongs_To_Relation(),
77
+			'Transaction'  => new EE_Belongs_To_Relation(),
78
+		];
79
+		parent::__construct($timezone);
80
+		$this->request = $this->getLoader()->getShared('EventEspresso\core\services\request\RequestInterface');
81
+	}
82 82
 
83 83
 
84
-    /**
85
-     * adds all default where conditions unless the current request originates from the admin
86
-     *
87
-     * @param array $query_params
88
-     * @return array
89
-     */
90
-    private function addDefaultWhereConditions(array $query_params): array
91
-    {
92
-        // might need to add a way to identify GQL requests for admin domains
93
-        $query_params['default_where_conditions'] = $this->request->isAdmin() || $this->request->isAdminAjax()
94
-            ? EEM_Base::default_where_conditions_none
95
-            : EEM_Base::default_where_conditions_all;
96
-        return $query_params;
97
-    }
84
+	/**
85
+	 * adds all default where conditions unless the current request originates from the admin
86
+	 *
87
+	 * @param array $query_params
88
+	 * @return array
89
+	 */
90
+	private function addDefaultWhereConditions(array $query_params): array
91
+	{
92
+		// might need to add a way to identify GQL requests for admin domains
93
+		$query_params['default_where_conditions'] = $this->request->isAdmin() || $this->request->isAdminAjax()
94
+			? EEM_Base::default_where_conditions_none
95
+			: EEM_Base::default_where_conditions_all;
96
+		return $query_params;
97
+	}
98 98
 
99 99
 
100
-    /**
101
-     * form sections should always be sorted in ascending order via the FSC_order field
102
-     *
103
-     * @param array $query_params
104
-     * @return array
105
-     */
106
-    private function addOrderByQueryParams(array $query_params): array
107
-    {
108
-        $query_params['order_by'] = ['FSB_submitted' => 'ASC'];
109
-        return $query_params;
110
-    }
100
+	/**
101
+	 * form sections should always be sorted in ascending order via the FSC_order field
102
+	 *
103
+	 * @param array $query_params
104
+	 * @return array
105
+	 */
106
+	private function addOrderByQueryParams(array $query_params): array
107
+	{
108
+		$query_params['order_by'] = ['FSB_submitted' => 'ASC'];
109
+		return $query_params;
110
+	}
111 111
 
112 112
 
113
-    /**
114
-     * @param EE_Event $event
115
-     * @return EE_Form_Submission[]|null
116
-     * @throws EE_Error
117
-     * @throws ReflectionException
118
-     */
119
-    public function getAllFormSubmissionsForEvent(EE_Event $event): ?array
120
-    {
121
-        $query_params = [['FSC_UUID' => $event->registrationFormUuid()]];
122
-        $query_params = $this->addDefaultWhereConditions($query_params);
123
-        $query_params = $this->addOrderByQueryParams($query_params);
124
-        return $this->get_all($query_params);
125
-    }
113
+	/**
114
+	 * @param EE_Event $event
115
+	 * @return EE_Form_Submission[]|null
116
+	 * @throws EE_Error
117
+	 * @throws ReflectionException
118
+	 */
119
+	public function getAllFormSubmissionsForEvent(EE_Event $event): ?array
120
+	{
121
+		$query_params = [['FSC_UUID' => $event->registrationFormUuid()]];
122
+		$query_params = $this->addDefaultWhereConditions($query_params);
123
+		$query_params = $this->addOrderByQueryParams($query_params);
124
+		return $this->get_all($query_params);
125
+	}
126 126
 
127 127
 
128
-    /**
129
-     * @param EE_Transaction $transaction
130
-     * @return EE_Form_Submission|null
131
-     * @throws EE_Error
132
-     * @throws ReflectionException
133
-     */
134
-    public function getFormSubmissionForTransaction(EE_Transaction $transaction): ?EE_Form_Submission
135
-    {
136
-        $query_params = [['TXN_ID' => $transaction->ID()]];
137
-        $query_params = $this->addDefaultWhereConditions($query_params);
138
-        return $this->get_one($query_params);
139
-    }
128
+	/**
129
+	 * @param EE_Transaction $transaction
130
+	 * @return EE_Form_Submission|null
131
+	 * @throws EE_Error
132
+	 * @throws ReflectionException
133
+	 */
134
+	public function getFormSubmissionForTransaction(EE_Transaction $transaction): ?EE_Form_Submission
135
+	{
136
+		$query_params = [['TXN_ID' => $transaction->ID()]];
137
+		$query_params = $this->addDefaultWhereConditions($query_params);
138
+		return $this->get_one($query_params);
139
+	}
140 140
 }
Please login to merge, or discard this patch.
core/helpers/EEH_Debug_Tools.helper.php 2 patches
Indentation   +700 added lines, -700 removed lines patch added patch discarded remove patch
@@ -13,691 +13,691 @@  discard block
 block discarded – undo
13 13
 class EEH_Debug_Tools
14 14
 {
15 15
 
16
-    /**
17
-     *    instance of the EEH_Autoloader object
18
-     *
19
-     * @var    $_instance
20
-     * @access    private
21
-     */
22
-    private static $_instance;
23
-
24
-    /**
25
-     * @var array
26
-     */
27
-    protected $_memory_usage_points = array();
28
-
29
-
30
-
31
-    /**
32
-     * @singleton method used to instantiate class object
33
-     * @access    public
34
-     * @return EEH_Debug_Tools
35
-     */
36
-    public static function instance()
37
-    {
38
-        // check if class object is instantiated, and instantiated properly
39
-        if (! self::$_instance instanceof EEH_Debug_Tools) {
40
-            self::$_instance = new self();
41
-        }
42
-        return self::$_instance;
43
-    }
44
-
45
-
46
-
47
-    /**
48
-     * private class constructor
49
-     */
50
-    private function __construct()
51
-    {
52
-        // load Kint PHP debugging library
53
-        if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php')) {
54
-            // despite EE4 having a check for an existing copy of the Kint debugging class,
55
-            // if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
56
-            // then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
57
-            // so we've moved it to our test folder so that it is not included with production releases
58
-            // plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
59
-            require_once(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php');
60
-        }
61
-        // if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
62
-        // add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
63
-        // }
64
-        $plugin = basename(EE_PLUGIN_DIR_PATH);
65
-        add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
66
-        add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
67
-        add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
68
-    }
69
-
70
-
71
-
72
-    /**
73
-     *    show_db_name
74
-     *
75
-     * @return void
76
-     */
77
-    public static function show_db_name()
78
-    {
79
-        if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
80
-            echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
81
-                 . DB_NAME
82
-                 . '</p>';
83
-        }
84
-        if (EE_DEBUG) {
85
-            Benchmark::displayResults();
86
-        }
87
-    }
88
-
89
-
90
-
91
-    /**
92
-     *    dump EE_Session object at bottom of page after everything else has happened
93
-     *
94
-     * @return void
95
-     */
96
-    public function espresso_session_footer_dump()
97
-    {
98
-        if (
99
-            (defined('WP_DEBUG') && WP_DEBUG)
100
-            && ! defined('DOING_AJAX')
101
-            && class_exists('Kint')
102
-            && function_exists('wp_get_current_user')
103
-            && current_user_can('update_core')
104
-            && class_exists('EE_Registry')
105
-        ) {
106
-            Kint::dump(EE_Registry::instance()->SSN->id());
107
-            Kint::dump(EE_Registry::instance()->SSN);
108
-            //          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
109
-            $this->espresso_list_hooked_functions();
110
-            Benchmark::displayResults();
111
-        }
112
-    }
113
-
114
-
115
-
116
-    /**
117
-     *    List All Hooked Functions
118
-     *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
119
-     *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
120
-     *
121
-     * @param string $tag
122
-     * @return void
123
-     */
124
-    public function espresso_list_hooked_functions($tag = '')
125
-    {
126
-        global $wp_filter;
127
-        echo '<br/><br/><br/><h3>Hooked Functions</h3>';
128
-        if ($tag) {
129
-            $hook[ $tag ] = $wp_filter[ $tag ];
130
-            if (! is_array($hook[ $tag ])) {
131
-                trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
132
-                return;
133
-            }
134
-            echo '<h5>For Tag: ' . $tag . '</h5>';
135
-        } else {
136
-            $hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
137
-            ksort($hook);
138
-        }
139
-        foreach ($hook as $tag_name => $priorities) {
140
-            echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag_name</strong><br />";
141
-            ksort($priorities);
142
-            foreach ($priorities as $priority => $function) {
143
-                echo $priority;
144
-                foreach ($function as $name => $properties) {
145
-                    echo "\t$name<br />";
146
-                }
147
-            }
148
-        }
149
-    }
150
-
151
-
152
-
153
-    /**
154
-     *    registered_filter_callbacks
155
-     *
156
-     * @param string $hook_name
157
-     * @return array
158
-     */
159
-    public static function registered_filter_callbacks($hook_name = '')
160
-    {
161
-        $filters = array();
162
-        global $wp_filter;
163
-        if (isset($wp_filter[ $hook_name ])) {
164
-            $filters[ $hook_name ] = array();
165
-            foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
166
-                $filters[ $hook_name ][ $priority ] = array();
167
-                foreach ($callbacks as $callback) {
168
-                    $filters[ $hook_name ][ $priority ][] = $callback['function'];
169
-                }
170
-            }
171
-        }
172
-        return $filters;
173
-    }
174
-
175
-
176
-
177
-    /**
178
-     *    captures plugin activation errors for debugging
179
-     *
180
-     * @return void
181
-     * @throws EE_Error
182
-     */
183
-    public static function ee_plugin_activation_errors()
184
-    {
185
-        if (WP_DEBUG) {
186
-            $activation_errors = ob_get_contents();
187
-            if (empty($activation_errors)) {
188
-                return;
189
-            }
190
-            $activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
191
-            espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
192
-            if (class_exists('EEH_File')) {
193
-                try {
194
-                    EEH_File::ensure_file_exists_and_is_writable(
195
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html'
196
-                    );
197
-                    EEH_File::write_to_file(
198
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
199
-                        $activation_errors
200
-                    );
201
-                } catch (EE_Error $e) {
202
-                    EE_Error::add_error(
203
-                        sprintf(
204
-                            __(
205
-                                'The Event Espresso activation errors file could not be setup because: %s',
206
-                                'event_espresso'
207
-                            ),
208
-                            $e->getMessage()
209
-                        ),
210
-                        __FILE__,
211
-                        __FUNCTION__,
212
-                        __LINE__
213
-                    );
214
-                }
215
-            } else {
216
-                // old school attempt
217
-                file_put_contents(
218
-                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
219
-                    $activation_errors
220
-                );
221
-            }
222
-            $activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
223
-            update_option('ee_plugin_activation_errors', $activation_errors);
224
-        }
225
-    }
226
-
227
-
228
-
229
-    /**
230
-     * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
231
-     * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
232
-     * or we want to make sure they use something the right way.
233
-     *
234
-     * @access public
235
-     * @param string $function      The function that was called
236
-     * @param string $message       A message explaining what has been done incorrectly
237
-     * @param string $version       The version of Event Espresso where the error was added
238
-     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
239
-     *                              for a deprecated function. This allows deprecation to occur during one version,
240
-     *                              but not have any notices appear until a later version. This allows developers
241
-     *                              extra time to update their code before notices appear.
242
-     * @param int    $error_type
243
-     * @uses   trigger_error()
244
-     */
245
-    public function doing_it_wrong(
246
-        $function,
247
-        $message,
248
-        $version,
249
-        $applies_when = '',
250
-        $error_type = null
251
-    ) {
252
-        $applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
253
-        $error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
254
-        // because we swapped the parameter order around for the last two params,
255
-        // let's verify that some third party isn't still passing an error type value for the third param
256
-        if (is_int($applies_when)) {
257
-            $error_type = $applies_when;
258
-            $applies_when = espresso_version();
259
-        }
260
-        // if not displaying notices yet, then just leave
261
-        if (version_compare(espresso_version(), $applies_when, '<')) {
262
-            return;
263
-        }
264
-        do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
265
-        $version = $version === null
266
-            ? ''
267
-            : sprintf(
268
-                __('(This message was added in version %s of Event Espresso)', 'event_espresso'),
269
-                $version
270
-            );
271
-        $error_message = sprintf(
272
-            esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
273
-            $function,
274
-            '<strong>',
275
-            '</strong>',
276
-            $message,
277
-            $version
278
-        );
279
-        // don't trigger error if doing ajax,
280
-        // instead we'll add a transient EE_Error notice that in theory should show on the next request.
281
-        if (defined('DOING_AJAX') && DOING_AJAX) {
282
-            $error_message .= ' ' . esc_html__(
283
-                'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
284
-                'event_espresso'
285
-            );
286
-            $error_message .= '<ul><li>';
287
-            $error_message .= implode('</li><li>', EE_Registry::instance()->REQ->params());
288
-            $error_message .= '</ul>';
289
-            EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
290
-            // now we set this on the transient so it shows up on the next request.
291
-            EE_Error::get_notices(false, true);
292
-        } else {
293
-            trigger_error($error_message, $error_type);
294
-        }
295
-    }
296
-
297
-
298
-
299
-
300
-    /**
301
-     * Logger helpers
302
-     */
303
-    /**
304
-     * debug
305
-     *
306
-     * @param string $class
307
-     * @param string $func
308
-     * @param string $line
309
-     * @param array  $info
310
-     * @param bool   $display_request
311
-     * @param string $debug_index
312
-     * @param string $debug_key
313
-     * @throws EE_Error
314
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
315
-     */
316
-    public static function log(
317
-        $class = '',
318
-        $func = '',
319
-        $line = '',
320
-        $info = array(),
321
-        $display_request = false,
322
-        $debug_index = '',
323
-        $debug_key = 'EE_DEBUG_SPCO'
324
-    ) {
325
-        if (WP_DEBUG) {
326
-            $debug_key = $debug_key . '_' . EE_Session::instance()->id();
327
-            $debug_data = get_option($debug_key, array());
328
-            $default_data = array(
329
-                $class => $func . '() : ' . $line,
330
-                'REQ'  => $display_request ? $_REQUEST : '',
331
-            );
332
-            // don't serialize objects
333
-            $info = self::strip_objects($info);
334
-            $index = ! empty($debug_index) ? $debug_index : 0;
335
-            if (! isset($debug_data[ $index ])) {
336
-                $debug_data[ $index ] = array();
337
-            }
338
-            $debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
339
-            update_option($debug_key, $debug_data);
340
-        }
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * strip_objects
347
-     *
348
-     * @param array $info
349
-     * @return array
350
-     */
351
-    public static function strip_objects($info = array())
352
-    {
353
-        foreach ($info as $key => $value) {
354
-            if (is_array($value)) {
355
-                $info[ $key ] = self::strip_objects($value);
356
-            } elseif (is_object($value)) {
357
-                $object_class = get_class($value);
358
-                $info[ $object_class ] = array();
359
-                $info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
360
-                if (method_exists($value, 'ID')) {
361
-                    $info[ $object_class ]['ID'] = $value->ID();
362
-                }
363
-                if (method_exists($value, 'status')) {
364
-                    $info[ $object_class ]['status'] = $value->status();
365
-                } elseif (method_exists($value, 'status_ID')) {
366
-                    $info[ $object_class ]['status'] = $value->status_ID();
367
-                }
368
-                unset($info[ $key ]);
369
-            }
370
-        }
371
-        return (array) $info;
372
-    }
373
-
374
-
375
-
376
-    /**
377
-     * @param mixed      $var
378
-     * @param string     $var_name
379
-     * @param string     $file
380
-     * @param int|string $line
381
-     * @param int|string $heading_tag
382
-     * @param bool       $die
383
-     * @param string     $margin
384
-     */
385
-    public static function printv(
386
-        $var,
387
-        $var_name = '',
388
-        $file = '',
389
-        $line = '',
390
-        $heading_tag = 5,
391
-        $die = false,
392
-        $margin = ''
393
-    ) {
394
-        $var_name = ! $var_name ? 'string' : $var_name;
395
-        $var_name = ucwords(str_replace('$', '', $var_name));
396
-        $is_method = method_exists($var_name, $var);
397
-        $var_name = ucwords(str_replace('_', ' ', $var_name));
398
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
399
-        // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
400
-        $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
401
-        $result .= $is_method
402
-            ? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
403
-            : EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
404
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
405
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
406
-        if ($die) {
407
-            die($result);
408
-        }
409
-        echo $result;
410
-    }
411
-
412
-
413
-    protected static function headingTag($heading_tag)
414
-    {
415
-        $heading_tag = absint($heading_tag);
416
-        return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
417
-    }
418
-
419
-
420
-    protected static function headingSpacer($heading_tag)
421
-    {
422
-        return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
423
-            ? "\n"
424
-            : '';
425
-    }
426
-
427
-
428
-    protected static function plainOutput()
429
-    {
430
-        return defined('EE_TESTS_DIR')
431
-               || (defined('DOING_AJAX') && DOING_AJAX && ! isset($_REQUEST['pretty_output']))
432
-               || (
433
-                   isset($_SERVER['REQUEST_URI'])
434
-                   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
435
-               );
436
-    }
437
-
438
-
439
-    /**
440
-     * @param string $var_name
441
-     * @param string $heading_tag
442
-     * @param string $margin
443
-     * @param int    $line
444
-     * @return string
445
-     */
446
-    protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
447
-    {
448
-        if (EEH_Debug_Tools::plainOutput()) {
449
-            switch ($heading_tag) {
450
-                case 'h1':
451
-                    $line_breaks = EEH_Debug_Tools::lineBreak(3);
452
-                    break;
453
-                case 'h2':
454
-                    $line_breaks = EEH_Debug_Tools::lineBreak(2);
455
-                    break;
456
-                default:
457
-                    $line_breaks = EEH_Debug_Tools::lineBreak();
458
-                    break;
459
-            }
460
-            return "{$line_breaks}{$line}) {$var_name}";
461
-        }
462
-        $margin = "25px 0 0 {$margin}";
463
-        return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
464
-    }
465
-
466
-
467
-
468
-    /**
469
-     * @param string $heading_tag
470
-     * @return string
471
-     */
472
-    protected static function headingX($heading_tag = 'h5')
473
-    {
474
-        if (EEH_Debug_Tools::plainOutput()) {
475
-            return '';
476
-        }
477
-        return '</' . $heading_tag . '>';
478
-    }
479
-
480
-
481
-
482
-    /**
483
-     * @param string $content
484
-     * @return string
485
-     */
486
-    protected static function grey_span($content = '')
487
-    {
488
-        if (EEH_Debug_Tools::plainOutput()) {
489
-            return $content;
490
-        }
491
-        return '<span style="color:#999">' . $content . '</span>';
492
-    }
493
-
494
-
495
-
496
-    /**
497
-     * @param string $file
498
-     * @param int    $line
499
-     * @return string
500
-     */
501
-    protected static function file_and_line($file, $line, $heading_tag)
502
-    {
503
-        if ($file === '' || $line === '') {
504
-            return '';
505
-        }
506
-        $file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
507
-        if (EEH_Debug_Tools::plainOutput()) {
508
-            if ($heading_tag === 'h1' || $heading_tag === 'h2') {
509
-                return " ({$file})";
510
-            }
511
-            return '';
512
-        }
513
-        return '<br /><span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
514
-               . $file
515
-               . '<br />line no: '
516
-               . $line
517
-               . '</span>';
518
-    }
519
-
520
-
521
-
522
-    /**
523
-     * @param string $content
524
-     * @return string
525
-     */
526
-    protected static function orange_span($content = '')
527
-    {
528
-        if (EEH_Debug_Tools::plainOutput()) {
529
-            return $content;
530
-        }
531
-        return '<span style="color:#E76700">' . $content . '</span>';
532
-    }
533
-
534
-
535
-
536
-    /**
537
-     * @param mixed $var
538
-     * @return string
539
-     */
540
-    protected static function pre_span($var)
541
-    {
542
-        ob_start();
543
-        var_dump($var);
544
-        $var = ob_get_clean();
545
-        if (EEH_Debug_Tools::plainOutput()) {
546
-            return $var;
547
-        }
548
-        return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">' . $var . '</pre>';
549
-    }
550
-
551
-
552
-
553
-    /**
554
-     * @param mixed      $var
555
-     * @param string     $var_name
556
-     * @param string     $file
557
-     * @param int|string $line
558
-     * @param int|string $heading_tag
559
-     * @param bool       $die
560
-     */
561
-    public static function printr(
562
-        $var,
563
-        $var_name = '',
564
-        $file = '',
565
-        $line = '',
566
-        $heading_tag = 5,
567
-        $die = false
568
-    ) {
569
-        // return;
570
-        $file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
571
-        if (empty($var) && empty($var_name)) {
572
-            $var = $file;
573
-            $var_name = "line $line";
574
-            $file = '';
575
-            $line = '';
576
-        }
577
-        $margin = is_admin() ? ' 180px' : '0';
578
-        // $print_r = false;
579
-        if (is_string($var)) {
580
-            EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
581
-            return;
582
-        }
583
-        if (is_object($var)) {
584
-            $var_name = ! $var_name ? 'object' : $var_name;
585
-            // $print_r = true;
586
-        } elseif (is_array($var)) {
587
-            $var_name = ! $var_name ? 'array' : $var_name;
588
-            // $print_r = true;
589
-        } elseif (is_numeric($var)) {
590
-            $var_name = ! $var_name ? 'numeric' : $var_name;
591
-        } elseif ($var === null) {
592
-            $var_name = ! $var_name ? 'null' : $var_name;
593
-        }
594
-        $var_name = ucwords(str_replace(array('$', '_'), array('', ' '), $var_name));
595
-        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
596
-        // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
597
-        $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
598
-        $result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
599
-            EEH_Debug_Tools::pre_span($var)
600
-        );
601
-        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
602
-        $result .= EEH_Debug_Tools::headingX($heading_tag);
603
-        if ($die) {
604
-            die($result);
605
-        }
606
-        echo $result;
607
-    }
608
-
609
-
610
-    private static function lineBreak($lines = 1): string
611
-    {
612
-        $linebreak = defined('DOING_AJAX') && DOING_AJAX ? '<br />' : PHP_EOL;
613
-        return str_repeat($linebreak, $lines);
614
-    }
615
-
616
-
617
-
618
-    /******************** deprecated ********************/
619
-
620
-
621
-
622
-    /**
623
-     * @deprecated 4.9.39.rc.034
624
-     */
625
-    public function reset_times()
626
-    {
627
-        Benchmark::resetTimes();
628
-    }
629
-
630
-
631
-
632
-    /**
633
-     * @deprecated 4.9.39.rc.034
634
-     * @param null $timer_name
635
-     */
636
-    public function start_timer($timer_name = null)
637
-    {
638
-        Benchmark::startTimer($timer_name);
639
-    }
640
-
641
-
642
-
643
-    /**
644
-     * @deprecated 4.9.39.rc.034
645
-     * @param string $timer_name
646
-     */
647
-    public function stop_timer($timer_name = '')
648
-    {
649
-        Benchmark::stopTimer($timer_name);
650
-    }
651
-
652
-
653
-
654
-    /**
655
-     * @deprecated 4.9.39.rc.034
656
-     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
657
-     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
658
-     * @return void
659
-     */
660
-    public function measure_memory($label, $output_now = false)
661
-    {
662
-        Benchmark::measureMemory($label, $output_now);
663
-    }
664
-
665
-
666
-
667
-    /**
668
-     * @deprecated 4.9.39.rc.034
669
-     * @param int $size
670
-     * @return string
671
-     */
672
-    public function convert($size)
673
-    {
674
-        return Benchmark::convert($size);
675
-    }
676
-
677
-
678
-
679
-    /**
680
-     * @deprecated 4.9.39.rc.034
681
-     * @param bool $output_now
682
-     * @return string
683
-     */
684
-    public function show_times($output_now = true)
685
-    {
686
-        return Benchmark::displayResults($output_now);
687
-    }
688
-
689
-
690
-
691
-    /**
692
-     * @deprecated 4.9.39.rc.034
693
-     * @param string $timer_name
694
-     * @param float  $total_time
695
-     * @return string
696
-     */
697
-    public function format_time($timer_name, $total_time)
698
-    {
699
-        return Benchmark::formatTime($timer_name, $total_time);
700
-    }
16
+	/**
17
+	 *    instance of the EEH_Autoloader object
18
+	 *
19
+	 * @var    $_instance
20
+	 * @access    private
21
+	 */
22
+	private static $_instance;
23
+
24
+	/**
25
+	 * @var array
26
+	 */
27
+	protected $_memory_usage_points = array();
28
+
29
+
30
+
31
+	/**
32
+	 * @singleton method used to instantiate class object
33
+	 * @access    public
34
+	 * @return EEH_Debug_Tools
35
+	 */
36
+	public static function instance()
37
+	{
38
+		// check if class object is instantiated, and instantiated properly
39
+		if (! self::$_instance instanceof EEH_Debug_Tools) {
40
+			self::$_instance = new self();
41
+		}
42
+		return self::$_instance;
43
+	}
44
+
45
+
46
+
47
+	/**
48
+	 * private class constructor
49
+	 */
50
+	private function __construct()
51
+	{
52
+		// load Kint PHP debugging library
53
+		if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php')) {
54
+			// despite EE4 having a check for an existing copy of the Kint debugging class,
55
+			// if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
56
+			// then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
57
+			// so we've moved it to our test folder so that it is not included with production releases
58
+			// plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
59
+			require_once(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php');
60
+		}
61
+		// if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
62
+		// add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
63
+		// }
64
+		$plugin = basename(EE_PLUGIN_DIR_PATH);
65
+		add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
66
+		add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
67
+		add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
68
+	}
69
+
70
+
71
+
72
+	/**
73
+	 *    show_db_name
74
+	 *
75
+	 * @return void
76
+	 */
77
+	public static function show_db_name()
78
+	{
79
+		if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
80
+			echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
81
+				 . DB_NAME
82
+				 . '</p>';
83
+		}
84
+		if (EE_DEBUG) {
85
+			Benchmark::displayResults();
86
+		}
87
+	}
88
+
89
+
90
+
91
+	/**
92
+	 *    dump EE_Session object at bottom of page after everything else has happened
93
+	 *
94
+	 * @return void
95
+	 */
96
+	public function espresso_session_footer_dump()
97
+	{
98
+		if (
99
+			(defined('WP_DEBUG') && WP_DEBUG)
100
+			&& ! defined('DOING_AJAX')
101
+			&& class_exists('Kint')
102
+			&& function_exists('wp_get_current_user')
103
+			&& current_user_can('update_core')
104
+			&& class_exists('EE_Registry')
105
+		) {
106
+			Kint::dump(EE_Registry::instance()->SSN->id());
107
+			Kint::dump(EE_Registry::instance()->SSN);
108
+			//          Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
109
+			$this->espresso_list_hooked_functions();
110
+			Benchmark::displayResults();
111
+		}
112
+	}
113
+
114
+
115
+
116
+	/**
117
+	 *    List All Hooked Functions
118
+	 *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
119
+	 *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
120
+	 *
121
+	 * @param string $tag
122
+	 * @return void
123
+	 */
124
+	public function espresso_list_hooked_functions($tag = '')
125
+	{
126
+		global $wp_filter;
127
+		echo '<br/><br/><br/><h3>Hooked Functions</h3>';
128
+		if ($tag) {
129
+			$hook[ $tag ] = $wp_filter[ $tag ];
130
+			if (! is_array($hook[ $tag ])) {
131
+				trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
132
+				return;
133
+			}
134
+			echo '<h5>For Tag: ' . $tag . '</h5>';
135
+		} else {
136
+			$hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
137
+			ksort($hook);
138
+		}
139
+		foreach ($hook as $tag_name => $priorities) {
140
+			echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag_name</strong><br />";
141
+			ksort($priorities);
142
+			foreach ($priorities as $priority => $function) {
143
+				echo $priority;
144
+				foreach ($function as $name => $properties) {
145
+					echo "\t$name<br />";
146
+				}
147
+			}
148
+		}
149
+	}
150
+
151
+
152
+
153
+	/**
154
+	 *    registered_filter_callbacks
155
+	 *
156
+	 * @param string $hook_name
157
+	 * @return array
158
+	 */
159
+	public static function registered_filter_callbacks($hook_name = '')
160
+	{
161
+		$filters = array();
162
+		global $wp_filter;
163
+		if (isset($wp_filter[ $hook_name ])) {
164
+			$filters[ $hook_name ] = array();
165
+			foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
166
+				$filters[ $hook_name ][ $priority ] = array();
167
+				foreach ($callbacks as $callback) {
168
+					$filters[ $hook_name ][ $priority ][] = $callback['function'];
169
+				}
170
+			}
171
+		}
172
+		return $filters;
173
+	}
174
+
175
+
176
+
177
+	/**
178
+	 *    captures plugin activation errors for debugging
179
+	 *
180
+	 * @return void
181
+	 * @throws EE_Error
182
+	 */
183
+	public static function ee_plugin_activation_errors()
184
+	{
185
+		if (WP_DEBUG) {
186
+			$activation_errors = ob_get_contents();
187
+			if (empty($activation_errors)) {
188
+				return;
189
+			}
190
+			$activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
191
+			espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
192
+			if (class_exists('EEH_File')) {
193
+				try {
194
+					EEH_File::ensure_file_exists_and_is_writable(
195
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html'
196
+					);
197
+					EEH_File::write_to_file(
198
+						EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
199
+						$activation_errors
200
+					);
201
+				} catch (EE_Error $e) {
202
+					EE_Error::add_error(
203
+						sprintf(
204
+							__(
205
+								'The Event Espresso activation errors file could not be setup because: %s',
206
+								'event_espresso'
207
+							),
208
+							$e->getMessage()
209
+						),
210
+						__FILE__,
211
+						__FUNCTION__,
212
+						__LINE__
213
+					);
214
+				}
215
+			} else {
216
+				// old school attempt
217
+				file_put_contents(
218
+					EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
219
+					$activation_errors
220
+				);
221
+			}
222
+			$activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
223
+			update_option('ee_plugin_activation_errors', $activation_errors);
224
+		}
225
+	}
226
+
227
+
228
+
229
+	/**
230
+	 * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
231
+	 * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
232
+	 * or we want to make sure they use something the right way.
233
+	 *
234
+	 * @access public
235
+	 * @param string $function      The function that was called
236
+	 * @param string $message       A message explaining what has been done incorrectly
237
+	 * @param string $version       The version of Event Espresso where the error was added
238
+	 * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
239
+	 *                              for a deprecated function. This allows deprecation to occur during one version,
240
+	 *                              but not have any notices appear until a later version. This allows developers
241
+	 *                              extra time to update their code before notices appear.
242
+	 * @param int    $error_type
243
+	 * @uses   trigger_error()
244
+	 */
245
+	public function doing_it_wrong(
246
+		$function,
247
+		$message,
248
+		$version,
249
+		$applies_when = '',
250
+		$error_type = null
251
+	) {
252
+		$applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
253
+		$error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
254
+		// because we swapped the parameter order around for the last two params,
255
+		// let's verify that some third party isn't still passing an error type value for the third param
256
+		if (is_int($applies_when)) {
257
+			$error_type = $applies_when;
258
+			$applies_when = espresso_version();
259
+		}
260
+		// if not displaying notices yet, then just leave
261
+		if (version_compare(espresso_version(), $applies_when, '<')) {
262
+			return;
263
+		}
264
+		do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
265
+		$version = $version === null
266
+			? ''
267
+			: sprintf(
268
+				__('(This message was added in version %s of Event Espresso)', 'event_espresso'),
269
+				$version
270
+			);
271
+		$error_message = sprintf(
272
+			esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
273
+			$function,
274
+			'<strong>',
275
+			'</strong>',
276
+			$message,
277
+			$version
278
+		);
279
+		// don't trigger error if doing ajax,
280
+		// instead we'll add a transient EE_Error notice that in theory should show on the next request.
281
+		if (defined('DOING_AJAX') && DOING_AJAX) {
282
+			$error_message .= ' ' . esc_html__(
283
+				'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
284
+				'event_espresso'
285
+			);
286
+			$error_message .= '<ul><li>';
287
+			$error_message .= implode('</li><li>', EE_Registry::instance()->REQ->params());
288
+			$error_message .= '</ul>';
289
+			EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
290
+			// now we set this on the transient so it shows up on the next request.
291
+			EE_Error::get_notices(false, true);
292
+		} else {
293
+			trigger_error($error_message, $error_type);
294
+		}
295
+	}
296
+
297
+
298
+
299
+
300
+	/**
301
+	 * Logger helpers
302
+	 */
303
+	/**
304
+	 * debug
305
+	 *
306
+	 * @param string $class
307
+	 * @param string $func
308
+	 * @param string $line
309
+	 * @param array  $info
310
+	 * @param bool   $display_request
311
+	 * @param string $debug_index
312
+	 * @param string $debug_key
313
+	 * @throws EE_Error
314
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
315
+	 */
316
+	public static function log(
317
+		$class = '',
318
+		$func = '',
319
+		$line = '',
320
+		$info = array(),
321
+		$display_request = false,
322
+		$debug_index = '',
323
+		$debug_key = 'EE_DEBUG_SPCO'
324
+	) {
325
+		if (WP_DEBUG) {
326
+			$debug_key = $debug_key . '_' . EE_Session::instance()->id();
327
+			$debug_data = get_option($debug_key, array());
328
+			$default_data = array(
329
+				$class => $func . '() : ' . $line,
330
+				'REQ'  => $display_request ? $_REQUEST : '',
331
+			);
332
+			// don't serialize objects
333
+			$info = self::strip_objects($info);
334
+			$index = ! empty($debug_index) ? $debug_index : 0;
335
+			if (! isset($debug_data[ $index ])) {
336
+				$debug_data[ $index ] = array();
337
+			}
338
+			$debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
339
+			update_option($debug_key, $debug_data);
340
+		}
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * strip_objects
347
+	 *
348
+	 * @param array $info
349
+	 * @return array
350
+	 */
351
+	public static function strip_objects($info = array())
352
+	{
353
+		foreach ($info as $key => $value) {
354
+			if (is_array($value)) {
355
+				$info[ $key ] = self::strip_objects($value);
356
+			} elseif (is_object($value)) {
357
+				$object_class = get_class($value);
358
+				$info[ $object_class ] = array();
359
+				$info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
360
+				if (method_exists($value, 'ID')) {
361
+					$info[ $object_class ]['ID'] = $value->ID();
362
+				}
363
+				if (method_exists($value, 'status')) {
364
+					$info[ $object_class ]['status'] = $value->status();
365
+				} elseif (method_exists($value, 'status_ID')) {
366
+					$info[ $object_class ]['status'] = $value->status_ID();
367
+				}
368
+				unset($info[ $key ]);
369
+			}
370
+		}
371
+		return (array) $info;
372
+	}
373
+
374
+
375
+
376
+	/**
377
+	 * @param mixed      $var
378
+	 * @param string     $var_name
379
+	 * @param string     $file
380
+	 * @param int|string $line
381
+	 * @param int|string $heading_tag
382
+	 * @param bool       $die
383
+	 * @param string     $margin
384
+	 */
385
+	public static function printv(
386
+		$var,
387
+		$var_name = '',
388
+		$file = '',
389
+		$line = '',
390
+		$heading_tag = 5,
391
+		$die = false,
392
+		$margin = ''
393
+	) {
394
+		$var_name = ! $var_name ? 'string' : $var_name;
395
+		$var_name = ucwords(str_replace('$', '', $var_name));
396
+		$is_method = method_exists($var_name, $var);
397
+		$var_name = ucwords(str_replace('_', ' ', $var_name));
398
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
399
+		// $result = EEH_Debug_Tools::headingSpacer($heading_tag);
400
+		$result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
401
+		$result .= $is_method
402
+			? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
403
+			: EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
404
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
405
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
406
+		if ($die) {
407
+			die($result);
408
+		}
409
+		echo $result;
410
+	}
411
+
412
+
413
+	protected static function headingTag($heading_tag)
414
+	{
415
+		$heading_tag = absint($heading_tag);
416
+		return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
417
+	}
418
+
419
+
420
+	protected static function headingSpacer($heading_tag)
421
+	{
422
+		return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
423
+			? "\n"
424
+			: '';
425
+	}
426
+
427
+
428
+	protected static function plainOutput()
429
+	{
430
+		return defined('EE_TESTS_DIR')
431
+			   || (defined('DOING_AJAX') && DOING_AJAX && ! isset($_REQUEST['pretty_output']))
432
+			   || (
433
+				   isset($_SERVER['REQUEST_URI'])
434
+				   && strpos(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), 'wp-json') !== false
435
+			   );
436
+	}
437
+
438
+
439
+	/**
440
+	 * @param string $var_name
441
+	 * @param string $heading_tag
442
+	 * @param string $margin
443
+	 * @param int    $line
444
+	 * @return string
445
+	 */
446
+	protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
447
+	{
448
+		if (EEH_Debug_Tools::plainOutput()) {
449
+			switch ($heading_tag) {
450
+				case 'h1':
451
+					$line_breaks = EEH_Debug_Tools::lineBreak(3);
452
+					break;
453
+				case 'h2':
454
+					$line_breaks = EEH_Debug_Tools::lineBreak(2);
455
+					break;
456
+				default:
457
+					$line_breaks = EEH_Debug_Tools::lineBreak();
458
+					break;
459
+			}
460
+			return "{$line_breaks}{$line}) {$var_name}";
461
+		}
462
+		$margin = "25px 0 0 {$margin}";
463
+		return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
464
+	}
465
+
466
+
467
+
468
+	/**
469
+	 * @param string $heading_tag
470
+	 * @return string
471
+	 */
472
+	protected static function headingX($heading_tag = 'h5')
473
+	{
474
+		if (EEH_Debug_Tools::plainOutput()) {
475
+			return '';
476
+		}
477
+		return '</' . $heading_tag . '>';
478
+	}
479
+
480
+
481
+
482
+	/**
483
+	 * @param string $content
484
+	 * @return string
485
+	 */
486
+	protected static function grey_span($content = '')
487
+	{
488
+		if (EEH_Debug_Tools::plainOutput()) {
489
+			return $content;
490
+		}
491
+		return '<span style="color:#999">' . $content . '</span>';
492
+	}
493
+
494
+
495
+
496
+	/**
497
+	 * @param string $file
498
+	 * @param int    $line
499
+	 * @return string
500
+	 */
501
+	protected static function file_and_line($file, $line, $heading_tag)
502
+	{
503
+		if ($file === '' || $line === '') {
504
+			return '';
505
+		}
506
+		$file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
507
+		if (EEH_Debug_Tools::plainOutput()) {
508
+			if ($heading_tag === 'h1' || $heading_tag === 'h2') {
509
+				return " ({$file})";
510
+			}
511
+			return '';
512
+		}
513
+		return '<br /><span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
514
+			   . $file
515
+			   . '<br />line no: '
516
+			   . $line
517
+			   . '</span>';
518
+	}
519
+
520
+
521
+
522
+	/**
523
+	 * @param string $content
524
+	 * @return string
525
+	 */
526
+	protected static function orange_span($content = '')
527
+	{
528
+		if (EEH_Debug_Tools::plainOutput()) {
529
+			return $content;
530
+		}
531
+		return '<span style="color:#E76700">' . $content . '</span>';
532
+	}
533
+
534
+
535
+
536
+	/**
537
+	 * @param mixed $var
538
+	 * @return string
539
+	 */
540
+	protected static function pre_span($var)
541
+	{
542
+		ob_start();
543
+		var_dump($var);
544
+		$var = ob_get_clean();
545
+		if (EEH_Debug_Tools::plainOutput()) {
546
+			return $var;
547
+		}
548
+		return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">' . $var . '</pre>';
549
+	}
550
+
551
+
552
+
553
+	/**
554
+	 * @param mixed      $var
555
+	 * @param string     $var_name
556
+	 * @param string     $file
557
+	 * @param int|string $line
558
+	 * @param int|string $heading_tag
559
+	 * @param bool       $die
560
+	 */
561
+	public static function printr(
562
+		$var,
563
+		$var_name = '',
564
+		$file = '',
565
+		$line = '',
566
+		$heading_tag = 5,
567
+		$die = false
568
+	) {
569
+		// return;
570
+		$file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
571
+		if (empty($var) && empty($var_name)) {
572
+			$var = $file;
573
+			$var_name = "line $line";
574
+			$file = '';
575
+			$line = '';
576
+		}
577
+		$margin = is_admin() ? ' 180px' : '0';
578
+		// $print_r = false;
579
+		if (is_string($var)) {
580
+			EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
581
+			return;
582
+		}
583
+		if (is_object($var)) {
584
+			$var_name = ! $var_name ? 'object' : $var_name;
585
+			// $print_r = true;
586
+		} elseif (is_array($var)) {
587
+			$var_name = ! $var_name ? 'array' : $var_name;
588
+			// $print_r = true;
589
+		} elseif (is_numeric($var)) {
590
+			$var_name = ! $var_name ? 'numeric' : $var_name;
591
+		} elseif ($var === null) {
592
+			$var_name = ! $var_name ? 'null' : $var_name;
593
+		}
594
+		$var_name = ucwords(str_replace(array('$', '_'), array('', ' '), $var_name));
595
+		$heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
596
+		// $result = EEH_Debug_Tools::headingSpacer($heading_tag);
597
+		$result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
598
+		$result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
599
+			EEH_Debug_Tools::pre_span($var)
600
+		);
601
+		$result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
602
+		$result .= EEH_Debug_Tools::headingX($heading_tag);
603
+		if ($die) {
604
+			die($result);
605
+		}
606
+		echo $result;
607
+	}
608
+
609
+
610
+	private static function lineBreak($lines = 1): string
611
+	{
612
+		$linebreak = defined('DOING_AJAX') && DOING_AJAX ? '<br />' : PHP_EOL;
613
+		return str_repeat($linebreak, $lines);
614
+	}
615
+
616
+
617
+
618
+	/******************** deprecated ********************/
619
+
620
+
621
+
622
+	/**
623
+	 * @deprecated 4.9.39.rc.034
624
+	 */
625
+	public function reset_times()
626
+	{
627
+		Benchmark::resetTimes();
628
+	}
629
+
630
+
631
+
632
+	/**
633
+	 * @deprecated 4.9.39.rc.034
634
+	 * @param null $timer_name
635
+	 */
636
+	public function start_timer($timer_name = null)
637
+	{
638
+		Benchmark::startTimer($timer_name);
639
+	}
640
+
641
+
642
+
643
+	/**
644
+	 * @deprecated 4.9.39.rc.034
645
+	 * @param string $timer_name
646
+	 */
647
+	public function stop_timer($timer_name = '')
648
+	{
649
+		Benchmark::stopTimer($timer_name);
650
+	}
651
+
652
+
653
+
654
+	/**
655
+	 * @deprecated 4.9.39.rc.034
656
+	 * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
657
+	 * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
658
+	 * @return void
659
+	 */
660
+	public function measure_memory($label, $output_now = false)
661
+	{
662
+		Benchmark::measureMemory($label, $output_now);
663
+	}
664
+
665
+
666
+
667
+	/**
668
+	 * @deprecated 4.9.39.rc.034
669
+	 * @param int $size
670
+	 * @return string
671
+	 */
672
+	public function convert($size)
673
+	{
674
+		return Benchmark::convert($size);
675
+	}
676
+
677
+
678
+
679
+	/**
680
+	 * @deprecated 4.9.39.rc.034
681
+	 * @param bool $output_now
682
+	 * @return string
683
+	 */
684
+	public function show_times($output_now = true)
685
+	{
686
+		return Benchmark::displayResults($output_now);
687
+	}
688
+
689
+
690
+
691
+	/**
692
+	 * @deprecated 4.9.39.rc.034
693
+	 * @param string $timer_name
694
+	 * @param float  $total_time
695
+	 * @return string
696
+	 */
697
+	public function format_time($timer_name, $total_time)
698
+	{
699
+		return Benchmark::formatTime($timer_name, $total_time);
700
+	}
701 701
 }
702 702
 
703 703
 
@@ -707,31 +707,31 @@  discard block
 block discarded – undo
707 707
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
708 708
  */
709 709
 if (class_exists('Kint') && ! function_exists('dump_wp_query')) {
710
-    function dump_wp_query()
711
-    {
712
-        global $wp_query;
713
-        d($wp_query);
714
-    }
710
+	function dump_wp_query()
711
+	{
712
+		global $wp_query;
713
+		d($wp_query);
714
+	}
715 715
 }
716 716
 /**
717 717
  * borrowed from Kint Debugger
718 718
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
719 719
  */
720 720
 if (class_exists('Kint') && ! function_exists('dump_wp')) {
721
-    function dump_wp()
722
-    {
723
-        global $wp;
724
-        d($wp);
725
-    }
721
+	function dump_wp()
722
+	{
723
+		global $wp;
724
+		d($wp);
725
+	}
726 726
 }
727 727
 /**
728 728
  * borrowed from Kint Debugger
729 729
  * Plugin URI: http://upthemes.com/plugins/kint-debugger/
730 730
  */
731 731
 if (class_exists('Kint') && ! function_exists('dump_post')) {
732
-    function dump_post()
733
-    {
734
-        global $post;
735
-        d($post);
736
-    }
732
+	function dump_post()
733
+	{
734
+		global $post;
735
+		d($post);
736
+	}
737 737
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
     public static function instance()
37 37
     {
38 38
         // check if class object is instantiated, and instantiated properly
39
-        if (! self::$_instance instanceof EEH_Debug_Tools) {
39
+        if ( ! self::$_instance instanceof EEH_Debug_Tools) {
40 40
             self::$_instance = new self();
41 41
         }
42 42
         return self::$_instance;
@@ -50,13 +50,13 @@  discard block
 block discarded – undo
50 50
     private function __construct()
51 51
     {
52 52
         // load Kint PHP debugging library
53
-        if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php')) {
53
+        if ( ! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH.'tests/kint/Kint.class.php')) {
54 54
             // despite EE4 having a check for an existing copy of the Kint debugging class,
55 55
             // if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
56 56
             // then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
57 57
             // so we've moved it to our test folder so that it is not included with production releases
58 58
             // plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
59
-            require_once(EE_PLUGIN_DIR_PATH . 'tests/kint/Kint.class.php');
59
+            require_once(EE_PLUGIN_DIR_PATH.'tests/kint/Kint.class.php');
60 60
         }
61 61
         // if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
62 62
         // add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
      */
77 77
     public static function show_db_name()
78 78
     {
79
-        if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
79
+        if ( ! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
80 80
             echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
81 81
                  . DB_NAME
82 82
                  . '</p>';
@@ -126,12 +126,12 @@  discard block
 block discarded – undo
126 126
         global $wp_filter;
127 127
         echo '<br/><br/><br/><h3>Hooked Functions</h3>';
128 128
         if ($tag) {
129
-            $hook[ $tag ] = $wp_filter[ $tag ];
130
-            if (! is_array($hook[ $tag ])) {
129
+            $hook[$tag] = $wp_filter[$tag];
130
+            if ( ! is_array($hook[$tag])) {
131 131
                 trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
132 132
                 return;
133 133
             }
134
-            echo '<h5>For Tag: ' . $tag . '</h5>';
134
+            echo '<h5>For Tag: '.$tag.'</h5>';
135 135
         } else {
136 136
             $hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
137 137
             ksort($hook);
@@ -160,12 +160,12 @@  discard block
 block discarded – undo
160 160
     {
161 161
         $filters = array();
162 162
         global $wp_filter;
163
-        if (isset($wp_filter[ $hook_name ])) {
164
-            $filters[ $hook_name ] = array();
165
-            foreach ($wp_filter[ $hook_name ] as $priority => $callbacks) {
166
-                $filters[ $hook_name ][ $priority ] = array();
163
+        if (isset($wp_filter[$hook_name])) {
164
+            $filters[$hook_name] = array();
165
+            foreach ($wp_filter[$hook_name] as $priority => $callbacks) {
166
+                $filters[$hook_name][$priority] = array();
167 167
                 foreach ($callbacks as $callback) {
168
-                    $filters[ $hook_name ][ $priority ][] = $callback['function'];
168
+                    $filters[$hook_name][$priority][] = $callback['function'];
169 169
                 }
170 170
             }
171 171
         }
@@ -187,15 +187,15 @@  discard block
 block discarded – undo
187 187
             if (empty($activation_errors)) {
188 188
                 return;
189 189
             }
190
-            $activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
191
-            espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
190
+            $activation_errors = date('Y-m-d H:i:s')."\n".$activation_errors;
191
+            espresso_load_required('EEH_File', EE_HELPERS.'EEH_File.helper.php');
192 192
             if (class_exists('EEH_File')) {
193 193
                 try {
194 194
                     EEH_File::ensure_file_exists_and_is_writable(
195
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html'
195
+                        EVENT_ESPRESSO_UPLOAD_DIR.'logs/espresso_plugin_activation_errors.html'
196 196
                     );
197 197
                     EEH_File::write_to_file(
198
-                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
198
+                        EVENT_ESPRESSO_UPLOAD_DIR.'logs/espresso_plugin_activation_errors.html',
199 199
                         $activation_errors
200 200
                     );
201 201
                 } catch (EE_Error $e) {
@@ -215,11 +215,11 @@  discard block
 block discarded – undo
215 215
             } else {
216 216
                 // old school attempt
217 217
                 file_put_contents(
218
-                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs/espresso_plugin_activation_errors.html',
218
+                    EVENT_ESPRESSO_UPLOAD_DIR.'logs/espresso_plugin_activation_errors.html',
219 219
                     $activation_errors
220 220
                 );
221 221
             }
222
-            $activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
222
+            $activation_errors = get_option('ee_plugin_activation_errors', '').$activation_errors;
223 223
             update_option('ee_plugin_activation_errors', $activation_errors);
224 224
         }
225 225
     }
@@ -279,7 +279,7 @@  discard block
 block discarded – undo
279 279
         // don't trigger error if doing ajax,
280 280
         // instead we'll add a transient EE_Error notice that in theory should show on the next request.
281 281
         if (defined('DOING_AJAX') && DOING_AJAX) {
282
-            $error_message .= ' ' . esc_html__(
282
+            $error_message .= ' '.esc_html__(
283 283
                 'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
284 284
                 'event_espresso'
285 285
             );
@@ -323,19 +323,19 @@  discard block
 block discarded – undo
323 323
         $debug_key = 'EE_DEBUG_SPCO'
324 324
     ) {
325 325
         if (WP_DEBUG) {
326
-            $debug_key = $debug_key . '_' . EE_Session::instance()->id();
326
+            $debug_key = $debug_key.'_'.EE_Session::instance()->id();
327 327
             $debug_data = get_option($debug_key, array());
328 328
             $default_data = array(
329
-                $class => $func . '() : ' . $line,
329
+                $class => $func.'() : '.$line,
330 330
                 'REQ'  => $display_request ? $_REQUEST : '',
331 331
             );
332 332
             // don't serialize objects
333 333
             $info = self::strip_objects($info);
334 334
             $index = ! empty($debug_index) ? $debug_index : 0;
335
-            if (! isset($debug_data[ $index ])) {
336
-                $debug_data[ $index ] = array();
335
+            if ( ! isset($debug_data[$index])) {
336
+                $debug_data[$index] = array();
337 337
             }
338
-            $debug_data[ $index ][ microtime() ] = array_merge($default_data, $info);
338
+            $debug_data[$index][microtime()] = array_merge($default_data, $info);
339 339
             update_option($debug_key, $debug_data);
340 340
         }
341 341
     }
@@ -352,20 +352,20 @@  discard block
 block discarded – undo
352 352
     {
353 353
         foreach ($info as $key => $value) {
354 354
             if (is_array($value)) {
355
-                $info[ $key ] = self::strip_objects($value);
355
+                $info[$key] = self::strip_objects($value);
356 356
             } elseif (is_object($value)) {
357 357
                 $object_class = get_class($value);
358
-                $info[ $object_class ] = array();
359
-                $info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
358
+                $info[$object_class] = array();
359
+                $info[$object_class]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
360 360
                 if (method_exists($value, 'ID')) {
361
-                    $info[ $object_class ]['ID'] = $value->ID();
361
+                    $info[$object_class]['ID'] = $value->ID();
362 362
                 }
363 363
                 if (method_exists($value, 'status')) {
364
-                    $info[ $object_class ]['status'] = $value->status();
364
+                    $info[$object_class]['status'] = $value->status();
365 365
                 } elseif (method_exists($value, 'status_ID')) {
366
-                    $info[ $object_class ]['status'] = $value->status_ID();
366
+                    $info[$object_class]['status'] = $value->status_ID();
367 367
                 }
368
-                unset($info[ $key ]);
368
+                unset($info[$key]);
369 369
             }
370 370
         }
371 371
         return (array) $info;
@@ -399,8 +399,8 @@  discard block
 block discarded – undo
399 399
         // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
400 400
         $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
401 401
         $result .= $is_method
402
-            ? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
403
-            : EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
402
+            ? EEH_Debug_Tools::grey_span('::').EEH_Debug_Tools::orange_span($var.'()')
403
+            : EEH_Debug_Tools::grey_span(' : ').EEH_Debug_Tools::orange_span($var);
404 404
         $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
405 405
         $result .= EEH_Debug_Tools::headingX($heading_tag);
406 406
         if ($die) {
@@ -460,7 +460,7 @@  discard block
 block discarded – undo
460 460
             return "{$line_breaks}{$line}) {$var_name}";
461 461
         }
462 462
         $margin = "25px 0 0 {$margin}";
463
-        return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
463
+        return '<'.$heading_tag.' style="color:#2EA2CC; margin:'.$margin.';"><b>'.$var_name.'</b>';
464 464
     }
465 465
 
466 466
 
@@ -474,7 +474,7 @@  discard block
 block discarded – undo
474 474
         if (EEH_Debug_Tools::plainOutput()) {
475 475
             return '';
476 476
         }
477
-        return '</' . $heading_tag . '>';
477
+        return '</'.$heading_tag.'>';
478 478
     }
479 479
 
480 480
 
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
         if (EEH_Debug_Tools::plainOutput()) {
489 489
             return $content;
490 490
         }
491
-        return '<span style="color:#999">' . $content . '</span>';
491
+        return '<span style="color:#999">'.$content.'</span>';
492 492
     }
493 493
 
494 494
 
@@ -528,7 +528,7 @@  discard block
 block discarded – undo
528 528
         if (EEH_Debug_Tools::plainOutput()) {
529 529
             return $content;
530 530
         }
531
-        return '<span style="color:#E76700">' . $content . '</span>';
531
+        return '<span style="color:#E76700">'.$content.'</span>';
532 532
     }
533 533
 
534 534
 
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
         if (EEH_Debug_Tools::plainOutput()) {
546 546
             return $var;
547 547
         }
548
-        return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">' . $var . '</pre>';
548
+        return '<pre style="color: #9C3; display: inline-block; padding:.4em .6em; background: #334">'.$var.'</pre>';
549 549
     }
550 550
 
551 551
 
@@ -595,7 +595,7 @@  discard block
 block discarded – undo
595 595
         $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
596 596
         // $result = EEH_Debug_Tools::headingSpacer($heading_tag);
597 597
         $result = EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
598
-        $result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
598
+        $result .= EEH_Debug_Tools::grey_span(' : ').EEH_Debug_Tools::orange_span(
599 599
             EEH_Debug_Tools::pre_span($var)
600 600
         );
601 601
         $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
Please login to merge, or discard this patch.
core/services/orm/tree_traversal/NodeGroupDao.php 2 patches
Indentation   +105 added lines, -105 removed lines patch added patch discarded remove patch
@@ -22,123 +22,123 @@
 block discarded – undo
22 22
  */
23 23
 class NodeGroupDao
24 24
 {
25
-    /**
26
-     * @return mixed|void
27
-     */
28
-    public function generateGroupCode()
29
-    {
30
-        return wp_generate_password(6, false);
31
-    }
25
+	/**
26
+	 * @return mixed|void
27
+	 */
28
+	public function generateGroupCode()
29
+	{
30
+		return wp_generate_password(6, false);
31
+	}
32 32
 
33 33
 
34
-    /**
35
-     * Gets the string we put in front of the WP Option name used to store the jobs.
36
-     *
37
-     * @return string
38
-     */
39
-    private function getOptionPrefix()
40
-    {
41
-        return 'ee_deletion_';
42
-    }
34
+	/**
35
+	 * Gets the string we put in front of the WP Option name used to store the jobs.
36
+	 *
37
+	 * @return string
38
+	 */
39
+	private function getOptionPrefix()
40
+	{
41
+		return 'ee_deletion_';
42
+	}
43 43
 
44 44
 
45
-    /**
46
-     * @param $code
47
-     * @return ModelObjNode[]
48
-     * @throws UnexpectedEntityException
49
-     * @throws Exception
50
-     */
51
-    public function getModelObjNodesInGroup($code)
52
-    {
53
-        if (! $code) {
54
-            throw new Exception(
55
-                esc_html__(
56
-                    'We aren’t sure which job you are performing. Please press back in your browser and try again.',
57
-                    'event_espresso'
58
-                )
59
-            );
60
-        }
61
-        $deletion_data = get_option($this->getOptionPrefix() . $code, []);
62
-        foreach ($deletion_data as $root) {
63
-            if (! $root instanceof ModelObjNode) {
64
-                throw new UnexpectedEntityException($root, 'ModelObjNode');
65
-            }
66
-        }
67
-        return $deletion_data;
68
-    }
45
+	/**
46
+	 * @param $code
47
+	 * @return ModelObjNode[]
48
+	 * @throws UnexpectedEntityException
49
+	 * @throws Exception
50
+	 */
51
+	public function getModelObjNodesInGroup($code)
52
+	{
53
+		if (! $code) {
54
+			throw new Exception(
55
+				esc_html__(
56
+					'We aren’t sure which job you are performing. Please press back in your browser and try again.',
57
+					'event_espresso'
58
+				)
59
+			);
60
+		}
61
+		$deletion_data = get_option($this->getOptionPrefix() . $code, []);
62
+		foreach ($deletion_data as $root) {
63
+			if (! $root instanceof ModelObjNode) {
64
+				throw new UnexpectedEntityException($root, 'ModelObjNode');
65
+			}
66
+		}
67
+		return $deletion_data;
68
+	}
69 69
 
70 70
 
71
-    /**
72
-     * Gets an array indicating what database rows are contained in the job.
73
-     * Each top-level key is a model name, and its value is an array of IDs.
74
-     *
75
-     * @param ModelObjNode[] $model_obj_nodes
76
-     * @return array
77
-     * @throws EE_Error
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     * @throws InvalidArgumentException
81
-     * @throws ReflectionException
82
-     */
83
-    public function getModelsAndIdsContainedIn(array $model_obj_nodes)
84
-    {
85
-        $models_and_ids_to_delete = [];
86
-        foreach ($model_obj_nodes as $root) {
87
-            $models_and_ids_to_delete = array_replace_recursive($models_and_ids_to_delete, $root->getIds());
88
-        }
89
-        return $models_and_ids_to_delete;
90
-    }
71
+	/**
72
+	 * Gets an array indicating what database rows are contained in the job.
73
+	 * Each top-level key is a model name, and its value is an array of IDs.
74
+	 *
75
+	 * @param ModelObjNode[] $model_obj_nodes
76
+	 * @return array
77
+	 * @throws EE_Error
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 * @throws InvalidArgumentException
81
+	 * @throws ReflectionException
82
+	 */
83
+	public function getModelsAndIdsContainedIn(array $model_obj_nodes)
84
+	{
85
+		$models_and_ids_to_delete = [];
86
+		foreach ($model_obj_nodes as $root) {
87
+			$models_and_ids_to_delete = array_replace_recursive($models_and_ids_to_delete, $root->getIds());
88
+		}
89
+		return $models_and_ids_to_delete;
90
+	}
91 91
 
92 92
 
93
-    /**
94
-     * Gets an array indicating what database rows are contained in the job.
95
-     * Each top-level key is a model name, and its value is an array of IDs.
96
-     *
97
-     * @param string $code
98
-     * @return array
99
-     * @throws EE_Error
100
-     * @throws InvalidArgumentException
101
-     * @throws InvalidDataTypeException
102
-     * @throws InvalidInterfaceException
103
-     * @throws ReflectionException
104
-     * @throws UnexpectedEntityException
105
-     * @throws Exception
106
-     */
107
-    public function getModelsAndIdsFromGroup($code)
108
-    {
109
-        $model_obj_nodes = $this->getModelObjNodesInGroup($code);
110
-        return $this->getModelsAndIdsContainedIn($model_obj_nodes);
111
-    }
93
+	/**
94
+	 * Gets an array indicating what database rows are contained in the job.
95
+	 * Each top-level key is a model name, and its value is an array of IDs.
96
+	 *
97
+	 * @param string $code
98
+	 * @return array
99
+	 * @throws EE_Error
100
+	 * @throws InvalidArgumentException
101
+	 * @throws InvalidDataTypeException
102
+	 * @throws InvalidInterfaceException
103
+	 * @throws ReflectionException
104
+	 * @throws UnexpectedEntityException
105
+	 * @throws Exception
106
+	 */
107
+	public function getModelsAndIdsFromGroup($code)
108
+	{
109
+		$model_obj_nodes = $this->getModelObjNodesInGroup($code);
110
+		return $this->getModelsAndIdsContainedIn($model_obj_nodes);
111
+	}
112 112
 
113 113
 
114
-    /**
115
-     * Persists the ModelObjNodes for future requests, using the code for reference.
116
-     *
117
-     * @param ModelObjNode[] $model_obj_nodes
118
-     * @param string         $code
119
-     * @return bool
120
-     */
121
-    public function persistModelObjNodesGroup(array $model_obj_nodes, $code)
122
-    {
123
-        return add_option(
124
-            $this->getOptionPrefix() . $code,
125
-            $model_obj_nodes,
126
-            null,
127
-            'no'
128
-        );
129
-    }
114
+	/**
115
+	 * Persists the ModelObjNodes for future requests, using the code for reference.
116
+	 *
117
+	 * @param ModelObjNode[] $model_obj_nodes
118
+	 * @param string         $code
119
+	 * @return bool
120
+	 */
121
+	public function persistModelObjNodesGroup(array $model_obj_nodes, $code)
122
+	{
123
+		return add_option(
124
+			$this->getOptionPrefix() . $code,
125
+			$model_obj_nodes,
126
+			null,
127
+			'no'
128
+		);
129
+	}
130 130
 
131 131
 
132
-    /**
133
-     * Forgets about the group of ModelObjNodes. Doesn't delete the rows in the database they reference though.
134
-     *
135
-     * @param $code
136
-     * @return bool
137
-     */
138
-    public function deleteModelObjNodesInGroup($code)
139
-    {
140
-        return delete_option($this->getOptionPrefix() . $code);
141
-    }
132
+	/**
133
+	 * Forgets about the group of ModelObjNodes. Doesn't delete the rows in the database they reference though.
134
+	 *
135
+	 * @param $code
136
+	 * @return bool
137
+	 */
138
+	public function deleteModelObjNodesInGroup($code)
139
+	{
140
+		return delete_option($this->getOptionPrefix() . $code);
141
+	}
142 142
 }
143 143
 // End of file NodeGroupDao.php
144 144
 // Location: EventEspresso\core\services\orm\tree_traversal/NodeGroupDao.php
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
      */
51 51
     public function getModelObjNodesInGroup($code)
52 52
     {
53
-        if (! $code) {
53
+        if ( ! $code) {
54 54
             throw new Exception(
55 55
                 esc_html__(
56 56
                     'We aren’t sure which job you are performing. Please press back in your browser and try again.',
@@ -58,9 +58,9 @@  discard block
 block discarded – undo
58 58
                 )
59 59
             );
60 60
         }
61
-        $deletion_data = get_option($this->getOptionPrefix() . $code, []);
61
+        $deletion_data = get_option($this->getOptionPrefix().$code, []);
62 62
         foreach ($deletion_data as $root) {
63
-            if (! $root instanceof ModelObjNode) {
63
+            if ( ! $root instanceof ModelObjNode) {
64 64
                 throw new UnexpectedEntityException($root, 'ModelObjNode');
65 65
             }
66 66
         }
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
     public function persistModelObjNodesGroup(array $model_obj_nodes, $code)
122 122
     {
123 123
         return add_option(
124
-            $this->getOptionPrefix() . $code,
124
+            $this->getOptionPrefix().$code,
125 125
             $model_obj_nodes,
126 126
             null,
127 127
             'no'
@@ -137,7 +137,7 @@  discard block
 block discarded – undo
137 137
      */
138 138
     public function deleteModelObjNodesInGroup($code)
139 139
     {
140
-        return delete_option($this->getOptionPrefix() . $code);
140
+        return delete_option($this->getOptionPrefix().$code);
141 141
     }
142 142
 }
143 143
 // End of file NodeGroupDao.php
Please login to merge, or discard this patch.
core/services/orm/tree_traversal/RelationNode.php 2 patches
Indentation   +303 added lines, -303 removed lines patch added patch discarded remove patch
@@ -25,309 +25,309 @@
 block discarded – undo
25 25
 class RelationNode extends BaseNode
26 26
 {
27 27
 
28
-    /**
29
-     * @var int
30
-     */
31
-    protected $count;
32
-
33
-    /**
34
-     * @var string|int
35
-     */
36
-    protected $id;
37
-
38
-    /**
39
-     * @var EEM_Base
40
-     */
41
-    protected $main_model;
42
-
43
-    /**
44
-     * @var ModelObjNode[]
45
-     */
46
-    protected $nodes;
47
-
48
-    /**
49
-     * @var EEM_Base
50
-     */
51
-    protected $related_model;
52
-
53
-
54
-    /**
55
-     * RelationNode constructor.
56
-     *
57
-     * @param          $main_model_obj_id
58
-     * @param EEM_Base $main_model
59
-     * @param EEM_Base $related_model
60
-     * @param array    $dont_traverse_models array of model names we DON'T want to traverse
61
-     */
62
-    public function __construct(
63
-        $main_model_obj_id,
64
-        EEM_Base $main_model,
65
-        EEM_Base $related_model,
66
-        array $dont_traverse_models = []
67
-    ) {
68
-        $this->id                   = $main_model_obj_id;
69
-        $this->main_model           = $main_model;
70
-        $this->related_model        = $related_model;
71
-        $this->nodes                = [];
72
-        $this->dont_traverse_models = $dont_traverse_models;
73
-    }
74
-
75
-
76
-    /**
77
-     * Here is where most of the work happens. We've counted how many related model objects exist, here we identify
78
-     * them (ie, learn their IDs). But its recursive, so we'll also find their related dependent model objects etc.
79
-     *
80
-     * @param int $model_objects_to_identify
81
-     * @return int
82
-     * @throws EE_Error
83
-     * @throws InvalidArgumentException
84
-     * @throws InvalidDataTypeException
85
-     * @throws InvalidInterfaceException
86
-     * @throws ReflectionException
87
-     */
88
-    protected function work($model_objects_to_identify)
89
-    {
90
-        $num_identified = $this->visitAlreadyDiscoveredNodes($this->nodes, $model_objects_to_identify);
91
-        if ($num_identified < $model_objects_to_identify) {
92
-            $related_model_objs = $this->related_model->get_all(
93
-                [
94
-                    $this->whereQueryParams(),
95
-                    'limit' => [
96
-                        count($this->nodes),
97
-                        $model_objects_to_identify - $num_identified,
98
-                    ],
99
-                ]
100
-            );
101
-            $new_item_nodes     = [];
102
-
103
-            // Add entity nodes for each of the model objects we fetched.
104
-            foreach ($related_model_objs as $related_model_obj) {
105
-                $entity_node                                = new ModelObjNode(
106
-                    $related_model_obj->ID(),
107
-                    $related_model_obj->get_model(),
108
-                    $this->dont_traverse_models
109
-                );
110
-                $this->nodes[ $related_model_obj->ID() ]    = $entity_node;
111
-                $new_item_nodes[ $related_model_obj->ID() ] = $entity_node;
112
-            }
113
-            $num_identified += count($new_item_nodes);
114
-            if ($num_identified < $model_objects_to_identify) {
115
-                // And lastly do the work.
116
-                $num_identified += $this->visitAlreadyDiscoveredNodes(
117
-                    $new_item_nodes,
118
-                    $model_objects_to_identify - $num_identified
119
-                );
120
-            }
121
-        }
122
-
123
-        if (count($this->nodes) >= $this->count && $this->allChildrenComplete()) {
124
-            $this->complete = true;
125
-        }
126
-        return $num_identified;
127
-    }
128
-
129
-
130
-    /**
131
-     * Checks if all the identified child nodes are complete or not.
132
-     *
133
-     * @return bool
134
-     */
135
-    protected function allChildrenComplete()
136
-    {
137
-        foreach ($this->nodes as $model_obj_node) {
138
-            if (! $model_obj_node->isComplete()) {
139
-                return false;
140
-            }
141
-        }
142
-        return true;
143
-    }
144
-
145
-
146
-    /**
147
-     * Visits the provided nodes and keeps track of how much work was done, making sure to not go over budget.
148
-     *
149
-     * @param ModelObjNode[] $model_obj_nodes
150
-     * @param                $work_budget
151
-     * @return int
152
-     */
153
-    protected function visitAlreadyDiscoveredNodes($model_obj_nodes, $work_budget)
154
-    {
155
-        $work_done = 0;
156
-        if (! $model_obj_nodes) {
157
-            return 0;
158
-        }
159
-        foreach ($model_obj_nodes as $model_obj_node) {
160
-            if ($work_done >= $work_budget) {
161
-                break;
162
-            }
163
-            $work_done += $model_obj_node->visit($work_budget - $work_done);
164
-        }
165
-        return $work_done;
166
-    }
167
-
168
-
169
-    /**
170
-     * Whether this item has already been initialized
171
-     */
172
-    protected function isDiscovered()
173
-    {
174
-        return $this->count !== null;
175
-    }
176
-
177
-
178
-    /**
179
-     * @return boolean
180
-     */
181
-    public function isComplete()
182
-    {
183
-        if ($this->complete === null) {
184
-            if (count($this->nodes) === $this->count) {
185
-                $this->complete = true;
186
-            } else {
187
-                $this->complete = false;
188
-            }
189
-        }
190
-        return $this->complete;
191
-    }
192
-
193
-
194
-    /**
195
-     * Discovers how many related model objects exist.
196
-     *
197
-     * @return void
198
-     * @throws EE_Error
199
-     * @throws InvalidArgumentException
200
-     * @throws InvalidDataTypeException
201
-     * @throws InvalidInterfaceException
202
-     * @throws ReflectionException
203
-     */
204
-    protected function discover()
205
-    {
206
-        $this->count = $this->related_model->count([$this->whereQueryParams()]);
207
-    }
208
-
209
-
210
-    /**
211
-     * @return array
212
-     * @throws EE_Error
213
-     * @throws InvalidDataTypeException
214
-     * @throws InvalidInterfaceException
215
-     * @throws InvalidArgumentException
216
-     */
217
-    protected function whereQueryParams()
218
-    {
219
-        $where_params = [
220
-            $this->related_model->get_foreign_key_to(
221
-                $this->main_model->get_this_model_name()
222
-            )->get_name() => $this->id,
223
-        ];
224
-        try {
225
-            $relation_settings = $this->main_model->related_settings_for($this->related_model->get_this_model_name());
226
-        } catch (EE_Error $e) {
227
-            // This will happen for has-and-belongs-to-many relations, when this node's related model is that join table
228
-            // which hasn't been explicitly declared in the main model object's model's relations.
229
-            $relation_settings = null;
230
-        }
231
-        if ($relation_settings instanceof EE_Has_Many_Any_Relation) {
232
-            $where_params[ $this->related_model->get_field_containing_related_model_name()->get_name() ] =
233
-                $this->main_model->get_this_model_name();
234
-        }
235
-        return $where_params;
236
-    }
237
-
238
-
239
-    /**
240
-     * @return array
241
-     * @throws EE_Error
242
-     * @throws ReflectionException
243
-     */
244
-    public function toArray()
245
-    {
246
-        $tree = [
247
-            'count'    => $this->count,
248
-            'complete' => $this->isComplete(),
249
-            'objs'     => [],
250
-        ];
251
-        foreach ($this->nodes as $id => $model_obj_node) {
252
-            $tree['objs'][ $id ] = $model_obj_node->toArray();
253
-        }
254
-        return $tree;
255
-    }
256
-
257
-
258
-    /**
259
-     * Gets the IDs of all the model objects to delete; indexed first by model object name.
260
-     *
261
-     * @return array
262
-     * @throws EE_Error
263
-     * @throws ReflectionException
264
-     */
265
-    public function getIds()
266
-    {
267
-        if (empty($this->nodes)) {
268
-            return [];
269
-        }
270
-        $ids = [
271
-            $this->related_model->get_this_model_name() => array_combine(
272
-                array_keys($this->nodes),
273
-                array_keys($this->nodes)
274
-            ),
275
-        ];
276
-        foreach ($this->nodes as $model_obj_node) {
277
-            $ids = array_replace_recursive($ids, $model_obj_node->getIds());
278
-        }
279
-        return $ids;
280
-    }
281
-
282
-
283
-    /**
284
-     * Returns the number of sub-nodes found (ie, related model objects across this relation.)
285
-     *
286
-     * @return int
287
-     */
288
-    public function countSubNodes()
289
-    {
290
-        return count($this->nodes);
291
-    }
292
-
293
-
294
-    /**
295
-     * Don't serialize the models. Just record their names on some dynamic properties.
296
-     *
297
-     * @return array
298
-     */
299
-    public function __sleep()
300
-    {
301
-        $this->m  = $this->main_model->get_this_model_name();
302
-        $this->rm = $this->related_model->get_this_model_name();
303
-        return array_merge(
304
-            [
305
-                'm',
306
-                'rm',
307
-                'id',
308
-                'count',
309
-                'nodes',
310
-            ],
311
-            parent::__sleep()
312
-        );
313
-    }
314
-
315
-
316
-    /**
317
-     * Use the dynamic properties to instantiate the models we use.
318
-     *
319
-     * @throws EE_Error
320
-     * @throws InvalidArgumentException
321
-     * @throws InvalidDataTypeException
322
-     * @throws InvalidInterfaceException
323
-     * @throws ReflectionException
324
-     */
325
-    public function __wakeup()
326
-    {
327
-        $this->main_model    = EE_Registry::instance()->load_model($this->m);
328
-        $this->related_model = EE_Registry::instance()->load_model($this->rm);
329
-        parent::__wakeup();
330
-    }
28
+	/**
29
+	 * @var int
30
+	 */
31
+	protected $count;
32
+
33
+	/**
34
+	 * @var string|int
35
+	 */
36
+	protected $id;
37
+
38
+	/**
39
+	 * @var EEM_Base
40
+	 */
41
+	protected $main_model;
42
+
43
+	/**
44
+	 * @var ModelObjNode[]
45
+	 */
46
+	protected $nodes;
47
+
48
+	/**
49
+	 * @var EEM_Base
50
+	 */
51
+	protected $related_model;
52
+
53
+
54
+	/**
55
+	 * RelationNode constructor.
56
+	 *
57
+	 * @param          $main_model_obj_id
58
+	 * @param EEM_Base $main_model
59
+	 * @param EEM_Base $related_model
60
+	 * @param array    $dont_traverse_models array of model names we DON'T want to traverse
61
+	 */
62
+	public function __construct(
63
+		$main_model_obj_id,
64
+		EEM_Base $main_model,
65
+		EEM_Base $related_model,
66
+		array $dont_traverse_models = []
67
+	) {
68
+		$this->id                   = $main_model_obj_id;
69
+		$this->main_model           = $main_model;
70
+		$this->related_model        = $related_model;
71
+		$this->nodes                = [];
72
+		$this->dont_traverse_models = $dont_traverse_models;
73
+	}
74
+
75
+
76
+	/**
77
+	 * Here is where most of the work happens. We've counted how many related model objects exist, here we identify
78
+	 * them (ie, learn their IDs). But its recursive, so we'll also find their related dependent model objects etc.
79
+	 *
80
+	 * @param int $model_objects_to_identify
81
+	 * @return int
82
+	 * @throws EE_Error
83
+	 * @throws InvalidArgumentException
84
+	 * @throws InvalidDataTypeException
85
+	 * @throws InvalidInterfaceException
86
+	 * @throws ReflectionException
87
+	 */
88
+	protected function work($model_objects_to_identify)
89
+	{
90
+		$num_identified = $this->visitAlreadyDiscoveredNodes($this->nodes, $model_objects_to_identify);
91
+		if ($num_identified < $model_objects_to_identify) {
92
+			$related_model_objs = $this->related_model->get_all(
93
+				[
94
+					$this->whereQueryParams(),
95
+					'limit' => [
96
+						count($this->nodes),
97
+						$model_objects_to_identify - $num_identified,
98
+					],
99
+				]
100
+			);
101
+			$new_item_nodes     = [];
102
+
103
+			// Add entity nodes for each of the model objects we fetched.
104
+			foreach ($related_model_objs as $related_model_obj) {
105
+				$entity_node                                = new ModelObjNode(
106
+					$related_model_obj->ID(),
107
+					$related_model_obj->get_model(),
108
+					$this->dont_traverse_models
109
+				);
110
+				$this->nodes[ $related_model_obj->ID() ]    = $entity_node;
111
+				$new_item_nodes[ $related_model_obj->ID() ] = $entity_node;
112
+			}
113
+			$num_identified += count($new_item_nodes);
114
+			if ($num_identified < $model_objects_to_identify) {
115
+				// And lastly do the work.
116
+				$num_identified += $this->visitAlreadyDiscoveredNodes(
117
+					$new_item_nodes,
118
+					$model_objects_to_identify - $num_identified
119
+				);
120
+			}
121
+		}
122
+
123
+		if (count($this->nodes) >= $this->count && $this->allChildrenComplete()) {
124
+			$this->complete = true;
125
+		}
126
+		return $num_identified;
127
+	}
128
+
129
+
130
+	/**
131
+	 * Checks if all the identified child nodes are complete or not.
132
+	 *
133
+	 * @return bool
134
+	 */
135
+	protected function allChildrenComplete()
136
+	{
137
+		foreach ($this->nodes as $model_obj_node) {
138
+			if (! $model_obj_node->isComplete()) {
139
+				return false;
140
+			}
141
+		}
142
+		return true;
143
+	}
144
+
145
+
146
+	/**
147
+	 * Visits the provided nodes and keeps track of how much work was done, making sure to not go over budget.
148
+	 *
149
+	 * @param ModelObjNode[] $model_obj_nodes
150
+	 * @param                $work_budget
151
+	 * @return int
152
+	 */
153
+	protected function visitAlreadyDiscoveredNodes($model_obj_nodes, $work_budget)
154
+	{
155
+		$work_done = 0;
156
+		if (! $model_obj_nodes) {
157
+			return 0;
158
+		}
159
+		foreach ($model_obj_nodes as $model_obj_node) {
160
+			if ($work_done >= $work_budget) {
161
+				break;
162
+			}
163
+			$work_done += $model_obj_node->visit($work_budget - $work_done);
164
+		}
165
+		return $work_done;
166
+	}
167
+
168
+
169
+	/**
170
+	 * Whether this item has already been initialized
171
+	 */
172
+	protected function isDiscovered()
173
+	{
174
+		return $this->count !== null;
175
+	}
176
+
177
+
178
+	/**
179
+	 * @return boolean
180
+	 */
181
+	public function isComplete()
182
+	{
183
+		if ($this->complete === null) {
184
+			if (count($this->nodes) === $this->count) {
185
+				$this->complete = true;
186
+			} else {
187
+				$this->complete = false;
188
+			}
189
+		}
190
+		return $this->complete;
191
+	}
192
+
193
+
194
+	/**
195
+	 * Discovers how many related model objects exist.
196
+	 *
197
+	 * @return void
198
+	 * @throws EE_Error
199
+	 * @throws InvalidArgumentException
200
+	 * @throws InvalidDataTypeException
201
+	 * @throws InvalidInterfaceException
202
+	 * @throws ReflectionException
203
+	 */
204
+	protected function discover()
205
+	{
206
+		$this->count = $this->related_model->count([$this->whereQueryParams()]);
207
+	}
208
+
209
+
210
+	/**
211
+	 * @return array
212
+	 * @throws EE_Error
213
+	 * @throws InvalidDataTypeException
214
+	 * @throws InvalidInterfaceException
215
+	 * @throws InvalidArgumentException
216
+	 */
217
+	protected function whereQueryParams()
218
+	{
219
+		$where_params = [
220
+			$this->related_model->get_foreign_key_to(
221
+				$this->main_model->get_this_model_name()
222
+			)->get_name() => $this->id,
223
+		];
224
+		try {
225
+			$relation_settings = $this->main_model->related_settings_for($this->related_model->get_this_model_name());
226
+		} catch (EE_Error $e) {
227
+			// This will happen for has-and-belongs-to-many relations, when this node's related model is that join table
228
+			// which hasn't been explicitly declared in the main model object's model's relations.
229
+			$relation_settings = null;
230
+		}
231
+		if ($relation_settings instanceof EE_Has_Many_Any_Relation) {
232
+			$where_params[ $this->related_model->get_field_containing_related_model_name()->get_name() ] =
233
+				$this->main_model->get_this_model_name();
234
+		}
235
+		return $where_params;
236
+	}
237
+
238
+
239
+	/**
240
+	 * @return array
241
+	 * @throws EE_Error
242
+	 * @throws ReflectionException
243
+	 */
244
+	public function toArray()
245
+	{
246
+		$tree = [
247
+			'count'    => $this->count,
248
+			'complete' => $this->isComplete(),
249
+			'objs'     => [],
250
+		];
251
+		foreach ($this->nodes as $id => $model_obj_node) {
252
+			$tree['objs'][ $id ] = $model_obj_node->toArray();
253
+		}
254
+		return $tree;
255
+	}
256
+
257
+
258
+	/**
259
+	 * Gets the IDs of all the model objects to delete; indexed first by model object name.
260
+	 *
261
+	 * @return array
262
+	 * @throws EE_Error
263
+	 * @throws ReflectionException
264
+	 */
265
+	public function getIds()
266
+	{
267
+		if (empty($this->nodes)) {
268
+			return [];
269
+		}
270
+		$ids = [
271
+			$this->related_model->get_this_model_name() => array_combine(
272
+				array_keys($this->nodes),
273
+				array_keys($this->nodes)
274
+			),
275
+		];
276
+		foreach ($this->nodes as $model_obj_node) {
277
+			$ids = array_replace_recursive($ids, $model_obj_node->getIds());
278
+		}
279
+		return $ids;
280
+	}
281
+
282
+
283
+	/**
284
+	 * Returns the number of sub-nodes found (ie, related model objects across this relation.)
285
+	 *
286
+	 * @return int
287
+	 */
288
+	public function countSubNodes()
289
+	{
290
+		return count($this->nodes);
291
+	}
292
+
293
+
294
+	/**
295
+	 * Don't serialize the models. Just record their names on some dynamic properties.
296
+	 *
297
+	 * @return array
298
+	 */
299
+	public function __sleep()
300
+	{
301
+		$this->m  = $this->main_model->get_this_model_name();
302
+		$this->rm = $this->related_model->get_this_model_name();
303
+		return array_merge(
304
+			[
305
+				'm',
306
+				'rm',
307
+				'id',
308
+				'count',
309
+				'nodes',
310
+			],
311
+			parent::__sleep()
312
+		);
313
+	}
314
+
315
+
316
+	/**
317
+	 * Use the dynamic properties to instantiate the models we use.
318
+	 *
319
+	 * @throws EE_Error
320
+	 * @throws InvalidArgumentException
321
+	 * @throws InvalidDataTypeException
322
+	 * @throws InvalidInterfaceException
323
+	 * @throws ReflectionException
324
+	 */
325
+	public function __wakeup()
326
+	{
327
+		$this->main_model    = EE_Registry::instance()->load_model($this->m);
328
+		$this->related_model = EE_Registry::instance()->load_model($this->rm);
329
+		parent::__wakeup();
330
+	}
331 331
 }
332 332
 // End of file RelationNode.php
333 333
 // Location: EventEspresso\core\services\orm\tree_traversal/RelationNode.php
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -98,17 +98,17 @@  discard block
 block discarded – undo
98 98
                     ],
99 99
                 ]
100 100
             );
101
-            $new_item_nodes     = [];
101
+            $new_item_nodes = [];
102 102
 
103 103
             // Add entity nodes for each of the model objects we fetched.
104 104
             foreach ($related_model_objs as $related_model_obj) {
105
-                $entity_node                                = new ModelObjNode(
105
+                $entity_node = new ModelObjNode(
106 106
                     $related_model_obj->ID(),
107 107
                     $related_model_obj->get_model(),
108 108
                     $this->dont_traverse_models
109 109
                 );
110
-                $this->nodes[ $related_model_obj->ID() ]    = $entity_node;
111
-                $new_item_nodes[ $related_model_obj->ID() ] = $entity_node;
110
+                $this->nodes[$related_model_obj->ID()]    = $entity_node;
111
+                $new_item_nodes[$related_model_obj->ID()] = $entity_node;
112 112
             }
113 113
             $num_identified += count($new_item_nodes);
114 114
             if ($num_identified < $model_objects_to_identify) {
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
     protected function allChildrenComplete()
136 136
     {
137 137
         foreach ($this->nodes as $model_obj_node) {
138
-            if (! $model_obj_node->isComplete()) {
138
+            if ( ! $model_obj_node->isComplete()) {
139 139
                 return false;
140 140
             }
141 141
         }
@@ -153,7 +153,7 @@  discard block
 block discarded – undo
153 153
     protected function visitAlreadyDiscoveredNodes($model_obj_nodes, $work_budget)
154 154
     {
155 155
         $work_done = 0;
156
-        if (! $model_obj_nodes) {
156
+        if ( ! $model_obj_nodes) {
157 157
             return 0;
158 158
         }
159 159
         foreach ($model_obj_nodes as $model_obj_node) {
@@ -229,7 +229,7 @@  discard block
 block discarded – undo
229 229
             $relation_settings = null;
230 230
         }
231 231
         if ($relation_settings instanceof EE_Has_Many_Any_Relation) {
232
-            $where_params[ $this->related_model->get_field_containing_related_model_name()->get_name() ] =
232
+            $where_params[$this->related_model->get_field_containing_related_model_name()->get_name()] =
233 233
                 $this->main_model->get_this_model_name();
234 234
         }
235 235
         return $where_params;
@@ -249,7 +249,7 @@  discard block
 block discarded – undo
249 249
             'objs'     => [],
250 250
         ];
251 251
         foreach ($this->nodes as $id => $model_obj_node) {
252
-            $tree['objs'][ $id ] = $model_obj_node->toArray();
252
+            $tree['objs'][$id] = $model_obj_node->toArray();
253 253
         }
254 254
         return $tree;
255 255
     }
Please login to merge, or discard this patch.