Completed
Branch master (d4ace2)
by
unknown
04:43
created
core/admin/EE_Admin_List_Table.core.php 2 patches
Indentation   +957 added lines, -957 removed lines patch added patch discarded remove patch
@@ -6,7 +6,7 @@  discard block
 block discarded – undo
6 6
 use EventEspresso\core\services\request\sanitizers\AllowedTags;
7 7
 
8 8
 if (! class_exists('WP_List_Table')) {
9
-    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
9
+	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
10 10
 }
11 11
 
12 12
 
@@ -24,939 +24,939 @@  discard block
 block discarded – undo
24 24
  */
25 25
 abstract class EE_Admin_List_Table extends WP_List_Table
26 26
 {
27
-    const ACTION_COPY    = 'duplicate';
28
-
29
-    const ACTION_DELETE  = 'delete';
30
-
31
-    const ACTION_EDIT    = 'edit';
32
-
33
-    const ACTION_RESTORE = 'restore';
34
-
35
-    const ACTION_TRASH   = 'trash';
36
-
37
-    protected static array $actions = [
38
-        self::ACTION_COPY,
39
-        self::ACTION_DELETE,
40
-        self::ACTION_EDIT,
41
-        self::ACTION_RESTORE,
42
-        self::ACTION_TRASH,
43
-    ];
44
-
45
-    /**
46
-     * holds the data that will be processed for the table
47
-     *
48
-     * @var array $_data
49
-     */
50
-    protected array $_data;
51
-
52
-
53
-    /**
54
-     * This holds the value of all the data available for the given view (for all pages).
55
-     *
56
-     * @var int $_all_data_count
57
-     */
58
-    protected int $_all_data_count;
59
-
60
-
61
-    /**
62
-     * Will contain the count of trashed items for the view label.
63
-     *
64
-     * @var int $_trashed_count
65
-     */
66
-    protected int $_trashed_count;
67
-
68
-
69
-    /**
70
-     * This is what will be referenced as the slug for the current screen
71
-     *
72
-     * @var string $_screen
73
-     */
74
-    protected string $_screen;
75
-
76
-
77
-    /**
78
-     * this is the EE_Admin_Page object
79
-     *
80
-     * @var EE_Admin_Page $_admin_page
81
-     */
82
-    protected EE_Admin_Page $_admin_page;
83
-
84
-
85
-    /**
86
-     * The current view
87
-     *
88
-     * @var string $_view
89
-     */
90
-    protected string $_view;
91
-
92
-
93
-    /**
94
-     * array of possible views for this table
95
-     *
96
-     * @var array $_views
97
-     */
98
-    protected array $_views;
99
-
100
-
101
-    /**
102
-     * An array of key => value pairs containing information about the current table
103
-     * array(
104
-     *        'plural' => 'plural label',
105
-     *        'singular' => 'singular label',
106
-     *        'ajax' => false, //whether to use ajax or not
107
-     *        'screen' => null, //string used to reference what screen this is
108
-     *        (WP_List_table converts to screen object)
109
-     * )
110
-     *
111
-     * @var array $_wp_list_args
112
-     */
113
-    protected array $_wp_list_args;
114
-
115
-    /**
116
-     * an array of column names
117
-     * array(
118
-     *    'internal-name' => 'Title'
119
-     * )
120
-     *
121
-     * @var array $_columns
122
-     */
123
-    protected array $_columns;
124
-
125
-    /**
126
-     * An array of sortable columns
127
-     * array(
128
-     *    'internal-name' => 'orderby' //or
129
-     *    'internal-name' => array( 'orderby', true )
130
-     * )
131
-     *
132
-     * @var array $_sortable_columns
133
-     */
134
-    protected array $_sortable_columns;
135
-
136
-    /**
137
-     * callback method used to perform AJAX row reordering
138
-     *
139
-     * @var string|null $_ajax_sorting_callback
140
-     */
141
-    protected ?string $_ajax_sorting_callback = null;
142
-
143
-    /**
144
-     * An array of hidden columns (if needed)
145
-     * array('internal-name', 'internal-name')
146
-     *
147
-     * @var array $_hidden_columns
148
-     */
149
-    protected array $_hidden_columns;
150
-
151
-    /**
152
-     * holds the per_page value
153
-     *
154
-     * @var int $_per_page
155
-     */
156
-    protected int $_per_page;
157
-
158
-    /**
159
-     * holds what page number is currently being viewed
160
-     *
161
-     * @var int $_current_page
162
-     */
163
-    protected int $_current_page;
164
-
165
-    /**
166
-     * the reference string for the nonce_action
167
-     *
168
-     * @var string $_nonce_action_ref
169
-     */
170
-    protected string $_nonce_action_ref;
171
-
172
-    /**
173
-     * property to hold incoming request data (as set by the admin_page_core)
174
-     *
175
-     * @var array $_req_data
176
-     */
177
-    protected array $_req_data;
178
-
179
-
180
-    /**
181
-     * yes / no array for admin form fields
182
-     *
183
-     * @var array $_yes_no
184
-     */
185
-    protected array $_yes_no = [];
186
-
187
-    /**
188
-     * Array describing buttons that should appear at the bottom of the page
189
-     * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
190
-     * and the values are another array with the following keys
191
-     * array(
192
-     *    'route' => 'page_route',
193
-     *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
194
-     * )
195
-     *
196
-     * @var array $_bottom_buttons
197
-     */
198
-    protected array $_bottom_buttons = [];
199
-
200
-
201
-    /**
202
-     * Used to indicate what should be the primary column for the list table.
203
-     * If not present then falls back to what WP calculates
204
-     * as the primary column.
205
-     *
206
-     * @type string $_primary_column
207
-     */
208
-    protected string $_primary_column = '';
209
-
210
-
211
-    /**
212
-     * Used to indicate whether the table has a checkbox column or not.
213
-     *
214
-     * @type bool $_has_checkbox_column
215
-     */
216
-    protected bool $_has_checkbox_column = false;
217
-
218
-    /**
219
-     * @var AdminListTableFilters|null
220
-     */
221
-    protected ?AdminListTableFilters $admin_list_table_filters = null;
222
-
223
-    protected ?RequestInterface    $request            = null;
224
-
225
-
226
-    /**
227
-     * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
228
-     * @param AdminListTableFilters|null $filters    to display list table filters
229
-     */
230
-    public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
231
-    {
232
-        $this->request       = $this->request ?? LoaderFactory::getShared(RequestInterface::class);
233
-        $this->_admin_page   = $admin_page;
234
-        $this->_req_data     = $this->_admin_page->get_request_data();
235
-        $this->_view         = $this->_admin_page->get_view();
236
-        $this->_views        = $this->_admin_page->get_list_table_view_RLs();
237
-        $this->_current_page = $this->get_pagenum();
238
-        $this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
239
-        $this->_yes_no       = [
240
-            esc_html__('No', 'event_espresso'),
241
-            esc_html__('Yes', 'event_espresso')
242
-        ];
243
-
244
-        $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
245
-
246
-        $this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247
-            ? $filters
248
-            : LoaderFactory::getShared(AdminListTableFilters::class);
249
-
250
-        $this->_setup_data();
251
-        $this->_add_view_counts();
252
-        // ensure changes made to views in child classes get ported back to the admin page
253
-        $this->_admin_page->updateViews($this->_views);
254
-
255
-        $this->_nonce_action_ref = $this->_view;
256
-
257
-        $this->_set_properties();
258
-
259
-        // set primary column
260
-        add_filter('list_table_primary_column', [$this, 'set_primary_column']);
261
-
262
-        // set parent defaults
263
-        parent::__construct($this->_wp_list_args);
264
-
265
-        $this->prepare_items();
266
-    }
267
-
268
-
269
-    /**
270
-     * _setup_data
271
-     * this method is used to setup the $_data, $_all_data_count, and _per_page properties
272
-     *
273
-     * @return void
274
-     * @uses $this->_admin_page
275
-     */
276
-    abstract protected function _setup_data();
277
-
278
-
279
-    /**
280
-     * set the properties that this class needs to be able to execute wp_list_table properly
281
-     * properties set:
282
-     * _wp_list_args = what the arguments required for the parent _wp_list_table.
283
-     * _columns = set the columns in an array.
284
-     * _sortable_columns = columns that are sortable (array).
285
-     * _hidden_columns = columns that are hidden (array)
286
-     * _default_orderby = the default orderby for sorting.
287
-     *
288
-     * @abstract
289
-     * @access protected
290
-     * @return void
291
-     */
292
-    abstract protected function _set_properties();
293
-
294
-
295
-    /**
296
-     * _get_table_filters
297
-     * We use this to assemble and return any filters that are associated with this table that help further refine what
298
-     * gets shown in the table.
299
-     *
300
-     * @abstract
301
-     * @access protected
302
-     * @return string[]
303
-     */
304
-    abstract protected function _get_table_filters();
305
-
306
-
307
-    /**
308
-     * this is a method that child class will do to add counts to the views array so when views are displayed the
309
-     * counts of the views is accurate.
310
-     *
311
-     * @abstract
312
-     * @access protected
313
-     * @return void
314
-     */
315
-    abstract protected function _add_view_counts();
316
-
317
-
318
-    /**
319
-     * _get_hidden_fields
320
-     * returns a html string of hidden fields so if any table filters are used the current view will be respected.
321
-     *
322
-     * @return string
323
-     */
324
-    protected function _get_hidden_fields()
325
-    {
326
-        $action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
327
-        $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
328
-        // if action is STILL empty, then we set it to default
329
-        $action = empty($action) ? 'default' : $action;
330
-        $field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
331
-        $field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
332
-        $field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
333
-
334
-        $bulk_actions = $this->_get_bulk_actions();
335
-        foreach ($bulk_actions as $bulk_action => $label) {
336
-            $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
337
-                      . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
338
-        }
339
-
340
-        return $field;
341
-    }
342
-
343
-
344
-    /**
345
-     * _set_column_info
346
-     * we're using this to set the column headers property.
347
-     *
348
-     * @access protected
349
-     * @return void
350
-     */
351
-    protected function _set_column_info()
352
-    {
353
-        $columns   = $this->get_columns();
354
-        $hidden    = $this->get_hidden_columns();
355
-        $_sortable = $this->get_sortable_columns();
356
-
357
-        /**
358
-         * Dynamic hook allowing for adding sortable columns in this list table.
359
-         * Note that $this->screen->id is in the format
360
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
361
-         * table it is: event-espresso_page_espresso_messages.
362
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
363
-         * hook prefix ("event-espresso") will be different.
364
-         *
365
-         * @var array
366
-         */
367
-        $_sortable = apply_filters(
368
-            "FHEE_manage_{$this->screen->id}_sortable_columns",
369
-            $_sortable,
370
-            $this->_screen,
371
-            $this
372
-        );
373
-
374
-        $sortable = [];
375
-        foreach ($_sortable as $id => $data) {
376
-            if (empty($data)) {
377
-                continue;
378
-            }
379
-            // fix for offset errors with WP_List_Table default get_columninfo()
380
-            if (is_array($data)) {
381
-                $_data[0] = key($data);
382
-                $_data[1] = isset($data[1]) ? $data[1] : false;
383
-            } else {
384
-                $_data[0] = $data;
385
-            }
386
-
387
-            $data = (array) $data;
388
-
389
-            if (! isset($data[1])) {
390
-                $_data[1] = false;
391
-            }
392
-
393
-            $sortable[ $id ] = $_data;
394
-        }
395
-        $primary               = $this->get_primary_column_name();
396
-        $this->_column_headers = [$columns, $hidden, $sortable, $primary];
397
-    }
398
-
399
-
400
-    /**
401
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
402
-     *
403
-     * @return string
404
-     */
405
-    protected function get_primary_column_name()
406
-    {
407
-        foreach (class_parents($this) as $parent) {
408
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
409
-                return parent::get_primary_column_name();
410
-            }
411
-        }
412
-        return $this->_primary_column;
413
-    }
414
-
415
-
416
-    /**
417
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
418
-     *
419
-     * @param EE_Base_Class $item
420
-     * @param string        $column_name
421
-     * @param string        $primary
422
-     * @return string
423
-     */
424
-    protected function handle_row_actions($item, $column_name, $primary)
425
-    {
426
-        foreach (class_parents($this) as $parent) {
427
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
428
-                return parent::handle_row_actions($item, $column_name, $primary);
429
-            }
430
-        }
431
-        return '';
432
-    }
433
-
434
-
435
-    /**
436
-     * _get_bulk_actions
437
-     * This is a wrapper called by WP_List_Table::get_bulk_actions()
438
-     *
439
-     * @access protected
440
-     * @return array bulk_actions
441
-     */
442
-    protected function _get_bulk_actions(): array
443
-    {
444
-        $actions = [];
445
-        // the _views property should have the bulk_actions, so let's go through and extract them into a properly
446
-        // formatted array for the wp_list_table();
447
-        foreach ($this->_views as $view => $args) {
448
-            if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
449
-                // each bulk action will correspond with a admin page route, so we can check whatever the capability is
450
-                // for that page route and skip adding the bulk action if no access for the current logged in user.
451
-                foreach ($args['bulk_action'] as $route => $label) {
452
-                    if ($this->_admin_page->check_user_access($route, true)) {
453
-                        $actions[ $route ] = $label;
454
-                    }
455
-                }
456
-            }
457
-        }
458
-        return $actions;
459
-    }
460
-
461
-
462
-    /**
463
-     * Generate the table navigation above or below the table.
464
-     * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
465
-     *
466
-     * @throws EE_Error
467
-     * @since 4.9.44.rc.001
468
-     */
469
-    public function display_tablenav($which)
470
-    {
471
-        if ('top' === $which) {
472
-            wp_nonce_field('bulk-' . $this->_args['plural']);
473
-        }
474
-        ?>
27
+	const ACTION_COPY    = 'duplicate';
28
+
29
+	const ACTION_DELETE  = 'delete';
30
+
31
+	const ACTION_EDIT    = 'edit';
32
+
33
+	const ACTION_RESTORE = 'restore';
34
+
35
+	const ACTION_TRASH   = 'trash';
36
+
37
+	protected static array $actions = [
38
+		self::ACTION_COPY,
39
+		self::ACTION_DELETE,
40
+		self::ACTION_EDIT,
41
+		self::ACTION_RESTORE,
42
+		self::ACTION_TRASH,
43
+	];
44
+
45
+	/**
46
+	 * holds the data that will be processed for the table
47
+	 *
48
+	 * @var array $_data
49
+	 */
50
+	protected array $_data;
51
+
52
+
53
+	/**
54
+	 * This holds the value of all the data available for the given view (for all pages).
55
+	 *
56
+	 * @var int $_all_data_count
57
+	 */
58
+	protected int $_all_data_count;
59
+
60
+
61
+	/**
62
+	 * Will contain the count of trashed items for the view label.
63
+	 *
64
+	 * @var int $_trashed_count
65
+	 */
66
+	protected int $_trashed_count;
67
+
68
+
69
+	/**
70
+	 * This is what will be referenced as the slug for the current screen
71
+	 *
72
+	 * @var string $_screen
73
+	 */
74
+	protected string $_screen;
75
+
76
+
77
+	/**
78
+	 * this is the EE_Admin_Page object
79
+	 *
80
+	 * @var EE_Admin_Page $_admin_page
81
+	 */
82
+	protected EE_Admin_Page $_admin_page;
83
+
84
+
85
+	/**
86
+	 * The current view
87
+	 *
88
+	 * @var string $_view
89
+	 */
90
+	protected string $_view;
91
+
92
+
93
+	/**
94
+	 * array of possible views for this table
95
+	 *
96
+	 * @var array $_views
97
+	 */
98
+	protected array $_views;
99
+
100
+
101
+	/**
102
+	 * An array of key => value pairs containing information about the current table
103
+	 * array(
104
+	 *        'plural' => 'plural label',
105
+	 *        'singular' => 'singular label',
106
+	 *        'ajax' => false, //whether to use ajax or not
107
+	 *        'screen' => null, //string used to reference what screen this is
108
+	 *        (WP_List_table converts to screen object)
109
+	 * )
110
+	 *
111
+	 * @var array $_wp_list_args
112
+	 */
113
+	protected array $_wp_list_args;
114
+
115
+	/**
116
+	 * an array of column names
117
+	 * array(
118
+	 *    'internal-name' => 'Title'
119
+	 * )
120
+	 *
121
+	 * @var array $_columns
122
+	 */
123
+	protected array $_columns;
124
+
125
+	/**
126
+	 * An array of sortable columns
127
+	 * array(
128
+	 *    'internal-name' => 'orderby' //or
129
+	 *    'internal-name' => array( 'orderby', true )
130
+	 * )
131
+	 *
132
+	 * @var array $_sortable_columns
133
+	 */
134
+	protected array $_sortable_columns;
135
+
136
+	/**
137
+	 * callback method used to perform AJAX row reordering
138
+	 *
139
+	 * @var string|null $_ajax_sorting_callback
140
+	 */
141
+	protected ?string $_ajax_sorting_callback = null;
142
+
143
+	/**
144
+	 * An array of hidden columns (if needed)
145
+	 * array('internal-name', 'internal-name')
146
+	 *
147
+	 * @var array $_hidden_columns
148
+	 */
149
+	protected array $_hidden_columns;
150
+
151
+	/**
152
+	 * holds the per_page value
153
+	 *
154
+	 * @var int $_per_page
155
+	 */
156
+	protected int $_per_page;
157
+
158
+	/**
159
+	 * holds what page number is currently being viewed
160
+	 *
161
+	 * @var int $_current_page
162
+	 */
163
+	protected int $_current_page;
164
+
165
+	/**
166
+	 * the reference string for the nonce_action
167
+	 *
168
+	 * @var string $_nonce_action_ref
169
+	 */
170
+	protected string $_nonce_action_ref;
171
+
172
+	/**
173
+	 * property to hold incoming request data (as set by the admin_page_core)
174
+	 *
175
+	 * @var array $_req_data
176
+	 */
177
+	protected array $_req_data;
178
+
179
+
180
+	/**
181
+	 * yes / no array for admin form fields
182
+	 *
183
+	 * @var array $_yes_no
184
+	 */
185
+	protected array $_yes_no = [];
186
+
187
+	/**
188
+	 * Array describing buttons that should appear at the bottom of the page
189
+	 * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
190
+	 * and the values are another array with the following keys
191
+	 * array(
192
+	 *    'route' => 'page_route',
193
+	 *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
194
+	 * )
195
+	 *
196
+	 * @var array $_bottom_buttons
197
+	 */
198
+	protected array $_bottom_buttons = [];
199
+
200
+
201
+	/**
202
+	 * Used to indicate what should be the primary column for the list table.
203
+	 * If not present then falls back to what WP calculates
204
+	 * as the primary column.
205
+	 *
206
+	 * @type string $_primary_column
207
+	 */
208
+	protected string $_primary_column = '';
209
+
210
+
211
+	/**
212
+	 * Used to indicate whether the table has a checkbox column or not.
213
+	 *
214
+	 * @type bool $_has_checkbox_column
215
+	 */
216
+	protected bool $_has_checkbox_column = false;
217
+
218
+	/**
219
+	 * @var AdminListTableFilters|null
220
+	 */
221
+	protected ?AdminListTableFilters $admin_list_table_filters = null;
222
+
223
+	protected ?RequestInterface    $request            = null;
224
+
225
+
226
+	/**
227
+	 * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
228
+	 * @param AdminListTableFilters|null $filters    to display list table filters
229
+	 */
230
+	public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
231
+	{
232
+		$this->request       = $this->request ?? LoaderFactory::getShared(RequestInterface::class);
233
+		$this->_admin_page   = $admin_page;
234
+		$this->_req_data     = $this->_admin_page->get_request_data();
235
+		$this->_view         = $this->_admin_page->get_view();
236
+		$this->_views        = $this->_admin_page->get_list_table_view_RLs();
237
+		$this->_current_page = $this->get_pagenum();
238
+		$this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
239
+		$this->_yes_no       = [
240
+			esc_html__('No', 'event_espresso'),
241
+			esc_html__('Yes', 'event_espresso')
242
+		];
243
+
244
+		$this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
245
+
246
+		$this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247
+			? $filters
248
+			: LoaderFactory::getShared(AdminListTableFilters::class);
249
+
250
+		$this->_setup_data();
251
+		$this->_add_view_counts();
252
+		// ensure changes made to views in child classes get ported back to the admin page
253
+		$this->_admin_page->updateViews($this->_views);
254
+
255
+		$this->_nonce_action_ref = $this->_view;
256
+
257
+		$this->_set_properties();
258
+
259
+		// set primary column
260
+		add_filter('list_table_primary_column', [$this, 'set_primary_column']);
261
+
262
+		// set parent defaults
263
+		parent::__construct($this->_wp_list_args);
264
+
265
+		$this->prepare_items();
266
+	}
267
+
268
+
269
+	/**
270
+	 * _setup_data
271
+	 * this method is used to setup the $_data, $_all_data_count, and _per_page properties
272
+	 *
273
+	 * @return void
274
+	 * @uses $this->_admin_page
275
+	 */
276
+	abstract protected function _setup_data();
277
+
278
+
279
+	/**
280
+	 * set the properties that this class needs to be able to execute wp_list_table properly
281
+	 * properties set:
282
+	 * _wp_list_args = what the arguments required for the parent _wp_list_table.
283
+	 * _columns = set the columns in an array.
284
+	 * _sortable_columns = columns that are sortable (array).
285
+	 * _hidden_columns = columns that are hidden (array)
286
+	 * _default_orderby = the default orderby for sorting.
287
+	 *
288
+	 * @abstract
289
+	 * @access protected
290
+	 * @return void
291
+	 */
292
+	abstract protected function _set_properties();
293
+
294
+
295
+	/**
296
+	 * _get_table_filters
297
+	 * We use this to assemble and return any filters that are associated with this table that help further refine what
298
+	 * gets shown in the table.
299
+	 *
300
+	 * @abstract
301
+	 * @access protected
302
+	 * @return string[]
303
+	 */
304
+	abstract protected function _get_table_filters();
305
+
306
+
307
+	/**
308
+	 * this is a method that child class will do to add counts to the views array so when views are displayed the
309
+	 * counts of the views is accurate.
310
+	 *
311
+	 * @abstract
312
+	 * @access protected
313
+	 * @return void
314
+	 */
315
+	abstract protected function _add_view_counts();
316
+
317
+
318
+	/**
319
+	 * _get_hidden_fields
320
+	 * returns a html string of hidden fields so if any table filters are used the current view will be respected.
321
+	 *
322
+	 * @return string
323
+	 */
324
+	protected function _get_hidden_fields()
325
+	{
326
+		$action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
327
+		$action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
328
+		// if action is STILL empty, then we set it to default
329
+		$action = empty($action) ? 'default' : $action;
330
+		$field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
331
+		$field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
332
+		$field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
333
+
334
+		$bulk_actions = $this->_get_bulk_actions();
335
+		foreach ($bulk_actions as $bulk_action => $label) {
336
+			$field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
337
+					  . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
338
+		}
339
+
340
+		return $field;
341
+	}
342
+
343
+
344
+	/**
345
+	 * _set_column_info
346
+	 * we're using this to set the column headers property.
347
+	 *
348
+	 * @access protected
349
+	 * @return void
350
+	 */
351
+	protected function _set_column_info()
352
+	{
353
+		$columns   = $this->get_columns();
354
+		$hidden    = $this->get_hidden_columns();
355
+		$_sortable = $this->get_sortable_columns();
356
+
357
+		/**
358
+		 * Dynamic hook allowing for adding sortable columns in this list table.
359
+		 * Note that $this->screen->id is in the format
360
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
361
+		 * table it is: event-espresso_page_espresso_messages.
362
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
363
+		 * hook prefix ("event-espresso") will be different.
364
+		 *
365
+		 * @var array
366
+		 */
367
+		$_sortable = apply_filters(
368
+			"FHEE_manage_{$this->screen->id}_sortable_columns",
369
+			$_sortable,
370
+			$this->_screen,
371
+			$this
372
+		);
373
+
374
+		$sortable = [];
375
+		foreach ($_sortable as $id => $data) {
376
+			if (empty($data)) {
377
+				continue;
378
+			}
379
+			// fix for offset errors with WP_List_Table default get_columninfo()
380
+			if (is_array($data)) {
381
+				$_data[0] = key($data);
382
+				$_data[1] = isset($data[1]) ? $data[1] : false;
383
+			} else {
384
+				$_data[0] = $data;
385
+			}
386
+
387
+			$data = (array) $data;
388
+
389
+			if (! isset($data[1])) {
390
+				$_data[1] = false;
391
+			}
392
+
393
+			$sortable[ $id ] = $_data;
394
+		}
395
+		$primary               = $this->get_primary_column_name();
396
+		$this->_column_headers = [$columns, $hidden, $sortable, $primary];
397
+	}
398
+
399
+
400
+	/**
401
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
402
+	 *
403
+	 * @return string
404
+	 */
405
+	protected function get_primary_column_name()
406
+	{
407
+		foreach (class_parents($this) as $parent) {
408
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
409
+				return parent::get_primary_column_name();
410
+			}
411
+		}
412
+		return $this->_primary_column;
413
+	}
414
+
415
+
416
+	/**
417
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
418
+	 *
419
+	 * @param EE_Base_Class $item
420
+	 * @param string        $column_name
421
+	 * @param string        $primary
422
+	 * @return string
423
+	 */
424
+	protected function handle_row_actions($item, $column_name, $primary)
425
+	{
426
+		foreach (class_parents($this) as $parent) {
427
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
428
+				return parent::handle_row_actions($item, $column_name, $primary);
429
+			}
430
+		}
431
+		return '';
432
+	}
433
+
434
+
435
+	/**
436
+	 * _get_bulk_actions
437
+	 * This is a wrapper called by WP_List_Table::get_bulk_actions()
438
+	 *
439
+	 * @access protected
440
+	 * @return array bulk_actions
441
+	 */
442
+	protected function _get_bulk_actions(): array
443
+	{
444
+		$actions = [];
445
+		// the _views property should have the bulk_actions, so let's go through and extract them into a properly
446
+		// formatted array for the wp_list_table();
447
+		foreach ($this->_views as $view => $args) {
448
+			if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
449
+				// each bulk action will correspond with a admin page route, so we can check whatever the capability is
450
+				// for that page route and skip adding the bulk action if no access for the current logged in user.
451
+				foreach ($args['bulk_action'] as $route => $label) {
452
+					if ($this->_admin_page->check_user_access($route, true)) {
453
+						$actions[ $route ] = $label;
454
+					}
455
+				}
456
+			}
457
+		}
458
+		return $actions;
459
+	}
460
+
461
+
462
+	/**
463
+	 * Generate the table navigation above or below the table.
464
+	 * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
465
+	 *
466
+	 * @throws EE_Error
467
+	 * @since 4.9.44.rc.001
468
+	 */
469
+	public function display_tablenav($which)
470
+	{
471
+		if ('top' === $which) {
472
+			wp_nonce_field('bulk-' . $this->_args['plural']);
473
+		}
474
+		?>
475 475
         <div class="tablenav <?php echo esc_attr($which); ?>">
476 476
             <?php if ($this->_get_bulk_actions()) { ?>
477 477
                 <div class="alignleft actions bulkactions">
478 478
                     <?php $this->bulk_actions(); ?>
479 479
                 </div>
480 480
             <?php }
481
-            $this->extra_tablenav($which);
482
-            $this->pagination($which);
483
-            ?>
481
+			$this->extra_tablenav($which);
482
+			$this->pagination($which);
483
+			?>
484 484
 
485 485
             <br class="clear" />
486 486
         </div>
487 487
         <?php
488
-    }
489
-
490
-
491
-    /**
492
-     * _filters
493
-     * This receives the filters array from children _get_table_filters() and assembles the string including the filter
494
-     * button.
495
-     *
496
-     * @access private
497
-     * @return void  echos html showing filters
498
-     */
499
-    private function _filters(): void
500
-    {
501
-        $classname = get_class($this);
502
-        $filters   = apply_filters(
503
-            "FHEE__{$classname}__filters",
504
-            $this->_get_table_filters(),
505
-            $this,
506
-            $this->_screen
507
-        );
508
-
509
-        if (empty($filters)) {
510
-            return;
511
-        }
512
-
513
-        $this->admin_list_table_filters->filters(
514
-            $filters,
515
-            $this->get_admin_page()->get_current_page_view_url()
516
-        );
517
-    }
518
-
519
-
520
-    /**
521
-     * Callback for 'list_table_primary_column' WordPress filter
522
-     * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
523
-     * column when class is instantiated.
524
-     *
525
-     * @param string $column_name
526
-     * @return string
527
-     * @see WP_List_Table::get_primary_column_name
528
-     */
529
-    public function set_primary_column($column_name)
530
-    {
531
-        return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
532
-    }
533
-
534
-
535
-    /**
536
-     *
537
-     */
538
-    public function prepare_items()
539
-    {
540
-        $this->_set_column_info();
541
-        $this->process_bulk_action();
542
-
543
-        $this->items = $this->_data;
544
-        $this->set_pagination_args(
545
-            [
546
-                'total_items' => $this->_all_data_count,
547
-                'per_page'    => $this->_per_page,
548
-                'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
549
-            ]
550
-        );
551
-    }
552
-
553
-
554
-    /**
555
-     * @param object|array $item
556
-     * @return string html content for the column
557
-     */
558
-    protected function column_cb($item)
559
-    {
560
-        return '';
561
-    }
562
-
563
-
564
-    /**
565
-     * This column is the default for when there is no defined column method for a registered column.
566
-     * This can be overridden by child classes, but allows for hooking in for custom columns.
567
-     *
568
-     * @param EE_Base_Class $item
569
-     * @param string        $column_name The column being called.
570
-     * @return string html content for the column
571
-     */
572
-    public function column_default($item, $column_name)
573
-    {
574
-        /**
575
-         * Dynamic hook allowing for adding additional column content in this list table.
576
-         * Note that $this->screen->id is in the format
577
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
578
-         * table it is: event-espresso_page_espresso_messages.
579
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
580
-         * hook prefix ("event-espresso") will be different.
581
-         */
582
-        ob_start();
583
-        do_action(
584
-            'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
585
-            $item,
586
-            $this->_screen
587
-        );
588
-        $content = ob_get_clean();
589
-        return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
590
-    }
591
-
592
-
593
-    /**
594
-     * Get a list of columns. The format is:
595
-     * 'internal-name' => 'Title'
596
-     *
597
-     * @return array
598
-     * @since  3.1.0
599
-     * @access public
600
-     * @abstract
601
-     */
602
-    public function get_columns()
603
-    {
604
-        /**
605
-         * Dynamic hook allowing for adding additional columns in this list table.
606
-         * Note that $this->screen->id is in the format
607
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
608
-         * table it is: event-espresso_page_espresso_messages.
609
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
610
-         * hook prefix ("event-espresso") will be different.
611
-         *
612
-         * @var array
613
-         */
614
-        return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
615
-    }
616
-
617
-
618
-    /**
619
-     * Get an associative array ( id => link ) with the list
620
-     * of views available on this table.
621
-     *
622
-     * @return array
623
-     * @since  3.1.0
624
-     * @access protected
625
-     */
626
-    public function get_views()
627
-    {
628
-        return $this->_views;
629
-    }
630
-
631
-
632
-    /**
633
-     * Generate the views html.
634
-     */
635
-    public function display_views()
636
-    {
637
-        $views           = $this->get_views();
638
-        $assembled_views = [];
639
-
640
-        if (empty($views)) {
641
-            return;
642
-        }
643
-        echo "<ul class='subsubsub'>\n";
644
-        foreach ($views as $view) {
645
-            $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
646
-            if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
647
-                $filter = "<li";
648
-                $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
649
-                $filter .= ">";
650
-                $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
651
-                $filter .= '<span class="count">(' . $count . ')</span>';
652
-                $filter .= '</li>';
653
-                $assembled_views[ $view['slug'] ] = $filter;
654
-            }
655
-        }
656
-
657
-        echo ! empty($assembled_views)
658
-            ? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
659
-            : '';
660
-        echo "</ul>";
661
-    }
662
-
663
-
664
-    /**
665
-     * Generates content for a single row of the table
666
-     *
667
-     * @param EE_Base_Class $item The current item
668
-     * @since  4.1
669
-     * @access public
670
-     */
671
-    public function single_row($item)
672
-    {
673
-        $row_class = $this->_get_row_class($item);
674
-        echo '<tr class="' . esc_attr($row_class) . '">';
675
-        $this->single_row_columns($item); // already escaped
676
-        echo '</tr>';
677
-    }
678
-
679
-
680
-    /**
681
-     * This simply sets up the row class for the table rows.
682
-     * Allows for easier overriding of child methods for setting up sorting.
683
-     *
684
-     * @param EE_Base_Class $item the current item
685
-     * @return string
686
-     */
687
-    protected function _get_row_class($item)
688
-    {
689
-        static $row_class = '';
690
-        $row_class = ($row_class === '' ? 'alternate' : '');
691
-
692
-        $new_row_class = $row_class;
693
-
694
-        if (! empty($this->_ajax_sorting_callback)) {
695
-            $new_row_class .= ' rowsortable';
696
-        }
697
-
698
-        return $new_row_class;
699
-    }
700
-
701
-
702
-    /**
703
-     * @return array
704
-     */
705
-    public function get_sortable_columns()
706
-    {
707
-        return (array) $this->_sortable_columns;
708
-    }
709
-
710
-
711
-    /**
712
-     * @return string
713
-     */
714
-    public function get_ajax_sorting_callback()
715
-    {
716
-        return $this->_ajax_sorting_callback;
717
-    }
718
-
719
-
720
-    /**
721
-     * @return array
722
-     */
723
-    public function get_hidden_columns(): array
724
-    {
725
-        $user_id     = get_current_user_id();
726
-        $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
727
-        if (empty($has_default) && ! empty($this->_hidden_columns)) {
728
-            update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
729
-            update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
730
-        }
731
-        $ref = 'manage' . $this->screen->id . 'columnshidden';
732
-        return (array) get_user_option($ref, $user_id);
733
-    }
734
-
735
-
736
-    /**
737
-     * Generates the columns for a single row of the table.
738
-     * Overridden from wp_list_table so as to allow us to filter the column content for a given
739
-     * column.
740
-     *
741
-     * @param EE_Base_Class $item The current item
742
-     * @since 3.1.0
743
-     */
744
-    public function single_row_columns($item)
745
-    {
746
-        [$columns, $hidden, $sortable, $primary] = $this->get_column_info();
747
-
748
-        foreach ($columns as $column_name => $column_display_name) {
749
-
750
-            /**
751
-             * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
752
-             * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
753
-             */
754
-            $hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
755
-
756
-            $classes = $column_name . ' column-' . $column_name . $hidden_class;
757
-            if ($primary === $column_name) {
758
-                $classes .= ' has-row-actions column-primary';
759
-            }
760
-
761
-            $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
762
-
763
-            $class = 'class="' . esc_attr($classes) . '"';
764
-
765
-            $attributes = "{$class}{$data}";
766
-
767
-            if ($column_name === 'cb') {
768
-                echo '<th scope="row" class="check-column">';
769
-                echo apply_filters(
770
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
771
-                    $this->column_cb($item), // already escaped
772
-                    $item,
773
-                    $this
774
-                );
775
-                echo '</th>';
776
-            } elseif (method_exists($this, "column_$column_name")) {
777
-                echo "<td $attributes>"; // already escaped
778
-                echo apply_filters(
779
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
780
-                    call_user_func([$this, "column_$column_name"], $item),
781
-                    $item,
782
-                    $this
783
-                );
784
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
785
-                echo "</td>";
786
-            } else {
787
-                echo "<td $attributes>"; // already escaped
788
-                echo apply_filters(
789
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
790
-                    $this->column_default($item, $column_name),
791
-                    $item,
792
-                    $column_name,
793
-                    $this
794
-                );
795
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
796
-                echo "</td>";
797
-            }
798
-        }
799
-    }
800
-
801
-
802
-    /**
803
-     * Extra controls to be displayed between bulk actions and pagination
804
-     *
805
-     * @access public
806
-     * @param string $which
807
-     * @throws EE_Error
808
-     */
809
-    public function extra_tablenav($which)
810
-    {
811
-        if ($which === 'top') {
812
-            $this->_filters();
813
-            echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
814
-        } else {
815
-            echo '<div class="list-table-bottom-buttons alignleft actions">';
816
-            foreach ($this->_bottom_buttons as $type => $action) {
817
-                $route         = $action['route'] ?? '';
818
-                $extra_request = $action['extra_request'] ?? [];
819
-                $btn_class     = $action['btn_class'] ?? 'button button--secondary';
820
-                // already escaped
821
-                echo wp_kses($this->_admin_page->get_action_link_or_button(
822
-                    $route,
823
-                    $type,
824
-                    $extra_request,
825
-                    $btn_class
826
-                ), AllowedTags::getWithFormTags());
827
-            }
828
-            do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
829
-            echo '</div>';
830
-        }
831
-    }
832
-
833
-
834
-    /**
835
-     * Get an associative array ( option_name => option_title ) with the list
836
-     * of bulk actions available on this table.
837
-     *
838
-     * @return array
839
-     * @since  3.1.0
840
-     * @access protected
841
-     */
842
-    public function get_bulk_actions()
843
-    {
844
-        return (array) $this->_get_bulk_actions();
845
-    }
846
-
847
-
848
-    /**
849
-     * Processing bulk actions.
850
-     */
851
-    public function process_bulk_action()
852
-    {
853
-        // this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
854
-        // reference in case there is a case where it gets used.
855
-    }
856
-
857
-
858
-    /**
859
-     * returns the EE admin page this list table is associated with
860
-     *
861
-     * @return EE_Admin_Page
862
-     */
863
-    public function get_admin_page()
864
-    {
865
-        return $this->_admin_page;
866
-    }
867
-
868
-
869
-    /**
870
-     * A "helper" function for all children to provide an html string of
871
-     * actions to output in their content.  It is preferable for child classes
872
-     * to use this method for generating their actions content so that it's
873
-     * filterable by plugins
874
-     *
875
-     * @param string        $action_container           what are the html container
876
-     *                                                  elements for this actions string?
877
-     * @param string        $action_class               What class is for the container
878
-     *                                                  element.
879
-     * @param string        $action_items               The contents for the action items
880
-     *                                                  container.  This is filtered before
881
-     *                                                  returned.
882
-     * @param string        $action_id                  What id (optional) is used for the
883
-     *                                                  container element.
884
-     * @param EE_Base_Class $item                       The object for the column displaying
885
-     *                                                  the actions.
886
-     * @return string The assembled action elements container.
887
-     */
888
-    protected function _action_string(
889
-        $action_items,
890
-        $item,
891
-        $action_container = 'ul',
892
-        $action_class = '',
893
-        $action_id = ''
894
-    ) {
895
-        $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
896
-        $action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
897
-        $open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
898
-        $close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
899
-        try {
900
-            $content = apply_filters(
901
-                'FHEE__EE_Admin_List_Table___action_string__action_items',
902
-                $action_items,
903
-                $item,
904
-                $this
905
-            );
906
-        } catch (Exception $e) {
907
-            if (WP_DEBUG) {
908
-                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
909
-            }
910
-            $content = $action_items;
911
-        }
912
-        return "{$open_tag}{$content}{$close_tag}";
913
-    }
914
-
915
-
916
-    /**
917
-     * @return string
918
-     */
919
-    protected function getReturnUrl()
920
-    {
921
-        $host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
922
-        $uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
923
-        return urlencode(esc_url_raw("//{$host}{$uri}"));
924
-    }
925
-
926
-
927
-    /**
928
-     * @param string $id
929
-     * @param string $content
930
-     * @param string $align     start (default), center, end
931
-     * @param string $layout    row (default) or stack
932
-     * @return string
933
-     * @since   5.0.0.p
934
-     */
935
-    protected function columnContent(
936
-        string $id,
937
-        string $content,
938
-        string $align = 'start',
939
-        string $layout = 'row'
940
-    ): string {
941
-        if (! isset($this->_columns[ $id ])) {
942
-            throw new DomainException('missing column id');
943
-        }
944
-        $heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
945
-        $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
946
-        $align = "ee-responsive-table-cell--$align";
947
-        $layout = $layout === 'row' ? 'ee-layout-row' : 'ee-layout-stack';
948
-
949
-        $html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-$id $align $layout'>";
950
-        $html .= "<div class='ee-responsive-table-cell__heading'>$heading</div>";
951
-        $html .= "<div class='ee-responsive-table-cell__content $layout'>$content</div>";
952
-        $html .= "</div>";
953
-        return $html;
954
-    }
955
-
956
-
957
-    protected function actionsModalMenu($actions): string
958
-    {
959
-        return '
488
+	}
489
+
490
+
491
+	/**
492
+	 * _filters
493
+	 * This receives the filters array from children _get_table_filters() and assembles the string including the filter
494
+	 * button.
495
+	 *
496
+	 * @access private
497
+	 * @return void  echos html showing filters
498
+	 */
499
+	private function _filters(): void
500
+	{
501
+		$classname = get_class($this);
502
+		$filters   = apply_filters(
503
+			"FHEE__{$classname}__filters",
504
+			$this->_get_table_filters(),
505
+			$this,
506
+			$this->_screen
507
+		);
508
+
509
+		if (empty($filters)) {
510
+			return;
511
+		}
512
+
513
+		$this->admin_list_table_filters->filters(
514
+			$filters,
515
+			$this->get_admin_page()->get_current_page_view_url()
516
+		);
517
+	}
518
+
519
+
520
+	/**
521
+	 * Callback for 'list_table_primary_column' WordPress filter
522
+	 * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
523
+	 * column when class is instantiated.
524
+	 *
525
+	 * @param string $column_name
526
+	 * @return string
527
+	 * @see WP_List_Table::get_primary_column_name
528
+	 */
529
+	public function set_primary_column($column_name)
530
+	{
531
+		return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
532
+	}
533
+
534
+
535
+	/**
536
+	 *
537
+	 */
538
+	public function prepare_items()
539
+	{
540
+		$this->_set_column_info();
541
+		$this->process_bulk_action();
542
+
543
+		$this->items = $this->_data;
544
+		$this->set_pagination_args(
545
+			[
546
+				'total_items' => $this->_all_data_count,
547
+				'per_page'    => $this->_per_page,
548
+				'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
549
+			]
550
+		);
551
+	}
552
+
553
+
554
+	/**
555
+	 * @param object|array $item
556
+	 * @return string html content for the column
557
+	 */
558
+	protected function column_cb($item)
559
+	{
560
+		return '';
561
+	}
562
+
563
+
564
+	/**
565
+	 * This column is the default for when there is no defined column method for a registered column.
566
+	 * This can be overridden by child classes, but allows for hooking in for custom columns.
567
+	 *
568
+	 * @param EE_Base_Class $item
569
+	 * @param string        $column_name The column being called.
570
+	 * @return string html content for the column
571
+	 */
572
+	public function column_default($item, $column_name)
573
+	{
574
+		/**
575
+		 * Dynamic hook allowing for adding additional column content in this list table.
576
+		 * Note that $this->screen->id is in the format
577
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
578
+		 * table it is: event-espresso_page_espresso_messages.
579
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
580
+		 * hook prefix ("event-espresso") will be different.
581
+		 */
582
+		ob_start();
583
+		do_action(
584
+			'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
585
+			$item,
586
+			$this->_screen
587
+		);
588
+		$content = ob_get_clean();
589
+		return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
590
+	}
591
+
592
+
593
+	/**
594
+	 * Get a list of columns. The format is:
595
+	 * 'internal-name' => 'Title'
596
+	 *
597
+	 * @return array
598
+	 * @since  3.1.0
599
+	 * @access public
600
+	 * @abstract
601
+	 */
602
+	public function get_columns()
603
+	{
604
+		/**
605
+		 * Dynamic hook allowing for adding additional columns in this list table.
606
+		 * Note that $this->screen->id is in the format
607
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
608
+		 * table it is: event-espresso_page_espresso_messages.
609
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
610
+		 * hook prefix ("event-espresso") will be different.
611
+		 *
612
+		 * @var array
613
+		 */
614
+		return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
615
+	}
616
+
617
+
618
+	/**
619
+	 * Get an associative array ( id => link ) with the list
620
+	 * of views available on this table.
621
+	 *
622
+	 * @return array
623
+	 * @since  3.1.0
624
+	 * @access protected
625
+	 */
626
+	public function get_views()
627
+	{
628
+		return $this->_views;
629
+	}
630
+
631
+
632
+	/**
633
+	 * Generate the views html.
634
+	 */
635
+	public function display_views()
636
+	{
637
+		$views           = $this->get_views();
638
+		$assembled_views = [];
639
+
640
+		if (empty($views)) {
641
+			return;
642
+		}
643
+		echo "<ul class='subsubsub'>\n";
644
+		foreach ($views as $view) {
645
+			$count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
646
+			if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
647
+				$filter = "<li";
648
+				$filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
649
+				$filter .= ">";
650
+				$filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
651
+				$filter .= '<span class="count">(' . $count . ')</span>';
652
+				$filter .= '</li>';
653
+				$assembled_views[ $view['slug'] ] = $filter;
654
+			}
655
+		}
656
+
657
+		echo ! empty($assembled_views)
658
+			? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
659
+			: '';
660
+		echo "</ul>";
661
+	}
662
+
663
+
664
+	/**
665
+	 * Generates content for a single row of the table
666
+	 *
667
+	 * @param EE_Base_Class $item The current item
668
+	 * @since  4.1
669
+	 * @access public
670
+	 */
671
+	public function single_row($item)
672
+	{
673
+		$row_class = $this->_get_row_class($item);
674
+		echo '<tr class="' . esc_attr($row_class) . '">';
675
+		$this->single_row_columns($item); // already escaped
676
+		echo '</tr>';
677
+	}
678
+
679
+
680
+	/**
681
+	 * This simply sets up the row class for the table rows.
682
+	 * Allows for easier overriding of child methods for setting up sorting.
683
+	 *
684
+	 * @param EE_Base_Class $item the current item
685
+	 * @return string
686
+	 */
687
+	protected function _get_row_class($item)
688
+	{
689
+		static $row_class = '';
690
+		$row_class = ($row_class === '' ? 'alternate' : '');
691
+
692
+		$new_row_class = $row_class;
693
+
694
+		if (! empty($this->_ajax_sorting_callback)) {
695
+			$new_row_class .= ' rowsortable';
696
+		}
697
+
698
+		return $new_row_class;
699
+	}
700
+
701
+
702
+	/**
703
+	 * @return array
704
+	 */
705
+	public function get_sortable_columns()
706
+	{
707
+		return (array) $this->_sortable_columns;
708
+	}
709
+
710
+
711
+	/**
712
+	 * @return string
713
+	 */
714
+	public function get_ajax_sorting_callback()
715
+	{
716
+		return $this->_ajax_sorting_callback;
717
+	}
718
+
719
+
720
+	/**
721
+	 * @return array
722
+	 */
723
+	public function get_hidden_columns(): array
724
+	{
725
+		$user_id     = get_current_user_id();
726
+		$has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
727
+		if (empty($has_default) && ! empty($this->_hidden_columns)) {
728
+			update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
729
+			update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
730
+		}
731
+		$ref = 'manage' . $this->screen->id . 'columnshidden';
732
+		return (array) get_user_option($ref, $user_id);
733
+	}
734
+
735
+
736
+	/**
737
+	 * Generates the columns for a single row of the table.
738
+	 * Overridden from wp_list_table so as to allow us to filter the column content for a given
739
+	 * column.
740
+	 *
741
+	 * @param EE_Base_Class $item The current item
742
+	 * @since 3.1.0
743
+	 */
744
+	public function single_row_columns($item)
745
+	{
746
+		[$columns, $hidden, $sortable, $primary] = $this->get_column_info();
747
+
748
+		foreach ($columns as $column_name => $column_display_name) {
749
+
750
+			/**
751
+			 * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
752
+			 * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
753
+			 */
754
+			$hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
755
+
756
+			$classes = $column_name . ' column-' . $column_name . $hidden_class;
757
+			if ($primary === $column_name) {
758
+				$classes .= ' has-row-actions column-primary';
759
+			}
760
+
761
+			$data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
762
+
763
+			$class = 'class="' . esc_attr($classes) . '"';
764
+
765
+			$attributes = "{$class}{$data}";
766
+
767
+			if ($column_name === 'cb') {
768
+				echo '<th scope="row" class="check-column">';
769
+				echo apply_filters(
770
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
771
+					$this->column_cb($item), // already escaped
772
+					$item,
773
+					$this
774
+				);
775
+				echo '</th>';
776
+			} elseif (method_exists($this, "column_$column_name")) {
777
+				echo "<td $attributes>"; // already escaped
778
+				echo apply_filters(
779
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
780
+					call_user_func([$this, "column_$column_name"], $item),
781
+					$item,
782
+					$this
783
+				);
784
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
785
+				echo "</td>";
786
+			} else {
787
+				echo "<td $attributes>"; // already escaped
788
+				echo apply_filters(
789
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
790
+					$this->column_default($item, $column_name),
791
+					$item,
792
+					$column_name,
793
+					$this
794
+				);
795
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
796
+				echo "</td>";
797
+			}
798
+		}
799
+	}
800
+
801
+
802
+	/**
803
+	 * Extra controls to be displayed between bulk actions and pagination
804
+	 *
805
+	 * @access public
806
+	 * @param string $which
807
+	 * @throws EE_Error
808
+	 */
809
+	public function extra_tablenav($which)
810
+	{
811
+		if ($which === 'top') {
812
+			$this->_filters();
813
+			echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
814
+		} else {
815
+			echo '<div class="list-table-bottom-buttons alignleft actions">';
816
+			foreach ($this->_bottom_buttons as $type => $action) {
817
+				$route         = $action['route'] ?? '';
818
+				$extra_request = $action['extra_request'] ?? [];
819
+				$btn_class     = $action['btn_class'] ?? 'button button--secondary';
820
+				// already escaped
821
+				echo wp_kses($this->_admin_page->get_action_link_or_button(
822
+					$route,
823
+					$type,
824
+					$extra_request,
825
+					$btn_class
826
+				), AllowedTags::getWithFormTags());
827
+			}
828
+			do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
829
+			echo '</div>';
830
+		}
831
+	}
832
+
833
+
834
+	/**
835
+	 * Get an associative array ( option_name => option_title ) with the list
836
+	 * of bulk actions available on this table.
837
+	 *
838
+	 * @return array
839
+	 * @since  3.1.0
840
+	 * @access protected
841
+	 */
842
+	public function get_bulk_actions()
843
+	{
844
+		return (array) $this->_get_bulk_actions();
845
+	}
846
+
847
+
848
+	/**
849
+	 * Processing bulk actions.
850
+	 */
851
+	public function process_bulk_action()
852
+	{
853
+		// this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
854
+		// reference in case there is a case where it gets used.
855
+	}
856
+
857
+
858
+	/**
859
+	 * returns the EE admin page this list table is associated with
860
+	 *
861
+	 * @return EE_Admin_Page
862
+	 */
863
+	public function get_admin_page()
864
+	{
865
+		return $this->_admin_page;
866
+	}
867
+
868
+
869
+	/**
870
+	 * A "helper" function for all children to provide an html string of
871
+	 * actions to output in their content.  It is preferable for child classes
872
+	 * to use this method for generating their actions content so that it's
873
+	 * filterable by plugins
874
+	 *
875
+	 * @param string        $action_container           what are the html container
876
+	 *                                                  elements for this actions string?
877
+	 * @param string        $action_class               What class is for the container
878
+	 *                                                  element.
879
+	 * @param string        $action_items               The contents for the action items
880
+	 *                                                  container.  This is filtered before
881
+	 *                                                  returned.
882
+	 * @param string        $action_id                  What id (optional) is used for the
883
+	 *                                                  container element.
884
+	 * @param EE_Base_Class $item                       The object for the column displaying
885
+	 *                                                  the actions.
886
+	 * @return string The assembled action elements container.
887
+	 */
888
+	protected function _action_string(
889
+		$action_items,
890
+		$item,
891
+		$action_container = 'ul',
892
+		$action_class = '',
893
+		$action_id = ''
894
+	) {
895
+		$action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
896
+		$action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
897
+		$open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
898
+		$close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
899
+		try {
900
+			$content = apply_filters(
901
+				'FHEE__EE_Admin_List_Table___action_string__action_items',
902
+				$action_items,
903
+				$item,
904
+				$this
905
+			);
906
+		} catch (Exception $e) {
907
+			if (WP_DEBUG) {
908
+				EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
909
+			}
910
+			$content = $action_items;
911
+		}
912
+		return "{$open_tag}{$content}{$close_tag}";
913
+	}
914
+
915
+
916
+	/**
917
+	 * @return string
918
+	 */
919
+	protected function getReturnUrl()
920
+	{
921
+		$host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
922
+		$uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
923
+		return urlencode(esc_url_raw("//{$host}{$uri}"));
924
+	}
925
+
926
+
927
+	/**
928
+	 * @param string $id
929
+	 * @param string $content
930
+	 * @param string $align     start (default), center, end
931
+	 * @param string $layout    row (default) or stack
932
+	 * @return string
933
+	 * @since   5.0.0.p
934
+	 */
935
+	protected function columnContent(
936
+		string $id,
937
+		string $content,
938
+		string $align = 'start',
939
+		string $layout = 'row'
940
+	): string {
941
+		if (! isset($this->_columns[ $id ])) {
942
+			throw new DomainException('missing column id');
943
+		}
944
+		$heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
945
+		$align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
946
+		$align = "ee-responsive-table-cell--$align";
947
+		$layout = $layout === 'row' ? 'ee-layout-row' : 'ee-layout-stack';
948
+
949
+		$html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-$id $align $layout'>";
950
+		$html .= "<div class='ee-responsive-table-cell__heading'>$heading</div>";
951
+		$html .= "<div class='ee-responsive-table-cell__content $layout'>$content</div>";
952
+		$html .= "</div>";
953
+		return $html;
954
+	}
955
+
956
+
957
+	protected function actionsModalMenu($actions): string
958
+	{
959
+		return '
960 960
         <div class="ee-modal-menu">
961 961
             <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip"
962 962
                     aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '"
@@ -968,43 +968,43 @@  discard block
 block discarded – undo
968 968
                 ' . $actions . '
969 969
             </div>
970 970
         </div>';
971
-    }
971
+	}
972 972
 
973 973
 
974
-    public function actionsColumnHeader(): string
975
-    {
976
-        return '
974
+	public function actionsColumnHeader(): string
975
+	{
976
+		return '
977 977
             <span class="ee-actions-column-header-wrap">
978 978
                 <span class="dashicons dashicons-screenoptions"></span>
979 979
                 <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span>
980 980
             </span>';
981
-    }
982
-
983
-
984
-    protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
985
-    {
986
-        $class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
987
-        $class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
988
-        $label = ! empty($label) ? " aria-label='{$label}'" : '';
989
-        return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
990
-    }
991
-
992
-    /**
993
-     * Override the search box method of WP List Table to include a reset button
994
-     *
995
-     * @param string $text     The 'submit' button label.
996
-     * @param string $input_id ID attribute value for the search input field.
997
-     */
998
-    public function search_box($text, $input_id)
999
-    {
1000
-        if (empty($_REQUEST['s']) && ! $this->has_items()) {
1001
-            return;
1002
-        }
1003
-
1004
-        $this->admin_list_table_filters->searchBox(
1005
-            $text,
1006
-            $input_id,
1007
-            $this->get_admin_page()->get_current_page_view_url()
1008
-        );
1009
-    }
981
+	}
982
+
983
+
984
+	protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
985
+	{
986
+		$class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
987
+		$class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
988
+		$label = ! empty($label) ? " aria-label='{$label}'" : '';
989
+		return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
990
+	}
991
+
992
+	/**
993
+	 * Override the search box method of WP List Table to include a reset button
994
+	 *
995
+	 * @param string $text     The 'submit' button label.
996
+	 * @param string $input_id ID attribute value for the search input field.
997
+	 */
998
+	public function search_box($text, $input_id)
999
+	{
1000
+		if (empty($_REQUEST['s']) && ! $this->has_items()) {
1001
+			return;
1002
+		}
1003
+
1004
+		$this->admin_list_table_filters->searchBox(
1005
+			$text,
1006
+			$input_id,
1007
+			$this->get_admin_page()->get_current_page_view_url()
1008
+		);
1009
+	}
1010 1010
 }
Please login to merge, or discard this patch.
Spacing   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -5,8 +5,8 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\services\request\RequestInterface;
6 6
 use EventEspresso\core\services\request\sanitizers\AllowedTags;
7 7
 
8
-if (! class_exists('WP_List_Table')) {
9
-    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
8
+if ( ! class_exists('WP_List_Table')) {
9
+    require_once ABSPATH.'wp-admin/includes/class-wp-list-table.php';
10 10
 }
11 11
 
12 12
 
@@ -220,7 +220,7 @@  discard block
 block discarded – undo
220 220
      */
221 221
     protected ?AdminListTableFilters $admin_list_table_filters = null;
222 222
 
223
-    protected ?RequestInterface    $request            = null;
223
+    protected ?RequestInterface    $request = null;
224 224
 
225 225
 
226 226
     /**
@@ -235,13 +235,13 @@  discard block
 block discarded – undo
235 235
         $this->_view         = $this->_admin_page->get_view();
236 236
         $this->_views        = $this->_admin_page->get_list_table_view_RLs();
237 237
         $this->_current_page = $this->get_pagenum();
238
-        $this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
238
+        $this->_screen       = $this->_admin_page->get_current_page().'_'.$this->_admin_page->get_current_view();
239 239
         $this->_yes_no       = [
240 240
             esc_html__('No', 'event_espresso'),
241 241
             esc_html__('Yes', 'event_espresso')
242 242
         ];
243 243
 
244
-        $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
244
+        $this->_per_page = $this->get_items_per_page($this->_screen.'_per_page');
245 245
 
246 246
         $this->admin_list_table_filters = $filters instanceof AdminListTableFilters
247 247
             ? $filters
@@ -327,14 +327,14 @@  discard block
 block discarded – undo
327 327
         $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
328 328
         // if action is STILL empty, then we set it to default
329 329
         $action = empty($action) ? 'default' : $action;
330
-        $field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
331
-        $field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
332
-        $field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
330
+        $field  = '<input type="hidden" name="page" value="'.esc_attr($this->_req_data['page']).'" />'."\n";
331
+        $field  .= '<input type="hidden" name="route" value="'.esc_attr($action).'" />'."\n";
332
+        $field  .= '<input type="hidden" name="perpage" value="'.esc_attr($this->_per_page).'" />'."\n";
333 333
 
334 334
         $bulk_actions = $this->_get_bulk_actions();
335 335
         foreach ($bulk_actions as $bulk_action => $label) {
336
-            $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
337
-                      . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
336
+            $field .= '<input type="hidden" name="'.$bulk_action.'_nonce"'
337
+                      . ' value="'.wp_create_nonce($bulk_action.'_nonce').'" />'."\n";
338 338
         }
339 339
 
340 340
         return $field;
@@ -386,11 +386,11 @@  discard block
 block discarded – undo
386 386
 
387 387
             $data = (array) $data;
388 388
 
389
-            if (! isset($data[1])) {
389
+            if ( ! isset($data[1])) {
390 390
                 $_data[1] = false;
391 391
             }
392 392
 
393
-            $sortable[ $id ] = $_data;
393
+            $sortable[$id] = $_data;
394 394
         }
395 395
         $primary               = $this->get_primary_column_name();
396 396
         $this->_column_headers = [$columns, $hidden, $sortable, $primary];
@@ -450,7 +450,7 @@  discard block
 block discarded – undo
450 450
                 // for that page route and skip adding the bulk action if no access for the current logged in user.
451 451
                 foreach ($args['bulk_action'] as $route => $label) {
452 452
                     if ($this->_admin_page->check_user_access($route, true)) {
453
-                        $actions[ $route ] = $label;
453
+                        $actions[$route] = $label;
454 454
                     }
455 455
                 }
456 456
             }
@@ -469,7 +469,7 @@  discard block
 block discarded – undo
469 469
     public function display_tablenav($which)
470 470
     {
471 471
         if ('top' === $which) {
472
-            wp_nonce_field('bulk-' . $this->_args['plural']);
472
+            wp_nonce_field('bulk-'.$this->_args['plural']);
473 473
         }
474 474
         ?>
475 475
         <div class="tablenav <?php echo esc_attr($which); ?>">
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
          */
582 582
         ob_start();
583 583
         do_action(
584
-            'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
584
+            'AHEE__EE_Admin_List_Table__column_'.$column_name.'__'.$this->screen->id,
585 585
             $item,
586 586
             $this->_screen
587 587
         );
@@ -645,12 +645,12 @@  discard block
 block discarded – undo
645 645
             $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
646 646
             if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
647 647
                 $filter = "<li";
648
-                $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
648
+                $filter .= $view['class'] ? " class='".esc_attr($view['class'])."'" : '';
649 649
                 $filter .= ">";
650
-                $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
651
-                $filter .= '<span class="count">(' . $count . ')</span>';
650
+                $filter .= '<a href="'.esc_url_raw($view['url']).'">'.esc_html($view['label']).'</a>';
651
+                $filter .= '<span class="count">('.$count.')</span>';
652 652
                 $filter .= '</li>';
653
-                $assembled_views[ $view['slug'] ] = $filter;
653
+                $assembled_views[$view['slug']] = $filter;
654 654
             }
655 655
         }
656 656
 
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
     public function single_row($item)
672 672
     {
673 673
         $row_class = $this->_get_row_class($item);
674
-        echo '<tr class="' . esc_attr($row_class) . '">';
674
+        echo '<tr class="'.esc_attr($row_class).'">';
675 675
         $this->single_row_columns($item); // already escaped
676 676
         echo '</tr>';
677 677
     }
@@ -691,7 +691,7 @@  discard block
 block discarded – undo
691 691
 
692 692
         $new_row_class = $row_class;
693 693
 
694
-        if (! empty($this->_ajax_sorting_callback)) {
694
+        if ( ! empty($this->_ajax_sorting_callback)) {
695 695
             $new_row_class .= ' rowsortable';
696 696
         }
697 697
 
@@ -723,12 +723,12 @@  discard block
 block discarded – undo
723 723
     public function get_hidden_columns(): array
724 724
     {
725 725
         $user_id     = get_current_user_id();
726
-        $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
726
+        $has_default = get_user_option('default'.$this->screen->id.'columnshidden', $user_id);
727 727
         if (empty($has_default) && ! empty($this->_hidden_columns)) {
728
-            update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
729
-            update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
728
+            update_user_option($user_id, 'default'.$this->screen->id.'columnshidden', true);
729
+            update_user_option($user_id, 'manage'.$this->screen->id.'columnshidden', $this->_hidden_columns, true);
730 730
         }
731
-        $ref = 'manage' . $this->screen->id . 'columnshidden';
731
+        $ref = 'manage'.$this->screen->id.'columnshidden';
732 732
         return (array) get_user_option($ref, $user_id);
733 733
     }
734 734
 
@@ -753,14 +753,14 @@  discard block
 block discarded – undo
753 753
              */
754 754
             $hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
755 755
 
756
-            $classes = $column_name . ' column-' . $column_name . $hidden_class;
756
+            $classes = $column_name.' column-'.$column_name.$hidden_class;
757 757
             if ($primary === $column_name) {
758 758
                 $classes .= ' has-row-actions column-primary';
759 759
             }
760 760
 
761
-            $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
761
+            $data = ' data-colname="'.wp_strip_all_tags($column_display_name).'"';
762 762
 
763
-            $class = 'class="' . esc_attr($classes) . '"';
763
+            $class = 'class="'.esc_attr($classes).'"';
764 764
 
765 765
             $attributes = "{$class}{$data}";
766 766
 
@@ -776,7 +776,7 @@  discard block
 block discarded – undo
776 776
             } elseif (method_exists($this, "column_$column_name")) {
777 777
                 echo "<td $attributes>"; // already escaped
778 778
                 echo apply_filters(
779
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
779
+                    'FHEE__EE_Admin_List_Table__single_row_columns__column_'.$column_name.'__column_content',
780 780
                     call_user_func([$this, "column_$column_name"], $item),
781 781
                     $item,
782 782
                     $this
@@ -892,10 +892,10 @@  discard block
 block discarded – undo
892 892
         $action_class = '',
893 893
         $action_id = ''
894 894
     ) {
895
-        $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
896
-        $action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
897
-        $open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
898
-        $close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
895
+        $action_class = ! empty($action_class) ? ' class="'.esc_attr($action_class).'"' : '';
896
+        $action_id    = ! empty($action_id) ? ' id="'.esc_attr($action_id).'"' : '';
897
+        $open_tag     = ! empty($action_container) ? '<'.$action_container.$action_class.$action_id.'>' : '';
898
+        $close_tag    = ! empty($action_container) ? '</'.$action_container.'>' : '';
899 899
         try {
900 900
             $content = apply_filters(
901 901
                 'FHEE__EE_Admin_List_Table___action_string__action_items',
@@ -938,10 +938,10 @@  discard block
 block discarded – undo
938 938
         string $align = 'start',
939 939
         string $layout = 'row'
940 940
     ): string {
941
-        if (! isset($this->_columns[ $id ])) {
941
+        if ( ! isset($this->_columns[$id])) {
942 942
             throw new DomainException('missing column id');
943 943
         }
944
-        $heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
944
+        $heading = $id !== 'cb' ? $this->_columns[$id] : '';
945 945
         $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
946 946
         $align = "ee-responsive-table-cell--$align";
947 947
         $layout = $layout === 'row' ? 'ee-layout-row' : 'ee-layout-stack';
@@ -959,13 +959,13 @@  discard block
 block discarded – undo
959 959
         return '
960 960
         <div class="ee-modal-menu">
961 961
             <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip"
962
-                    aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '"
962
+                    aria-label="' . esc_attr__('list table actions menu', 'event_espresso').'"
963 963
             >
964 964
                 <span class="dashicons dashicons-menu"></span>
965 965
             </button>
966 966
             <div class="ee-modal-menu__content ee-admin-container">
967 967
                 <span class="ee-modal-menu__close dashicons dashicons-no"></span>
968
-                ' . $actions . '
968
+                ' . $actions.'
969 969
             </div>
970 970
         </div>';
971 971
     }
@@ -976,7 +976,7 @@  discard block
 block discarded – undo
976 976
         return '
977 977
             <span class="ee-actions-column-header-wrap">
978 978
                 <span class="dashicons dashicons-screenoptions"></span>
979
-                <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span>
979
+                <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso').'</span>
980 980
             </span>';
981 981
     }
982 982
 
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page.core.php 2 patches
Indentation   +4218 added lines, -4218 removed lines patch added patch discarded remove patch
@@ -25,4310 +25,4310 @@
 block discarded – undo
25 25
  */
26 26
 abstract class EE_Admin_Page extends EE_Base implements InterminableInterface
27 27
 {
28
-    protected ?EE_Admin_Config     $admin_config       = null;
28
+	protected ?EE_Admin_Config     $admin_config       = null;
29 29
 
30
-    protected ?EE_Admin_Hooks      $_hook_obj          = null;
30
+	protected ?EE_Admin_Hooks      $_hook_obj          = null;
31 31
 
32
-    protected ?EE_Admin_List_Table $_list_table_object = null;
32
+	protected ?EE_Admin_List_Table $_list_table_object = null;
33 33
 
34
-    protected ?EE_Capabilities     $capabilities       = null;
34
+	protected ?EE_Capabilities     $capabilities       = null;
35 35
 
36
-    protected ?EE_Registry         $EE                 = null;
36
+	protected ?EE_Registry         $EE                 = null;
37 37
 
38
-    protected ?FeatureFlags        $feature            = null;
38
+	protected ?FeatureFlags        $feature            = null;
39 39
 
40
-    protected ?LoaderInterface     $loader             = null;
40
+	protected ?LoaderInterface     $loader             = null;
41 41
 
42
-    protected ?RequestInterface    $request            = null;
42
+	protected ?RequestInterface    $request            = null;
43 43
 
44
-    protected ?WP_Screen           $_current_screen    = null;
44
+	protected ?WP_Screen           $_current_screen    = null;
45 45
 
46
-    /**
47
-     * @var array
48
-     * @since 5.0.0.p
49
-     */
50
-    private array $publish_post_meta_box_hidden_fields = [];
51
-
52
-    /**
53
-     * some default things shared by all child classes
54
-     *
55
-     * @var string[]
56
-     */
57
-    protected array $_default_espresso_metaboxes = [
58
-        '_espresso_news_post_box',
59
-        '_espresso_links_post_box',
60
-        '_espresso_ratings_request',
61
-        '_espresso_sponsors_post_box',
62
-    ];
63
-
64
-    /**
65
-     * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
66
-     * actions.
67
-     *
68
-     * @since 4.6.x
69
-     */
70
-    protected array $_default_route_query_args = [];
71
-
72
-    protected array $_labels                   = [];
73
-
74
-    protected array $_nav_tabs                 = [];
75
-
76
-    protected array $_page_config              = [];
77
-
78
-    /**
79
-     * action => method pairs used for routing incoming requests
80
-     *
81
-     * @var array
82
-     */
83
-    protected array $_page_routes   = [];
84
-
85
-    protected array $_req_data      = [];
86
-
87
-    protected array $_route_config  = [];
88
-
89
-    protected array $_template_args = [];
90
-
91
-    protected array $_views         = [];
92
-
93
-    /**
94
-     * yes / no array for admin form fields
95
-     *
96
-     * @var array|array[]
97
-     */
98
-    protected array $_yes_no_values = [];
99
-
100
-    /**
101
-     * this starts at null so we can have no header routes progress through two states.
102
-     */
103
-    protected ?bool $_is_UI_request = null;
104
-
105
-    protected bool  $_is_caf        = false;                                                                                                                                                                                                                                  // This is just a property that flags whether the given route is a caffeinated route or not.
106
-
107
-    protected bool  $_routing       = false;
108
-
109
-    /**
110
-     * whether initializePage() has run
111
-     *
112
-     * @var bool
113
-     */
114
-    protected bool $initialized = false;
115
-
116
-
117
-    protected string $_admin_base_path      = '';
118
-
119
-    protected string $_admin_base_url       = '';
120
-
121
-    protected string $_admin_page_title     = '';
122
-
123
-    protected string $_column_template_path = '';
124
-
125
-    protected bool   $_cpt_route            = false;
126
-
127
-    /**
128
-     * set via request page and action args.
129
-     */
130
-    protected string $_current_page          = '';
131
-
132
-    protected string $_current_page_view_url = '';
133
-
134
-    protected string $_current_view          = '';
135
-
136
-    protected string $_default_nav_tab_name  = 'overview';
137
-
138
-    /**
139
-     * sanitized request action
140
-     */
141
-    protected string $_req_action = '';
142
-
143
-    /**
144
-     * sanitized request action nonce
145
-     */
146
-    protected string $_req_nonce        = '';
147
-
148
-    protected string $_search_btn_label = '';
149
-
150
-    protected string $_template_path    = '';
151
-
152
-    protected string $_view             = '';
153
-
154
-    /**
155
-     * set early within EE_Admin_Init
156
-     *
157
-     * @var string
158
-     */
159
-    protected string $_wp_page_slug = '';
160
-
161
-    /**
162
-     * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
163
-     * then this would be the parent classname: Events_Admin_Page
164
-     *
165
-     * @var string
166
-     */
167
-    public string $base_class_name = '';
168
-
169
-    public string $class_name      = '';
170
-
171
-    /**
172
-     * unprocessed value for the 'action' request param (default '')
173
-     *
174
-     * @var string
175
-     */
176
-    protected string $raw_req_action = '';
177
-
178
-    /**
179
-     * unprocessed value for the 'page' request param (default '')
180
-     *
181
-     * @var string
182
-     */
183
-    protected string $raw_req_page = '';
184
-
185
-    public string    $page_folder  = '';
186
-
187
-    public string    $page_label   = '';
188
-
189
-    public string    $page_slug    = '';
190
-
191
-
192
-    /**
193
-     * the current page route and route config
194
-     *
195
-     * @var array|callable|string|null
196
-     */
197
-    protected $_route = null;
198
-
199
-
200
-    /**
201
-     * @Constructor
202
-     * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
203
-     * @throws InvalidArgumentException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     * @throws ReflectionException
207
-     */
208
-    public function __construct($routing = true)
209
-    {
210
-        $this->loader       = LoaderFactory::getLoader();
211
-        $this->admin_config = $this->loader->getShared(EE_Admin_Config::class);
212
-        $this->feature      = $this->loader->getShared(FeatureFlags::class);
213
-        $this->request      = $this->loader->getShared(RequestInterface::class);
214
-        $this->capabilities = $this->loader->getShared(EE_Capabilities::class);
215
-        // routing enabled?
216
-        $this->_routing = $routing;
217
-
218
-        $this->class_name      = get_class($this);
219
-        $this->base_class_name = strpos($this->class_name, 'Extend_') === 0
220
-            ? str_replace('Extend_', '', $this->class_name)
221
-            : '';
222
-
223
-        if (strpos($this->_get_dir(), 'caffeinated') !== false) {
224
-            $this->_is_caf = true;
225
-        }
226
-        $this->_yes_no_values = [
227
-            ['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
228
-            ['id' => false, 'text' => esc_html__('No', 'event_espresso')],
229
-        ];
230
-        // set the _req_data property.
231
-        $this->_req_data = $this->request->requestParams();
232
-    }
233
-
234
-
235
-    /**
236
-     * @return EE_Admin_Config
237
-     */
238
-    public function adminConfig(): EE_Admin_Config
239
-    {
240
-        return $this->admin_config;
241
-    }
242
-
243
-
244
-    /**
245
-     * @return FeatureFlags
246
-     */
247
-    public function feature(): FeatureFlags
248
-    {
249
-        return $this->feature;
250
-    }
251
-
252
-
253
-    /**
254
-     * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
255
-     * for child classes that needed to set properties prior to these methods getting called,
256
-     * but also needed the parent class to have its construction completed as well.
257
-     * Bottom line is that constructors should ONLY be used for setting initial properties
258
-     * and any complex initialization logic should only run after instantiation is complete.
259
-     * This method gets called immediately after construction from within
260
-     *      EE_Admin_Page_Init::_initialize_admin_page()
261
-     *
262
-     * @throws EE_Error
263
-     * @throws InvalidArgumentException
264
-     * @throws InvalidDataTypeException
265
-     * @throws InvalidInterfaceException
266
-     * @throws ReflectionException
267
-     * @throws Throwable
268
-     * @since 5.0.0.p
269
-     */
270
-    public function initializePage()
271
-    {
272
-        if ($this->initialized) {
273
-            return;
274
-        }
275
-        // set initial page props (child method)
276
-        $this->_init_page_props();
277
-        // set global defaults
278
-        $this->_set_defaults();
279
-        // set early because incoming requests could be ajax related and we need to register those hooks.
280
-        $this->_global_ajax_hooks();
281
-        $this->_ajax_hooks();
282
-        // other_page_hooks have to be early too.
283
-        $this->_do_other_page_hooks();
284
-        // set up page dependencies
285
-        $this->_before_page_setup();
286
-        $this->_page_setup();
287
-        $this->initialized = true;
288
-    }
289
-
290
-
291
-    /**
292
-     * _init_page_props
293
-     * Child classes use to set at least the following properties:
294
-     * $page_slug.
295
-     * $page_label.
296
-     *
297
-     * @abstract
298
-     * @return void
299
-     */
300
-    abstract protected function _init_page_props();
301
-
302
-
303
-    /**
304
-     * _ajax_hooks
305
-     * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
306
-     * Note: within the ajax callback methods.
307
-     *
308
-     * @abstract
309
-     * @return void
310
-     */
311
-    abstract protected function _ajax_hooks();
312
-
313
-
314
-    /**
315
-     * _define_page_props
316
-     * child classes define page properties in here.  Must include at least:
317
-     * $_admin_base_url = base_url for all admin pages
318
-     * $_admin_page_title = default admin_page_title for admin pages
319
-     * $_labels = array of default labels for various automatically generated elements:
320
-     *    array(
321
-     *        'buttons' => array(
322
-     *            'add' => esc_html__('label for add new button'),
323
-     *            'edit' => esc_html__('label for edit button'),
324
-     *            'delete' => esc_html__('label for delete button')
325
-     *            )
326
-     *        )
327
-     *
328
-     * @abstract
329
-     * @return void
330
-     */
331
-    abstract protected function _define_page_props();
332
-
333
-
334
-    /**
335
-     * _set_page_routes
336
-     * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
337
-     * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
338
-     * have a 'default' route. Here's the format
339
-     * $this->_page_routes = array(
340
-     *        'default' => array(
341
-     *            'func' => '_default_method_handling_route',
342
-     *            'args' => array('array','of','args'),
343
-     *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
344
-     *            ajax request, backend processing)
345
-     *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
346
-     *            headers route after.  The string you enter here should match the defined route reference for a
347
-     *            headers sent route.
348
-     *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
349
-     *            this route.
350
-     *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
351
-     *            checks).
352
-     *        ),
353
-     *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
354
-     *        handling method.
355
-     *        )
356
-     * )
357
-     *
358
-     * @abstract
359
-     * @return void
360
-     */
361
-    abstract protected function _set_page_routes();
362
-
363
-
364
-    /**
365
-     * _set_page_config
366
-     * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
367
-     * array corresponds to the page_route for the loaded page. Format:
368
-     * $this->_page_config = array(
369
-     *        'default' => array(
370
-     *            'labels' => array(
371
-     *                'buttons' => array(
372
-     *                    'add' => esc_html__('label for adding item'),
373
-     *                    'edit' => esc_html__('label for editing item'),
374
-     *                    'delete' => esc_html__('label for deleting item')
375
-     *                ),
376
-     *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
377
-     *            ), //optional an array of custom labels for various automatically generated elements to use on the
378
-     *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
379
-     *            _define_page_props() method
380
-     *            'nav' => array(
381
-     *                'label' => esc_html__('Label for Tab', 'event_espresso').
382
-     *                'url' => 'http://someurl', //automatically generated UNLESS you define
383
-     *                'css_class' => 'css-class', //automatically generated UNLESS you define
384
-     *                'order' => 10, //required to indicate tab position.
385
-     *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
386
-     *                displayed then add this parameter.
387
-     *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
388
-     *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
389
-     *            metaboxes set for eventespresso admin pages.
390
-     *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
391
-     *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
392
-     *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
393
-     *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
394
-     *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
395
-     *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
396
-     *            array indicates the max number of columns (4) and the default number of columns on page load (2).
397
-     *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
398
-     *            want to display.
399
-     *            'help_tabs' => array( //this is used for adding help tabs to a page
400
-     *                'tab_id' => array(
401
-     *                    'title' => 'tab_title',
402
-     *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
403
-     *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
404
-     *                    should match a file in the admin folder's "help_tabs" dir (ie..
405
-     *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
406
-     *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
407
-     *                    attempt to use the callback which should match the name of a method in the class
408
-     *                    ),
409
-     *                'tab2_id' => array(
410
-     *                    'title' => 'tab2 title',
411
-     *                    'filename' => 'file_name_2'
412
-     *                    'callback' => 'callback_method_for_content',
413
-     *                 ),
414
-     *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
415
-     *            help tab area on an admin page. @return void
416
-     *
417
-     * @abstract
418
-     */
419
-    abstract protected function _set_page_config();
46
+	/**
47
+	 * @var array
48
+	 * @since 5.0.0.p
49
+	 */
50
+	private array $publish_post_meta_box_hidden_fields = [];
420 51
 
52
+	/**
53
+	 * some default things shared by all child classes
54
+	 *
55
+	 * @var string[]
56
+	 */
57
+	protected array $_default_espresso_metaboxes = [
58
+		'_espresso_news_post_box',
59
+		'_espresso_links_post_box',
60
+		'_espresso_ratings_request',
61
+		'_espresso_sponsors_post_box',
62
+	];
421 63
 
422
-    /**
423
-     * _add_screen_options
424
-     * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
425
-     * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
426
-     * to a particular view.
427
-     *
428
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
429
-     *         see also WP_Screen object documents...
430
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
431
-     * @abstract
432
-     * @return void
433
-     */
434
-    abstract protected function _add_screen_options();
64
+	/**
65
+	 * Used to hold default query args for list table routes to help preserve stickiness of filters for carried out
66
+	 * actions.
67
+	 *
68
+	 * @since 4.6.x
69
+	 */
70
+	protected array $_default_route_query_args = [];
435 71
 
72
+	protected array $_labels                   = [];
436 73
 
437
-    /**
438
-     * _add_feature_pointers
439
-     * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
440
-     * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
441
-     * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
442
-     * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
443
-     * extended) also see:
444
-     *
445
-     * @link   http://eamann.com/tech/wordpress-portland/
446
-     * @abstract
447
-     * @return void
448
-     */
449
-    abstract protected function _add_feature_pointers();
74
+	protected array $_nav_tabs                 = [];
450 75
 
76
+	protected array $_page_config              = [];
451 77
 
452
-    /**
453
-     * load_scripts_styles
454
-     * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
455
-     * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
456
-     * scripts/styles per view by putting them in a dynamic function in this format
457
-     * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
458
-     *
459
-     * @abstract
460
-     * @return void
461
-     */
462
-    abstract public function load_scripts_styles();
78
+	/**
79
+	 * action => method pairs used for routing incoming requests
80
+	 *
81
+	 * @var array
82
+	 */
83
+	protected array $_page_routes   = [];
463 84
 
85
+	protected array $_req_data      = [];
464 86
 
465
-    /**
466
-     * admin_init
467
-     * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
468
-     * all pages/views loaded by child class.
469
-     *
470
-     * @abstract
471
-     * @return void
472
-     */
473
-    abstract public function admin_init();
474
-
87
+	protected array $_route_config  = [];
475 88
 
476
-    /**
477
-     * admin_notices
478
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
479
-     * all pages/views loaded by child class.
480
-     *
481
-     * @abstract
482
-     * @return void
483
-     */
484
-    abstract public function admin_notices();
89
+	protected array $_template_args = [];
485 90
 
91
+	protected array $_views         = [];
486 92
 
487
-    /**
488
-     * admin_footer_scripts
489
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
490
-     * will apply to all pages/views loaded by child class.
491
-     *
492
-     * @return void
493
-     */
494
-    abstract public function admin_footer_scripts();
93
+	/**
94
+	 * yes / no array for admin form fields
95
+	 *
96
+	 * @var array|array[]
97
+	 */
98
+	protected array $_yes_no_values = [];
495 99
 
100
+	/**
101
+	 * this starts at null so we can have no header routes progress through two states.
102
+	 */
103
+	protected ?bool $_is_UI_request = null;
496 104
 
497
-    /**
498
-     * admin_footer
499
-     * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
500
-     * apply to all pages/views loaded by child class.
501
-     *
502
-     * @return void
503
-     */
504
-    public function admin_footer()
505
-    {
506
-    }
105
+	protected bool  $_is_caf        = false;                                                                                                                                                                                                                                  // This is just a property that flags whether the given route is a caffeinated route or not.
507 106
 
107
+	protected bool  $_routing       = false;
508 108
 
509
-    /**
510
-     * _global_ajax_hooks
511
-     * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
512
-     * Note: within the ajax callback methods.
513
-     *
514
-     * @abstract
515
-     * @return void
516
-     */
517
-    protected function _global_ajax_hooks()
518
-    {
519
-        // for lazy loading of metabox content
520
-        add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content']);
521
-
522
-        add_action(
523
-            'wp_ajax_espresso_hide_status_change_notice',
524
-            [$this, 'hideStatusChangeNotice']
525
-        );
526
-        add_action(
527
-            'wp_ajax_nopriv_espresso_hide_status_change_notice',
528
-            [$this, 'hideStatusChangeNotice']
529
-        );
530
-    }
531
-
532
-
533
-    public function ajax_metabox_content()
534
-    {
535
-        $content_id  = $this->request->getRequestParam('contentid', '');
536
-        $content_url = $this->request->getRequestParam('contenturl', '', DataType::URL);
537
-        EE_Admin_Page::cached_rss_display($content_id, $content_url);
538
-        wp_die();
539
-    }
540
-
541
-
542
-    public function hideStatusChangeNotice()
543
-    {
544
-        $response = [];
545
-        try {
546
-            /** @var StatusChangeNotice $status_change_notice */
547
-            $status_change_notice = $this->loader->getShared(
548
-                'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
549
-            );
550
-            $response['success']  = $status_change_notice->dismiss() > -1;
551
-        } catch (Exception $exception) {
552
-            $response['errors'] = $exception->getMessage();
553
-        }
554
-        echo wp_json_encode($response);
555
-        exit();
556
-    }
109
+	/**
110
+	 * whether initializePage() has run
111
+	 *
112
+	 * @var bool
113
+	 */
114
+	protected bool $initialized = false;
557 115
 
558 116
 
559
-    /**
560
-     * allows extending classes do something specific before the parent constructor runs _page_setup().
561
-     *
562
-     * @return void
563
-     */
564
-    protected function _before_page_setup()
565
-    {
566
-        // default is to do nothing
567
-    }
117
+	protected string $_admin_base_path      = '';
568 118
 
119
+	protected string $_admin_base_url       = '';
569 120
 
570
-    /**
571
-     * Makes sure any things that need to be loaded early get handled.
572
-     * We also escape early here if the page requested doesn't match the object.
573
-     *
574
-     * @final
575
-     * @return void
576
-     * @throws EE_Error
577
-     * @throws InvalidArgumentException
578
-     * @throws ReflectionException
579
-     * @throws InvalidDataTypeException
580
-     * @throws InvalidInterfaceException
581
-     * @throws Throwable
582
-     */
583
-    final protected function _page_setup()
584
-    {
585
-        // requires?
586
-        // admin_init stuff - global - we're setting this REALLY early
587
-        // so if EE_Admin pages have to hook into other WP pages they can.
588
-        // But keep in mind, not everything is available from the EE_Admin Page object at this point.
589
-        add_action('admin_init', [$this, 'admin_init_global'], 5);
590
-        // next verify if we need to load anything...
591
-        $this->_current_page = $this->request->getRequestParam('page', '', DataType::KEY);
592
-        $this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, DataType::KEY);
593
-        $this->page_folder   = strtolower(
594
-            str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
595
-        );
596
-        global $ee_menu_slugs;
597
-        $ee_menu_slugs = (array) $ee_menu_slugs;
598
-        if (
599
-            ! $this->request->isAjax()
600
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
601
-        ) {
602
-            return;
603
-        }
604
-        // because WP List tables have two duplicate select inputs for choosing bulk actions,
605
-        // we need to copy the action from the second to the first
606
-        $action     = $this->request->getRequestParam('action', '-1', DataType::KEY);
607
-        $action2    = $this->request->getRequestParam('action2', '-1', DataType::KEY);
608
-        $action     = $action !== '-1' ? $action : $action2;
609
-        $req_action = $action !== '-1' ? $action : 'default';
610
-
611
-        // if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
612
-        // then let's use the route as the action.
613
-        // This covers cases where we're coming in from a list table that isn't on the default route.
614
-        $route             = $this->request->getRequestParam('route');
615
-        $this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
616
-            ? $route
617
-            : $req_action;
618
-        $this->_current_view = $this->_req_action;
619
-        $this->_req_nonce    = $this->_req_action . '_nonce';
620
-        $this->_define_page_props();
621
-        $this->_current_page_view_url = add_query_arg(
622
-            ['page' => $this->_current_page, 'action' => $this->_current_view],
623
-            $this->_admin_base_url
624
-        );
625
-        // set page configs
626
-        $this->_set_page_routes();
627
-        $this->_set_page_config();
628
-        // let's include any referrer data in our default_query_args for this route for "stickiness".
629
-        if ($this->request->requestParamIsSet('wp_referer')) {
630
-            $wp_referer = $this->request->getRequestParam('wp_referer');
631
-            if ($wp_referer) {
632
-                $this->_default_route_query_args['wp_referer'] = $wp_referer;
633
-            }
634
-        }
635
-        // for CPT and other extended functionality.
636
-        // If there is an _extend_page_config_for_cpt
637
-        // then let's run that to modify all the various page configuration arrays.
638
-        if (method_exists($this, '_extend_page_config_for_cpt')) {
639
-            $this->_extend_page_config_for_cpt();
640
-        }
641
-        // filter routes and page_config so addons can add their stuff. Filtering done per class
642
-        $this->_page_routes = apply_filters(
643
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
644
-            $this->_page_routes,
645
-            $this
646
-        );
647
-        $this->_page_config = apply_filters(
648
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
649
-            $this->_page_config,
650
-            $this
651
-        );
652
-        if ($this->base_class_name !== '') {
653
-            $this->_page_routes = apply_filters(
654
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
655
-                $this->_page_routes,
656
-                $this
657
-            );
658
-            $this->_page_config = apply_filters(
659
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
660
-                $this->_page_config,
661
-                $this
662
-            );
663
-        }
664
-        // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
665
-        // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
666
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
667
-            add_action(
668
-                'AHEE__EE_Admin_Page__route_admin_request',
669
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
670
-                10,
671
-                2
672
-            );
673
-        }
674
-        // next route only if routing enabled
675
-        if ($this->_routing && ! $this->request->isAjax()) {
676
-            $this->_verify_routes();
677
-            // next let's just check user_access and kill if no access
678
-            $this->check_user_access();
679
-            if ($this->_is_UI_request) {
680
-                // admin_init stuff - global, all views for this page class, specific view
681
-                add_action('admin_init', [$this, 'admin_init']);
682
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
683
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
684
-                }
685
-            } else {
686
-                // hijack regular WP loading and route admin request immediately
687
-                @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
688
-                $this->route_admin_request();
689
-            }
690
-        }
691
-    }
121
+	protected string $_admin_page_title     = '';
692 122
 
123
+	protected string $_column_template_path = '';
693 124
 
694
-    /**
695
-     * Provides a way for related child admin pages to load stuff on the loaded admin page.
696
-     *
697
-     * @return void
698
-     * @throws EE_Error
699
-     */
700
-    private function _do_other_page_hooks()
701
-    {
702
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
703
-        foreach ($registered_pages as $page) {
704
-            // now let's setup the file name and class that should be present
705
-            $classname = str_replace('.class.php', '', $page);
706
-            // autoloaders should take care of loading file
707
-            if (! class_exists($classname)) {
708
-                $error_msg[] = sprintf(
709
-                    esc_html__(
710
-                        'Something went wrong with loading the %s admin hooks page.',
711
-                        'event_espresso'
712
-                    ),
713
-                    $page
714
-                );
715
-                $error_msg[] = $error_msg[0]
716
-                               . "\r\n"
717
-                               . sprintf(
718
-                                   esc_html__(
719
-                                       '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',
720
-                                       'event_espresso'
721
-                                   ),
722
-                                   $page,
723
-                                   '<br />',
724
-                                   '<strong>' . $classname . '</strong>'
725
-                               );
726
-                throw new EE_Error(implode('||', $error_msg));
727
-            }
728
-            // don't load the same class twice
729
-            static $loaded = [];
730
-            if (in_array($classname, $loaded, true)) {
731
-                continue;
732
-            }
733
-            $loaded[] = $classname;
734
-            // notice we are passing the instance of this class to the hook object.
735
-            $this->loader->getShared($classname, [$this]);
736
-        }
737
-    }
125
+	protected bool   $_cpt_route            = false;
738 126
 
127
+	/**
128
+	 * set via request page and action args.
129
+	 */
130
+	protected string $_current_page          = '';
739 131
 
740
-    /**
741
-     * @throws ReflectionException
742
-     * @throws EE_Error
743
-     */
744
-    public function load_page_dependencies()
745
-    {
746
-        try {
747
-            $this->_load_page_dependencies();
748
-        } catch (EE_Error $e) {
749
-            $e->get_error();
750
-        }
751
-    }
132
+	protected string $_current_page_view_url = '';
752 133
 
134
+	protected string $_current_view          = '';
753 135
 
754
-    /**
755
-     * load_page_dependencies
756
-     * loads things specific to this page class when its loaded.  Really helps with efficiency.
757
-     *
758
-     * @return void
759
-     * @throws DomainException
760
-     * @throws EE_Error
761
-     * @throws InvalidArgumentException
762
-     * @throws InvalidDataTypeException
763
-     * @throws InvalidInterfaceException
764
-     * @throws ReflectionException
765
-     */
766
-    protected function _load_page_dependencies()
767
-    {
768
-        // let's set the current_screen and screen options to override what WP set
769
-        $this->_current_screen = get_current_screen();
770
-        // load admin_notices - global, page class, and view specific
771
-        add_action('admin_notices', [$this, 'admin_notices_global'], 5);
772
-        add_action('admin_notices', [$this, 'admin_notices']);
773
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
774
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
775
-        }
776
-        // load network admin_notices - global, page class, and view specific
777
-        add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
778
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
779
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
780
-        }
781
-        // this will save any per_page screen options if they are present
782
-        $this->_set_per_page_screen_options();
783
-        // setup list table properties
784
-        $this->_set_list_table();
785
-        // child classes can "register" a metabox to be automatically handled via the _page_config array property.
786
-        // However in some cases the metaboxes will need to be added within a route handling callback.
787
-        add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
788
-        // hack because promos admin was loading the edited promotion object in the metaboxes callback
789
-        // which should NOT be generated on non-UI requests like POST updates/inserts
790
-        if (
791
-            $this->class_name === 'Promotions_Admin_Page'
792
-            && ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
793
-        ) {
794
-            $this->addRegisteredMetaBoxes();
795
-        }
796
-        $this->_add_screen_columns();
797
-        // add screen options - global, page child class, and view specific
798
-        $this->_add_global_screen_options();
799
-        $this->_add_screen_options();
800
-        $add_screen_options = "_add_screen_options_$this->_current_view";
801
-        if (method_exists($this, $add_screen_options)) {
802
-            $this->{$add_screen_options}();
803
-        }
804
-        // add help tab(s) - set via page_config and qtips.
805
-        $this->_add_help_tabs();
806
-        $this->_add_qtips();
807
-        // add feature_pointers - global, page child class, and view specific
808
-        $this->_add_feature_pointers();
809
-        $this->_add_global_feature_pointers();
810
-        $add_feature_pointer = "_add_feature_pointer_$this->_current_view";
811
-        if (method_exists($this, $add_feature_pointer)) {
812
-            $this->{$add_feature_pointer}();
813
-        }
814
-        // enqueue scripts/styles - global, page class, and view specific
815
-        add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
816
-        add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles']);
817
-        if (method_exists($this, "load_scripts_styles_$this->_current_view")) {
818
-            add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_$this->_current_view"], 15);
819
-        }
820
-        add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 100);
821
-        // admin_print_footer_scripts - global, page child class, and view specific.
822
-        // NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
823
-        // In most cases that's doing_it_wrong().  But adding hidden container elements etc.
824
-        // is a good use case. Notice the late priority we're giving these
825
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
826
-        add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
827
-        if (method_exists($this, "admin_footer_scripts_$this->_current_view")) {
828
-            add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_$this->_current_view"], 101);
829
-        }
830
-        // admin footer scripts
831
-        add_action('admin_footer', [$this, 'admin_footer_global'], 99);
832
-        add_action('admin_footer', [$this, 'admin_footer'], 100);
833
-        if (method_exists($this, "admin_footer_$this->_current_view")) {
834
-            add_action('admin_footer', [$this, "admin_footer_$this->_current_view"], 101);
835
-        }
836
-        do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
837
-        // targeted hook
838
-        do_action(
839
-            "FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__$this->_req_action"
840
-        );
841
-    }
842
-
843
-
844
-    /**
845
-     * _set_defaults
846
-     * This sets some global defaults for class properties.
847
-     */
848
-    private function _set_defaults()
849
-    {
850
-        // init template args
851
-        $this->set_template_args(
852
-            [
853
-                'admin_page_header'  => '',
854
-                'admin_page_content' => '',
855
-                'post_body_content'  => '',
856
-                'before_list_table'  => '',
857
-                'after_list_table'   => '',
858
-            ]
859
-        );
860
-    }
861
-
862
-
863
-    /**
864
-     * route_admin_request
865
-     *
866
-     * @return void
867
-     * @throws InvalidArgumentException
868
-     * @throws InvalidInterfaceException
869
-     * @throws InvalidDataTypeException
870
-     * @throws EE_Error
871
-     * @throws ReflectionException
872
-     * @throws Throwable
873
-     * @see    _route_admin_request()
874
-     */
875
-    public function route_admin_request()
876
-    {
877
-        try {
878
-            $this->_route_admin_request();
879
-        } catch (EE_Error $e) {
880
-            $e->get_error();
881
-        }
882
-    }
883
-
884
-
885
-    public function set_wp_page_slug($wp_page_slug)
886
-    {
887
-        $this->_wp_page_slug = $wp_page_slug;
888
-        // if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
889
-        if (is_network_admin()) {
890
-            $this->_wp_page_slug .= '-network';
891
-        }
892
-    }
893
-
894
-
895
-    /**
896
-     * _verify_routes
897
-     * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
898
-     * we know if we need to drop out.
899
-     *
900
-     * @return bool
901
-     * @throws EE_Error
902
-     */
903
-    protected function _verify_routes(): bool
904
-    {
905
-        if (! $this->_current_page && ! $this->request->isAjax()) {
906
-            return false;
907
-        }
908
-        // check that the page_routes array is not empty
909
-        if (empty($this->_page_routes)) {
910
-            // user error msg
911
-            $error_msg = sprintf(
912
-                esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
913
-                $this->_admin_page_title
914
-            );
915
-            // developer error msg
916
-            $error_msg .= '||' . $error_msg
917
-                          . esc_html__(
918
-                              ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
919
-                              'event_espresso'
920
-                          );
921
-            throw new EE_Error($error_msg);
922
-        }
923
-        // route 'editpost' routes to CPT 'edit' routes
924
-        $alt_edit_route = $this instanceof EE_Admin_Page_CPT ? $this->cpt_editpost_route : 'edit';
925
-        if (
926
-            $this->_req_action === 'editpost'
927
-            && ! isset($this->_page_routes['editpost'])
928
-            && isset($this->_page_routes[$alt_edit_route])
929
-        ) {
930
-            $this->_req_action = $alt_edit_route;
931
-        }
932
-        // and that the requested page route exists
933
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
934
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
935
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
936
-        } else {
937
-            // user error msg
938
-            $error_msg = sprintf(
939
-                esc_html__(
940
-                    'The requested page route does not exist for the %s admin page.',
941
-                    'event_espresso'
942
-                ),
943
-                $this->_admin_page_title
944
-            );
945
-            // developer error msg
946
-            $error_msg .= '||' . $error_msg
947
-                          . sprintf(
948
-                              esc_html__(
949
-                                  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
950
-                                  'event_espresso'
951
-                              ),
952
-                              $this->_req_action
953
-                          );
954
-            throw new EE_Error($error_msg);
955
-        }
956
-        // and that a default route exists
957
-        if (! array_key_exists('default', $this->_page_routes)) {
958
-            // user error msg
959
-            $error_msg = sprintf(
960
-                esc_html__(
961
-                    'A default page route has not been set for the % admin page.',
962
-                    'event_espresso'
963
-                ),
964
-                $this->_admin_page_title
965
-            );
966
-            // developer error msg
967
-            $error_msg .= '||' . $error_msg
968
-                          . esc_html__(
969
-                              ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
970
-                              'event_espresso'
971
-                          );
972
-            throw new EE_Error($error_msg);
973
-        }
974
-
975
-        // first lets' catch if the UI request has EVER been set.
976
-        if ($this->_is_UI_request === null) {
977
-            // lets set if this is a UI request or not.
978
-            $this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, DataType::BOOL);
979
-            // wait a minute... we might have a noheader in the route array
980
-            $this->_is_UI_request = ! (isset($this->_route['noheader']) && $this->_route['noheader'])
981
-                ? $this->_is_UI_request
982
-                : false;
983
-        }
984
-        $this->_set_current_labels();
985
-        return true;
986
-    }
987
-
988
-
989
-    /**
990
-     * this method simply verifies a given route and makes sure its an actual route available for the loaded page
991
-     *
992
-     * @param string $route the route name we're verifying
993
-     * @return bool we'll throw an exception if this isn't a valid route.
994
-     * @throws EE_Error
995
-     */
996
-    protected function _verify_route(string $route): bool
997
-    {
998
-        if (array_key_exists($this->_req_action, $this->_page_routes)) {
999
-            return true;
1000
-        }
1001
-        // user error msg
1002
-        $error_msg = sprintf(
1003
-            esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1004
-            $this->_admin_page_title
1005
-        );
1006
-        // developer error msg
1007
-        $error_msg .= '||' . $error_msg
1008
-                      . sprintf(
1009
-                          esc_html__(
1010
-                              ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1011
-                              'event_espresso'
1012
-                          ),
1013
-                          $route
1014
-                      );
1015
-        throw new EE_Error($error_msg);
1016
-    }
136
+	protected string $_default_nav_tab_name  = 'overview';
1017 137
 
1018
-
1019
-    /**
1020
-     * perform nonce verification
1021
-     * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1022
-     * using this method (and save retyping!)
1023
-     *
1024
-     * @param string $nonce     The nonce sent
1025
-     * @param string $nonce_ref The nonce reference string (name0)
1026
-     * @return void
1027
-     * @throws EE_Error
1028
-     * @throws InvalidArgumentException
1029
-     * @throws InvalidDataTypeException
1030
-     * @throws InvalidInterfaceException
1031
-     */
1032
-    protected function _verify_nonce(string $nonce, string $nonce_ref)
1033
-    {
1034
-        // verify nonce against expected value
1035
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1036
-            // these are not the droids you are looking for !!!
1037
-            $msg = sprintf(
1038
-                esc_html__('%sNonce Fail.%s', 'event_espresso'),
1039
-                '<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1040
-                '</a>'
1041
-            );
1042
-            if (WP_DEBUG) {
1043
-                $msg .= "\n  ";
1044
-                $msg .= sprintf(
1045
-                    esc_html__(
1046
-                        'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1047
-                        'event_espresso'
1048
-                    ),
1049
-                    __CLASS__
1050
-                );
1051
-            }
1052
-            if (! $this->request->isAjax()) {
1053
-                wp_die($msg);
1054
-            }
1055
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1056
-            $this->_return_json();
1057
-        }
1058
-    }
1059
-
1060
-
1061
-    /**
1062
-     * _route_admin_request()
1063
-     * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1064
-     * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1065
-     * in the page routes and then will try to load the corresponding method.
1066
-     *
1067
-     * @return void
1068
-     * @throws EE_Error
1069
-     * @throws InvalidArgumentException
1070
-     * @throws InvalidDataTypeException
1071
-     * @throws InvalidInterfaceException
1072
-     * @throws ReflectionException
1073
-     * @throws Throwable
1074
-     */
1075
-    protected function _route_admin_request()
1076
-    {
1077
-        if (! $this->_is_UI_request) {
1078
-            $this->_verify_routes();
1079
-        }
1080
-        $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1081
-        if ($this->_req_action !== 'default' && $nonce_check) {
1082
-            // set nonce from post data
1083
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
1084
-            $this->_verify_nonce($nonce, $this->_req_nonce);
1085
-        }
1086
-        // set the nav_tabs array but ONLY if this is  UI_request
1087
-        if ($this->_is_UI_request) {
1088
-            $this->_set_nav_tabs();
1089
-        }
1090
-        // grab callback function
1091
-        $func = $this->_route['func'] ?? $this->_route;
1092
-        // check if callback has args
1093
-        $args = $this->_route['args'] ?? [];
1094
-
1095
-        // action right before calling route
1096
-        // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1097
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1098
-            do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1099
-        }
1100
-        // strip _wp_http_referer from the server REQUEST_URI
1101
-        // else it grows in length on every submission due to recursion,
1102
-        // ultimately causing a "Request-URI Too Large" error
1103
-        $this->request->unSetRequestParam('_wp_http_referer');
1104
-        $this->request->unSetServerParam('_wp_http_referer');
1105
-        $cleaner_request_uri = remove_query_arg(
1106
-            '_wp_http_referer',
1107
-            wp_unslash($this->request->getServerParam('REQUEST_URI'))
1108
-        );
1109
-        $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1110
-        $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1111
-        $route_callback = [];
1112
-        if (! empty($func)) {
1113
-            if (is_array($func) && is_callable($func)) {
1114
-                $route_callback = $func;
1115
-            } elseif (is_string($func)) {
1116
-                if (strpos($func, '::') !== false) {
1117
-                    $route_callback = explode('::', $func);
1118
-                } elseif (method_exists($this, $func)) {
1119
-                    $route_callback = [$this, $func];
1120
-                } else {
1121
-                    $route_callback = $func;
1122
-                }
1123
-            }
1124
-            [$class, $method] = $route_callback;
1125
-            // is it neither a class method NOR a standalone function?
1126
-            if (! is_callable($route_callback)) {
1127
-                // user error msg
1128
-                $error_msg = esc_html__(
1129
-                    'An error occurred. The  requested page route could not be found.',
1130
-                    'event_espresso'
1131
-                );
1132
-                // developer error msg
1133
-                $error_msg .= '||';
1134
-                $error_msg .= sprintf(
1135
-                    esc_html__(
1136
-                        'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1137
-                        'event_espresso'
1138
-                    ),
1139
-                    $method
1140
-                );
1141
-                throw new DomainException($error_msg);
1142
-            }
1143
-            if ($class !== $this && ! in_array($this, $args)) {
1144
-                // send along this admin page object for access by addons.
1145
-                $args['admin_page'] = $this;
1146
-            }
1147
-
1148
-            call_user_func_array($route_callback, $args);
1149
-        }
1150
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1151
-        // then we need to reset the routing properties to the new route.
1152
-        // 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.
1153
-        if (
1154
-            $this->_is_UI_request === false
1155
-            && is_array($this->_route)
1156
-            && ! empty($this->_route['headers_sent_route'])
1157
-        ) {
1158
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1159
-        }
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * This method just allows the resetting of page properties in the case where a no headers
1165
-     * route redirects to a headers route in its route config.
1166
-     *
1167
-     * @param string $new_route New (non header) route to redirect to.
1168
-     * @return void
1169
-     * @throws ReflectionException
1170
-     * @throws InvalidArgumentException
1171
-     * @throws InvalidInterfaceException
1172
-     * @throws InvalidDataTypeException
1173
-     * @throws EE_Error
1174
-     * @throws Throwable
1175
-     * @since   4.3.0
1176
-     */
1177
-    protected function _reset_routing_properties(string $new_route)
1178
-    {
1179
-        $this->_is_UI_request = true;
1180
-        // now we set the current route to whatever the headers_sent_route is set at
1181
-        $this->request->setRequestParam('action', $new_route);
1182
-        // rerun page setup
1183
-        $this->_page_setup();
1184
-    }
1185
-
1186
-
1187
-    /**
1188
-     * _add_query_arg
1189
-     * adds nonce to array of arguments then calls WP add_query_arg function
1190
-     *(internally just uses EEH_URL's function with the same name)
1191
-     *
1192
-     * @param array  $args
1193
-     * @param string $url
1194
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1195
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1196
-     *                                        Example usage: If the current page is:
1197
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1198
-     *                                        &action=default&event_id=20&month_range=March%202015
1199
-     *                                        &_wpnonce=5467821
1200
-     *                                        and you call:
1201
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1202
-     *                                        array(
1203
-     *                                        'action' => 'resend_something',
1204
-     *                                        'page=>espresso_registrations'
1205
-     *                                        ),
1206
-     *                                        $some_url,
1207
-     *                                        true
1208
-     *                                        );
1209
-     *                                        It will produce a url in this structure:
1210
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1211
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1212
-     *                                        month_range]=March%202015
1213
-     * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1214
-     * @param int    $context
1215
-     * @return string
1216
-     */
1217
-    public static function add_query_args_and_nonce(
1218
-        array $args = [],
1219
-        string $url = '',
1220
-        bool $sticky = false,
1221
-        bool $exclude_nonce = false,
1222
-        int $context = EEH_URL::CONTEXT_NONE
1223
-    ): string {
1224
-        // if there is a _wp_http_referer include the values from the request but only if sticky = true
1225
-        if ($sticky) {
1226
-            /** @var RequestInterface $request */
1227
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1228
-            $request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1229
-            $request->unSetServerParam('_wp_http_referer', true);
1230
-            foreach ($request->requestParams() as $key => $value) {
1231
-                // do not add nonces
1232
-                if (strpos($key, 'nonce') !== false) {
1233
-                    continue;
1234
-                }
1235
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1236
-            }
1237
-        }
1238
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * This returns a generated link that will load the related help tab.
1244
-     *
1245
-     * @param string $help_tab_id the id for the connected help tab
1246
-     * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1247
-     * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1248
-     * @return string              generated link
1249
-     * @uses EEH_Template::get_help_tab_link()
1250
-     */
1251
-    protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1252
-    {
1253
-        return EEH_Template::get_help_tab_link(
1254
-            $help_tab_id,
1255
-            $this->page_slug,
1256
-            $this->_req_action,
1257
-            $icon_style,
1258
-            $help_text
1259
-        );
1260
-    }
1261
-
1262
-
1263
-    /**
1264
-     * _add_help_tabs
1265
-     * Note child classes define their help tabs within the page_config array.
1266
-     *
1267
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1268
-     * @return void
1269
-     * @throws DomainException
1270
-     * @throws EE_Error
1271
-     * @throws ReflectionException
1272
-     */
1273
-    protected function _add_help_tabs()
1274
-    {
1275
-        if (isset($this->_page_config[ $this->_req_action ])) {
1276
-            $config = $this->_page_config[ $this->_req_action ];
1277
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1278
-            if (is_array($config) && isset($config['help_sidebar'])) {
1279
-                // check that the callback given is valid
1280
-                if (! method_exists($this, $config['help_sidebar'])) {
1281
-                    throw new EE_Error(
1282
-                        sprintf(
1283
-                            esc_html__(
1284
-                                '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',
1285
-                                'event_espresso'
1286
-                            ),
1287
-                            $config['help_sidebar'],
1288
-                            $this->class_name
1289
-                        )
1290
-                    );
1291
-                }
1292
-                $content = apply_filters(
1293
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1294
-                    $this->{$config['help_sidebar']}()
1295
-                );
1296
-                $this->_current_screen->set_help_sidebar($content);
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 = $cfg['content'];
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
-                    && (
1363
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1364
-                    )
1365
-                ) {
1366
-                    EE_Error::add_error(
1367
-                        sprintf(
1368
-                            esc_html__(
1369
-                                '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.',
1370
-                                'event_espresso'
1371
-                            ),
1372
-                            $cfg['title']
1373
-                        ),
1374
-                        __FILE__,
1375
-                        __FUNCTION__,
1376
-                        __LINE__
1377
-                    );
1378
-                    return;
1379
-                }
1380
-                // setup config array for help tab method
1381
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1382
-                $_ht = [
1383
-                    'id'       => $id,
1384
-                    'title'    => $cfg['title'],
1385
-                    'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1386
-                    'content'  => $content,
1387
-                ];
1388
-                $this->_current_screen->add_help_tab($_ht);
1389
-            }
1390
-        }
1391
-    }
1392
-
1393
-
1394
-    /**
1395
-     * This simply sets up any qtips that have been defined in the page config
1396
-     *
1397
-     * @return void
1398
-     * @throws ReflectionException
1399
-     * @throws EE_Error
1400
-     */
1401
-    protected function _add_qtips()
1402
-    {
1403
-        if (isset($this->_route_config['qtips'])) {
1404
-            $qtips = (array) $this->_route_config['qtips'];
1405
-            // load qtip loader
1406
-            $path = [
1407
-                $this->_get_dir() . '/qtips/',
1408
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1409
-            ];
1410
-            EEH_Qtip_Loader::instance()->register($qtips, $path);
1411
-        }
1412
-    }
1413
-
1414
-
1415
-    /**
1416
-     * _set_nav_tabs
1417
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1418
-     * wish to add additional tabs or modify accordingly.
1419
-     *
1420
-     * @return void
1421
-     * @throws InvalidArgumentException
1422
-     * @throws InvalidInterfaceException
1423
-     * @throws InvalidDataTypeException
1424
-     */
1425
-    protected function _set_nav_tabs()
1426
-    {
1427
-        $i        = 0;
1428
-        $only_tab = count($this->_page_config) < 2;
1429
-        foreach ($this->_page_config as $slug => $config) {
1430
-            if (! is_array($config) || empty($config['nav'])) {
1431
-                continue;
1432
-            }
1433
-            // no nav tab for this config
1434
-            // check for persistent flag
1435
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1436
-                // nav tab is only to appear when route requested.
1437
-                continue;
1438
-            }
1439
-            if (! $this->check_user_access($slug, true)) {
1440
-                // no nav tab because current user does not have access.
1441
-                continue;
1442
-            }
1443
-            $css_class = $config['css_class'] ?? '';
1444
-            $css_class .= $only_tab ? ' ee-only-tab' : '';
1445
-            $css_class .= " ee-nav-tab__$slug";
1446
-
1447
-            $this->_nav_tabs[ $slug ] = [
1448
-                'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1449
-                        ['action' => $slug],
1450
-                        $this->_admin_base_url
1451
-                    ),
1452
-                'link_text' => $this->navTabLabel($config['nav'], $slug),
1453
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1454
-                'order'     => $config['nav']['order'] ?? $i,
1455
-            ];
1456
-            $i++;
1457
-        }
1458
-        // if $this->_nav_tabs is empty then lets set the default
1459
-        if (empty($this->_nav_tabs)) {
1460
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1461
-                'url'       => $this->_admin_base_url,
1462
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1463
-                'css_class' => 'nav-tab-active',
1464
-                'order'     => 10,
1465
-            ];
1466
-        }
1467
-        // now let's sort the tabs according to order
1468
-        usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1469
-    }
1470
-
1471
-
1472
-    private function navTabLabel(array $nav_tab, string $slug): string
1473
-    {
1474
-        $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1475
-        $icon  = $nav_tab['icon'] ?? null;
1476
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1477
-        return '
138
+	/**
139
+	 * sanitized request action
140
+	 */
141
+	protected string $_req_action = '';
142
+
143
+	/**
144
+	 * sanitized request action nonce
145
+	 */
146
+	protected string $_req_nonce        = '';
147
+
148
+	protected string $_search_btn_label = '';
149
+
150
+	protected string $_template_path    = '';
151
+
152
+	protected string $_view             = '';
153
+
154
+	/**
155
+	 * set early within EE_Admin_Init
156
+	 *
157
+	 * @var string
158
+	 */
159
+	protected string $_wp_page_slug = '';
160
+
161
+	/**
162
+	 * if the current class is an admin page extension, like: Extend_Events_Admin_Page,
163
+	 * then this would be the parent classname: Events_Admin_Page
164
+	 *
165
+	 * @var string
166
+	 */
167
+	public string $base_class_name = '';
168
+
169
+	public string $class_name      = '';
170
+
171
+	/**
172
+	 * unprocessed value for the 'action' request param (default '')
173
+	 *
174
+	 * @var string
175
+	 */
176
+	protected string $raw_req_action = '';
177
+
178
+	/**
179
+	 * unprocessed value for the 'page' request param (default '')
180
+	 *
181
+	 * @var string
182
+	 */
183
+	protected string $raw_req_page = '';
184
+
185
+	public string    $page_folder  = '';
186
+
187
+	public string    $page_label   = '';
188
+
189
+	public string    $page_slug    = '';
190
+
191
+
192
+	/**
193
+	 * the current page route and route config
194
+	 *
195
+	 * @var array|callable|string|null
196
+	 */
197
+	protected $_route = null;
198
+
199
+
200
+	/**
201
+	 * @Constructor
202
+	 * @param bool $routing indicate whether we want to just load the object and handle routing or just load the object.
203
+	 * @throws InvalidArgumentException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 * @throws ReflectionException
207
+	 */
208
+	public function __construct($routing = true)
209
+	{
210
+		$this->loader       = LoaderFactory::getLoader();
211
+		$this->admin_config = $this->loader->getShared(EE_Admin_Config::class);
212
+		$this->feature      = $this->loader->getShared(FeatureFlags::class);
213
+		$this->request      = $this->loader->getShared(RequestInterface::class);
214
+		$this->capabilities = $this->loader->getShared(EE_Capabilities::class);
215
+		// routing enabled?
216
+		$this->_routing = $routing;
217
+
218
+		$this->class_name      = get_class($this);
219
+		$this->base_class_name = strpos($this->class_name, 'Extend_') === 0
220
+			? str_replace('Extend_', '', $this->class_name)
221
+			: '';
222
+
223
+		if (strpos($this->_get_dir(), 'caffeinated') !== false) {
224
+			$this->_is_caf = true;
225
+		}
226
+		$this->_yes_no_values = [
227
+			['id' => true, 'text' => esc_html__('Yes', 'event_espresso')],
228
+			['id' => false, 'text' => esc_html__('No', 'event_espresso')],
229
+		];
230
+		// set the _req_data property.
231
+		$this->_req_data = $this->request->requestParams();
232
+	}
233
+
234
+
235
+	/**
236
+	 * @return EE_Admin_Config
237
+	 */
238
+	public function adminConfig(): EE_Admin_Config
239
+	{
240
+		return $this->admin_config;
241
+	}
242
+
243
+
244
+	/**
245
+	 * @return FeatureFlags
246
+	 */
247
+	public function feature(): FeatureFlags
248
+	{
249
+		return $this->feature;
250
+	}
251
+
252
+
253
+	/**
254
+	 * This logic used to be in the constructor, but that caused a chicken <--> egg scenario
255
+	 * for child classes that needed to set properties prior to these methods getting called,
256
+	 * but also needed the parent class to have its construction completed as well.
257
+	 * Bottom line is that constructors should ONLY be used for setting initial properties
258
+	 * and any complex initialization logic should only run after instantiation is complete.
259
+	 * This method gets called immediately after construction from within
260
+	 *      EE_Admin_Page_Init::_initialize_admin_page()
261
+	 *
262
+	 * @throws EE_Error
263
+	 * @throws InvalidArgumentException
264
+	 * @throws InvalidDataTypeException
265
+	 * @throws InvalidInterfaceException
266
+	 * @throws ReflectionException
267
+	 * @throws Throwable
268
+	 * @since 5.0.0.p
269
+	 */
270
+	public function initializePage()
271
+	{
272
+		if ($this->initialized) {
273
+			return;
274
+		}
275
+		// set initial page props (child method)
276
+		$this->_init_page_props();
277
+		// set global defaults
278
+		$this->_set_defaults();
279
+		// set early because incoming requests could be ajax related and we need to register those hooks.
280
+		$this->_global_ajax_hooks();
281
+		$this->_ajax_hooks();
282
+		// other_page_hooks have to be early too.
283
+		$this->_do_other_page_hooks();
284
+		// set up page dependencies
285
+		$this->_before_page_setup();
286
+		$this->_page_setup();
287
+		$this->initialized = true;
288
+	}
289
+
290
+
291
+	/**
292
+	 * _init_page_props
293
+	 * Child classes use to set at least the following properties:
294
+	 * $page_slug.
295
+	 * $page_label.
296
+	 *
297
+	 * @abstract
298
+	 * @return void
299
+	 */
300
+	abstract protected function _init_page_props();
301
+
302
+
303
+	/**
304
+	 * _ajax_hooks
305
+	 * child classes put all their add_action('wp_ajax_{name_of_hook}') hooks in here.
306
+	 * Note: within the ajax callback methods.
307
+	 *
308
+	 * @abstract
309
+	 * @return void
310
+	 */
311
+	abstract protected function _ajax_hooks();
312
+
313
+
314
+	/**
315
+	 * _define_page_props
316
+	 * child classes define page properties in here.  Must include at least:
317
+	 * $_admin_base_url = base_url for all admin pages
318
+	 * $_admin_page_title = default admin_page_title for admin pages
319
+	 * $_labels = array of default labels for various automatically generated elements:
320
+	 *    array(
321
+	 *        'buttons' => array(
322
+	 *            'add' => esc_html__('label for add new button'),
323
+	 *            'edit' => esc_html__('label for edit button'),
324
+	 *            'delete' => esc_html__('label for delete button')
325
+	 *            )
326
+	 *        )
327
+	 *
328
+	 * @abstract
329
+	 * @return void
330
+	 */
331
+	abstract protected function _define_page_props();
332
+
333
+
334
+	/**
335
+	 * _set_page_routes
336
+	 * child classes use this to define the page routes for all subpages handled by the class.  Page routes are
337
+	 * assigned to a action => method pairs in an array and to the $_page_routes property.  Each page route must also
338
+	 * have a 'default' route. Here's the format
339
+	 * $this->_page_routes = array(
340
+	 *        'default' => array(
341
+	 *            'func' => '_default_method_handling_route',
342
+	 *            'args' => array('array','of','args'),
343
+	 *            'noheader' => true, //add this in if this page route is processed before any headers are loaded (i.e.
344
+	 *            ajax request, backend processing)
345
+	 *            'headers_sent_route'=>'headers_route_reference', //add this if noheader=>true, and you want to load a
346
+	 *            headers route after.  The string you enter here should match the defined route reference for a
347
+	 *            headers sent route.
348
+	 *            'capability' => 'route_capability', //indicate a string for minimum capability required to access
349
+	 *            this route.
350
+	 *            'obj_id' => 10 // if this route has an object id, then this can include it (used for capability
351
+	 *            checks).
352
+	 *        ),
353
+	 *        'insert_item' => '_method_for_handling_insert_item' //this can be used if all we need to have is a
354
+	 *        handling method.
355
+	 *        )
356
+	 * )
357
+	 *
358
+	 * @abstract
359
+	 * @return void
360
+	 */
361
+	abstract protected function _set_page_routes();
362
+
363
+
364
+	/**
365
+	 * _set_page_config
366
+	 * child classes use this to define the _page_config array for all subpages handled by the class. Each key in the
367
+	 * array corresponds to the page_route for the loaded page. Format:
368
+	 * $this->_page_config = array(
369
+	 *        'default' => array(
370
+	 *            'labels' => array(
371
+	 *                'buttons' => array(
372
+	 *                    'add' => esc_html__('label for adding item'),
373
+	 *                    'edit' => esc_html__('label for editing item'),
374
+	 *                    'delete' => esc_html__('label for deleting item')
375
+	 *                ),
376
+	 *                'publishbox' => esc_html__('Localized Title for Publish metabox', 'event_espresso')
377
+	 *            ), //optional an array of custom labels for various automatically generated elements to use on the
378
+	 *            page. If this isn't present then the defaults will be used as set for the $this->_labels in
379
+	 *            _define_page_props() method
380
+	 *            'nav' => array(
381
+	 *                'label' => esc_html__('Label for Tab', 'event_espresso').
382
+	 *                'url' => 'http://someurl', //automatically generated UNLESS you define
383
+	 *                'css_class' => 'css-class', //automatically generated UNLESS you define
384
+	 *                'order' => 10, //required to indicate tab position.
385
+	 *                'persistent' => false //if you want the nav tab to ONLY display when the specific route is
386
+	 *                displayed then add this parameter.
387
+	 *            'list_table' => 'name_of_list_table' //string for list table class to be loaded for this admin_page.
388
+	 *            'metaboxes' => array('metabox1', 'metabox2'), //if present this key indicates we want to load
389
+	 *            metaboxes set for eventespresso admin pages.
390
+	 *            'has_metaboxes' => true, //this boolean flag can simply be used to indicate if the route will have
391
+	 *            metaboxes.  Typically this is used if the 'metaboxes' index is not used because metaboxes are added
392
+	 *            later.  We just use this flag to make sure the necessary js gets enqueued on page load.
393
+	 *            'has_help_popups' => false //defaults(true) //this boolean flag can simply be used to indicate if the
394
+	 *            given route has help popups setup and if it does then we need to make sure thickbox is enqueued.
395
+	 *            'columns' => array(4, 2), //this key triggers the setup of a page that uses columns (metaboxes).  The
396
+	 *            array indicates the max number of columns (4) and the default number of columns on page load (2).
397
+	 *            There is an option in the "screen_options" dropdown that is setup so users can pick what columns they
398
+	 *            want to display.
399
+	 *            'help_tabs' => array( //this is used for adding help tabs to a page
400
+	 *                'tab_id' => array(
401
+	 *                    'title' => 'tab_title',
402
+	 *                    'filename' => 'name_of_file_containing_content', //this is the primary method for setting
403
+	 *                    help tab content.  The fallback if it isn't present is to try a the callback.  Filename
404
+	 *                    should match a file in the admin folder's "help_tabs" dir (ie..
405
+	 *                    events/help_tabs/name_of_file_containing_content.help_tab.php)
406
+	 *                    'callback' => 'callback_method_for_content', //if 'filename' isn't present then system will
407
+	 *                    attempt to use the callback which should match the name of a method in the class
408
+	 *                    ),
409
+	 *                'tab2_id' => array(
410
+	 *                    'title' => 'tab2 title',
411
+	 *                    'filename' => 'file_name_2'
412
+	 *                    'callback' => 'callback_method_for_content',
413
+	 *                 ),
414
+	 *            'help_sidebar' => 'callback_for_sidebar_content', //this is used for setting up the sidebar in the
415
+	 *            help tab area on an admin page. @return void
416
+	 *
417
+	 * @abstract
418
+	 */
419
+	abstract protected function _set_page_config();
420
+
421
+
422
+	/**
423
+	 * _add_screen_options
424
+	 * Child classes can add any extra wp_screen_options within this method using built-in WP functions/methods for
425
+	 * doing so. Note child classes can also define _add_screen_options_($this->_current_view) to limit screen options
426
+	 * to a particular view.
427
+	 *
428
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
429
+	 *         see also WP_Screen object documents...
430
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
431
+	 * @abstract
432
+	 * @return void
433
+	 */
434
+	abstract protected function _add_screen_options();
435
+
436
+
437
+	/**
438
+	 * _add_feature_pointers
439
+	 * Child classes should use this method for implementing any "feature pointers" (using built-in WP styling js).
440
+	 * Note child classes can also define _add_feature_pointers_($this->_current_view) to limit screen options to a
441
+	 * particular view. Note: this is just a placeholder for now.  Implementation will come down the road See:
442
+	 * WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
443
+	 * extended) also see:
444
+	 *
445
+	 * @link   http://eamann.com/tech/wordpress-portland/
446
+	 * @abstract
447
+	 * @return void
448
+	 */
449
+	abstract protected function _add_feature_pointers();
450
+
451
+
452
+	/**
453
+	 * load_scripts_styles
454
+	 * child classes put their wp_enqueue_script and wp_enqueue_style hooks in here for anything they need loaded for
455
+	 * their pages/subpages.  Note this is for all pages/subpages of the system.  You can also load only specific
456
+	 * scripts/styles per view by putting them in a dynamic function in this format
457
+	 * (load_scripts_styles_{$this->_current_view}) which matches your page route (action request arg)
458
+	 *
459
+	 * @abstract
460
+	 * @return void
461
+	 */
462
+	abstract public function load_scripts_styles();
463
+
464
+
465
+	/**
466
+	 * admin_init
467
+	 * Anything that should be set/executed at 'admin_init' WP hook runtime should be put in here.  This will apply to
468
+	 * all pages/views loaded by child class.
469
+	 *
470
+	 * @abstract
471
+	 * @return void
472
+	 */
473
+	abstract public function admin_init();
474
+
475
+
476
+	/**
477
+	 * admin_notices
478
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply to
479
+	 * all pages/views loaded by child class.
480
+	 *
481
+	 * @abstract
482
+	 * @return void
483
+	 */
484
+	abstract public function admin_notices();
485
+
486
+
487
+	/**
488
+	 * admin_footer_scripts
489
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
490
+	 * will apply to all pages/views loaded by child class.
491
+	 *
492
+	 * @return void
493
+	 */
494
+	abstract public function admin_footer_scripts();
495
+
496
+
497
+	/**
498
+	 * admin_footer
499
+	 * anything triggered by the 'admin_footer' WP action hook should be added to here. This particular method will
500
+	 * apply to all pages/views loaded by child class.
501
+	 *
502
+	 * @return void
503
+	 */
504
+	public function admin_footer()
505
+	{
506
+	}
507
+
508
+
509
+	/**
510
+	 * _global_ajax_hooks
511
+	 * all global add_action('wp_ajax_{name_of_hook}') hooks in here.
512
+	 * Note: within the ajax callback methods.
513
+	 *
514
+	 * @abstract
515
+	 * @return void
516
+	 */
517
+	protected function _global_ajax_hooks()
518
+	{
519
+		// for lazy loading of metabox content
520
+		add_action('wp_ajax_espresso-ajax-content', [$this, 'ajax_metabox_content']);
521
+
522
+		add_action(
523
+			'wp_ajax_espresso_hide_status_change_notice',
524
+			[$this, 'hideStatusChangeNotice']
525
+		);
526
+		add_action(
527
+			'wp_ajax_nopriv_espresso_hide_status_change_notice',
528
+			[$this, 'hideStatusChangeNotice']
529
+		);
530
+	}
531
+
532
+
533
+	public function ajax_metabox_content()
534
+	{
535
+		$content_id  = $this->request->getRequestParam('contentid', '');
536
+		$content_url = $this->request->getRequestParam('contenturl', '', DataType::URL);
537
+		EE_Admin_Page::cached_rss_display($content_id, $content_url);
538
+		wp_die();
539
+	}
540
+
541
+
542
+	public function hideStatusChangeNotice()
543
+	{
544
+		$response = [];
545
+		try {
546
+			/** @var StatusChangeNotice $status_change_notice */
547
+			$status_change_notice = $this->loader->getShared(
548
+				'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
549
+			);
550
+			$response['success']  = $status_change_notice->dismiss() > -1;
551
+		} catch (Exception $exception) {
552
+			$response['errors'] = $exception->getMessage();
553
+		}
554
+		echo wp_json_encode($response);
555
+		exit();
556
+	}
557
+
558
+
559
+	/**
560
+	 * allows extending classes do something specific before the parent constructor runs _page_setup().
561
+	 *
562
+	 * @return void
563
+	 */
564
+	protected function _before_page_setup()
565
+	{
566
+		// default is to do nothing
567
+	}
568
+
569
+
570
+	/**
571
+	 * Makes sure any things that need to be loaded early get handled.
572
+	 * We also escape early here if the page requested doesn't match the object.
573
+	 *
574
+	 * @final
575
+	 * @return void
576
+	 * @throws EE_Error
577
+	 * @throws InvalidArgumentException
578
+	 * @throws ReflectionException
579
+	 * @throws InvalidDataTypeException
580
+	 * @throws InvalidInterfaceException
581
+	 * @throws Throwable
582
+	 */
583
+	final protected function _page_setup()
584
+	{
585
+		// requires?
586
+		// admin_init stuff - global - we're setting this REALLY early
587
+		// so if EE_Admin pages have to hook into other WP pages they can.
588
+		// But keep in mind, not everything is available from the EE_Admin Page object at this point.
589
+		add_action('admin_init', [$this, 'admin_init_global'], 5);
590
+		// next verify if we need to load anything...
591
+		$this->_current_page = $this->request->getRequestParam('page', '', DataType::KEY);
592
+		$this->_current_page = $this->request->getRequestParam('current_page', $this->_current_page, DataType::KEY);
593
+		$this->page_folder   = strtolower(
594
+			str_replace(['_Admin_Page', 'Extend_'], '', $this->class_name)
595
+		);
596
+		global $ee_menu_slugs;
597
+		$ee_menu_slugs = (array) $ee_menu_slugs;
598
+		if (
599
+			! $this->request->isAjax()
600
+			&& (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
601
+		) {
602
+			return;
603
+		}
604
+		// because WP List tables have two duplicate select inputs for choosing bulk actions,
605
+		// we need to copy the action from the second to the first
606
+		$action     = $this->request->getRequestParam('action', '-1', DataType::KEY);
607
+		$action2    = $this->request->getRequestParam('action2', '-1', DataType::KEY);
608
+		$action     = $action !== '-1' ? $action : $action2;
609
+		$req_action = $action !== '-1' ? $action : 'default';
610
+
611
+		// if a specific 'route' has been set, and the action is 'default' OR we are doing_ajax
612
+		// then let's use the route as the action.
613
+		// This covers cases where we're coming in from a list table that isn't on the default route.
614
+		$route             = $this->request->getRequestParam('route');
615
+		$this->_req_action = $route && ($req_action === 'default' || $this->request->isAjax())
616
+			? $route
617
+			: $req_action;
618
+		$this->_current_view = $this->_req_action;
619
+		$this->_req_nonce    = $this->_req_action . '_nonce';
620
+		$this->_define_page_props();
621
+		$this->_current_page_view_url = add_query_arg(
622
+			['page' => $this->_current_page, 'action' => $this->_current_view],
623
+			$this->_admin_base_url
624
+		);
625
+		// set page configs
626
+		$this->_set_page_routes();
627
+		$this->_set_page_config();
628
+		// let's include any referrer data in our default_query_args for this route for "stickiness".
629
+		if ($this->request->requestParamIsSet('wp_referer')) {
630
+			$wp_referer = $this->request->getRequestParam('wp_referer');
631
+			if ($wp_referer) {
632
+				$this->_default_route_query_args['wp_referer'] = $wp_referer;
633
+			}
634
+		}
635
+		// for CPT and other extended functionality.
636
+		// If there is an _extend_page_config_for_cpt
637
+		// then let's run that to modify all the various page configuration arrays.
638
+		if (method_exists($this, '_extend_page_config_for_cpt')) {
639
+			$this->_extend_page_config_for_cpt();
640
+		}
641
+		// filter routes and page_config so addons can add their stuff. Filtering done per class
642
+		$this->_page_routes = apply_filters(
643
+			'FHEE__' . $this->class_name . '__page_setup__page_routes',
644
+			$this->_page_routes,
645
+			$this
646
+		);
647
+		$this->_page_config = apply_filters(
648
+			'FHEE__' . $this->class_name . '__page_setup__page_config',
649
+			$this->_page_config,
650
+			$this
651
+		);
652
+		if ($this->base_class_name !== '') {
653
+			$this->_page_routes = apply_filters(
654
+				'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
655
+				$this->_page_routes,
656
+				$this
657
+			);
658
+			$this->_page_config = apply_filters(
659
+				'FHEE__' . $this->base_class_name . '__page_setup__page_config',
660
+				$this->_page_config,
661
+				$this
662
+			);
663
+		}
664
+		// if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
665
+		// then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
666
+		if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
667
+			add_action(
668
+				'AHEE__EE_Admin_Page__route_admin_request',
669
+				[$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
670
+				10,
671
+				2
672
+			);
673
+		}
674
+		// next route only if routing enabled
675
+		if ($this->_routing && ! $this->request->isAjax()) {
676
+			$this->_verify_routes();
677
+			// next let's just check user_access and kill if no access
678
+			$this->check_user_access();
679
+			if ($this->_is_UI_request) {
680
+				// admin_init stuff - global, all views for this page class, specific view
681
+				add_action('admin_init', [$this, 'admin_init']);
682
+				if (method_exists($this, 'admin_init_' . $this->_current_view)) {
683
+					add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
684
+				}
685
+			} else {
686
+				// hijack regular WP loading and route admin request immediately
687
+				@ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT));
688
+				$this->route_admin_request();
689
+			}
690
+		}
691
+	}
692
+
693
+
694
+	/**
695
+	 * Provides a way for related child admin pages to load stuff on the loaded admin page.
696
+	 *
697
+	 * @return void
698
+	 * @throws EE_Error
699
+	 */
700
+	private function _do_other_page_hooks()
701
+	{
702
+		$registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
703
+		foreach ($registered_pages as $page) {
704
+			// now let's setup the file name and class that should be present
705
+			$classname = str_replace('.class.php', '', $page);
706
+			// autoloaders should take care of loading file
707
+			if (! class_exists($classname)) {
708
+				$error_msg[] = sprintf(
709
+					esc_html__(
710
+						'Something went wrong with loading the %s admin hooks page.',
711
+						'event_espresso'
712
+					),
713
+					$page
714
+				);
715
+				$error_msg[] = $error_msg[0]
716
+							   . "\r\n"
717
+							   . sprintf(
718
+								   esc_html__(
719
+									   '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',
720
+									   'event_espresso'
721
+								   ),
722
+								   $page,
723
+								   '<br />',
724
+								   '<strong>' . $classname . '</strong>'
725
+							   );
726
+				throw new EE_Error(implode('||', $error_msg));
727
+			}
728
+			// don't load the same class twice
729
+			static $loaded = [];
730
+			if (in_array($classname, $loaded, true)) {
731
+				continue;
732
+			}
733
+			$loaded[] = $classname;
734
+			// notice we are passing the instance of this class to the hook object.
735
+			$this->loader->getShared($classname, [$this]);
736
+		}
737
+	}
738
+
739
+
740
+	/**
741
+	 * @throws ReflectionException
742
+	 * @throws EE_Error
743
+	 */
744
+	public function load_page_dependencies()
745
+	{
746
+		try {
747
+			$this->_load_page_dependencies();
748
+		} catch (EE_Error $e) {
749
+			$e->get_error();
750
+		}
751
+	}
752
+
753
+
754
+	/**
755
+	 * load_page_dependencies
756
+	 * loads things specific to this page class when its loaded.  Really helps with efficiency.
757
+	 *
758
+	 * @return void
759
+	 * @throws DomainException
760
+	 * @throws EE_Error
761
+	 * @throws InvalidArgumentException
762
+	 * @throws InvalidDataTypeException
763
+	 * @throws InvalidInterfaceException
764
+	 * @throws ReflectionException
765
+	 */
766
+	protected function _load_page_dependencies()
767
+	{
768
+		// let's set the current_screen and screen options to override what WP set
769
+		$this->_current_screen = get_current_screen();
770
+		// load admin_notices - global, page class, and view specific
771
+		add_action('admin_notices', [$this, 'admin_notices_global'], 5);
772
+		add_action('admin_notices', [$this, 'admin_notices']);
773
+		if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
774
+			add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
775
+		}
776
+		// load network admin_notices - global, page class, and view specific
777
+		add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
778
+		if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
779
+			add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
780
+		}
781
+		// this will save any per_page screen options if they are present
782
+		$this->_set_per_page_screen_options();
783
+		// setup list table properties
784
+		$this->_set_list_table();
785
+		// child classes can "register" a metabox to be automatically handled via the _page_config array property.
786
+		// However in some cases the metaboxes will need to be added within a route handling callback.
787
+		add_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
788
+		// hack because promos admin was loading the edited promotion object in the metaboxes callback
789
+		// which should NOT be generated on non-UI requests like POST updates/inserts
790
+		if (
791
+			$this->class_name === 'Promotions_Admin_Page'
792
+			&& ($this->_req_action === 'edit' || $this->_req_action === 'create_new')
793
+		) {
794
+			$this->addRegisteredMetaBoxes();
795
+		}
796
+		$this->_add_screen_columns();
797
+		// add screen options - global, page child class, and view specific
798
+		$this->_add_global_screen_options();
799
+		$this->_add_screen_options();
800
+		$add_screen_options = "_add_screen_options_$this->_current_view";
801
+		if (method_exists($this, $add_screen_options)) {
802
+			$this->{$add_screen_options}();
803
+		}
804
+		// add help tab(s) - set via page_config and qtips.
805
+		$this->_add_help_tabs();
806
+		$this->_add_qtips();
807
+		// add feature_pointers - global, page child class, and view specific
808
+		$this->_add_feature_pointers();
809
+		$this->_add_global_feature_pointers();
810
+		$add_feature_pointer = "_add_feature_pointer_$this->_current_view";
811
+		if (method_exists($this, $add_feature_pointer)) {
812
+			$this->{$add_feature_pointer}();
813
+		}
814
+		// enqueue scripts/styles - global, page class, and view specific
815
+		add_action('admin_enqueue_scripts', [$this, 'load_global_scripts_styles'], 5);
816
+		add_action('admin_enqueue_scripts', [$this, 'load_scripts_styles']);
817
+		if (method_exists($this, "load_scripts_styles_$this->_current_view")) {
818
+			add_action('admin_enqueue_scripts', [$this, "load_scripts_styles_$this->_current_view"], 15);
819
+		}
820
+		add_action('admin_enqueue_scripts', [$this, 'admin_footer_scripts_eei18n_js_strings'], 100);
821
+		// admin_print_footer_scripts - global, page child class, and view specific.
822
+		// NOTE, despite the name, whenever possible, scripts should NOT be loaded using this.
823
+		// In most cases that's doing_it_wrong().  But adding hidden container elements etc.
824
+		// is a good use case. Notice the late priority we're giving these
825
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts_global'], 99);
826
+		add_action('admin_print_footer_scripts', [$this, 'admin_footer_scripts'], 100);
827
+		if (method_exists($this, "admin_footer_scripts_$this->_current_view")) {
828
+			add_action('admin_print_footer_scripts', [$this, "admin_footer_scripts_$this->_current_view"], 101);
829
+		}
830
+		// admin footer scripts
831
+		add_action('admin_footer', [$this, 'admin_footer_global'], 99);
832
+		add_action('admin_footer', [$this, 'admin_footer'], 100);
833
+		if (method_exists($this, "admin_footer_$this->_current_view")) {
834
+			add_action('admin_footer', [$this, "admin_footer_$this->_current_view"], 101);
835
+		}
836
+		do_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', $this->page_slug);
837
+		// targeted hook
838
+		do_action(
839
+			"FHEE__EE_Admin_Page___load_page_dependencies__after_load__{$this->page_slug}__$this->_req_action"
840
+		);
841
+	}
842
+
843
+
844
+	/**
845
+	 * _set_defaults
846
+	 * This sets some global defaults for class properties.
847
+	 */
848
+	private function _set_defaults()
849
+	{
850
+		// init template args
851
+		$this->set_template_args(
852
+			[
853
+				'admin_page_header'  => '',
854
+				'admin_page_content' => '',
855
+				'post_body_content'  => '',
856
+				'before_list_table'  => '',
857
+				'after_list_table'   => '',
858
+			]
859
+		);
860
+	}
861
+
862
+
863
+	/**
864
+	 * route_admin_request
865
+	 *
866
+	 * @return void
867
+	 * @throws InvalidArgumentException
868
+	 * @throws InvalidInterfaceException
869
+	 * @throws InvalidDataTypeException
870
+	 * @throws EE_Error
871
+	 * @throws ReflectionException
872
+	 * @throws Throwable
873
+	 * @see    _route_admin_request()
874
+	 */
875
+	public function route_admin_request()
876
+	{
877
+		try {
878
+			$this->_route_admin_request();
879
+		} catch (EE_Error $e) {
880
+			$e->get_error();
881
+		}
882
+	}
883
+
884
+
885
+	public function set_wp_page_slug($wp_page_slug)
886
+	{
887
+		$this->_wp_page_slug = $wp_page_slug;
888
+		// if in network admin then we need to append "-network" to the page slug. Why? Because that's how WP rolls...
889
+		if (is_network_admin()) {
890
+			$this->_wp_page_slug .= '-network';
891
+		}
892
+	}
893
+
894
+
895
+	/**
896
+	 * _verify_routes
897
+	 * All this method does is verify the incoming request and make sure that routes exist for it.  We do this early so
898
+	 * we know if we need to drop out.
899
+	 *
900
+	 * @return bool
901
+	 * @throws EE_Error
902
+	 */
903
+	protected function _verify_routes(): bool
904
+	{
905
+		if (! $this->_current_page && ! $this->request->isAjax()) {
906
+			return false;
907
+		}
908
+		// check that the page_routes array is not empty
909
+		if (empty($this->_page_routes)) {
910
+			// user error msg
911
+			$error_msg = sprintf(
912
+				esc_html__('No page routes have been set for the %s admin page.', 'event_espresso'),
913
+				$this->_admin_page_title
914
+			);
915
+			// developer error msg
916
+			$error_msg .= '||' . $error_msg
917
+						  . esc_html__(
918
+							  ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
919
+							  'event_espresso'
920
+						  );
921
+			throw new EE_Error($error_msg);
922
+		}
923
+		// route 'editpost' routes to CPT 'edit' routes
924
+		$alt_edit_route = $this instanceof EE_Admin_Page_CPT ? $this->cpt_editpost_route : 'edit';
925
+		if (
926
+			$this->_req_action === 'editpost'
927
+			&& ! isset($this->_page_routes['editpost'])
928
+			&& isset($this->_page_routes[$alt_edit_route])
929
+		) {
930
+			$this->_req_action = $alt_edit_route;
931
+		}
932
+		// and that the requested page route exists
933
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
934
+			$this->_route        = $this->_page_routes[ $this->_req_action ];
935
+			$this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
936
+		} else {
937
+			// user error msg
938
+			$error_msg = sprintf(
939
+				esc_html__(
940
+					'The requested page route does not exist for the %s admin page.',
941
+					'event_espresso'
942
+				),
943
+				$this->_admin_page_title
944
+			);
945
+			// developer error msg
946
+			$error_msg .= '||' . $error_msg
947
+						  . sprintf(
948
+							  esc_html__(
949
+								  ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
950
+								  'event_espresso'
951
+							  ),
952
+							  $this->_req_action
953
+						  );
954
+			throw new EE_Error($error_msg);
955
+		}
956
+		// and that a default route exists
957
+		if (! array_key_exists('default', $this->_page_routes)) {
958
+			// user error msg
959
+			$error_msg = sprintf(
960
+				esc_html__(
961
+					'A default page route has not been set for the % admin page.',
962
+					'event_espresso'
963
+				),
964
+				$this->_admin_page_title
965
+			);
966
+			// developer error msg
967
+			$error_msg .= '||' . $error_msg
968
+						  . esc_html__(
969
+							  ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
970
+							  'event_espresso'
971
+						  );
972
+			throw new EE_Error($error_msg);
973
+		}
974
+
975
+		// first lets' catch if the UI request has EVER been set.
976
+		if ($this->_is_UI_request === null) {
977
+			// lets set if this is a UI request or not.
978
+			$this->_is_UI_request = ! $this->request->getRequestParam('noheader', false, DataType::BOOL);
979
+			// wait a minute... we might have a noheader in the route array
980
+			$this->_is_UI_request = ! (isset($this->_route['noheader']) && $this->_route['noheader'])
981
+				? $this->_is_UI_request
982
+				: false;
983
+		}
984
+		$this->_set_current_labels();
985
+		return true;
986
+	}
987
+
988
+
989
+	/**
990
+	 * this method simply verifies a given route and makes sure its an actual route available for the loaded page
991
+	 *
992
+	 * @param string $route the route name we're verifying
993
+	 * @return bool we'll throw an exception if this isn't a valid route.
994
+	 * @throws EE_Error
995
+	 */
996
+	protected function _verify_route(string $route): bool
997
+	{
998
+		if (array_key_exists($this->_req_action, $this->_page_routes)) {
999
+			return true;
1000
+		}
1001
+		// user error msg
1002
+		$error_msg = sprintf(
1003
+			esc_html__('The given page route does not exist for the %s admin page.', 'event_espresso'),
1004
+			$this->_admin_page_title
1005
+		);
1006
+		// developer error msg
1007
+		$error_msg .= '||' . $error_msg
1008
+					  . sprintf(
1009
+						  esc_html__(
1010
+							  ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
1011
+							  'event_espresso'
1012
+						  ),
1013
+						  $route
1014
+					  );
1015
+		throw new EE_Error($error_msg);
1016
+	}
1017
+
1018
+
1019
+	/**
1020
+	 * perform nonce verification
1021
+	 * This method has be encapsulated here so that any ajax requests that bypass normal routes can verify their nonces
1022
+	 * using this method (and save retyping!)
1023
+	 *
1024
+	 * @param string $nonce     The nonce sent
1025
+	 * @param string $nonce_ref The nonce reference string (name0)
1026
+	 * @return void
1027
+	 * @throws EE_Error
1028
+	 * @throws InvalidArgumentException
1029
+	 * @throws InvalidDataTypeException
1030
+	 * @throws InvalidInterfaceException
1031
+	 */
1032
+	protected function _verify_nonce(string $nonce, string $nonce_ref)
1033
+	{
1034
+		// verify nonce against expected value
1035
+		if (! wp_verify_nonce($nonce, $nonce_ref)) {
1036
+			// these are not the droids you are looking for !!!
1037
+			$msg = sprintf(
1038
+				esc_html__('%sNonce Fail.%s', 'event_espresso'),
1039
+				'<a href="https://www.youtube.com/watch?v=56_S0WeTkzs">',
1040
+				'</a>'
1041
+			);
1042
+			if (WP_DEBUG) {
1043
+				$msg .= "\n  ";
1044
+				$msg .= sprintf(
1045
+					esc_html__(
1046
+						'In order to dynamically generate nonces for your actions, use the %s::add_query_args_and_nonce() method. May the Nonce be with you!',
1047
+						'event_espresso'
1048
+					),
1049
+					__CLASS__
1050
+				);
1051
+			}
1052
+			if (! $this->request->isAjax()) {
1053
+				wp_die($msg);
1054
+			}
1055
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1056
+			$this->_return_json();
1057
+		}
1058
+	}
1059
+
1060
+
1061
+	/**
1062
+	 * _route_admin_request()
1063
+	 * Meat and potatoes of the class.  Basically, this dude checks out what's being requested and sees if there are
1064
+	 * some doodads to work the magic and handle the flingjangy. Translation:  Checks if the requested action is listed
1065
+	 * in the page routes and then will try to load the corresponding method.
1066
+	 *
1067
+	 * @return void
1068
+	 * @throws EE_Error
1069
+	 * @throws InvalidArgumentException
1070
+	 * @throws InvalidDataTypeException
1071
+	 * @throws InvalidInterfaceException
1072
+	 * @throws ReflectionException
1073
+	 * @throws Throwable
1074
+	 */
1075
+	protected function _route_admin_request()
1076
+	{
1077
+		if (! $this->_is_UI_request) {
1078
+			$this->_verify_routes();
1079
+		}
1080
+		$nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
1081
+		if ($this->_req_action !== 'default' && $nonce_check) {
1082
+			// set nonce from post data
1083
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
1084
+			$this->_verify_nonce($nonce, $this->_req_nonce);
1085
+		}
1086
+		// set the nav_tabs array but ONLY if this is  UI_request
1087
+		if ($this->_is_UI_request) {
1088
+			$this->_set_nav_tabs();
1089
+		}
1090
+		// grab callback function
1091
+		$func = $this->_route['func'] ?? $this->_route;
1092
+		// check if callback has args
1093
+		$args = $this->_route['args'] ?? [];
1094
+
1095
+		// action right before calling route
1096
+		// (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1097
+		if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1098
+			do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1099
+		}
1100
+		// strip _wp_http_referer from the server REQUEST_URI
1101
+		// else it grows in length on every submission due to recursion,
1102
+		// ultimately causing a "Request-URI Too Large" error
1103
+		$this->request->unSetRequestParam('_wp_http_referer');
1104
+		$this->request->unSetServerParam('_wp_http_referer');
1105
+		$cleaner_request_uri = remove_query_arg(
1106
+			'_wp_http_referer',
1107
+			wp_unslash($this->request->getServerParam('REQUEST_URI'))
1108
+		);
1109
+		$this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1110
+		$this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1111
+		$route_callback = [];
1112
+		if (! empty($func)) {
1113
+			if (is_array($func) && is_callable($func)) {
1114
+				$route_callback = $func;
1115
+			} elseif (is_string($func)) {
1116
+				if (strpos($func, '::') !== false) {
1117
+					$route_callback = explode('::', $func);
1118
+				} elseif (method_exists($this, $func)) {
1119
+					$route_callback = [$this, $func];
1120
+				} else {
1121
+					$route_callback = $func;
1122
+				}
1123
+			}
1124
+			[$class, $method] = $route_callback;
1125
+			// is it neither a class method NOR a standalone function?
1126
+			if (! is_callable($route_callback)) {
1127
+				// user error msg
1128
+				$error_msg = esc_html__(
1129
+					'An error occurred. The  requested page route could not be found.',
1130
+					'event_espresso'
1131
+				);
1132
+				// developer error msg
1133
+				$error_msg .= '||';
1134
+				$error_msg .= sprintf(
1135
+					esc_html__(
1136
+						'Page route "%s" could not be called. Check that the spelling for method names and actions in the "_page_routes" array are all correct.',
1137
+						'event_espresso'
1138
+					),
1139
+					$method
1140
+				);
1141
+				throw new DomainException($error_msg);
1142
+			}
1143
+			if ($class !== $this && ! in_array($this, $args)) {
1144
+				// send along this admin page object for access by addons.
1145
+				$args['admin_page'] = $this;
1146
+			}
1147
+
1148
+			call_user_func_array($route_callback, $args);
1149
+		}
1150
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1151
+		// then we need to reset the routing properties to the new route.
1152
+		// 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.
1153
+		if (
1154
+			$this->_is_UI_request === false
1155
+			&& is_array($this->_route)
1156
+			&& ! empty($this->_route['headers_sent_route'])
1157
+		) {
1158
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1159
+		}
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * This method just allows the resetting of page properties in the case where a no headers
1165
+	 * route redirects to a headers route in its route config.
1166
+	 *
1167
+	 * @param string $new_route New (non header) route to redirect to.
1168
+	 * @return void
1169
+	 * @throws ReflectionException
1170
+	 * @throws InvalidArgumentException
1171
+	 * @throws InvalidInterfaceException
1172
+	 * @throws InvalidDataTypeException
1173
+	 * @throws EE_Error
1174
+	 * @throws Throwable
1175
+	 * @since   4.3.0
1176
+	 */
1177
+	protected function _reset_routing_properties(string $new_route)
1178
+	{
1179
+		$this->_is_UI_request = true;
1180
+		// now we set the current route to whatever the headers_sent_route is set at
1181
+		$this->request->setRequestParam('action', $new_route);
1182
+		// rerun page setup
1183
+		$this->_page_setup();
1184
+	}
1185
+
1186
+
1187
+	/**
1188
+	 * _add_query_arg
1189
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1190
+	 *(internally just uses EEH_URL's function with the same name)
1191
+	 *
1192
+	 * @param array  $args
1193
+	 * @param string $url
1194
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1195
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1196
+	 *                                        Example usage: If the current page is:
1197
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1198
+	 *                                        &action=default&event_id=20&month_range=March%202015
1199
+	 *                                        &_wpnonce=5467821
1200
+	 *                                        and you call:
1201
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1202
+	 *                                        array(
1203
+	 *                                        'action' => 'resend_something',
1204
+	 *                                        'page=>espresso_registrations'
1205
+	 *                                        ),
1206
+	 *                                        $some_url,
1207
+	 *                                        true
1208
+	 *                                        );
1209
+	 *                                        It will produce a url in this structure:
1210
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1211
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1212
+	 *                                        month_range]=March%202015
1213
+	 * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1214
+	 * @param int    $context
1215
+	 * @return string
1216
+	 */
1217
+	public static function add_query_args_and_nonce(
1218
+		array $args = [],
1219
+		string $url = '',
1220
+		bool $sticky = false,
1221
+		bool $exclude_nonce = false,
1222
+		int $context = EEH_URL::CONTEXT_NONE
1223
+	): string {
1224
+		// if there is a _wp_http_referer include the values from the request but only if sticky = true
1225
+		if ($sticky) {
1226
+			/** @var RequestInterface $request */
1227
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1228
+			$request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1229
+			$request->unSetServerParam('_wp_http_referer', true);
1230
+			foreach ($request->requestParams() as $key => $value) {
1231
+				// do not add nonces
1232
+				if (strpos($key, 'nonce') !== false) {
1233
+					continue;
1234
+				}
1235
+				$args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1236
+			}
1237
+		}
1238
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * This returns a generated link that will load the related help tab.
1244
+	 *
1245
+	 * @param string $help_tab_id the id for the connected help tab
1246
+	 * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1247
+	 * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1248
+	 * @return string              generated link
1249
+	 * @uses EEH_Template::get_help_tab_link()
1250
+	 */
1251
+	protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1252
+	{
1253
+		return EEH_Template::get_help_tab_link(
1254
+			$help_tab_id,
1255
+			$this->page_slug,
1256
+			$this->_req_action,
1257
+			$icon_style,
1258
+			$help_text
1259
+		);
1260
+	}
1261
+
1262
+
1263
+	/**
1264
+	 * _add_help_tabs
1265
+	 * Note child classes define their help tabs within the page_config array.
1266
+	 *
1267
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1268
+	 * @return void
1269
+	 * @throws DomainException
1270
+	 * @throws EE_Error
1271
+	 * @throws ReflectionException
1272
+	 */
1273
+	protected function _add_help_tabs()
1274
+	{
1275
+		if (isset($this->_page_config[ $this->_req_action ])) {
1276
+			$config = $this->_page_config[ $this->_req_action ];
1277
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1278
+			if (is_array($config) && isset($config['help_sidebar'])) {
1279
+				// check that the callback given is valid
1280
+				if (! method_exists($this, $config['help_sidebar'])) {
1281
+					throw new EE_Error(
1282
+						sprintf(
1283
+							esc_html__(
1284
+								'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',
1285
+								'event_espresso'
1286
+							),
1287
+							$config['help_sidebar'],
1288
+							$this->class_name
1289
+						)
1290
+					);
1291
+				}
1292
+				$content = apply_filters(
1293
+					'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1294
+					$this->{$config['help_sidebar']}()
1295
+				);
1296
+				$this->_current_screen->set_help_sidebar($content);
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 = $cfg['content'];
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
+					&& (
1363
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1364
+					)
1365
+				) {
1366
+					EE_Error::add_error(
1367
+						sprintf(
1368
+							esc_html__(
1369
+								'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.',
1370
+								'event_espresso'
1371
+							),
1372
+							$cfg['title']
1373
+						),
1374
+						__FILE__,
1375
+						__FUNCTION__,
1376
+						__LINE__
1377
+					);
1378
+					return;
1379
+				}
1380
+				// setup config array for help tab method
1381
+				$id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1382
+				$_ht = [
1383
+					'id'       => $id,
1384
+					'title'    => $cfg['title'],
1385
+					'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1386
+					'content'  => $content,
1387
+				];
1388
+				$this->_current_screen->add_help_tab($_ht);
1389
+			}
1390
+		}
1391
+	}
1392
+
1393
+
1394
+	/**
1395
+	 * This simply sets up any qtips that have been defined in the page config
1396
+	 *
1397
+	 * @return void
1398
+	 * @throws ReflectionException
1399
+	 * @throws EE_Error
1400
+	 */
1401
+	protected function _add_qtips()
1402
+	{
1403
+		if (isset($this->_route_config['qtips'])) {
1404
+			$qtips = (array) $this->_route_config['qtips'];
1405
+			// load qtip loader
1406
+			$path = [
1407
+				$this->_get_dir() . '/qtips/',
1408
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1409
+			];
1410
+			EEH_Qtip_Loader::instance()->register($qtips, $path);
1411
+		}
1412
+	}
1413
+
1414
+
1415
+	/**
1416
+	 * _set_nav_tabs
1417
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1418
+	 * wish to add additional tabs or modify accordingly.
1419
+	 *
1420
+	 * @return void
1421
+	 * @throws InvalidArgumentException
1422
+	 * @throws InvalidInterfaceException
1423
+	 * @throws InvalidDataTypeException
1424
+	 */
1425
+	protected function _set_nav_tabs()
1426
+	{
1427
+		$i        = 0;
1428
+		$only_tab = count($this->_page_config) < 2;
1429
+		foreach ($this->_page_config as $slug => $config) {
1430
+			if (! is_array($config) || empty($config['nav'])) {
1431
+				continue;
1432
+			}
1433
+			// no nav tab for this config
1434
+			// check for persistent flag
1435
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1436
+				// nav tab is only to appear when route requested.
1437
+				continue;
1438
+			}
1439
+			if (! $this->check_user_access($slug, true)) {
1440
+				// no nav tab because current user does not have access.
1441
+				continue;
1442
+			}
1443
+			$css_class = $config['css_class'] ?? '';
1444
+			$css_class .= $only_tab ? ' ee-only-tab' : '';
1445
+			$css_class .= " ee-nav-tab__$slug";
1446
+
1447
+			$this->_nav_tabs[ $slug ] = [
1448
+				'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1449
+						['action' => $slug],
1450
+						$this->_admin_base_url
1451
+					),
1452
+				'link_text' => $this->navTabLabel($config['nav'], $slug),
1453
+				'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1454
+				'order'     => $config['nav']['order'] ?? $i,
1455
+			];
1456
+			$i++;
1457
+		}
1458
+		// if $this->_nav_tabs is empty then lets set the default
1459
+		if (empty($this->_nav_tabs)) {
1460
+			$this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1461
+				'url'       => $this->_admin_base_url,
1462
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1463
+				'css_class' => 'nav-tab-active',
1464
+				'order'     => 10,
1465
+			];
1466
+		}
1467
+		// now let's sort the tabs according to order
1468
+		usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1469
+	}
1470
+
1471
+
1472
+	private function navTabLabel(array $nav_tab, string $slug): string
1473
+	{
1474
+		$label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1475
+		$icon  = $nav_tab['icon'] ?? null;
1476
+		$icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1477
+		return '
1478 1478
             <span class="ee-admin-screen-tab__label">
1479 1479
                 ' . $icon . '
1480 1480
                 <span class="ee-nav-label__text">' . $label . '</span>
1481 1481
             </span>';
1482
-    }
1483
-
1484
-
1485
-    /**
1486
-     * _set_current_labels
1487
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1488
-     * property array
1489
-     *
1490
-     * @return void
1491
-     */
1492
-    private function _set_current_labels()
1493
-    {
1494
-        if (isset($this->_route_config['labels'])) {
1495
-            foreach ($this->_route_config['labels'] as $label => $text) {
1496
-                if (is_array($text)) {
1497
-                    foreach ($text as $sublabel => $subtext) {
1498
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1499
-                    }
1500
-                } else {
1501
-                    $this->_labels[ $label ] = $text;
1502
-                }
1503
-            }
1504
-        }
1505
-    }
1506
-
1507
-
1508
-    /**
1509
-     *        verifies user access for this admin page
1510
-     *
1511
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1512
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1513
-     *                               return false if verify fail.
1514
-     * @return bool
1515
-     * @throws InvalidArgumentException
1516
-     * @throws InvalidDataTypeException
1517
-     * @throws InvalidInterfaceException
1518
-     */
1519
-    public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1520
-    {
1521
-        // if no route_to_check is passed in then use the current route set via _req_action
1522
-        $action = $route_to_check ?: $this->_req_action;
1523
-        $capability = ! empty($this->_page_routes[ $action ]['capability'])
1524
-            ? $this->_page_routes[ $action ]['capability']
1525
-            : null;
1526
-
1527
-        if (empty($capability)) {
1528
-            $capability = empty($route_to_check) && ! empty($this->_route['capability'])
1529
-                ? $this->_route['capability']
1530
-                : 'manage_options';
1531
-        }
1532
-
1533
-        $id = $this->_route['obj_id'] ?? 0;
1534
-
1535
-        if (
1536
-            ! $this->request->isAjax()
1537
-            && (
1538
-                ! function_exists('is_admin')
1539
-                || ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1540
-            )
1541
-        ) {
1542
-            if ($verify_only) {
1543
-                return false;
1544
-            }
1545
-            if (is_user_logged_in()) {
1546
-                wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1547
-            }
1548
-            return false;
1549
-        }
1550
-        return true;
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * @param string                 $box_id
1556
-     * @param string                 $title
1557
-     * @param callable|string|null   $callback
1558
-     * @param string|array|WP_Screen $screen
1559
-     * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1560
-     *                                              Comments screen contexts include 'normal' and 'side'.
1561
-     *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1562
-     * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1563
-     * @param array|null             $callback_args
1564
-     */
1565
-    protected function addMetaBox(
1566
-        string $box_id,
1567
-        string $title,
1568
-        $callback,
1569
-        $screen,
1570
-        string $context = 'normal',
1571
-        string $priority = 'default',
1572
-        ?array $callback_args = null
1573
-    ) {
1574
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1575
-            return;
1576
-        }
1577
-
1578
-        add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1579
-        add_filter(
1580
-            "postbox_classes_{$this->_wp_page_slug}_$box_id",
1581
-            function ($classes) {
1582
-                $classes[] = 'ee-admin-container';
1583
-                return $classes;
1584
-            }
1585
-        );
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * admin_init_global
1591
-     * This runs all the code that we want executed within the WP admin_init hook.
1592
-     * This method executes for ALL EE Admin pages.
1593
-     *
1594
-     * @return void
1595
-     */
1596
-    public function admin_init_global()
1597
-    {
1598
-    }
1599
-
1600
-
1601
-    /**
1602
-     * wp_loaded_global
1603
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1604
-     * EE_Admin page and will execute on every EE Admin Page load
1605
-     *
1606
-     * @return void
1607
-     */
1608
-    public function wp_loaded()
1609
-    {
1610
-    }
1611
-
1612
-
1613
-    /**
1614
-     * admin_notices
1615
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1616
-     * ALL EE_Admin pages.
1617
-     *
1618
-     * @return void
1619
-     */
1620
-    public function admin_notices_global()
1621
-    {
1622
-        $this->_display_no_javascript_warning();
1623
-        $this->_display_espresso_notices();
1624
-    }
1625
-
1626
-
1627
-    public function network_admin_notices_global()
1628
-    {
1629
-        $this->_display_no_javascript_warning();
1630
-        $this->_display_espresso_notices();
1631
-    }
1632
-
1633
-
1634
-    /**
1635
-     * admin_footer_scripts_global
1636
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1637
-     * will apply on ALL EE_Admin pages.
1638
-     *
1639
-     * @return void
1640
-     */
1641
-    public function admin_footer_scripts_global()
1642
-    {
1643
-        $this->_add_admin_page_ajax_loading_img();
1644
-        $this->_add_admin_page_overlay();
1645
-        // if metaboxes are present we need to add the nonce field
1646
-        if (
1647
-            isset($this->_route_config['metaboxes'])
1648
-            || isset($this->_route_config['list_table'])
1649
-            || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1650
-        ) {
1651
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1652
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1653
-        }
1654
-    }
1655
-
1656
-
1657
-    /**
1658
-     * admin_footer_global
1659
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1660
-     * This particular method will apply on ALL EE_Admin Pages.
1661
-     *
1662
-     * @return void
1663
-     */
1664
-    public function admin_footer_global()
1665
-    {
1666
-        // dialog container for dialog helper
1667
-        echo '
1482
+	}
1483
+
1484
+
1485
+	/**
1486
+	 * _set_current_labels
1487
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1488
+	 * property array
1489
+	 *
1490
+	 * @return void
1491
+	 */
1492
+	private function _set_current_labels()
1493
+	{
1494
+		if (isset($this->_route_config['labels'])) {
1495
+			foreach ($this->_route_config['labels'] as $label => $text) {
1496
+				if (is_array($text)) {
1497
+					foreach ($text as $sublabel => $subtext) {
1498
+						$this->_labels[ $label ][ $sublabel ] = $subtext;
1499
+					}
1500
+				} else {
1501
+					$this->_labels[ $label ] = $text;
1502
+				}
1503
+			}
1504
+		}
1505
+	}
1506
+
1507
+
1508
+	/**
1509
+	 *        verifies user access for this admin page
1510
+	 *
1511
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1512
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1513
+	 *                               return false if verify fail.
1514
+	 * @return bool
1515
+	 * @throws InvalidArgumentException
1516
+	 * @throws InvalidDataTypeException
1517
+	 * @throws InvalidInterfaceException
1518
+	 */
1519
+	public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1520
+	{
1521
+		// if no route_to_check is passed in then use the current route set via _req_action
1522
+		$action = $route_to_check ?: $this->_req_action;
1523
+		$capability = ! empty($this->_page_routes[ $action ]['capability'])
1524
+			? $this->_page_routes[ $action ]['capability']
1525
+			: null;
1526
+
1527
+		if (empty($capability)) {
1528
+			$capability = empty($route_to_check) && ! empty($this->_route['capability'])
1529
+				? $this->_route['capability']
1530
+				: 'manage_options';
1531
+		}
1532
+
1533
+		$id = $this->_route['obj_id'] ?? 0;
1534
+
1535
+		if (
1536
+			! $this->request->isAjax()
1537
+			&& (
1538
+				! function_exists('is_admin')
1539
+				|| ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1540
+			)
1541
+		) {
1542
+			if ($verify_only) {
1543
+				return false;
1544
+			}
1545
+			if (is_user_logged_in()) {
1546
+				wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1547
+			}
1548
+			return false;
1549
+		}
1550
+		return true;
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * @param string                 $box_id
1556
+	 * @param string                 $title
1557
+	 * @param callable|string|null   $callback
1558
+	 * @param string|array|WP_Screen $screen
1559
+	 * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1560
+	 *                                              Comments screen contexts include 'normal' and 'side'.
1561
+	 *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1562
+	 * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1563
+	 * @param array|null             $callback_args
1564
+	 */
1565
+	protected function addMetaBox(
1566
+		string $box_id,
1567
+		string $title,
1568
+		$callback,
1569
+		$screen,
1570
+		string $context = 'normal',
1571
+		string $priority = 'default',
1572
+		?array $callback_args = null
1573
+	) {
1574
+		if (! (is_callable($callback) || ! function_exists($callback))) {
1575
+			return;
1576
+		}
1577
+
1578
+		add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1579
+		add_filter(
1580
+			"postbox_classes_{$this->_wp_page_slug}_$box_id",
1581
+			function ($classes) {
1582
+				$classes[] = 'ee-admin-container';
1583
+				return $classes;
1584
+			}
1585
+		);
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * admin_init_global
1591
+	 * This runs all the code that we want executed within the WP admin_init hook.
1592
+	 * This method executes for ALL EE Admin pages.
1593
+	 *
1594
+	 * @return void
1595
+	 */
1596
+	public function admin_init_global()
1597
+	{
1598
+	}
1599
+
1600
+
1601
+	/**
1602
+	 * wp_loaded_global
1603
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1604
+	 * EE_Admin page and will execute on every EE Admin Page load
1605
+	 *
1606
+	 * @return void
1607
+	 */
1608
+	public function wp_loaded()
1609
+	{
1610
+	}
1611
+
1612
+
1613
+	/**
1614
+	 * admin_notices
1615
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1616
+	 * ALL EE_Admin pages.
1617
+	 *
1618
+	 * @return void
1619
+	 */
1620
+	public function admin_notices_global()
1621
+	{
1622
+		$this->_display_no_javascript_warning();
1623
+		$this->_display_espresso_notices();
1624
+	}
1625
+
1626
+
1627
+	public function network_admin_notices_global()
1628
+	{
1629
+		$this->_display_no_javascript_warning();
1630
+		$this->_display_espresso_notices();
1631
+	}
1632
+
1633
+
1634
+	/**
1635
+	 * admin_footer_scripts_global
1636
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1637
+	 * will apply on ALL EE_Admin pages.
1638
+	 *
1639
+	 * @return void
1640
+	 */
1641
+	public function admin_footer_scripts_global()
1642
+	{
1643
+		$this->_add_admin_page_ajax_loading_img();
1644
+		$this->_add_admin_page_overlay();
1645
+		// if metaboxes are present we need to add the nonce field
1646
+		if (
1647
+			isset($this->_route_config['metaboxes'])
1648
+			|| isset($this->_route_config['list_table'])
1649
+			|| (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1650
+		) {
1651
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1652
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1653
+		}
1654
+	}
1655
+
1656
+
1657
+	/**
1658
+	 * admin_footer_global
1659
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1660
+	 * This particular method will apply on ALL EE_Admin Pages.
1661
+	 *
1662
+	 * @return void
1663
+	 */
1664
+	public function admin_footer_global()
1665
+	{
1666
+		// dialog container for dialog helper
1667
+		echo '
1668 1668
         <div class="ee-admin-dialog-container auto-hide hidden">
1669 1669
             <div class="ee-notices"></div>
1670 1670
             <div class="ee-admin-dialog-container-inner-content"></div>
1671 1671
         </div>
1672 1672
         <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>
1673 1673
         <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page) . '"/>';
1674
-    }
1675
-
1676
-
1677
-    /**
1678
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1679
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1680
-     * help popups then in your templates or your content you set "triggers" for the content using the
1681
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1682
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1683
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1684
-     * for the
1685
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1686
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1687
-     *    'help_trigger_id' => array(
1688
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1689
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1690
-     *    )
1691
-     * );
1692
-     * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1693
-     *
1694
-     * @param array $help_array
1695
-     * @param bool  $display
1696
-     * @return string content
1697
-     * @throws DomainException
1698
-     * @throws EE_Error
1699
-     */
1700
-    protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1701
-    {
1702
-        $content    = '';
1703
-        $help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1704
-        // loop through the array and setup content
1705
-        foreach ($help_array as $trigger => $help) {
1706
-            // make sure the array is setup properly
1707
-            if (! isset($help['title'], $help['content'])) {
1708
-                throw new EE_Error(
1709
-                    esc_html__(
1710
-                        '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',
1711
-                        'event_espresso'
1712
-                    )
1713
-                );
1714
-            }
1715
-            // we're good so let's setup the template vars and then assign parsed template content to our content.
1716
-            $template_args = [
1717
-                'help_popup_id'      => $trigger,
1718
-                'help_popup_title'   => $help['title'],
1719
-                'help_popup_content' => $help['content'],
1720
-            ];
1721
-            $content       .= EEH_Template::display_template(
1722
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1723
-                $template_args,
1724
-                true
1725
-            );
1726
-        }
1727
-        if ($display) {
1728
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1729
-            return '';
1730
-        }
1731
-        return $content;
1732
-    }
1733
-
1734
-
1735
-    /**
1736
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1737
-     *
1738
-     * @return array properly formatted array for help popup content
1739
-     * @throws EE_Error
1740
-     */
1741
-    private function _get_help_content(): array
1742
-    {
1743
-        // what is the method we're looking for?
1744
-        $method_name = '_help_popup_content_' . $this->_req_action;
1745
-        // if method doesn't exist let's get out.
1746
-        if (! method_exists($this, $method_name)) {
1747
-            return [];
1748
-        }
1749
-        // k we're good to go let's retrieve the help array
1750
-        $help_array = $this->{$method_name}();
1751
-        // make sure we've got an array!
1752
-        if (! is_array($help_array)) {
1753
-            throw new EE_Error(
1754
-                esc_html__(
1755
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1756
-                    'event_espresso'
1757
-                )
1758
-            );
1759
-        }
1760
-        return $help_array;
1761
-    }
1762
-
1763
-
1764
-    /**
1765
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1766
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1767
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1768
-     *
1769
-     * @param string $trigger_id reference for retrieving the trigger content for the popup
1770
-     * @param bool   $display    if false then we return the trigger string
1771
-     * @param array  $dimensions an array of dimensions for the box (array(h,w))
1772
-     * @return string
1773
-     * @throws DomainException
1774
-     * @throws EE_Error
1775
-     */
1776
-    protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1777
-    {
1778
-        if ($this->request->isAjax()) {
1779
-            return '';
1780
-        }
1781
-        // 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
1782
-        $help_array   = $this->_get_help_content();
1783
-        $help_content = '';
1784
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1785
-            $help_array[ $trigger_id ] = [
1786
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1787
-                'content' => esc_html__(
1788
-                    '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.)',
1789
-                    'event_espresso'
1790
-                ),
1791
-            ];
1792
-            $help_content              = $this->_set_help_popup_content($help_array);
1793
-        }
1794
-        $height   = esc_attr($dimensions[0]) ?? 400;
1795
-        $width    = esc_attr($dimensions[1]) ?? 640;
1796
-        $inlineId = esc_attr($trigger_id);
1797
-        // let's setup the trigger
1798
-        $content = "
1674
+	}
1675
+
1676
+
1677
+	/**
1678
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1679
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1680
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1681
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1682
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1683
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1684
+	 * for the
1685
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1686
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1687
+	 *    'help_trigger_id' => array(
1688
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1689
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1690
+	 *    )
1691
+	 * );
1692
+	 * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1693
+	 *
1694
+	 * @param array $help_array
1695
+	 * @param bool  $display
1696
+	 * @return string content
1697
+	 * @throws DomainException
1698
+	 * @throws EE_Error
1699
+	 */
1700
+	protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1701
+	{
1702
+		$content    = '';
1703
+		$help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1704
+		// loop through the array and setup content
1705
+		foreach ($help_array as $trigger => $help) {
1706
+			// make sure the array is setup properly
1707
+			if (! isset($help['title'], $help['content'])) {
1708
+				throw new EE_Error(
1709
+					esc_html__(
1710
+						'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',
1711
+						'event_espresso'
1712
+					)
1713
+				);
1714
+			}
1715
+			// we're good so let's setup the template vars and then assign parsed template content to our content.
1716
+			$template_args = [
1717
+				'help_popup_id'      => $trigger,
1718
+				'help_popup_title'   => $help['title'],
1719
+				'help_popup_content' => $help['content'],
1720
+			];
1721
+			$content       .= EEH_Template::display_template(
1722
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1723
+				$template_args,
1724
+				true
1725
+			);
1726
+		}
1727
+		if ($display) {
1728
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1729
+			return '';
1730
+		}
1731
+		return $content;
1732
+	}
1733
+
1734
+
1735
+	/**
1736
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1737
+	 *
1738
+	 * @return array properly formatted array for help popup content
1739
+	 * @throws EE_Error
1740
+	 */
1741
+	private function _get_help_content(): array
1742
+	{
1743
+		// what is the method we're looking for?
1744
+		$method_name = '_help_popup_content_' . $this->_req_action;
1745
+		// if method doesn't exist let's get out.
1746
+		if (! method_exists($this, $method_name)) {
1747
+			return [];
1748
+		}
1749
+		// k we're good to go let's retrieve the help array
1750
+		$help_array = $this->{$method_name}();
1751
+		// make sure we've got an array!
1752
+		if (! is_array($help_array)) {
1753
+			throw new EE_Error(
1754
+				esc_html__(
1755
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1756
+					'event_espresso'
1757
+				)
1758
+			);
1759
+		}
1760
+		return $help_array;
1761
+	}
1762
+
1763
+
1764
+	/**
1765
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1766
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1767
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1768
+	 *
1769
+	 * @param string $trigger_id reference for retrieving the trigger content for the popup
1770
+	 * @param bool   $display    if false then we return the trigger string
1771
+	 * @param array  $dimensions an array of dimensions for the box (array(h,w))
1772
+	 * @return string
1773
+	 * @throws DomainException
1774
+	 * @throws EE_Error
1775
+	 */
1776
+	protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1777
+	{
1778
+		if ($this->request->isAjax()) {
1779
+			return '';
1780
+		}
1781
+		// 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
1782
+		$help_array   = $this->_get_help_content();
1783
+		$help_content = '';
1784
+		if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1785
+			$help_array[ $trigger_id ] = [
1786
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1787
+				'content' => esc_html__(
1788
+					'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.)',
1789
+					'event_espresso'
1790
+				),
1791
+			];
1792
+			$help_content              = $this->_set_help_popup_content($help_array);
1793
+		}
1794
+		$height   = esc_attr($dimensions[0]) ?? 400;
1795
+		$width    = esc_attr($dimensions[1]) ?? 640;
1796
+		$inlineId = esc_attr($trigger_id);
1797
+		// let's setup the trigger
1798
+		$content = "
1799 1799
         <a class='ee-dialog' href='?height=$height&width=$width&inlineId=$inlineId' target='_blank'>
1800 1800
             <span class='question ee-help-popup-question'></span>
1801 1801
         </a>";
1802
-        $content .= $help_content;
1803
-        if ($display) {
1804
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1805
-            return '';
1806
-        }
1807
-        return $content;
1808
-    }
1809
-
1810
-
1811
-    /**
1812
-     * _add_global_screen_options
1813
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1814
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1815
-     *
1816
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1817
-     *         see also WP_Screen object documents...
1818
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1819
-     * @abstract
1820
-     * @return void
1821
-     */
1822
-    private function _add_global_screen_options()
1823
-    {
1824
-    }
1825
-
1826
-
1827
-    /**
1828
-     * _add_global_feature_pointers
1829
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1830
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1831
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1832
-     *
1833
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1834
-     *         extended) also see:
1835
-     * @link   http://eamann.com/tech/wordpress-portland/
1836
-     * @abstract
1837
-     * @return void
1838
-     */
1839
-    private function _add_global_feature_pointers()
1840
-    {
1841
-    }
1842
-
1843
-
1844
-    /**
1845
-     * load_global_scripts_styles
1846
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1847
-     *
1848
-     * @return void
1849
-     */
1850
-    public function load_global_scripts_styles()
1851
-    {
1852
-        // add debugging styles
1853
-        if (WP_DEBUG) {
1854
-            add_action('admin_head', [$this, 'add_xdebug_style']);
1855
-        }
1856
-        // taking care of metaboxes
1857
-        if (
1858
-            empty($this->_cpt_route)
1859
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1860
-        ) {
1861
-            wp_enqueue_script('dashboard');
1862
-        }
1863
-
1864
-        wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1865
-        wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1866
-        // LOCALIZED DATA
1867
-        // localize script for ajax lazy loading
1868
-        wp_localize_script(
1869
-            EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1870
-            'eeLazyLoadingContainers',
1871
-            apply_filters(
1872
-                'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1873
-                ['espresso_news_post_box_content']
1874
-            )
1875
-        );
1876
-        StatusChangeNotice::loadAssets();
1877
-
1878
-        add_filter(
1879
-            'admin_body_class',
1880
-            function ($classes) {
1881
-                if (strpos($classes, 'espresso-admin') === false) {
1882
-                    $classes .= ' espresso-admin';
1883
-                }
1884
-                return $classes;
1885
-            }
1886
-        );
1887
-    }
1888
-
1889
-
1890
-    /**
1891
-     *        admin_footer_scripts_eei18n_js_strings
1892
-     *
1893
-     * @return        void
1894
-     */
1895
-    public function admin_footer_scripts_eei18n_js_strings()
1896
-    {
1897
-        EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1898
-        EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1899
-            __(
1900
-                '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!!!',
1901
-                'event_espresso'
1902
-            )
1903
-        );
1904
-        EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1905
-        EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1906
-        EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1907
-        EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1908
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1909
-        EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1910
-        EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1911
-        EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1912
-        EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1913
-        EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1914
-        EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1915
-        EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1916
-        EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1917
-        EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1918
-        EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1919
-        EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1920
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1921
-        EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1922
-        EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1923
-        EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1924
-        EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1925
-        EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1926
-        EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1927
-        EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1928
-        EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1929
-        EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1930
-        EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1931
-        EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1932
-        EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1933
-        EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1934
-        EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1935
-        EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1936
-        EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
1937
-        EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
1938
-        EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
1939
-        EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
1940
-        EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
1941
-        EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
1942
-    }
1943
-
1944
-
1945
-    /**
1946
-     *        load enhanced xdebug styles for ppl with failing eyesight
1947
-     *
1948
-     * @return        void
1949
-     */
1950
-    public function add_xdebug_style()
1951
-    {
1952
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1953
-    }
1954
-
1955
-
1956
-    /************************/
1957
-    /** LIST TABLE METHODS **/
1958
-    /************************/
1959
-    /**
1960
-     * this sets up the list table if the current view requires it.
1961
-     *
1962
-     * @return void
1963
-     * @throws EE_Error
1964
-     * @throws InvalidArgumentException
1965
-     * @throws InvalidDataTypeException
1966
-     * @throws InvalidInterfaceException
1967
-     */
1968
-    protected function _set_list_table()
1969
-    {
1970
-        // first is this a list_table view?
1971
-        if (! isset($this->_route_config['list_table'])) {
1972
-            return;
1973
-        } //not a list_table view so get out.
1974
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
1975
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
1976
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
1977
-            // user error msg
1978
-            $error_msg = esc_html__(
1979
-                'An error occurred. The requested list table views could not be found.',
1980
-                'event_espresso'
1981
-            );
1982
-            // developer error msg
1983
-            $error_msg .= '||'
1984
-                          . sprintf(
1985
-                              esc_html__(
1986
-                                  '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.',
1987
-                                  'event_espresso'
1988
-                              ),
1989
-                              $this->_req_action,
1990
-                              $list_table_view
1991
-                          );
1992
-            throw new EE_Error($error_msg);
1993
-        }
1994
-        // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
1995
-        $this->_views = apply_filters(
1996
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
1997
-            $this->_views
1998
-        );
1999
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2000
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2001
-        $this->_set_list_table_view();
2002
-        $this->_set_list_table_object();
2003
-    }
2004
-
2005
-
2006
-    /**
2007
-     * set current view for List Table
2008
-     *
2009
-     * @return void
2010
-     */
2011
-    protected function _set_list_table_view()
2012
-    {
2013
-        $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2014
-        $status      = $this->request->getRequestParam('status', null, DataType::KEY);
2015
-        $this->_view = $status && array_key_exists($status, $this->_views)
2016
-            ? $status
2017
-            : $this->_view;
2018
-    }
2019
-
2020
-
2021
-    /**
2022
-     * _set_list_table_object
2023
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2024
-     *
2025
-     * @throws InvalidInterfaceException
2026
-     * @throws InvalidArgumentException
2027
-     * @throws InvalidDataTypeException
2028
-     * @throws EE_Error
2029
-     * @throws InvalidInterfaceException
2030
-     */
2031
-    protected function _set_list_table_object()
2032
-    {
2033
-        if (isset($this->_route_config['list_table'])) {
2034
-            if (! class_exists($this->_route_config['list_table'])) {
2035
-                throw new EE_Error(
2036
-                    sprintf(
2037
-                        esc_html__(
2038
-                            '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.',
2039
-                            'event_espresso'
2040
-                        ),
2041
-                        $this->_route_config['list_table'],
2042
-                        $this->class_name
2043
-                    )
2044
-                );
2045
-            }
2046
-            $this->_list_table_object = $this->loader->getShared(
2047
-                $this->_route_config['list_table'],
2048
-                [
2049
-                    $this,
2050
-                    LoaderFactory::getShared(AdminListTableFilters::class),
2051
-                ]
2052
-            );
2053
-        }
2054
-    }
2055
-
2056
-
2057
-    /**
2058
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2059
-     *
2060
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2061
-     *                                                    urls.  The array should be indexed by the view it is being
2062
-     *                                                    added to.
2063
-     * @return array
2064
-     */
2065
-    public function get_list_table_view_RLs(array $extra_query_args = []): array
2066
-    {
2067
-        $extra_query_args = apply_filters(
2068
-            'FHEE__EE_Admin_Page__get_list_table_view_RLs__extra_query_args',
2069
-            $extra_query_args,
2070
-            $this
2071
-        );
2072
-        // cycle thru views
2073
-        foreach ($this->_views as $key => $view) {
2074
-            $query_args = [];
2075
-            // check for current view
2076
-            $this->_views[ $key ]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2077
-            $query_args['action']          = $this->_req_action;
2078
-            $action_nonce                  = "{$this->_req_action}_nonce";
2079
-            $query_args[ $action_nonce ]   = wp_create_nonce($action_nonce);
2080
-            $query_args['status']          = $view['slug'];
2081
-            // merge any other arguments sent in.
2082
-            if (isset($extra_query_args[ $view['slug'] ])) {
2083
-                $query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2084
-            }
2085
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2086
-        }
2087
-        return $this->_views;
2088
-    }
2089
-
2090
-
2091
-    /**
2092
-     * generates a dropdown box for selecting the number of visible rows in an admin page list table
2093
-     *
2094
-     * @param int $max_entries total number of rows in the table
2095
-     * @return string
2096
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2097
-     *                         WP does it.
2098
-     */
2099
-    protected function _entries_per_page_dropdown(int $max_entries = 0): string
2100
-    {
2101
-        $values   = [10, 25, 50, 100];
2102
-        $per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2103
-        if ($max_entries) {
2104
-            $values[] = $max_entries;
2105
-            sort($values);
2106
-        }
2107
-        $entries_per_page_dropdown = '
1802
+		$content .= $help_content;
1803
+		if ($display) {
1804
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1805
+			return '';
1806
+		}
1807
+		return $content;
1808
+	}
1809
+
1810
+
1811
+	/**
1812
+	 * _add_global_screen_options
1813
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1814
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1815
+	 *
1816
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1817
+	 *         see also WP_Screen object documents...
1818
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1819
+	 * @abstract
1820
+	 * @return void
1821
+	 */
1822
+	private function _add_global_screen_options()
1823
+	{
1824
+	}
1825
+
1826
+
1827
+	/**
1828
+	 * _add_global_feature_pointers
1829
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1830
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1831
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1832
+	 *
1833
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1834
+	 *         extended) also see:
1835
+	 * @link   http://eamann.com/tech/wordpress-portland/
1836
+	 * @abstract
1837
+	 * @return void
1838
+	 */
1839
+	private function _add_global_feature_pointers()
1840
+	{
1841
+	}
1842
+
1843
+
1844
+	/**
1845
+	 * load_global_scripts_styles
1846
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1847
+	 *
1848
+	 * @return void
1849
+	 */
1850
+	public function load_global_scripts_styles()
1851
+	{
1852
+		// add debugging styles
1853
+		if (WP_DEBUG) {
1854
+			add_action('admin_head', [$this, 'add_xdebug_style']);
1855
+		}
1856
+		// taking care of metaboxes
1857
+		if (
1858
+			empty($this->_cpt_route)
1859
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1860
+		) {
1861
+			wp_enqueue_script('dashboard');
1862
+		}
1863
+
1864
+		wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1865
+		wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1866
+		// LOCALIZED DATA
1867
+		// localize script for ajax lazy loading
1868
+		wp_localize_script(
1869
+			EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1870
+			'eeLazyLoadingContainers',
1871
+			apply_filters(
1872
+				'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1873
+				['espresso_news_post_box_content']
1874
+			)
1875
+		);
1876
+		StatusChangeNotice::loadAssets();
1877
+
1878
+		add_filter(
1879
+			'admin_body_class',
1880
+			function ($classes) {
1881
+				if (strpos($classes, 'espresso-admin') === false) {
1882
+					$classes .= ' espresso-admin';
1883
+				}
1884
+				return $classes;
1885
+			}
1886
+		);
1887
+	}
1888
+
1889
+
1890
+	/**
1891
+	 *        admin_footer_scripts_eei18n_js_strings
1892
+	 *
1893
+	 * @return        void
1894
+	 */
1895
+	public function admin_footer_scripts_eei18n_js_strings()
1896
+	{
1897
+		EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1898
+		EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1899
+			__(
1900
+				'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!!!',
1901
+				'event_espresso'
1902
+			)
1903
+		);
1904
+		EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1905
+		EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1906
+		EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1907
+		EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1908
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1909
+		EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1910
+		EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1911
+		EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1912
+		EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1913
+		EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1914
+		EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1915
+		EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1916
+		EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1917
+		EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1918
+		EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1919
+		EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1920
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1921
+		EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1922
+		EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1923
+		EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1924
+		EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1925
+		EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1926
+		EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1927
+		EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1928
+		EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1929
+		EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1930
+		EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1931
+		EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1932
+		EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1933
+		EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1934
+		EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1935
+		EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1936
+		EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
1937
+		EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
1938
+		EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
1939
+		EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
1940
+		EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
1941
+		EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
1942
+	}
1943
+
1944
+
1945
+	/**
1946
+	 *        load enhanced xdebug styles for ppl with failing eyesight
1947
+	 *
1948
+	 * @return        void
1949
+	 */
1950
+	public function add_xdebug_style()
1951
+	{
1952
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1953
+	}
1954
+
1955
+
1956
+	/************************/
1957
+	/** LIST TABLE METHODS **/
1958
+	/************************/
1959
+	/**
1960
+	 * this sets up the list table if the current view requires it.
1961
+	 *
1962
+	 * @return void
1963
+	 * @throws EE_Error
1964
+	 * @throws InvalidArgumentException
1965
+	 * @throws InvalidDataTypeException
1966
+	 * @throws InvalidInterfaceException
1967
+	 */
1968
+	protected function _set_list_table()
1969
+	{
1970
+		// first is this a list_table view?
1971
+		if (! isset($this->_route_config['list_table'])) {
1972
+			return;
1973
+		} //not a list_table view so get out.
1974
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
1975
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
1976
+		if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
1977
+			// user error msg
1978
+			$error_msg = esc_html__(
1979
+				'An error occurred. The requested list table views could not be found.',
1980
+				'event_espresso'
1981
+			);
1982
+			// developer error msg
1983
+			$error_msg .= '||'
1984
+						  . sprintf(
1985
+							  esc_html__(
1986
+								  '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.',
1987
+								  'event_espresso'
1988
+							  ),
1989
+							  $this->_req_action,
1990
+							  $list_table_view
1991
+						  );
1992
+			throw new EE_Error($error_msg);
1993
+		}
1994
+		// let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
1995
+		$this->_views = apply_filters(
1996
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
1997
+			$this->_views
1998
+		);
1999
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2000
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2001
+		$this->_set_list_table_view();
2002
+		$this->_set_list_table_object();
2003
+	}
2004
+
2005
+
2006
+	/**
2007
+	 * set current view for List Table
2008
+	 *
2009
+	 * @return void
2010
+	 */
2011
+	protected function _set_list_table_view()
2012
+	{
2013
+		$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2014
+		$status      = $this->request->getRequestParam('status', null, DataType::KEY);
2015
+		$this->_view = $status && array_key_exists($status, $this->_views)
2016
+			? $status
2017
+			: $this->_view;
2018
+	}
2019
+
2020
+
2021
+	/**
2022
+	 * _set_list_table_object
2023
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2024
+	 *
2025
+	 * @throws InvalidInterfaceException
2026
+	 * @throws InvalidArgumentException
2027
+	 * @throws InvalidDataTypeException
2028
+	 * @throws EE_Error
2029
+	 * @throws InvalidInterfaceException
2030
+	 */
2031
+	protected function _set_list_table_object()
2032
+	{
2033
+		if (isset($this->_route_config['list_table'])) {
2034
+			if (! class_exists($this->_route_config['list_table'])) {
2035
+				throw new EE_Error(
2036
+					sprintf(
2037
+						esc_html__(
2038
+							'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.',
2039
+							'event_espresso'
2040
+						),
2041
+						$this->_route_config['list_table'],
2042
+						$this->class_name
2043
+					)
2044
+				);
2045
+			}
2046
+			$this->_list_table_object = $this->loader->getShared(
2047
+				$this->_route_config['list_table'],
2048
+				[
2049
+					$this,
2050
+					LoaderFactory::getShared(AdminListTableFilters::class),
2051
+				]
2052
+			);
2053
+		}
2054
+	}
2055
+
2056
+
2057
+	/**
2058
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2059
+	 *
2060
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2061
+	 *                                                    urls.  The array should be indexed by the view it is being
2062
+	 *                                                    added to.
2063
+	 * @return array
2064
+	 */
2065
+	public function get_list_table_view_RLs(array $extra_query_args = []): array
2066
+	{
2067
+		$extra_query_args = apply_filters(
2068
+			'FHEE__EE_Admin_Page__get_list_table_view_RLs__extra_query_args',
2069
+			$extra_query_args,
2070
+			$this
2071
+		);
2072
+		// cycle thru views
2073
+		foreach ($this->_views as $key => $view) {
2074
+			$query_args = [];
2075
+			// check for current view
2076
+			$this->_views[ $key ]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2077
+			$query_args['action']          = $this->_req_action;
2078
+			$action_nonce                  = "{$this->_req_action}_nonce";
2079
+			$query_args[ $action_nonce ]   = wp_create_nonce($action_nonce);
2080
+			$query_args['status']          = $view['slug'];
2081
+			// merge any other arguments sent in.
2082
+			if (isset($extra_query_args[ $view['slug'] ])) {
2083
+				$query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2084
+			}
2085
+			$this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2086
+		}
2087
+		return $this->_views;
2088
+	}
2089
+
2090
+
2091
+	/**
2092
+	 * generates a dropdown box for selecting the number of visible rows in an admin page list table
2093
+	 *
2094
+	 * @param int $max_entries total number of rows in the table
2095
+	 * @return string
2096
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2097
+	 *                         WP does it.
2098
+	 */
2099
+	protected function _entries_per_page_dropdown(int $max_entries = 0): string
2100
+	{
2101
+		$values   = [10, 25, 50, 100];
2102
+		$per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2103
+		if ($max_entries) {
2104
+			$values[] = $max_entries;
2105
+			sort($values);
2106
+		}
2107
+		$entries_per_page_dropdown = '
2108 2108
 			<div id="entries-per-page-dv" class="alignleft actions">
2109 2109
 				<label class="hide-if-no-js">
2110 2110
 					Show
2111 2111
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2112
-        foreach ($values as $value) {
2113
-            if ($value < $max_entries) {
2114
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2115
-                $entries_per_page_dropdown .= '
2112
+		foreach ($values as $value) {
2113
+			if ($value < $max_entries) {
2114
+				$selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2115
+				$entries_per_page_dropdown .= '
2116 2116
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2117
-            }
2118
-        }
2119
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2120
-        $entries_per_page_dropdown .= '
2117
+			}
2118
+		}
2119
+		$selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2120
+		$entries_per_page_dropdown .= '
2121 2121
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2122
-        $entries_per_page_dropdown .= '
2122
+		$entries_per_page_dropdown .= '
2123 2123
 					</select>
2124 2124
 					entries
2125 2125
 				</label>
2126 2126
 				<input id="entries-per-page-btn" class="button button--secondary" type="submit" value="Go" >
2127 2127
 			</div>
2128 2128
 		';
2129
-        return $entries_per_page_dropdown;
2130
-    }
2131
-
2132
-
2133
-    /**
2134
-     *        _set_search_attributes
2135
-     *
2136
-     * @return        void
2137
-     */
2138
-    public function _set_search_attributes()
2139
-    {
2140
-        $this->_template_args['search']['btn_label'] = sprintf(
2141
-            esc_html__('Search %s', 'event_espresso'),
2142
-            empty($this->_search_btn_label) ? $this->page_label
2143
-                : $this->_search_btn_label
2144
-        );
2145
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2146
-    }
2147
-
2148
-
2149
-
2150
-    /*** END LIST TABLE METHODS **/
2151
-
2152
-    /**
2153
-     * @return void
2154
-     * @throws EE_Error
2155
-     */
2156
-    public function addRegisteredMetaBoxes()
2157
-    {
2158
-        remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2159
-        $this->_add_registered_meta_boxes();
2160
-    }
2161
-
2162
-
2163
-    /**
2164
-     * _add_registered_metaboxes
2165
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2166
-     *
2167
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2168
-     * @return void
2169
-     * @throws EE_Error
2170
-     */
2171
-    private function _add_registered_meta_boxes()
2172
-    {
2173
-        // we only add meta boxes if the page_route calls for it
2174
-        if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2175
-            // this simply loops through the callbacks provided
2176
-            // and checks if there is a corresponding callback registered by the child
2177
-            // if there is then we go ahead and process the metabox loader.
2178
-            foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2179
-                // first check for Closures
2180
-                if ($metabox_callback instanceof Closure) {
2181
-                    $result = $metabox_callback();
2182
-                } elseif (is_callable($metabox_callback)) {
2183
-                    $result = call_user_func($metabox_callback);
2184
-                } elseif (method_exists($this, $metabox_callback)) {
2185
-                    $result = $this->{$metabox_callback}();
2186
-                } else {
2187
-                    $result = false;
2188
-                }
2189
-                if ($result === false) {
2190
-                    // user error msg
2191
-                    $error_msg = esc_html__(
2192
-                        'An error occurred. The  requested metabox could not be found.',
2193
-                        'event_espresso'
2194
-                    );
2195
-                    // developer error msg
2196
-                    $error_msg .= '||'
2197
-                                  . sprintf(
2198
-                                      esc_html__(
2199
-                                          '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.',
2200
-                                          'event_espresso'
2201
-                                      ),
2202
-                                      $metabox_callback
2203
-                                  );
2204
-                    throw new EE_Error($error_msg);
2205
-                }
2206
-                unset($this->_route_config['metaboxes'][ $key ]);
2207
-            }
2208
-        }
2209
-    }
2210
-
2211
-
2212
-    /**
2213
-     * _add_screen_columns
2214
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2215
-     * the dynamic column template and we'll setup the column options for the page.
2216
-     *
2217
-     * @return void
2218
-     */
2219
-    private function _add_screen_columns()
2220
-    {
2221
-        if (
2222
-            isset($this->_route_config['columns'])
2223
-            && is_array($this->_route_config['columns'])
2224
-            && count($this->_route_config['columns']) === 2
2225
-        ) {
2226
-            add_screen_option(
2227
-                'layout_columns',
2228
-                [
2229
-                    'max'     => (int) $this->_route_config['columns'][0],
2230
-                    'default' => (int) $this->_route_config['columns'][1],
2231
-                ]
2232
-            );
2233
-            $this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2234
-            $screen_id                                           = $this->_current_screen->id;
2235
-            $screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2236
-            $total_columns                                       = ! empty($screen_columns)
2237
-                ? $screen_columns
2238
-                : $this->_route_config['columns'][1];
2239
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2240
-            $this->_template_args['current_page']                = $this->_wp_page_slug;
2241
-            $this->_template_args['screen']                      = $this->_current_screen;
2242
-            $this->_column_template_path                         = EE_ADMIN_TEMPLATE
2243
-                                                                   . 'admin_details_metabox_column_wrapper.template.php';
2244
-            // finally if we don't have has_metaboxes set in the route config
2245
-            // let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2246
-            $this->_route_config['has_metaboxes'] = true;
2247
-        }
2248
-    }
2249
-
2250
-
2251
-
2252
-    /** GLOBALLY AVAILABLE METABOXES **/
2253
-
2254
-
2255
-    /**
2256
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2257
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2258
-     * these get loaded on.
2259
-     */
2260
-    private function _espresso_news_post_box()
2261
-    {
2262
-        $news_box_title = apply_filters(
2263
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2264
-            esc_html__('New @ Event Espresso', 'event_espresso')
2265
-        );
2266
-        $this->addMetaBox(
2267
-            'espresso_news_post_box',
2268
-            $news_box_title,
2269
-            [
2270
-                $this,
2271
-                'espresso_news_post_box',
2272
-            ],
2273
-            $this->_wp_page_slug,
2274
-            'side',
2275
-            'low'
2276
-        );
2277
-    }
2278
-
2279
-
2280
-    /**
2281
-     * Code for setting up espresso ratings request metabox.
2282
-     */
2283
-    protected function _espresso_ratings_request()
2284
-    {
2285
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2286
-            return;
2287
-        }
2288
-        $ratings_box_title = apply_filters(
2289
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2290
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2291
-        );
2292
-        $this->addMetaBox(
2293
-            'espresso_ratings_request',
2294
-            $ratings_box_title,
2295
-            [
2296
-                $this,
2297
-                'espresso_ratings_request',
2298
-            ],
2299
-            $this->_wp_page_slug,
2300
-            'side'
2301
-        );
2302
-    }
2303
-
2304
-
2305
-    /**
2306
-     * Code for setting up espresso ratings request metabox content.
2307
-     *
2308
-     * @throws DomainException
2309
-     */
2310
-    public function espresso_ratings_request()
2311
-    {
2312
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2313
-    }
2314
-
2315
-
2316
-    public static function cached_rss_display(string $rss_id, string $url): bool
2317
-    {
2318
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2319
-                     . esc_html__('Loading&#8230;', 'event_espresso')
2320
-                     . '</p><p class="hide-if-js">'
2321
-                     . esc_html__('This widget requires JavaScript.', 'event_espresso')
2322
-                     . '</p>';
2323
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2324
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2325
-        $post      = '</div>' . "\n";
2326
-        $cache_key = 'ee_rss_' . md5($rss_id);
2327
-        $output    = get_transient($cache_key);
2328
-        if ($output !== false) {
2329
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2330
-            return true;
2331
-        }
2332
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2333
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2334
-            return false;
2335
-        }
2336
-        ob_start();
2337
-        wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2338
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2339
-        return true;
2340
-    }
2341
-
2342
-
2343
-    public function espresso_news_post_box()
2344
-    {
2345
-        ?>
2129
+		return $entries_per_page_dropdown;
2130
+	}
2131
+
2132
+
2133
+	/**
2134
+	 *        _set_search_attributes
2135
+	 *
2136
+	 * @return        void
2137
+	 */
2138
+	public function _set_search_attributes()
2139
+	{
2140
+		$this->_template_args['search']['btn_label'] = sprintf(
2141
+			esc_html__('Search %s', 'event_espresso'),
2142
+			empty($this->_search_btn_label) ? $this->page_label
2143
+				: $this->_search_btn_label
2144
+		);
2145
+		$this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2146
+	}
2147
+
2148
+
2149
+
2150
+	/*** END LIST TABLE METHODS **/
2151
+
2152
+	/**
2153
+	 * @return void
2154
+	 * @throws EE_Error
2155
+	 */
2156
+	public function addRegisteredMetaBoxes()
2157
+	{
2158
+		remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2159
+		$this->_add_registered_meta_boxes();
2160
+	}
2161
+
2162
+
2163
+	/**
2164
+	 * _add_registered_metaboxes
2165
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2166
+	 *
2167
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2168
+	 * @return void
2169
+	 * @throws EE_Error
2170
+	 */
2171
+	private function _add_registered_meta_boxes()
2172
+	{
2173
+		// we only add meta boxes if the page_route calls for it
2174
+		if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2175
+			// this simply loops through the callbacks provided
2176
+			// and checks if there is a corresponding callback registered by the child
2177
+			// if there is then we go ahead and process the metabox loader.
2178
+			foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2179
+				// first check for Closures
2180
+				if ($metabox_callback instanceof Closure) {
2181
+					$result = $metabox_callback();
2182
+				} elseif (is_callable($metabox_callback)) {
2183
+					$result = call_user_func($metabox_callback);
2184
+				} elseif (method_exists($this, $metabox_callback)) {
2185
+					$result = $this->{$metabox_callback}();
2186
+				} else {
2187
+					$result = false;
2188
+				}
2189
+				if ($result === false) {
2190
+					// user error msg
2191
+					$error_msg = esc_html__(
2192
+						'An error occurred. The  requested metabox could not be found.',
2193
+						'event_espresso'
2194
+					);
2195
+					// developer error msg
2196
+					$error_msg .= '||'
2197
+								  . sprintf(
2198
+									  esc_html__(
2199
+										  '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.',
2200
+										  'event_espresso'
2201
+									  ),
2202
+									  $metabox_callback
2203
+								  );
2204
+					throw new EE_Error($error_msg);
2205
+				}
2206
+				unset($this->_route_config['metaboxes'][ $key ]);
2207
+			}
2208
+		}
2209
+	}
2210
+
2211
+
2212
+	/**
2213
+	 * _add_screen_columns
2214
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2215
+	 * the dynamic column template and we'll setup the column options for the page.
2216
+	 *
2217
+	 * @return void
2218
+	 */
2219
+	private function _add_screen_columns()
2220
+	{
2221
+		if (
2222
+			isset($this->_route_config['columns'])
2223
+			&& is_array($this->_route_config['columns'])
2224
+			&& count($this->_route_config['columns']) === 2
2225
+		) {
2226
+			add_screen_option(
2227
+				'layout_columns',
2228
+				[
2229
+					'max'     => (int) $this->_route_config['columns'][0],
2230
+					'default' => (int) $this->_route_config['columns'][1],
2231
+				]
2232
+			);
2233
+			$this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2234
+			$screen_id                                           = $this->_current_screen->id;
2235
+			$screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2236
+			$total_columns                                       = ! empty($screen_columns)
2237
+				? $screen_columns
2238
+				: $this->_route_config['columns'][1];
2239
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2240
+			$this->_template_args['current_page']                = $this->_wp_page_slug;
2241
+			$this->_template_args['screen']                      = $this->_current_screen;
2242
+			$this->_column_template_path                         = EE_ADMIN_TEMPLATE
2243
+																   . 'admin_details_metabox_column_wrapper.template.php';
2244
+			// finally if we don't have has_metaboxes set in the route config
2245
+			// let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2246
+			$this->_route_config['has_metaboxes'] = true;
2247
+		}
2248
+	}
2249
+
2250
+
2251
+
2252
+	/** GLOBALLY AVAILABLE METABOXES **/
2253
+
2254
+
2255
+	/**
2256
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2257
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2258
+	 * these get loaded on.
2259
+	 */
2260
+	private function _espresso_news_post_box()
2261
+	{
2262
+		$news_box_title = apply_filters(
2263
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2264
+			esc_html__('New @ Event Espresso', 'event_espresso')
2265
+		);
2266
+		$this->addMetaBox(
2267
+			'espresso_news_post_box',
2268
+			$news_box_title,
2269
+			[
2270
+				$this,
2271
+				'espresso_news_post_box',
2272
+			],
2273
+			$this->_wp_page_slug,
2274
+			'side',
2275
+			'low'
2276
+		);
2277
+	}
2278
+
2279
+
2280
+	/**
2281
+	 * Code for setting up espresso ratings request metabox.
2282
+	 */
2283
+	protected function _espresso_ratings_request()
2284
+	{
2285
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2286
+			return;
2287
+		}
2288
+		$ratings_box_title = apply_filters(
2289
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2290
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2291
+		);
2292
+		$this->addMetaBox(
2293
+			'espresso_ratings_request',
2294
+			$ratings_box_title,
2295
+			[
2296
+				$this,
2297
+				'espresso_ratings_request',
2298
+			],
2299
+			$this->_wp_page_slug,
2300
+			'side'
2301
+		);
2302
+	}
2303
+
2304
+
2305
+	/**
2306
+	 * Code for setting up espresso ratings request metabox content.
2307
+	 *
2308
+	 * @throws DomainException
2309
+	 */
2310
+	public function espresso_ratings_request()
2311
+	{
2312
+		EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2313
+	}
2314
+
2315
+
2316
+	public static function cached_rss_display(string $rss_id, string $url): bool
2317
+	{
2318
+		$loading   = '<p class="widget-loading hide-if-no-js">'
2319
+					 . esc_html__('Loading&#8230;', 'event_espresso')
2320
+					 . '</p><p class="hide-if-js">'
2321
+					 . esc_html__('This widget requires JavaScript.', 'event_espresso')
2322
+					 . '</p>';
2323
+		$pre       = '<div class="espresso-rss-display">' . "\n\t";
2324
+		$pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2325
+		$post      = '</div>' . "\n";
2326
+		$cache_key = 'ee_rss_' . md5($rss_id);
2327
+		$output    = get_transient($cache_key);
2328
+		if ($output !== false) {
2329
+			echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2330
+			return true;
2331
+		}
2332
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2333
+			echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2334
+			return false;
2335
+		}
2336
+		ob_start();
2337
+		wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2338
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2339
+		return true;
2340
+	}
2341
+
2342
+
2343
+	public function espresso_news_post_box()
2344
+	{
2345
+		?>
2346 2346
 <div class="padding">
2347 2347
 	<div id="espresso_news_post_box_content" class="infolinks">
2348 2348
 		<?php
2349
-                // Get RSS Feed(s)
2350
-                EE_Admin_Page::cached_rss_display(
2351
-                    'espresso_news_post_box_content',
2352
-                    esc_url_raw(
2353
-                        apply_filters(
2354
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2355
-                            'https://eventespresso.com/feed/'
2356
-                        )
2357
-                    )
2358
-                );
2359
-                ?>
2349
+				// Get RSS Feed(s)
2350
+				EE_Admin_Page::cached_rss_display(
2351
+					'espresso_news_post_box_content',
2352
+					esc_url_raw(
2353
+						apply_filters(
2354
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2355
+							'https://eventespresso.com/feed/'
2356
+						)
2357
+					)
2358
+				);
2359
+				?>
2360 2360
 	</div>
2361 2361
 	<?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2362 2362
 </div>
2363 2363
 <?php
2364
-    }
2365
-
2366
-
2367
-    private function _espresso_links_post_box()
2368
-    {
2369
-        // Hiding until we actually have content to put in here...
2370
-        // $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2371
-    }
2372
-
2373
-
2374
-    public function espresso_links_post_box()
2375
-    {
2376
-        // Hiding until we actually have content to put in here...
2377
-        // EEH_Template::display_template(
2378
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2379
-        // );
2380
-    }
2381
-
2382
-
2383
-    protected function _espresso_sponsors_post_box()
2384
-    {
2385
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2386
-            $this->addMetaBox(
2387
-                'espresso_sponsors_post_box',
2388
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2389
-                [$this, 'espresso_sponsors_post_box'],
2390
-                $this->_wp_page_slug,
2391
-                'side'
2392
-            );
2393
-        }
2394
-    }
2395
-
2396
-
2397
-    public function espresso_sponsors_post_box()
2398
-    {
2399
-        EEH_Template::display_template(
2400
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2401
-        );
2402
-    }
2403
-
2404
-
2405
-    /**
2406
-     * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2407
-     * present in the _page_config array, then we'll use that for the metabox label.
2408
-     * Otherwise we'll just use publish
2409
-     * (publishbox itself could be an array of labels indexed by routes)
2410
-     *
2411
-     * @return string
2412
-     * @since   5.0.0.p
2413
-     */
2414
-    protected function getPublishBoxTitle(): string
2415
-    {
2416
-        $publish_box_title = esc_html__('Publish', 'event_espresso');
2417
-        if (! empty($this->_labels['publishbox'])) {
2418
-            if (is_array($this->_labels['publishbox'])) {
2419
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2420
-            } else {
2421
-                $publish_box_title = $this->_labels['publishbox'];
2422
-            }
2423
-        }
2424
-        return apply_filters(
2425
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2426
-            $publish_box_title,
2427
-            $this->_req_action,
2428
-            $this
2429
-        );
2430
-    }
2431
-
2432
-
2433
-    /**
2434
-     * @throws EE_Error
2435
-     */
2436
-    private function _publish_post_box()
2437
-    {
2438
-        $title = $this->getPublishBoxTitle();
2439
-        if (empty($this->_template_args['save_buttons'])) {
2440
-            $this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2441
-        } else {
2442
-            $this->addPublishPostMetaBoxHiddenFields(
2443
-                sanitize_key($title),
2444
-                ['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2445
-            );
2446
-        }
2447
-        $this->addMetaBox(
2448
-            "espresso_{$this->page_slug}_editor_overview",
2449
-            $title,
2450
-            [$this, 'editor_overview'],
2451
-            $this->_current_screen->id,
2452
-            'side',
2453
-            'high'
2454
-        );
2455
-    }
2456
-
2457
-
2458
-    public function editor_overview()
2459
-    {
2460
-        /**
2461
-         * @var string $publish_box_extra_content
2462
-         * @var string $publish_hidden_fields
2463
-         * @var string $publish_delete_link
2464
-         * @var string $save_buttons
2465
-         */
2466
-        // if we have extra content set let's add it in if not make sure its empty
2467
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2468
-        echo EEH_Template::display_template(
2469
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2470
-            $this->_template_args,
2471
-            true
2472
-        );
2473
-    }
2474
-
2475
-
2476
-    /** end of globally available metaboxes section **/
2477
-
2478
-
2479
-    /**
2480
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2481
-     * Note: currently there is no validation for this.  However, if you want the delete button, the
2482
-     * save, and save and close buttons to work properly, then you will want to include a
2483
-     * values for the name and id arguments.
2484
-     *
2485
-     * @param string|null $name                     key used for the action ID (i.e. event_id)
2486
-     * @param int|string  $id                       id attached to the item published
2487
-     * @param string|null $delete                   page route callback for the delete action
2488
-     * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2489
-     * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2490
-     *                                              or just the "Save" button
2491
-     * @throws EE_Error
2492
-     * @throws InvalidArgumentException
2493
-     * @throws InvalidDataTypeException
2494
-     * @throws InvalidInterfaceException
2495
-     * @todo  Add in validation for name/id arguments.
2496
-     */
2497
-    protected function _set_publish_post_box_vars(
2498
-        ?string $name = '',
2499
-        $id = 0,
2500
-        ?string $delete = '',
2501
-        ?string $save_close_redirect_URL = '',
2502
-        bool $both_btns = true
2503
-    ) {
2504
-        // if Save & Close, use a custom redirect URL or default to the main page?
2505
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2506
-            ? $save_close_redirect_URL
2507
-            : $this->_admin_base_url;
2508
-        // create the Save & Close and Save buttons
2509
-        $this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2510
-        // if we have extra content set let's add it in if not make sure its empty
2511
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2512
-        if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2513
-            // make sure we have a default if just true is sent.
2514
-            $delete                                      = ! empty($delete) ? $delete : 'delete';
2515
-            $this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2516
-                $delete,
2517
-                $delete,
2518
-                [$name => $id],
2519
-                'submitdelete deletion button button--outline button--caution'
2520
-            );
2521
-        }
2522
-        if (! isset($this->_template_args['publish_delete_link'])) {
2523
-            $this->_template_args['publish_delete_link'] = '';
2524
-        }
2525
-        if (! empty($name) && ! empty($id)) {
2526
-            $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2527
-        }
2528
-        $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2529
-        // add hidden fields
2530
-        $this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2531
-        foreach ($hidden_fields as $hidden_field) {
2532
-            $this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2533
-        }
2534
-    }
2535
-
2536
-
2537
-    /**
2538
-     * @param string|null $name
2539
-     * @param int|string  $id
2540
-     * @param string|null $delete
2541
-     * @param string|null $save_close_redirect_URL
2542
-     * @param bool        $both_btns
2543
-     * @throws EE_Error
2544
-     */
2545
-    public function set_publish_post_box_vars(
2546
-        ?string $name = '',
2547
-        $id = 0,
2548
-        ?string $delete = '',
2549
-        ?string $save_close_redirect_URL = '',
2550
-        bool $both_btns = false
2551
-    ) {
2552
-        $this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2553
-    }
2554
-
2555
-
2556
-    protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2557
-    {
2558
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2559
-    }
2560
-
2561
-
2562
-    /**
2563
-     * displays an error message to ppl who have javascript disabled
2564
-     *
2565
-     * @return void
2566
-     */
2567
-    private function _display_no_javascript_warning()
2568
-    {
2569
-        ?>
2364
+	}
2365
+
2366
+
2367
+	private function _espresso_links_post_box()
2368
+	{
2369
+		// Hiding until we actually have content to put in here...
2370
+		// $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2371
+	}
2372
+
2373
+
2374
+	public function espresso_links_post_box()
2375
+	{
2376
+		// Hiding until we actually have content to put in here...
2377
+		// EEH_Template::display_template(
2378
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2379
+		// );
2380
+	}
2381
+
2382
+
2383
+	protected function _espresso_sponsors_post_box()
2384
+	{
2385
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2386
+			$this->addMetaBox(
2387
+				'espresso_sponsors_post_box',
2388
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2389
+				[$this, 'espresso_sponsors_post_box'],
2390
+				$this->_wp_page_slug,
2391
+				'side'
2392
+			);
2393
+		}
2394
+	}
2395
+
2396
+
2397
+	public function espresso_sponsors_post_box()
2398
+	{
2399
+		EEH_Template::display_template(
2400
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2401
+		);
2402
+	}
2403
+
2404
+
2405
+	/**
2406
+	 * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2407
+	 * present in the _page_config array, then we'll use that for the metabox label.
2408
+	 * Otherwise we'll just use publish
2409
+	 * (publishbox itself could be an array of labels indexed by routes)
2410
+	 *
2411
+	 * @return string
2412
+	 * @since   5.0.0.p
2413
+	 */
2414
+	protected function getPublishBoxTitle(): string
2415
+	{
2416
+		$publish_box_title = esc_html__('Publish', 'event_espresso');
2417
+		if (! empty($this->_labels['publishbox'])) {
2418
+			if (is_array($this->_labels['publishbox'])) {
2419
+				$publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2420
+			} else {
2421
+				$publish_box_title = $this->_labels['publishbox'];
2422
+			}
2423
+		}
2424
+		return apply_filters(
2425
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2426
+			$publish_box_title,
2427
+			$this->_req_action,
2428
+			$this
2429
+		);
2430
+	}
2431
+
2432
+
2433
+	/**
2434
+	 * @throws EE_Error
2435
+	 */
2436
+	private function _publish_post_box()
2437
+	{
2438
+		$title = $this->getPublishBoxTitle();
2439
+		if (empty($this->_template_args['save_buttons'])) {
2440
+			$this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2441
+		} else {
2442
+			$this->addPublishPostMetaBoxHiddenFields(
2443
+				sanitize_key($title),
2444
+				['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2445
+			);
2446
+		}
2447
+		$this->addMetaBox(
2448
+			"espresso_{$this->page_slug}_editor_overview",
2449
+			$title,
2450
+			[$this, 'editor_overview'],
2451
+			$this->_current_screen->id,
2452
+			'side',
2453
+			'high'
2454
+		);
2455
+	}
2456
+
2457
+
2458
+	public function editor_overview()
2459
+	{
2460
+		/**
2461
+		 * @var string $publish_box_extra_content
2462
+		 * @var string $publish_hidden_fields
2463
+		 * @var string $publish_delete_link
2464
+		 * @var string $save_buttons
2465
+		 */
2466
+		// if we have extra content set let's add it in if not make sure its empty
2467
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2468
+		echo EEH_Template::display_template(
2469
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2470
+			$this->_template_args,
2471
+			true
2472
+		);
2473
+	}
2474
+
2475
+
2476
+	/** end of globally available metaboxes section **/
2477
+
2478
+
2479
+	/**
2480
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2481
+	 * Note: currently there is no validation for this.  However, if you want the delete button, the
2482
+	 * save, and save and close buttons to work properly, then you will want to include a
2483
+	 * values for the name and id arguments.
2484
+	 *
2485
+	 * @param string|null $name                     key used for the action ID (i.e. event_id)
2486
+	 * @param int|string  $id                       id attached to the item published
2487
+	 * @param string|null $delete                   page route callback for the delete action
2488
+	 * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2489
+	 * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2490
+	 *                                              or just the "Save" button
2491
+	 * @throws EE_Error
2492
+	 * @throws InvalidArgumentException
2493
+	 * @throws InvalidDataTypeException
2494
+	 * @throws InvalidInterfaceException
2495
+	 * @todo  Add in validation for name/id arguments.
2496
+	 */
2497
+	protected function _set_publish_post_box_vars(
2498
+		?string $name = '',
2499
+		$id = 0,
2500
+		?string $delete = '',
2501
+		?string $save_close_redirect_URL = '',
2502
+		bool $both_btns = true
2503
+	) {
2504
+		// if Save & Close, use a custom redirect URL or default to the main page?
2505
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2506
+			? $save_close_redirect_URL
2507
+			: $this->_admin_base_url;
2508
+		// create the Save & Close and Save buttons
2509
+		$this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2510
+		// if we have extra content set let's add it in if not make sure its empty
2511
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2512
+		if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2513
+			// make sure we have a default if just true is sent.
2514
+			$delete                                      = ! empty($delete) ? $delete : 'delete';
2515
+			$this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2516
+				$delete,
2517
+				$delete,
2518
+				[$name => $id],
2519
+				'submitdelete deletion button button--outline button--caution'
2520
+			);
2521
+		}
2522
+		if (! isset($this->_template_args['publish_delete_link'])) {
2523
+			$this->_template_args['publish_delete_link'] = '';
2524
+		}
2525
+		if (! empty($name) && ! empty($id)) {
2526
+			$this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2527
+		}
2528
+		$hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2529
+		// add hidden fields
2530
+		$this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2531
+		foreach ($hidden_fields as $hidden_field) {
2532
+			$this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2533
+		}
2534
+	}
2535
+
2536
+
2537
+	/**
2538
+	 * @param string|null $name
2539
+	 * @param int|string  $id
2540
+	 * @param string|null $delete
2541
+	 * @param string|null $save_close_redirect_URL
2542
+	 * @param bool        $both_btns
2543
+	 * @throws EE_Error
2544
+	 */
2545
+	public function set_publish_post_box_vars(
2546
+		?string $name = '',
2547
+		$id = 0,
2548
+		?string $delete = '',
2549
+		?string $save_close_redirect_URL = '',
2550
+		bool $both_btns = false
2551
+	) {
2552
+		$this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2553
+	}
2554
+
2555
+
2556
+	protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2557
+	{
2558
+		$this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2559
+	}
2560
+
2561
+
2562
+	/**
2563
+	 * displays an error message to ppl who have javascript disabled
2564
+	 *
2565
+	 * @return void
2566
+	 */
2567
+	private function _display_no_javascript_warning()
2568
+	{
2569
+		?>
2570 2570
 <noscript>
2571 2571
 	<div id="no-js-message" class="error">
2572 2572
 		<p style="font-size:1.3em;">
2573 2573
 			<span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2574 2574
 			<?php esc_html_e(
2575
-                        '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.',
2576
-                        'event_espresso'
2577
-                    ); ?>
2575
+						'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.',
2576
+						'event_espresso'
2577
+					); ?>
2578 2578
 		</p>
2579 2579
 	</div>
2580 2580
 </noscript>
2581 2581
 <?php
2582
-    }
2583
-
2584
-
2585
-    /**
2586
-     * displays espresso success and/or error notices
2587
-     *
2588
-     * @return void
2589
-     */
2590
-    protected function _display_espresso_notices()
2591
-    {
2592
-        $notices = (array) $this->_get_transient(true);
2593
-        foreach ($notices as $notice) {
2594
-            echo $notice ? stripslashes($notice) : '';
2595
-        }
2596
-    }
2597
-
2598
-
2599
-    /**
2600
-     * spinny things pacify the masses
2601
-     *
2602
-     * @return void
2603
-     */
2604
-    protected function _add_admin_page_ajax_loading_img()
2605
-    {
2606
-        ?>
2582
+	}
2583
+
2584
+
2585
+	/**
2586
+	 * displays espresso success and/or error notices
2587
+	 *
2588
+	 * @return void
2589
+	 */
2590
+	protected function _display_espresso_notices()
2591
+	{
2592
+		$notices = (array) $this->_get_transient(true);
2593
+		foreach ($notices as $notice) {
2594
+			echo $notice ? stripslashes($notice) : '';
2595
+		}
2596
+	}
2597
+
2598
+
2599
+	/**
2600
+	 * spinny things pacify the masses
2601
+	 *
2602
+	 * @return void
2603
+	 */
2604
+	protected function _add_admin_page_ajax_loading_img()
2605
+	{
2606
+		?>
2607 2607
 <div id="espresso-ajax-loading" class="ajax-loading-grey">
2608 2608
 	<span class="ee-spinner ee-spin"></span><span class="hidden"><?php
2609
-                esc_html_e('loading...', 'event_espresso'); ?></span>
2609
+				esc_html_e('loading...', 'event_espresso'); ?></span>
2610 2610
 </div>
2611 2611
 <?php
2612
-    }
2612
+	}
2613 2613
 
2614 2614
 
2615
-    /**
2616
-     * add admin page overlay for modal boxes
2617
-     *
2618
-     * @return void
2619
-     */
2620
-    protected function _add_admin_page_overlay()
2621
-    {
2622
-        ?>
2615
+	/**
2616
+	 * add admin page overlay for modal boxes
2617
+	 *
2618
+	 * @return void
2619
+	 */
2620
+	protected function _add_admin_page_overlay()
2621
+	{
2622
+		?>
2623 2623
 <div id="espresso-admin-page-overlay-dv" class=""></div>
2624 2624
 <?php
2625
-    }
2626
-
2627
-
2628
-    /**
2629
-     * facade for $this->addMetaBox()
2630
-     *
2631
-     * @param string   $action        where the metabox gets displayed
2632
-     * @param string   $title         Title of Metabox (output in metabox header)
2633
-     * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2634
-     *                                instead of the one created in here.
2635
-     * @param array    $callback_args an array of args supplied for the metabox
2636
-     * @param string   $column        what metabox column
2637
-     * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2638
-     * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2639
-     *                                created but just set our own callback for wp's add_meta_box.
2640
-     * @throws DomainException
2641
-     */
2642
-    public function _add_admin_page_meta_box(
2643
-        string $action,
2644
-        string $title,
2645
-        callable $callback,
2646
-        array $callback_args,
2647
-        string $column = 'normal',
2648
-        string $priority = 'high',
2649
-        bool $create_func = true
2650
-    ) {
2651
-        // 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.
2652
-        if (empty($callback_args) && $create_func) {
2653
-            $callback_args = [
2654
-                'template_path' => $this->_template_path,
2655
-                'template_args' => $this->_template_args,
2656
-            ];
2657
-        }
2658
-        // 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)
2659
-        $call_back_func = $create_func
2660
-            ? static function ($post, $metabox) {
2661
-                echo EEH_Template::display_template(
2662
-                    $metabox['args']['template_path'],
2663
-                    $metabox['args']['template_args'],
2664
-                    true
2665
-                );
2666
-            }
2667
-            : $callback;
2668
-        $this->addMetaBox(
2669
-            str_replace('_', '-', $action) . '-mbox',
2670
-            $title,
2671
-            $call_back_func,
2672
-            $this->_wp_page_slug,
2673
-            $column,
2674
-            $priority,
2675
-            $callback_args
2676
-        );
2677
-    }
2678
-
2679
-
2680
-    /**
2681
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2682
-     *
2683
-     * @throws DomainException
2684
-     * @throws EE_Error
2685
-     * @throws InvalidArgumentException
2686
-     * @throws InvalidDataTypeException
2687
-     * @throws InvalidInterfaceException
2688
-     */
2689
-    public function display_admin_page_with_metabox_columns()
2690
-    {
2691
-        $this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2692
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2693
-            $this->_column_template_path,
2694
-            $this->_template_args,
2695
-            true
2696
-        );
2697
-        // the final wrapper
2698
-        $this->admin_page_wrapper();
2699
-    }
2700
-
2701
-
2702
-    /**
2703
-     * generates  HTML wrapper for an admin details page
2704
-     *
2705
-     * @return void
2706
-     * @throws DomainException
2707
-     * @throws EE_Error
2708
-     * @throws InvalidArgumentException
2709
-     * @throws InvalidDataTypeException
2710
-     * @throws InvalidInterfaceException
2711
-     */
2712
-    public function display_admin_page_with_sidebar()
2713
-    {
2714
-        $this->_display_admin_page(true);
2715
-    }
2716
-
2717
-
2718
-    /**
2719
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2720
-     *
2721
-     * @return void
2722
-     * @throws DomainException
2723
-     * @throws EE_Error
2724
-     * @throws InvalidArgumentException
2725
-     * @throws InvalidDataTypeException
2726
-     * @throws InvalidInterfaceException
2727
-     */
2728
-    public function display_admin_page_with_no_sidebar()
2729
-    {
2730
-        $this->_display_admin_page();
2731
-    }
2732
-
2733
-
2734
-    /**
2735
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2736
-     *
2737
-     * @return void
2738
-     * @throws DomainException
2739
-     * @throws EE_Error
2740
-     * @throws InvalidArgumentException
2741
-     * @throws InvalidDataTypeException
2742
-     * @throws InvalidInterfaceException
2743
-     */
2744
-    public function display_about_admin_page()
2745
-    {
2746
-        $this->_display_admin_page(false, true);
2747
-    }
2748
-
2749
-
2750
-    /**
2751
-     * display_admin_page
2752
-     * contains the code for actually displaying an admin page
2753
-     *
2754
-     * @param bool $sidebar true with sidebar, false without
2755
-     * @param bool $about   use the about admin wrapper instead of the default.
2756
-     * @return void
2757
-     * @throws DomainException
2758
-     * @throws EE_Error
2759
-     * @throws InvalidArgumentException
2760
-     * @throws InvalidDataTypeException
2761
-     * @throws InvalidInterfaceException
2762
-     */
2763
-    private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2764
-    {
2765
-        // custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2766
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2767
-
2768
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2769
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2770
-        $post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2771
-
2772
-        $this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2773
-                                                  && $this->_req_action !== 'data_reset'
2774
-                                                  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2775
-                                                  && strpos($post_body_content, 'wp-list-table') === false;
2776
-
2777
-        $this->_template_args['current_page']                 = $this->_wp_page_slug;
2778
-        $this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2779
-            ? 'poststuff'
2780
-            : 'espresso-default-admin';
2781
-        $this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2782
-                                                                    'event-espresso_page_espresso_',
2783
-                                                                    '',
2784
-                                                                    $this->_wp_page_slug
2785
-                                                                ) . ' ' . $this->_req_action . '-route';
2786
-
2787
-        $template_path = $sidebar
2788
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2789
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2790
-
2791
-        $this->_template_args['is_ajax'] = $this->request->isAjax();
2792
-        if ($this->request->isAjax()) {
2793
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2794
-        }
2795
-        $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2796
-
2797
-        $this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2798
-        $this->_template_args['before_admin_page_content'] = $post_body_content;
2799
-        $this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2800
-
2801
-        // ensure $post_type and $post are set
2802
-        // to prevent WooCommerce from blowing things up if not using CPT
2803
-        global $post_type, $post;
2804
-        $this->_template_args['post_type'] = $post_type ?? '';
2805
-        $this->_template_args['post']  = $post ?? new WP_Post( (object) [ 'ID' => 0, 'filter' => 'raw' ] );
2806
-
2807
-        $this->_template_args['post_body_content'] = EEH_Template::display_template(
2808
-            EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2809
-            $this->_template_args,
2810
-            true
2811
-        );
2812
-
2813
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2814
-            $template_path,
2815
-            $this->_template_args,
2816
-            true
2817
-        );
2818
-        // the final template wrapper
2819
-        $this->admin_page_wrapper($about);
2820
-    }
2821
-
2822
-
2823
-    /**
2824
-     * This is used to display caf preview pages.
2825
-     *
2826
-     * @param string $utm_campaign_source what is the key used for google analytics link
2827
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2828
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2829
-     * @return void
2830
-     * @throws DomainException
2831
-     * @throws EE_Error
2832
-     * @throws InvalidArgumentException
2833
-     * @throws InvalidDataTypeException
2834
-     * @throws InvalidInterfaceException
2835
-     * @since 4.3.2
2836
-     */
2837
-    public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2838
-    {
2839
-        // let's generate a default preview action button if there isn't one already present.
2840
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2841
-            'Upgrade to Event Espresso 4 Right Now',
2842
-            'event_espresso'
2843
-        );
2844
-        $buy_now_url                                   = add_query_arg(
2845
-            [
2846
-                'ee_ver'       => 'ee4',
2847
-                'utm_source'   => 'ee4_plugin_admin',
2848
-                'utm_medium'   => 'link',
2849
-                'utm_campaign' => $utm_campaign_source,
2850
-                'utm_content'  => 'buy_now_button',
2851
-            ],
2852
-            'https://eventespresso.com/pricing/'
2853
-        );
2854
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2855
-            ? $this->get_action_link_or_button(
2856
-                '',
2857
-                'buy_now',
2858
-                [],
2859
-                'button button--primary button--big',
2860
-                esc_url_raw($buy_now_url),
2861
-                true
2862
-            )
2863
-            : $this->_template_args['preview_action_button'];
2864
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2865
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2866
-            $this->_template_args,
2867
-            true
2868
-        );
2869
-        $this->_display_admin_page($display_sidebar);
2870
-    }
2871
-
2872
-
2873
-    /**
2874
-     * display_admin_list_table_page_with_sidebar
2875
-     * generates HTML wrapper for an admin_page with list_table
2876
-     *
2877
-     * @return void
2878
-     * @throws DomainException
2879
-     * @throws EE_Error
2880
-     * @throws InvalidArgumentException
2881
-     * @throws InvalidDataTypeException
2882
-     * @throws InvalidInterfaceException
2883
-     */
2884
-    public function display_admin_list_table_page_with_sidebar()
2885
-    {
2886
-        $this->_display_admin_list_table_page(true);
2887
-    }
2888
-
2889
-
2890
-    /**
2891
-     * display_admin_list_table_page_with_no_sidebar
2892
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2893
-     *
2894
-     * @return void
2895
-     * @throws DomainException
2896
-     * @throws EE_Error
2897
-     * @throws InvalidArgumentException
2898
-     * @throws InvalidDataTypeException
2899
-     * @throws InvalidInterfaceException
2900
-     */
2901
-    public function display_admin_list_table_page_with_no_sidebar()
2902
-    {
2903
-        $this->_display_admin_list_table_page();
2904
-    }
2905
-
2906
-
2907
-    /**
2908
-     * generates html wrapper for an admin_list_table page
2909
-     *
2910
-     * @param bool $sidebar whether to display with sidebar or not.
2911
-     * @return void
2912
-     * @throws DomainException
2913
-     * @throws EE_Error
2914
-     * @throws InvalidArgumentException
2915
-     * @throws InvalidDataTypeException
2916
-     * @throws InvalidInterfaceException
2917
-     */
2918
-    private function _display_admin_list_table_page(bool $sidebar = false)
2919
-    {
2920
-        // setup search attributes
2921
-        $this->_set_search_attributes();
2922
-        $this->_template_args['current_page']     = $this->_wp_page_slug;
2923
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2924
-        $this->_template_args['table_url']        = $this->request->isAjax()
2925
-            ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2926
-            : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2927
-        $this->_template_args['list_table']       = $this->_list_table_object;
2928
-        $this->_template_args['current_route']    = $this->_req_action;
2929
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2930
-        $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2931
-        if (! empty($ajax_sorting_callback)) {
2932
-            $sortable_list_table_form_fields = wp_nonce_field(
2933
-                $ajax_sorting_callback . '_nonce',
2934
-                $ajax_sorting_callback . '_nonce',
2935
-                false,
2936
-                false
2937
-            );
2938
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2939
-                                                . $this->page_slug
2940
-                                                . '" />';
2941
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2942
-                                                . $ajax_sorting_callback
2943
-                                                . '" />';
2944
-        } else {
2945
-            $sortable_list_table_form_fields = '';
2946
-        }
2947
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2948
-
2949
-        $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2950
-
2951
-        $nonce_ref          = $this->_req_action . '_nonce';
2952
-        $hidden_form_fields .= '
2625
+	}
2626
+
2627
+
2628
+	/**
2629
+	 * facade for $this->addMetaBox()
2630
+	 *
2631
+	 * @param string   $action        where the metabox gets displayed
2632
+	 * @param string   $title         Title of Metabox (output in metabox header)
2633
+	 * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2634
+	 *                                instead of the one created in here.
2635
+	 * @param array    $callback_args an array of args supplied for the metabox
2636
+	 * @param string   $column        what metabox column
2637
+	 * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2638
+	 * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2639
+	 *                                created but just set our own callback for wp's add_meta_box.
2640
+	 * @throws DomainException
2641
+	 */
2642
+	public function _add_admin_page_meta_box(
2643
+		string $action,
2644
+		string $title,
2645
+		callable $callback,
2646
+		array $callback_args,
2647
+		string $column = 'normal',
2648
+		string $priority = 'high',
2649
+		bool $create_func = true
2650
+	) {
2651
+		// 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.
2652
+		if (empty($callback_args) && $create_func) {
2653
+			$callback_args = [
2654
+				'template_path' => $this->_template_path,
2655
+				'template_args' => $this->_template_args,
2656
+			];
2657
+		}
2658
+		// 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)
2659
+		$call_back_func = $create_func
2660
+			? static function ($post, $metabox) {
2661
+				echo EEH_Template::display_template(
2662
+					$metabox['args']['template_path'],
2663
+					$metabox['args']['template_args'],
2664
+					true
2665
+				);
2666
+			}
2667
+			: $callback;
2668
+		$this->addMetaBox(
2669
+			str_replace('_', '-', $action) . '-mbox',
2670
+			$title,
2671
+			$call_back_func,
2672
+			$this->_wp_page_slug,
2673
+			$column,
2674
+			$priority,
2675
+			$callback_args
2676
+		);
2677
+	}
2678
+
2679
+
2680
+	/**
2681
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2682
+	 *
2683
+	 * @throws DomainException
2684
+	 * @throws EE_Error
2685
+	 * @throws InvalidArgumentException
2686
+	 * @throws InvalidDataTypeException
2687
+	 * @throws InvalidInterfaceException
2688
+	 */
2689
+	public function display_admin_page_with_metabox_columns()
2690
+	{
2691
+		$this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2692
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2693
+			$this->_column_template_path,
2694
+			$this->_template_args,
2695
+			true
2696
+		);
2697
+		// the final wrapper
2698
+		$this->admin_page_wrapper();
2699
+	}
2700
+
2701
+
2702
+	/**
2703
+	 * generates  HTML wrapper for an admin details page
2704
+	 *
2705
+	 * @return void
2706
+	 * @throws DomainException
2707
+	 * @throws EE_Error
2708
+	 * @throws InvalidArgumentException
2709
+	 * @throws InvalidDataTypeException
2710
+	 * @throws InvalidInterfaceException
2711
+	 */
2712
+	public function display_admin_page_with_sidebar()
2713
+	{
2714
+		$this->_display_admin_page(true);
2715
+	}
2716
+
2717
+
2718
+	/**
2719
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2720
+	 *
2721
+	 * @return void
2722
+	 * @throws DomainException
2723
+	 * @throws EE_Error
2724
+	 * @throws InvalidArgumentException
2725
+	 * @throws InvalidDataTypeException
2726
+	 * @throws InvalidInterfaceException
2727
+	 */
2728
+	public function display_admin_page_with_no_sidebar()
2729
+	{
2730
+		$this->_display_admin_page();
2731
+	}
2732
+
2733
+
2734
+	/**
2735
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2736
+	 *
2737
+	 * @return void
2738
+	 * @throws DomainException
2739
+	 * @throws EE_Error
2740
+	 * @throws InvalidArgumentException
2741
+	 * @throws InvalidDataTypeException
2742
+	 * @throws InvalidInterfaceException
2743
+	 */
2744
+	public function display_about_admin_page()
2745
+	{
2746
+		$this->_display_admin_page(false, true);
2747
+	}
2748
+
2749
+
2750
+	/**
2751
+	 * display_admin_page
2752
+	 * contains the code for actually displaying an admin page
2753
+	 *
2754
+	 * @param bool $sidebar true with sidebar, false without
2755
+	 * @param bool $about   use the about admin wrapper instead of the default.
2756
+	 * @return void
2757
+	 * @throws DomainException
2758
+	 * @throws EE_Error
2759
+	 * @throws InvalidArgumentException
2760
+	 * @throws InvalidDataTypeException
2761
+	 * @throws InvalidInterfaceException
2762
+	 */
2763
+	private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2764
+	{
2765
+		// custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2766
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2767
+
2768
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2769
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2770
+		$post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2771
+
2772
+		$this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2773
+												  && $this->_req_action !== 'data_reset'
2774
+												  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2775
+												  && strpos($post_body_content, 'wp-list-table') === false;
2776
+
2777
+		$this->_template_args['current_page']                 = $this->_wp_page_slug;
2778
+		$this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2779
+			? 'poststuff'
2780
+			: 'espresso-default-admin';
2781
+		$this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2782
+																	'event-espresso_page_espresso_',
2783
+																	'',
2784
+																	$this->_wp_page_slug
2785
+																) . ' ' . $this->_req_action . '-route';
2786
+
2787
+		$template_path = $sidebar
2788
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2789
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2790
+
2791
+		$this->_template_args['is_ajax'] = $this->request->isAjax();
2792
+		if ($this->request->isAjax()) {
2793
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2794
+		}
2795
+		$template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2796
+
2797
+		$this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2798
+		$this->_template_args['before_admin_page_content'] = $post_body_content;
2799
+		$this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2800
+
2801
+		// ensure $post_type and $post are set
2802
+		// to prevent WooCommerce from blowing things up if not using CPT
2803
+		global $post_type, $post;
2804
+		$this->_template_args['post_type'] = $post_type ?? '';
2805
+		$this->_template_args['post']  = $post ?? new WP_Post( (object) [ 'ID' => 0, 'filter' => 'raw' ] );
2806
+
2807
+		$this->_template_args['post_body_content'] = EEH_Template::display_template(
2808
+			EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2809
+			$this->_template_args,
2810
+			true
2811
+		);
2812
+
2813
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2814
+			$template_path,
2815
+			$this->_template_args,
2816
+			true
2817
+		);
2818
+		// the final template wrapper
2819
+		$this->admin_page_wrapper($about);
2820
+	}
2821
+
2822
+
2823
+	/**
2824
+	 * This is used to display caf preview pages.
2825
+	 *
2826
+	 * @param string $utm_campaign_source what is the key used for google analytics link
2827
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2828
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2829
+	 * @return void
2830
+	 * @throws DomainException
2831
+	 * @throws EE_Error
2832
+	 * @throws InvalidArgumentException
2833
+	 * @throws InvalidDataTypeException
2834
+	 * @throws InvalidInterfaceException
2835
+	 * @since 4.3.2
2836
+	 */
2837
+	public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2838
+	{
2839
+		// let's generate a default preview action button if there isn't one already present.
2840
+		$this->_labels['buttons']['buy_now']           = esc_html__(
2841
+			'Upgrade to Event Espresso 4 Right Now',
2842
+			'event_espresso'
2843
+		);
2844
+		$buy_now_url                                   = add_query_arg(
2845
+			[
2846
+				'ee_ver'       => 'ee4',
2847
+				'utm_source'   => 'ee4_plugin_admin',
2848
+				'utm_medium'   => 'link',
2849
+				'utm_campaign' => $utm_campaign_source,
2850
+				'utm_content'  => 'buy_now_button',
2851
+			],
2852
+			'https://eventespresso.com/pricing/'
2853
+		);
2854
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2855
+			? $this->get_action_link_or_button(
2856
+				'',
2857
+				'buy_now',
2858
+				[],
2859
+				'button button--primary button--big',
2860
+				esc_url_raw($buy_now_url),
2861
+				true
2862
+			)
2863
+			: $this->_template_args['preview_action_button'];
2864
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
2865
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2866
+			$this->_template_args,
2867
+			true
2868
+		);
2869
+		$this->_display_admin_page($display_sidebar);
2870
+	}
2871
+
2872
+
2873
+	/**
2874
+	 * display_admin_list_table_page_with_sidebar
2875
+	 * generates HTML wrapper for an admin_page with list_table
2876
+	 *
2877
+	 * @return void
2878
+	 * @throws DomainException
2879
+	 * @throws EE_Error
2880
+	 * @throws InvalidArgumentException
2881
+	 * @throws InvalidDataTypeException
2882
+	 * @throws InvalidInterfaceException
2883
+	 */
2884
+	public function display_admin_list_table_page_with_sidebar()
2885
+	{
2886
+		$this->_display_admin_list_table_page(true);
2887
+	}
2888
+
2889
+
2890
+	/**
2891
+	 * display_admin_list_table_page_with_no_sidebar
2892
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2893
+	 *
2894
+	 * @return void
2895
+	 * @throws DomainException
2896
+	 * @throws EE_Error
2897
+	 * @throws InvalidArgumentException
2898
+	 * @throws InvalidDataTypeException
2899
+	 * @throws InvalidInterfaceException
2900
+	 */
2901
+	public function display_admin_list_table_page_with_no_sidebar()
2902
+	{
2903
+		$this->_display_admin_list_table_page();
2904
+	}
2905
+
2906
+
2907
+	/**
2908
+	 * generates html wrapper for an admin_list_table page
2909
+	 *
2910
+	 * @param bool $sidebar whether to display with sidebar or not.
2911
+	 * @return void
2912
+	 * @throws DomainException
2913
+	 * @throws EE_Error
2914
+	 * @throws InvalidArgumentException
2915
+	 * @throws InvalidDataTypeException
2916
+	 * @throws InvalidInterfaceException
2917
+	 */
2918
+	private function _display_admin_list_table_page(bool $sidebar = false)
2919
+	{
2920
+		// setup search attributes
2921
+		$this->_set_search_attributes();
2922
+		$this->_template_args['current_page']     = $this->_wp_page_slug;
2923
+		$template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2924
+		$this->_template_args['table_url']        = $this->request->isAjax()
2925
+			? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2926
+			: add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2927
+		$this->_template_args['list_table']       = $this->_list_table_object;
2928
+		$this->_template_args['current_route']    = $this->_req_action;
2929
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2930
+		$ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2931
+		if (! empty($ajax_sorting_callback)) {
2932
+			$sortable_list_table_form_fields = wp_nonce_field(
2933
+				$ajax_sorting_callback . '_nonce',
2934
+				$ajax_sorting_callback . '_nonce',
2935
+				false,
2936
+				false
2937
+			);
2938
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2939
+												. $this->page_slug
2940
+												. '" />';
2941
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2942
+												. $ajax_sorting_callback
2943
+												. '" />';
2944
+		} else {
2945
+			$sortable_list_table_form_fields = '';
2946
+		}
2947
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2948
+
2949
+		$hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2950
+
2951
+		$nonce_ref          = $this->_req_action . '_nonce';
2952
+		$hidden_form_fields .= '
2953 2953
             <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2954 2954
 
2955
-        $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2956
-        // display message about search results?
2957
-        $search                                    = $this->request->getRequestParam('s');
2958
-        $this->_template_args['before_list_table'] .= ! empty($search)
2959
-            ? '<p class="ee-search-results">' . sprintf(
2960
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2961
-                trim($search, '%')
2962
-            ) . '</p>'
2963
-            : '';
2964
-        // filter before_list_table template arg
2965
-        $this->_template_args['before_list_table'] = apply_filters(
2966
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2967
-            $this->_template_args['before_list_table'],
2968
-            $this->page_slug,
2969
-            $this->request->requestParams(),
2970
-            $this->_req_action
2971
-        );
2972
-        // convert to array and filter again
2973
-        // arrays are easier to inject new items in a specific location,
2974
-        // but would not be backwards compatible, so we have to add a new filter
2975
-        $this->_template_args['before_list_table'] = implode(
2976
-            " \n",
2977
-            (array) apply_filters(
2978
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2979
-                (array) $this->_template_args['before_list_table'],
2980
-                $this->page_slug,
2981
-                $this->request->requestParams(),
2982
-                $this->_req_action
2983
-            )
2984
-        );
2985
-        // filter after_list_table template arg
2986
-        $this->_template_args['after_list_table'] = apply_filters(
2987
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
2988
-            $this->_template_args['after_list_table'],
2989
-            $this->page_slug,
2990
-            $this->request->requestParams(),
2991
-            $this->_req_action
2992
-        );
2993
-        // convert to array and filter again
2994
-        // arrays are easier to inject new items in a specific location,
2995
-        // but would not be backwards compatible, so we have to add a new filter
2996
-        $this->_template_args['after_list_table']   = implode(
2997
-            " \n",
2998
-            (array) apply_filters(
2999
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3000
-                (array) $this->_template_args['after_list_table'],
3001
-                $this->page_slug,
3002
-                $this->request->requestParams(),
3003
-                $this->_req_action
3004
-            )
3005
-        );
3006
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3007
-            $template_path,
3008
-            $this->_template_args,
3009
-            true
3010
-        );
3011
-        // the final template wrapper
3012
-        if ($sidebar) {
3013
-            $this->display_admin_page_with_sidebar();
3014
-        } else {
3015
-            $this->display_admin_page_with_no_sidebar();
3016
-        }
3017
-    }
3018
-
3019
-
3020
-    /**
3021
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3022
-     * html string for the legend.
3023
-     * $items are expected in an array in the following format:
3024
-     * $legend_items = array(
3025
-     *        'item_id' => array(
3026
-     *            'icon' => 'http://url_to_icon_being_described.png',
3027
-     *            'desc' => esc_html__('localized description of item');
3028
-     *        )
3029
-     * );
3030
-     *
3031
-     * @param array $items see above for format of array
3032
-     * @return string html string of legend
3033
-     * @throws DomainException
3034
-     */
3035
-    protected function _display_legend(array $items): string
3036
-    {
3037
-        $this->_template_args['items'] = (array) apply_filters(
3038
-            'FHEE__EE_Admin_Page___display_legend__items',
3039
-            $items,
3040
-            $this
3041
-        );
3042
-        /** @var StatusChangeNotice $status_change_notice */
3043
-        $status_change_notice                         = $this->loader->getShared(
3044
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3045
-        );
3046
-        $this->_template_args['status_change_notice'] = $status_change_notice->display(
3047
-            '__admin-legend',
3048
-            $this->page_slug
3049
-        );
3050
-        return EEH_Template::display_template(
3051
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3052
-            $this->_template_args,
3053
-            true
3054
-        );
3055
-    }
3056
-
3057
-
3058
-    /**
3059
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3060
-     * The returned json object is created from an array in the following format:
3061
-     * array(
3062
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3063
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3064
-     *  'notices' => '', // - contains any EE_Error formatted notices
3065
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3066
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3067
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3068
-     *  that might be included in here)
3069
-     * )
3070
-     * The json object is populated by whatever is set in the $_template_args property.
3071
-     *
3072
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3073
-     *                                 instead of displayed.
3074
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3075
-     * @return void
3076
-     * @throws EE_Error
3077
-     * @throws InvalidArgumentException
3078
-     * @throws InvalidDataTypeException
3079
-     * @throws InvalidInterfaceException
3080
-     */
3081
-    protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3082
-    {
3083
-        // make sure any EE_Error notices have been handled.
3084
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3085
-        $data = $this->_template_args['data'] ?? [];
3086
-        unset($this->_template_args['data']);
3087
-        $json = [
3088
-            'error'     => $this->_template_args['error'] ?? false,
3089
-            'success'   => $this->_template_args['success'] ?? false,
3090
-            'errors'    => $this->_template_args['errors'] ?? false,
3091
-            'attention' => $this->_template_args['attention'] ?? false,
3092
-            'notices'   => EE_Error::get_notices(),
3093
-            'content'   => $this->_template_args['admin_page_content'] ?? '',
3094
-            'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3095
-            'isEEajax'  => true,
3096
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3097
-        ];
3098
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3099
-        if (null === error_get_last() || ! headers_sent()) {
3100
-            header('Content-Type: application/json; charset=UTF-8');
3101
-        }
3102
-        echo wp_json_encode($json);
3103
-        exit();
3104
-    }
3105
-
3106
-
3107
-    /**
3108
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3109
-     *
3110
-     * @return void
3111
-     * @throws EE_Error
3112
-     * @throws InvalidArgumentException
3113
-     * @throws InvalidDataTypeException
3114
-     * @throws InvalidInterfaceException
3115
-     */
3116
-    public function return_json()
3117
-    {
3118
-        if ($this->request->isAjax()) {
3119
-            $this->_return_json();
3120
-        } else {
3121
-            throw new EE_Error(
3122
-                sprintf(
3123
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3124
-                    __FUNCTION__
3125
-                )
3126
-            );
3127
-        }
3128
-    }
3129
-
3130
-
3131
-    /**
3132
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3133
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3134
-     *
3135
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3136
-     * @deprecated  5.0.8.p
3137
-     */
3138
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3139
-    {
3140
-        $this->_hook_obj = $hook_obj;
3141
-    }
3142
-
3143
-
3144
-    /**
3145
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3146
-     *
3147
-     * @param bool $about whether to use the special about page wrapper or default.
3148
-     * @return void
3149
-     * @throws DomainException
3150
-     * @throws EE_Error
3151
-     * @throws InvalidArgumentException
3152
-     * @throws InvalidDataTypeException
3153
-     * @throws InvalidInterfaceException
3154
-     */
3155
-    public function admin_page_wrapper(bool $about = false)
3156
-    {
3157
-        $this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3158
-        $this->_template_args['admin_page_title'] = $this->_admin_page_title;
3159
-
3160
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3161
-            "FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3162
-            $this->_template_args['before_admin_page_content'] ?? ''
3163
-        );
3164
-
3165
-        $this->_template_args['after_admin_page_content'] = apply_filters(
3166
-            "FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3167
-            $this->_template_args['after_admin_page_content'] ?? ''
3168
-        );
3169
-        $this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3170
-
3171
-        if ($this->request->isAjax()) {
3172
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3173
-            // $template_path,
3174
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3175
-                $this->_template_args,
3176
-                true
3177
-            );
3178
-            $this->_return_json();
3179
-        }
3180
-        // load settings page wrapper template
3181
-        $template_path = $about
3182
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3183
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3184
-
3185
-        EEH_Template::display_template($template_path, $this->_template_args);
3186
-    }
3187
-
3188
-
3189
-    /**
3190
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3191
-     *
3192
-     * @return string html
3193
-     * @throws EE_Error
3194
-     */
3195
-    protected function _get_main_nav_tabs(): string
3196
-    {
3197
-        // let's generate the html using the EEH_Tabbed_Content helper.
3198
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3199
-        // (rather than setting in the page_routes array)
3200
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3201
-    }
3202
-
3203
-
3204
-    /**
3205
-     *        sort nav tabs
3206
-     *
3207
-     * @param array $a
3208
-     * @param array $b
3209
-     * @return int
3210
-     */
3211
-    private function _sort_nav_tabs(array $a, array $b): int
3212
-    {
3213
-        if ($a['order'] === $b['order']) {
3214
-            return 0;
3215
-        }
3216
-        return ($a['order'] < $b['order']) ? -1 : 1;
3217
-    }
3218
-
3219
-
3220
-    /**
3221
-     * generates HTML for the forms used on admin pages
3222
-     *
3223
-     * @param array  $input_vars - array of input field details
3224
-     * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3225
-     * @param bool   $id
3226
-     * @return array|string
3227
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3228
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3229
-     */
3230
-    protected function _generate_admin_form_fields(
3231
-        array $input_vars = [],
3232
-        string $generator = 'string',
3233
-        bool $id = false
3234
-    ) {
3235
-        return $generator === 'string'
3236
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3237
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3238
-    }
3239
-
3240
-
3241
-    /**
3242
-     * generates the "Save" and "Save & Close" buttons for edit forms
3243
-     *
3244
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3245
-     *                                   Close" button.
3246
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3247
-     *                                   'Save', [1] => 'save & close')
3248
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3249
-     *                                   via the "name" value in the button).  We can also use this to just dump
3250
-     *                                   default actions by submitting some other value.
3251
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3252
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3253
-     *                                   close (normal form handling).
3254
-     */
3255
-    protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3256
-    {
3257
-        $referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3258
-        $button_text   = ! empty($text)
3259
-            ? $text
3260
-            : [
3261
-                esc_html__('Save', 'event_espresso'),
3262
-                esc_html__('Save and Close', 'event_espresso'),
3263
-            ];
3264
-        $default_names = ['save', 'save_and_close'];
3265
-        $buttons       = '';
3266
-        foreach ($button_text as $key => $button) {
3267
-            $ref     = $default_names[ $key ];
3268
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3269
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3270
-                        . 'value="' . $button . '" name="' . $name . '" '
3271
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3272
-            if (! $both) {
3273
-                break;
3274
-            }
3275
-        }
3276
-        // add in a hidden index for the current page (so save and close redirects properly)
3277
-        $buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3278
-                    . $referrer_url
3279
-                    . '" />';
3280
-
3281
-        $this->_template_args['save_buttons'] = $buttons;
3282
-    }
3283
-
3284
-
3285
-    /**
3286
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3287
-     *
3288
-     * @param string $route
3289
-     * @param array  $additional_hidden_fields
3290
-     * @see   $this->_set_add_edit_form_tags() for details on params
3291
-     * @since 4.6.0
3292
-     */
3293
-    public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3294
-    {
3295
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3296
-    }
3297
-
3298
-
3299
-    /**
3300
-     * set form open and close tags on add/edit pages.
3301
-     *
3302
-     * @param string $route                    the route you want the form to direct to
3303
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3304
-     * @return void
3305
-     */
3306
-    protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3307
-    {
3308
-        if (empty($route)) {
3309
-            $user_msg = esc_html__(
3310
-                'An error occurred. No action was set for this page\'s form.',
3311
-                'event_espresso'
3312
-            );
3313
-            $dev_msg  = $user_msg . "\n"
3314
-                        . sprintf(
3315
-                            esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3316
-                            __FUNCTION__,
3317
-                            __CLASS__
3318
-                        );
3319
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3320
-        }
3321
-        // open form
3322
-        $action                                            = $this->_admin_base_url;
3323
-        $this->_template_args['before_admin_page_content'] = "
2955
+		$this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2956
+		// display message about search results?
2957
+		$search                                    = $this->request->getRequestParam('s');
2958
+		$this->_template_args['before_list_table'] .= ! empty($search)
2959
+			? '<p class="ee-search-results">' . sprintf(
2960
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2961
+				trim($search, '%')
2962
+			) . '</p>'
2963
+			: '';
2964
+		// filter before_list_table template arg
2965
+		$this->_template_args['before_list_table'] = apply_filters(
2966
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2967
+			$this->_template_args['before_list_table'],
2968
+			$this->page_slug,
2969
+			$this->request->requestParams(),
2970
+			$this->_req_action
2971
+		);
2972
+		// convert to array and filter again
2973
+		// arrays are easier to inject new items in a specific location,
2974
+		// but would not be backwards compatible, so we have to add a new filter
2975
+		$this->_template_args['before_list_table'] = implode(
2976
+			" \n",
2977
+			(array) apply_filters(
2978
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2979
+				(array) $this->_template_args['before_list_table'],
2980
+				$this->page_slug,
2981
+				$this->request->requestParams(),
2982
+				$this->_req_action
2983
+			)
2984
+		);
2985
+		// filter after_list_table template arg
2986
+		$this->_template_args['after_list_table'] = apply_filters(
2987
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
2988
+			$this->_template_args['after_list_table'],
2989
+			$this->page_slug,
2990
+			$this->request->requestParams(),
2991
+			$this->_req_action
2992
+		);
2993
+		// convert to array and filter again
2994
+		// arrays are easier to inject new items in a specific location,
2995
+		// but would not be backwards compatible, so we have to add a new filter
2996
+		$this->_template_args['after_list_table']   = implode(
2997
+			" \n",
2998
+			(array) apply_filters(
2999
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3000
+				(array) $this->_template_args['after_list_table'],
3001
+				$this->page_slug,
3002
+				$this->request->requestParams(),
3003
+				$this->_req_action
3004
+			)
3005
+		);
3006
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3007
+			$template_path,
3008
+			$this->_template_args,
3009
+			true
3010
+		);
3011
+		// the final template wrapper
3012
+		if ($sidebar) {
3013
+			$this->display_admin_page_with_sidebar();
3014
+		} else {
3015
+			$this->display_admin_page_with_no_sidebar();
3016
+		}
3017
+	}
3018
+
3019
+
3020
+	/**
3021
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3022
+	 * html string for the legend.
3023
+	 * $items are expected in an array in the following format:
3024
+	 * $legend_items = array(
3025
+	 *        'item_id' => array(
3026
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3027
+	 *            'desc' => esc_html__('localized description of item');
3028
+	 *        )
3029
+	 * );
3030
+	 *
3031
+	 * @param array $items see above for format of array
3032
+	 * @return string html string of legend
3033
+	 * @throws DomainException
3034
+	 */
3035
+	protected function _display_legend(array $items): string
3036
+	{
3037
+		$this->_template_args['items'] = (array) apply_filters(
3038
+			'FHEE__EE_Admin_Page___display_legend__items',
3039
+			$items,
3040
+			$this
3041
+		);
3042
+		/** @var StatusChangeNotice $status_change_notice */
3043
+		$status_change_notice                         = $this->loader->getShared(
3044
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3045
+		);
3046
+		$this->_template_args['status_change_notice'] = $status_change_notice->display(
3047
+			'__admin-legend',
3048
+			$this->page_slug
3049
+		);
3050
+		return EEH_Template::display_template(
3051
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3052
+			$this->_template_args,
3053
+			true
3054
+		);
3055
+	}
3056
+
3057
+
3058
+	/**
3059
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3060
+	 * The returned json object is created from an array in the following format:
3061
+	 * array(
3062
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3063
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3064
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3065
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3066
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3067
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3068
+	 *  that might be included in here)
3069
+	 * )
3070
+	 * The json object is populated by whatever is set in the $_template_args property.
3071
+	 *
3072
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3073
+	 *                                 instead of displayed.
3074
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3075
+	 * @return void
3076
+	 * @throws EE_Error
3077
+	 * @throws InvalidArgumentException
3078
+	 * @throws InvalidDataTypeException
3079
+	 * @throws InvalidInterfaceException
3080
+	 */
3081
+	protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3082
+	{
3083
+		// make sure any EE_Error notices have been handled.
3084
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3085
+		$data = $this->_template_args['data'] ?? [];
3086
+		unset($this->_template_args['data']);
3087
+		$json = [
3088
+			'error'     => $this->_template_args['error'] ?? false,
3089
+			'success'   => $this->_template_args['success'] ?? false,
3090
+			'errors'    => $this->_template_args['errors'] ?? false,
3091
+			'attention' => $this->_template_args['attention'] ?? false,
3092
+			'notices'   => EE_Error::get_notices(),
3093
+			'content'   => $this->_template_args['admin_page_content'] ?? '',
3094
+			'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3095
+			'isEEajax'  => true,
3096
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3097
+		];
3098
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3099
+		if (null === error_get_last() || ! headers_sent()) {
3100
+			header('Content-Type: application/json; charset=UTF-8');
3101
+		}
3102
+		echo wp_json_encode($json);
3103
+		exit();
3104
+	}
3105
+
3106
+
3107
+	/**
3108
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3109
+	 *
3110
+	 * @return void
3111
+	 * @throws EE_Error
3112
+	 * @throws InvalidArgumentException
3113
+	 * @throws InvalidDataTypeException
3114
+	 * @throws InvalidInterfaceException
3115
+	 */
3116
+	public function return_json()
3117
+	{
3118
+		if ($this->request->isAjax()) {
3119
+			$this->_return_json();
3120
+		} else {
3121
+			throw new EE_Error(
3122
+				sprintf(
3123
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3124
+					__FUNCTION__
3125
+				)
3126
+			);
3127
+		}
3128
+	}
3129
+
3130
+
3131
+	/**
3132
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3133
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3134
+	 *
3135
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3136
+	 * @deprecated  5.0.8.p
3137
+	 */
3138
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3139
+	{
3140
+		$this->_hook_obj = $hook_obj;
3141
+	}
3142
+
3143
+
3144
+	/**
3145
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3146
+	 *
3147
+	 * @param bool $about whether to use the special about page wrapper or default.
3148
+	 * @return void
3149
+	 * @throws DomainException
3150
+	 * @throws EE_Error
3151
+	 * @throws InvalidArgumentException
3152
+	 * @throws InvalidDataTypeException
3153
+	 * @throws InvalidInterfaceException
3154
+	 */
3155
+	public function admin_page_wrapper(bool $about = false)
3156
+	{
3157
+		$this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3158
+		$this->_template_args['admin_page_title'] = $this->_admin_page_title;
3159
+
3160
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3161
+			"FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3162
+			$this->_template_args['before_admin_page_content'] ?? ''
3163
+		);
3164
+
3165
+		$this->_template_args['after_admin_page_content'] = apply_filters(
3166
+			"FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3167
+			$this->_template_args['after_admin_page_content'] ?? ''
3168
+		);
3169
+		$this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3170
+
3171
+		if ($this->request->isAjax()) {
3172
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3173
+			// $template_path,
3174
+				EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3175
+				$this->_template_args,
3176
+				true
3177
+			);
3178
+			$this->_return_json();
3179
+		}
3180
+		// load settings page wrapper template
3181
+		$template_path = $about
3182
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3183
+			: EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3184
+
3185
+		EEH_Template::display_template($template_path, $this->_template_args);
3186
+	}
3187
+
3188
+
3189
+	/**
3190
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3191
+	 *
3192
+	 * @return string html
3193
+	 * @throws EE_Error
3194
+	 */
3195
+	protected function _get_main_nav_tabs(): string
3196
+	{
3197
+		// let's generate the html using the EEH_Tabbed_Content helper.
3198
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3199
+		// (rather than setting in the page_routes array)
3200
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3201
+	}
3202
+
3203
+
3204
+	/**
3205
+	 *        sort nav tabs
3206
+	 *
3207
+	 * @param array $a
3208
+	 * @param array $b
3209
+	 * @return int
3210
+	 */
3211
+	private function _sort_nav_tabs(array $a, array $b): int
3212
+	{
3213
+		if ($a['order'] === $b['order']) {
3214
+			return 0;
3215
+		}
3216
+		return ($a['order'] < $b['order']) ? -1 : 1;
3217
+	}
3218
+
3219
+
3220
+	/**
3221
+	 * generates HTML for the forms used on admin pages
3222
+	 *
3223
+	 * @param array  $input_vars - array of input field details
3224
+	 * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3225
+	 * @param bool   $id
3226
+	 * @return array|string
3227
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3228
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3229
+	 */
3230
+	protected function _generate_admin_form_fields(
3231
+		array $input_vars = [],
3232
+		string $generator = 'string',
3233
+		bool $id = false
3234
+	) {
3235
+		return $generator === 'string'
3236
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3237
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3238
+	}
3239
+
3240
+
3241
+	/**
3242
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3243
+	 *
3244
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3245
+	 *                                   Close" button.
3246
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3247
+	 *                                   'Save', [1] => 'save & close')
3248
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3249
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3250
+	 *                                   default actions by submitting some other value.
3251
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3252
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3253
+	 *                                   close (normal form handling).
3254
+	 */
3255
+	protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3256
+	{
3257
+		$referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3258
+		$button_text   = ! empty($text)
3259
+			? $text
3260
+			: [
3261
+				esc_html__('Save', 'event_espresso'),
3262
+				esc_html__('Save and Close', 'event_espresso'),
3263
+			];
3264
+		$default_names = ['save', 'save_and_close'];
3265
+		$buttons       = '';
3266
+		foreach ($button_text as $key => $button) {
3267
+			$ref     = $default_names[ $key ];
3268
+			$name    = ! empty($actions) ? $actions[ $key ] : $ref;
3269
+			$buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3270
+						. 'value="' . $button . '" name="' . $name . '" '
3271
+						. 'id="' . $this->_current_view . '_' . $ref . '" />';
3272
+			if (! $both) {
3273
+				break;
3274
+			}
3275
+		}
3276
+		// add in a hidden index for the current page (so save and close redirects properly)
3277
+		$buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3278
+					. $referrer_url
3279
+					. '" />';
3280
+
3281
+		$this->_template_args['save_buttons'] = $buttons;
3282
+	}
3283
+
3284
+
3285
+	/**
3286
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3287
+	 *
3288
+	 * @param string $route
3289
+	 * @param array  $additional_hidden_fields
3290
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3291
+	 * @since 4.6.0
3292
+	 */
3293
+	public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3294
+	{
3295
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3296
+	}
3297
+
3298
+
3299
+	/**
3300
+	 * set form open and close tags on add/edit pages.
3301
+	 *
3302
+	 * @param string $route                    the route you want the form to direct to
3303
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3304
+	 * @return void
3305
+	 */
3306
+	protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3307
+	{
3308
+		if (empty($route)) {
3309
+			$user_msg = esc_html__(
3310
+				'An error occurred. No action was set for this page\'s form.',
3311
+				'event_espresso'
3312
+			);
3313
+			$dev_msg  = $user_msg . "\n"
3314
+						. sprintf(
3315
+							esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3316
+							__FUNCTION__,
3317
+							__CLASS__
3318
+						);
3319
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3320
+		}
3321
+		// open form
3322
+		$action                                            = $this->_admin_base_url;
3323
+		$this->_template_args['before_admin_page_content'] = "
3324 3324
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3325 3325
             ";
3326
-        // add nonce
3327
-        $nonce                                             =
3328
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3329
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3330
-        // add REQUIRED form action
3331
-        $hidden_fields = [
3332
-            'action' => ['type' => 'hidden', 'value' => $route],
3333
-        ];
3334
-        // merge arrays
3335
-        $hidden_fields = is_array($additional_hidden_fields)
3336
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3337
-            : $hidden_fields;
3338
-        // generate form fields
3339
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3340
-        // add fields to form
3341
-        foreach ((array) $form_fields as $form_field) {
3342
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3343
-        }
3344
-        // close form
3345
-        $this->_template_args['after_admin_page_content'] = '</form>';
3346
-    }
3347
-
3348
-
3349
-    /**
3350
-     * Public Wrapper for _redirect_after_action() method since its
3351
-     * discovered it would be useful for external code to have access.
3352
-     *
3353
-     * @param bool|int $success
3354
-     * @param string   $what
3355
-     * @param string   $action_desc
3356
-     * @param array    $query_args
3357
-     * @param bool     $override_overwrite
3358
-     * @throws EE_Error
3359
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3360
-     * @since 4.5.0
3361
-     */
3362
-    public function redirect_after_action(
3363
-        $success = false,
3364
-        string $what = 'item',
3365
-        string $action_desc = 'processed',
3366
-        array $query_args = [],
3367
-        bool $override_overwrite = false
3368
-    ) {
3369
-        $this->_redirect_after_action(
3370
-            $success,
3371
-            $what,
3372
-            $action_desc,
3373
-            $query_args,
3374
-            $override_overwrite
3375
-        );
3376
-    }
3377
-
3378
-
3379
-    /**
3380
-     * Helper method for merging existing request data with the returned redirect url.
3381
-     * This is typically used for redirects after an action so that if the original view was a filtered view those
3382
-     * filters are still applied.
3383
-     *
3384
-     * @param array $new_route_data
3385
-     * @return array
3386
-     */
3387
-    protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3388
-    {
3389
-        foreach ($this->request->requestParams() as $ref => $value) {
3390
-            // unset nonces
3391
-            if (strpos($ref, 'nonce') !== false) {
3392
-                $this->request->unSetRequestParam($ref);
3393
-                continue;
3394
-            }
3395
-            // urlencode values.
3396
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3397
-            $this->request->setRequestParam($ref, $value);
3398
-        }
3399
-        return array_merge($this->request->requestParams(), $new_route_data);
3400
-    }
3401
-
3402
-
3403
-    /**
3404
-     * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3405
-     * @param string           $what               - what the action was performed on
3406
-     * @param string           $action_desc        - what was done ie: updated, deleted, etc
3407
-     * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3408
-     * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3409
-     *                                             this allows you to override this so that they show.
3410
-     * @return void
3411
-     * @throws EE_Error
3412
-     * @throws InvalidArgumentException
3413
-     * @throws InvalidDataTypeException
3414
-     * @throws InvalidInterfaceException
3415
-     */
3416
-    protected function _redirect_after_action(
3417
-        $success = 0,
3418
-        string $what = 'item',
3419
-        string $action_desc = 'processed',
3420
-        array $query_args = [],
3421
-        bool $override_overwrite = false
3422
-    ) {
3423
-        $notices = EE_Error::get_notices(false);
3424
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3425
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3426
-            EE_Error::overwrite_success();
3427
-        }
3428
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3429
-            // how many records affected ? more than one record ? or just one ?
3430
-            EE_Error::add_success(
3431
-                sprintf(
3432
-                    esc_html(
3433
-                        _n(
3434
-                            'The "%1$s" has been successfully %2$s.',
3435
-                            'The "%1$s" have been successfully %2$s.',
3436
-                            $success,
3437
-                            'event_espresso'
3438
-                        )
3439
-                    ),
3440
-                    $what,
3441
-                    $action_desc
3442
-                ),
3443
-                __FILE__,
3444
-                __FUNCTION__,
3445
-                __LINE__
3446
-            );
3447
-        }
3448
-        // check that $query_args isn't something crazy
3449
-        $query_args = is_array($query_args) ? $query_args : [];
3450
-        /**
3451
-         * Allow injecting actions before the query_args are modified for possible different
3452
-         * redirections on save and close actions
3453
-         *
3454
-         * @param array $query_args       The original query_args array coming into the
3455
-         *                                method.
3456
-         * @since 4.2.0
3457
-         */
3458
-        do_action(
3459
-            "AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3460
-            $query_args
3461
-        );
3462
-        // set redirect url.
3463
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3464
-        // otherwise we go with whatever is set as the _admin_base_url
3465
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3466
-        // calculate where we're going (if we have a "save and close" button pushed)
3467
-        if (
3468
-            $this->request->requestParamIsSet('save_and_close')
3469
-            && $this->request->requestParamIsSet('save_and_close_referrer')
3470
-        ) {
3471
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3472
-            $parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3473
-            // regenerate query args array from referrer URL
3474
-            parse_str($parsed_url['query'], $query_args);
3475
-            // correct page and action will be in the query args now
3476
-            $redirect_url = admin_url('admin.php');
3477
-        }
3478
-        // merge any default query_args set in _default_route_query_args property
3479
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3480
-            $args_to_merge = [];
3481
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3482
-                // is there a wp_referer array in our _default_route_query_args property?
3483
-                if ($query_param === 'wp_referer') {
3484
-                    $query_value = (array) $query_value;
3485
-                    foreach ($query_value as $reference => $value) {
3486
-                        if (strpos($reference, 'nonce') !== false) {
3487
-                            continue;
3488
-                        }
3489
-                        // finally we will override any arguments in the referer with
3490
-                        // what might be set on the _default_route_query_args array.
3491
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3492
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3493
-                        } else {
3494
-                            $args_to_merge[ $reference ] = urlencode($value);
3495
-                        }
3496
-                    }
3497
-                    continue;
3498
-                }
3499
-                $args_to_merge[ $query_param ] = $query_value;
3500
-            }
3501
-            // now let's merge these arguments but override with what was specifically sent in to the
3502
-            // redirect.
3503
-            $query_args = array_merge($args_to_merge, $query_args);
3504
-        }
3505
-        $this->_process_notices($query_args);
3506
-        // generate redirect url
3507
-        // if redirecting to anything other than the main page, add a nonce
3508
-        if (isset($query_args['action'])) {
3509
-            // manually generate wp_nonce and merge that with the query vars
3510
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3511
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3512
-        }
3513
-        // we're adding some hooks and filters in here for processing any things just before redirects
3514
-        // (example: an admin page has done an insert or update and we want to run something after that).
3515
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3516
-        $redirect_url = apply_filters(
3517
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3518
-            EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3519
-            $query_args
3520
-        );
3521
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3522
-        if ($this->request->isAjax()) {
3523
-            $default_data                    = [
3524
-                'close'        => true,
3525
-                'redirect_url' => $redirect_url,
3526
-                'where'        => 'main',
3527
-                'what'         => 'append',
3528
-            ];
3529
-            $this->_template_args['success'] = $success;
3530
-            $this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3531
-                $default_data,
3532
-                $this->_template_args['data']
3533
-            ) : $default_data;
3534
-            $this->_return_json();
3535
-        }
3536
-        wp_safe_redirect($redirect_url);
3537
-        exit();
3538
-    }
3539
-
3540
-
3541
-    /**
3542
-     * process any notices before redirecting (or returning ajax request)
3543
-     * This method sets the $this->_template_args['notices'] attribute;
3544
-     *
3545
-     * @param array $query_args         any query args that need to be used for notice transient ('action')
3546
-     * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3547
-     *                                  page_routes haven't been defined yet.
3548
-     * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3549
-     *                                  still save a transient for the notice.
3550
-     * @return void
3551
-     * @throws EE_Error
3552
-     * @throws InvalidArgumentException
3553
-     * @throws InvalidDataTypeException
3554
-     * @throws InvalidInterfaceException
3555
-     */
3556
-    protected function _process_notices(
3557
-        array $query_args = [],
3558
-        bool $skip_route_verify = false,
3559
-        bool $sticky_notices = true
3560
-    ) {
3561
-        // first let's set individual error properties if doing_ajax and the properties aren't already set.
3562
-        if ($this->request->isAjax()) {
3563
-            $notices = EE_Error::get_notices(false);
3564
-            if (empty($this->_template_args['success'])) {
3565
-                $this->_template_args['success'] = $notices['success'] ?? false;
3566
-            }
3567
-            if (empty($this->_template_args['errors'])) {
3568
-                $this->_template_args['errors'] = $notices['errors'] ?? false;
3569
-            }
3570
-            if (empty($this->_template_args['attention'])) {
3571
-                $this->_template_args['attention'] = $notices['attention'] ?? false;
3572
-            }
3573
-        }
3574
-        $this->_template_args['notices'] = EE_Error::get_notices();
3575
-        // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3576
-        if (! $this->request->isAjax() || $sticky_notices) {
3577
-            $route = $query_args['action'] ?? 'default';
3578
-            $this->_add_transient(
3579
-                $route,
3580
-                (array) $this->_template_args['notices'],
3581
-                true,
3582
-                $skip_route_verify
3583
-            );
3584
-        }
3585
-    }
3586
-
3587
-
3588
-    /**
3589
-     * get_action_link_or_button
3590
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3591
-     *
3592
-     * @param string $action        use this to indicate which action the url is generated with.
3593
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3594
-     *                              property.
3595
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3596
-     * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3597
-     * @param string $base_url      If this is not provided
3598
-     *                              the _admin_base_url will be used as the default for the button base_url.
3599
-     *                              Otherwise this value will be used.
3600
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3601
-     * @return string
3602
-     * @throws InvalidArgumentException
3603
-     * @throws InvalidInterfaceException
3604
-     * @throws InvalidDataTypeException
3605
-     * @throws EE_Error
3606
-     */
3607
-    public function get_action_link_or_button(
3608
-        string $action,
3609
-        string $type = 'add',
3610
-        array $extra_request = [],
3611
-        string $class = 'button button--primary',
3612
-        string $base_url = '',
3613
-        bool $exclude_nonce = false
3614
-    ): string {
3615
-        // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3616
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3617
-            throw new EE_Error(
3618
-                sprintf(
3619
-                    esc_html__(
3620
-                        'There is no page route for given action for the button.  This action was given: %s',
3621
-                        'event_espresso'
3622
-                    ),
3623
-                    $action
3624
-                )
3625
-            );
3626
-        }
3627
-        if (! isset($this->_labels['buttons'][ $type ])) {
3628
-            throw new EE_Error(
3629
-                sprintf(
3630
-                    esc_html__(
3631
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3632
-                        'event_espresso'
3633
-                    ),
3634
-                    $type
3635
-                )
3636
-            );
3637
-        }
3638
-        // finally check user access for this button.
3639
-        $has_access = $this->check_user_access($action, true);
3640
-        if (! $has_access) {
3641
-            return '';
3642
-        }
3643
-        $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3644
-        $query_args = [
3645
-            'action' => $action,
3646
-        ];
3647
-        // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3648
-        if (! empty($extra_request)) {
3649
-            $query_args = array_merge($extra_request, $query_args);
3650
-        }
3651
-        $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3652
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3653
-    }
3654
-
3655
-
3656
-    /**
3657
-     * _per_page_screen_option
3658
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3659
-     *
3660
-     * @return void
3661
-     * @throws InvalidArgumentException
3662
-     * @throws InvalidInterfaceException
3663
-     * @throws InvalidDataTypeException
3664
-     */
3665
-    protected function _per_page_screen_option()
3666
-    {
3667
-        $option = 'per_page';
3668
-        $args   = [
3669
-            'label'   => apply_filters(
3670
-                'FHEE__EE_Admin_Page___per_page_screen_options___label',
3671
-                $this->_admin_page_title,
3672
-                $this
3673
-            ),
3674
-            'default' => (int) apply_filters(
3675
-                'FHEE__EE_Admin_Page___per_page_screen_options__default',
3676
-                20
3677
-            ),
3678
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3679
-        ];
3680
-        // ONLY add the screen option if the user has access to it.
3681
-        if ($this->check_user_access($this->_current_view, true)) {
3682
-            add_screen_option($option, $args);
3683
-        }
3684
-    }
3685
-
3686
-
3687
-    /**
3688
-     * set_per_page_screen_option
3689
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3690
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3691
-     * admin_menu.
3692
-     *
3693
-     * @return void
3694
-     */
3695
-    private function _set_per_page_screen_options()
3696
-    {
3697
-        if ($this->request->requestParamIsSet('wp_screen_options')) {
3698
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3699
-            if (! $user = wp_get_current_user()) {
3700
-                return;
3701
-            }
3702
-            $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3703
-            if (! $option) {
3704
-                return;
3705
-            }
3706
-            $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3707
-            $map_option = $option;
3708
-            $option     = str_replace('-', '_', $option);
3709
-            switch ($map_option) {
3710
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3711
-                    $max_value = apply_filters(
3712
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3713
-                        999,
3714
-                        $this->_current_page,
3715
-                        $this->_current_view
3716
-                    );
3717
-                    if ($value < 1) {
3718
-                        return;
3719
-                    }
3720
-                    $value = min($value, $max_value);
3721
-                    break;
3722
-                default:
3723
-                    $value = apply_filters(
3724
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3725
-                        false,
3726
-                        $option,
3727
-                        $value
3728
-                    );
3729
-                    if (false === $value) {
3730
-                        return;
3731
-                    }
3732
-                    break;
3733
-            }
3734
-            update_user_meta($user->ID, $option, $value);
3735
-            wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3736
-            exit;
3737
-        }
3738
-    }
3739
-
3740
-
3741
-    /**
3742
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3743
-     *
3744
-     * @param array $data array that will be assigned to template args.
3745
-     */
3746
-    public function set_template_args(array $data)
3747
-    {
3748
-        $this->_template_args = array_merge($this->_template_args, $data);
3749
-    }
3750
-
3751
-
3752
-    public function setAdminPageTitle(string $title)
3753
-    {
3754
-        $this->_admin_page_title = sanitize_text_field($title);
3755
-    }
3756
-
3757
-
3758
-    /**
3759
-     * This makes available the WP transient system for temporarily moving data between routes
3760
-     *
3761
-     * @param string $route             the route that should receive the transient
3762
-     * @param array  $data              the data that gets sent
3763
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3764
-     *                                  normal route transient.
3765
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3766
-     *                                  when we are adding a transient before page_routes have been defined.
3767
-     * @return void
3768
-     * @throws EE_Error
3769
-     */
3770
-    protected function _add_transient(
3771
-        string $route,
3772
-        array $data,
3773
-        bool $notices = false,
3774
-        bool $skip_route_verify = false
3775
-    ) {
3776
-        $user_id = get_current_user_id();
3777
-        if (! $skip_route_verify) {
3778
-            $this->_verify_route($route);
3779
-        }
3780
-        // now let's set the string for what kind of transient we're setting
3781
-        $transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3782
-        $data      = $notices ? ['notices' => $data] : $data;
3783
-        // is there already a transient for this route?  If there is then let's ADD to that transient
3784
-        $existing = is_multisite() && is_network_admin()
3785
-            ? get_site_transient($transient)
3786
-            : get_transient($transient);
3787
-        if ($existing) {
3788
-            $data = array_merge($data, (array) $existing);
3789
-        }
3790
-        if (is_multisite() && is_network_admin()) {
3791
-            set_site_transient($transient, $data, 8);
3792
-        } else {
3793
-            set_transient($transient, $data, 8);
3794
-        }
3795
-    }
3796
-
3797
-
3798
-    /**
3799
-     * this retrieves the temporary transient that has been set for moving data between routes.
3800
-     *
3801
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3802
-     * @param string $route
3803
-     * @return mixed data
3804
-     */
3805
-    protected function _get_transient(bool $notices = false, string $route = '')
3806
-    {
3807
-        $user_id   = get_current_user_id();
3808
-        $route     = ! $route ? $this->_req_action : $route;
3809
-        $transient = $notices
3810
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3811
-            : 'rte_tx_' . $route . '_' . $user_id;
3812
-        $data      = is_multisite() && is_network_admin()
3813
-            ? get_site_transient($transient)
3814
-            : get_transient($transient);
3815
-        // delete transient after retrieval (just in case it hasn't expired);
3816
-        if (is_multisite() && is_network_admin()) {
3817
-            delete_site_transient($transient);
3818
-        } else {
3819
-            delete_transient($transient);
3820
-        }
3821
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3822
-    }
3823
-
3824
-
3825
-    /**
3826
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3827
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3828
-     * default route callback on the EE_Admin page you want it run.)
3829
-     *
3830
-     * @return void
3831
-     */
3832
-    protected function _transient_garbage_collection()
3833
-    {
3834
-        global $wpdb;
3835
-        // retrieve all existing transients
3836
-        $query =
3837
-            "SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3838
-        if ($results = $wpdb->get_results($query)) {
3839
-            foreach ($results as $result) {
3840
-                $transient = str_replace('_transient_', '', $result->option_name);
3841
-                get_transient($transient);
3842
-                if (is_multisite() && is_network_admin()) {
3843
-                    get_site_transient($transient);
3844
-                }
3845
-            }
3846
-        }
3847
-    }
3848
-
3849
-
3850
-    /**
3851
-     * get_view
3852
-     *
3853
-     * @return string content of _view property
3854
-     */
3855
-    public function get_view(): string
3856
-    {
3857
-        return $this->_view;
3858
-    }
3859
-
3860
-
3861
-    /**
3862
-     * getter for the protected $_views property
3863
-     *
3864
-     * @return array
3865
-     */
3866
-    public function get_views(): array
3867
-    {
3868
-        return $this->_views;
3869
-    }
3870
-
3871
-
3872
-    /**
3873
-     * @param array $views
3874
-     * @return void
3875
-     * @since 5.0.13.p
3876
-     */
3877
-    public function updateViews(array $views)
3878
-    {
3879
-        $this->_views = array_merge($this->_views, $views);
3880
-    }
3881
-
3882
-
3883
-    /**
3884
-    /**
3885
-     * get_current_page
3886
-     *
3887
-     * @return string _current_page property value
3888
-     */
3889
-    public function get_current_page(): string
3890
-    {
3891
-        return $this->_current_page;
3892
-    }
3893
-
3894
-
3895
-    /**
3896
-     * get_current_view
3897
-     *
3898
-     * @return string _current_view property value
3899
-     */
3900
-    public function get_current_view(): string
3901
-    {
3902
-        return $this->_current_view;
3903
-    }
3904
-
3905
-
3906
-    /**
3907
-     * get_current_screen
3908
-     *
3909
-     * @return object The current WP_Screen object
3910
-     */
3911
-    public function get_current_screen()
3912
-    {
3913
-        return $this->_current_screen;
3914
-    }
3915
-
3916
-
3917
-    /**
3918
-     * get_current_page_view_url
3919
-     *
3920
-     * @return string This returns the url for the current_page_view.
3921
-     */
3922
-    public function get_current_page_view_url(): string
3923
-    {
3924
-        return $this->_current_page_view_url;
3925
-    }
3926
-
3927
-
3928
-    /**
3929
-     * just returns the Request
3930
-     *
3931
-     * @return RequestInterface
3932
-     */
3933
-    public function get_request(): ?RequestInterface
3934
-    {
3935
-        return $this->request;
3936
-    }
3937
-
3938
-
3939
-    /**
3940
-     * just returns the _req_data property
3941
-     *
3942
-     * @return array
3943
-     */
3944
-    public function get_request_data(): array
3945
-    {
3946
-        return $this->request->requestParams();
3947
-    }
3948
-
3949
-
3950
-    /**
3951
-     * returns the _req_data protected property
3952
-     *
3953
-     * @return string
3954
-     */
3955
-    public function get_req_action(): string
3956
-    {
3957
-        return $this->_req_action;
3958
-    }
3959
-
3960
-
3961
-    /**
3962
-     * @return bool  value of $_is_caf property
3963
-     */
3964
-    public function is_caf(): bool
3965
-    {
3966
-        return $this->_is_caf;
3967
-    }
3968
-
3969
-
3970
-    /**
3971
-     * @return array
3972
-     */
3973
-    public function default_espresso_metaboxes(): array
3974
-    {
3975
-        return $this->_default_espresso_metaboxes;
3976
-    }
3977
-
3978
-
3979
-    /**
3980
-     * @return string
3981
-     */
3982
-    public function admin_base_url(): string
3983
-    {
3984
-        return $this->_admin_base_url;
3985
-    }
3986
-
3987
-
3988
-    /**
3989
-     * @return string
3990
-     */
3991
-    public function wp_page_slug(): string
3992
-    {
3993
-        return $this->_wp_page_slug;
3994
-    }
3995
-
3996
-
3997
-    /**
3998
-     * updates  espresso configuration settings
3999
-     *
4000
-     * @param string                   $tab
4001
-     * @param EE_Config_Base|EE_Config $config
4002
-     * @param string                   $file file where error occurred
4003
-     * @param string                   $func function  where error occurred
4004
-     * @param string                   $line line no where error occurred
4005
-     * @return bool
4006
-     */
4007
-    protected function _update_espresso_configuration(
4008
-        string $tab,
4009
-        $config,
4010
-        string $file = '',
4011
-        string $func = '',
4012
-        string $line = ''
4013
-    ): bool {
4014
-        // remove any options that are NOT going to be saved with the config settings.
4015
-        if (isset($config->core->ee_ueip_optin)) {
4016
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4017
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4018
-            update_option('ee_ueip_has_notified', true);
4019
-        }
4020
-        // and save it (note we're also doing the network save here)
4021
-        $net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4022
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4023
-        if ($config_saved && $net_saved) {
4024
-            EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4025
-            return true;
4026
-        }
4027
-        EE_Error::add_error(
4028
-            sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4029
-            $file,
4030
-            $func,
4031
-            $line
4032
-        );
4033
-        return false;
4034
-    }
4035
-
4036
-
4037
-    /**
4038
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4039
-     *
4040
-     * @return array
4041
-     */
4042
-    public function get_yes_no_values(): array
4043
-    {
4044
-        return $this->_yes_no_values;
4045
-    }
4046
-
4047
-
4048
-    /**
4049
-     * @return string
4050
-     * @throws ReflectionException
4051
-     * @since 5.0.0.p
4052
-     */
4053
-    protected function _get_dir(): string
4054
-    {
4055
-        $reflector = new ReflectionClass($this->class_name);
4056
-        return dirname($reflector->getFileName());
4057
-    }
4058
-
4059
-
4060
-    /**
4061
-     * A helper for getting a "next link".
4062
-     *
4063
-     * @param string $url   The url to link to
4064
-     * @param string $class The class to use.
4065
-     * @return string
4066
-     */
4067
-    protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4068
-    {
4069
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4070
-    }
4071
-
4072
-
4073
-    /**
4074
-     * A helper for getting a "previous link".
4075
-     *
4076
-     * @param string $url   The url to link to
4077
-     * @param string $class The class to use.
4078
-     * @return string
4079
-     */
4080
-    protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4081
-    {
4082
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4083
-    }
4084
-
4085
-
4086
-
4087
-
4088
-
4089
-
4090
-
4091
-    // below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4092
-
4093
-
4094
-    /**
4095
-     * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4096
-     * 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
4097
-     * _req_data array.
4098
-     *
4099
-     * @return bool success/fail
4100
-     * @throws EE_Error
4101
-     * @throws InvalidArgumentException
4102
-     * @throws ReflectionException
4103
-     * @throws InvalidDataTypeException
4104
-     * @throws InvalidInterfaceException
4105
-     */
4106
-    protected function _process_resend_registration(): bool
4107
-    {
4108
-        $this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4109
-        do_action(
4110
-            'AHEE__EE_Admin_Page___process_resend_registration',
4111
-            $this->_template_args['success'],
4112
-            $this->request->requestParams()
4113
-        );
4114
-        return $this->_template_args['success'];
4115
-    }
4116
-
4117
-
4118
-    /**
4119
-     * This automatically processes any payment message notifications when manual payment has been applied.
4120
-     *
4121
-     * @param EE_Payment $payment
4122
-     * @return bool success/fail
4123
-     */
4124
-    protected function _process_payment_notification(EE_Payment $payment): bool
4125
-    {
4126
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4127
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4128
-        $this->_template_args['success'] = apply_filters(
4129
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4130
-            false,
4131
-            $payment
4132
-        );
4133
-        return $this->_template_args['success'];
4134
-    }
4135
-
4136
-
4137
-    /**
4138
-     * @param EEM_Base      $entity_model
4139
-     * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4140
-     * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4141
-     * @param string        $delete_column  name of the field that denotes whether entity is trashed
4142
-     * @param callable|null $callback       called after entity is trashed, restored, or deleted
4143
-     * @return int|float
4144
-     * @throws EE_Error
4145
-     */
4146
-    protected function trashRestoreDeleteEntities(
4147
-        EEM_Base $entity_model,
4148
-        string $entity_PK_name,
4149
-        string $action = EE_Admin_List_Table::ACTION_DELETE,
4150
-        string $delete_column = '',
4151
-        ?callable $callback = null
4152
-    ) {
4153
-        $entity_PK      = $entity_model->get_primary_key_field();
4154
-        $entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4155
-        $entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4156
-        // grab ID if deleting a single entity
4157
-        if ($this->request->requestParamIsSet($entity_PK_name)) {
4158
-            $ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4159
-            return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4160
-        }
4161
-        // or grab checkbox array if bulk deleting
4162
-        $checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4163
-        if (empty($checkboxes)) {
4164
-            return 0;
4165
-        }
4166
-        $success = 0;
4167
-        $IDs     = array_keys($checkboxes);
4168
-        // cycle thru bulk action checkboxes
4169
-        foreach ($IDs as $ID) {
4170
-            // increment $success
4171
-            if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4172
-                $success++;
4173
-            }
4174
-        }
4175
-        $count = (int) count($checkboxes);
4176
-        // if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4177
-        // otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4178
-        return $success === $count ? $count : $success / $count;
4179
-    }
4180
-
4181
-
4182
-    /**
4183
-     * @param EE_Primary_Key_Field_Base $entity_PK
4184
-     * @return string
4185
-     * @throws EE_Error
4186
-     * @since   4.10.30.p
4187
-     */
4188
-    private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4189
-    {
4190
-        $entity_PK_type = $entity_PK->getSchemaType();
4191
-        switch ($entity_PK_type) {
4192
-            case 'boolean':
4193
-                return DataType::BOOL;
4194
-            case 'integer':
4195
-                return DataType::INT;
4196
-            case 'number':
4197
-                return DataType::FLOAT;
4198
-            case 'string':
4199
-                return DataType::STRING;
4200
-        }
4201
-        throw new RuntimeException(
4202
-            sprintf(
4203
-                esc_html__(
4204
-                    '"%1$s" is an invalid schema type for the %2$s primary key.',
4205
-                    'event_espresso'
4206
-                ),
4207
-                $entity_PK_type,
4208
-                $entity_PK->get_name()
4209
-            )
4210
-        );
4211
-    }
4212
-
4213
-
4214
-    /**
4215
-     * @param EEM_Base      $entity_model
4216
-     * @param int|string    $entity_ID
4217
-     * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4218
-     * @param string        $delete_column name of the field that denotes whether entity is trashed
4219
-     * @param callable|null $callback      called after entity is trashed, restored, or deleted
4220
-     * @return bool
4221
-     */
4222
-    protected function trashRestoreDeleteEntity(
4223
-        EEM_Base $entity_model,
4224
-        $entity_ID,
4225
-        string $action,
4226
-        string $delete_column,
4227
-        ?callable $callback = null
4228
-    ): bool {
4229
-        $entity_ID = absint($entity_ID);
4230
-        if (! $entity_ID) {
4231
-            $this->trashRestoreDeleteError($action, $entity_model);
4232
-        }
4233
-        $result = 0;
4234
-        try {
4235
-            $entity = $entity_model->get_one_by_ID($entity_ID);
4236
-            if (! $entity instanceof EE_Base_Class) {
4237
-                throw new DomainException(
4238
-                    sprintf(
4239
-                        esc_html__(
4240
-                            'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4241
-                            'event_espresso'
4242
-                        ),
4243
-                        str_replace('EEM_', '', $entity_model->get_this_model_name()),
4244
-                        $entity_ID
4245
-                    )
4246
-                );
4247
-            }
4248
-            switch ($action) {
4249
-                case EE_Admin_List_Table::ACTION_DELETE:
4250
-                    $result = (bool) $entity->delete_permanently();
4251
-                    break;
4252
-                case EE_Admin_List_Table::ACTION_RESTORE:
4253
-                    $result = $entity->delete_or_restore(false);
4254
-                    break;
4255
-                case EE_Admin_List_Table::ACTION_TRASH:
4256
-                    $result = $entity->delete_or_restore();
4257
-                    break;
4258
-            }
4259
-        } catch (Exception $exception) {
4260
-            $this->trashRestoreDeleteError($action, $entity_model, $exception);
4261
-        }
4262
-        if (is_callable($callback)) {
4263
-            call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4264
-        }
4265
-        return $result;
4266
-    }
4267
-
4268
-
4269
-    /**
4270
-     * @param EEM_Base $entity_model
4271
-     * @param string   $delete_column
4272
-     * @since 4.10.30.p
4273
-     */
4274
-    private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4275
-    {
4276
-        if (empty($delete_column)) {
4277
-            throw new DomainException(
4278
-                sprintf(
4279
-                    esc_html__(
4280
-                        'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4281
-                        'event_espresso'
4282
-                    ),
4283
-                    $entity_model->get_this_model_name()
4284
-                )
4285
-            );
4286
-        }
4287
-        if (! $entity_model->has_field($delete_column)) {
4288
-            throw new DomainException(
4289
-                sprintf(
4290
-                    esc_html__(
4291
-                        'The %1$s field does not exist on the %2$s model.',
4292
-                        'event_espresso'
4293
-                    ),
4294
-                    $delete_column,
4295
-                    $entity_model->get_this_model_name()
4296
-                )
4297
-            );
4298
-        }
4299
-    }
4300
-
4301
-
4302
-    /**
4303
-     * @param EEM_Base       $entity_model
4304
-     * @param Exception|null $exception
4305
-     * @param string         $action
4306
-     * @since 4.10.30.p
4307
-     */
4308
-    private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4309
-    {
4310
-        if ($exception instanceof Exception) {
4311
-            throw new RuntimeException(
4312
-                sprintf(
4313
-                    esc_html__(
4314
-                        'Could not %1$s the %2$s because the following error occurred: %3$s',
4315
-                        'event_espresso'
4316
-                    ),
4317
-                    $action,
4318
-                    $entity_model->get_this_model_name(),
4319
-                    $exception->getMessage()
4320
-                )
4321
-            );
4322
-        }
4323
-        throw new RuntimeException(
4324
-            sprintf(
4325
-                esc_html__(
4326
-                    'Could not %1$s the %2$s because an invalid ID was received.',
4327
-                    'event_espresso'
4328
-                ),
4329
-                $action,
4330
-                $entity_model->get_this_model_name()
4331
-            )
4332
-        );
4333
-    }
3326
+		// add nonce
3327
+		$nonce                                             =
3328
+			wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3329
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3330
+		// add REQUIRED form action
3331
+		$hidden_fields = [
3332
+			'action' => ['type' => 'hidden', 'value' => $route],
3333
+		];
3334
+		// merge arrays
3335
+		$hidden_fields = is_array($additional_hidden_fields)
3336
+			? array_merge($hidden_fields, $additional_hidden_fields)
3337
+			: $hidden_fields;
3338
+		// generate form fields
3339
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3340
+		// add fields to form
3341
+		foreach ((array) $form_fields as $form_field) {
3342
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3343
+		}
3344
+		// close form
3345
+		$this->_template_args['after_admin_page_content'] = '</form>';
3346
+	}
3347
+
3348
+
3349
+	/**
3350
+	 * Public Wrapper for _redirect_after_action() method since its
3351
+	 * discovered it would be useful for external code to have access.
3352
+	 *
3353
+	 * @param bool|int $success
3354
+	 * @param string   $what
3355
+	 * @param string   $action_desc
3356
+	 * @param array    $query_args
3357
+	 * @param bool     $override_overwrite
3358
+	 * @throws EE_Error
3359
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3360
+	 * @since 4.5.0
3361
+	 */
3362
+	public function redirect_after_action(
3363
+		$success = false,
3364
+		string $what = 'item',
3365
+		string $action_desc = 'processed',
3366
+		array $query_args = [],
3367
+		bool $override_overwrite = false
3368
+	) {
3369
+		$this->_redirect_after_action(
3370
+			$success,
3371
+			$what,
3372
+			$action_desc,
3373
+			$query_args,
3374
+			$override_overwrite
3375
+		);
3376
+	}
3377
+
3378
+
3379
+	/**
3380
+	 * Helper method for merging existing request data with the returned redirect url.
3381
+	 * This is typically used for redirects after an action so that if the original view was a filtered view those
3382
+	 * filters are still applied.
3383
+	 *
3384
+	 * @param array $new_route_data
3385
+	 * @return array
3386
+	 */
3387
+	protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3388
+	{
3389
+		foreach ($this->request->requestParams() as $ref => $value) {
3390
+			// unset nonces
3391
+			if (strpos($ref, 'nonce') !== false) {
3392
+				$this->request->unSetRequestParam($ref);
3393
+				continue;
3394
+			}
3395
+			// urlencode values.
3396
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3397
+			$this->request->setRequestParam($ref, $value);
3398
+		}
3399
+		return array_merge($this->request->requestParams(), $new_route_data);
3400
+	}
3401
+
3402
+
3403
+	/**
3404
+	 * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3405
+	 * @param string           $what               - what the action was performed on
3406
+	 * @param string           $action_desc        - what was done ie: updated, deleted, etc
3407
+	 * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3408
+	 * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3409
+	 *                                             this allows you to override this so that they show.
3410
+	 * @return void
3411
+	 * @throws EE_Error
3412
+	 * @throws InvalidArgumentException
3413
+	 * @throws InvalidDataTypeException
3414
+	 * @throws InvalidInterfaceException
3415
+	 */
3416
+	protected function _redirect_after_action(
3417
+		$success = 0,
3418
+		string $what = 'item',
3419
+		string $action_desc = 'processed',
3420
+		array $query_args = [],
3421
+		bool $override_overwrite = false
3422
+	) {
3423
+		$notices = EE_Error::get_notices(false);
3424
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3425
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3426
+			EE_Error::overwrite_success();
3427
+		}
3428
+		if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3429
+			// how many records affected ? more than one record ? or just one ?
3430
+			EE_Error::add_success(
3431
+				sprintf(
3432
+					esc_html(
3433
+						_n(
3434
+							'The "%1$s" has been successfully %2$s.',
3435
+							'The "%1$s" have been successfully %2$s.',
3436
+							$success,
3437
+							'event_espresso'
3438
+						)
3439
+					),
3440
+					$what,
3441
+					$action_desc
3442
+				),
3443
+				__FILE__,
3444
+				__FUNCTION__,
3445
+				__LINE__
3446
+			);
3447
+		}
3448
+		// check that $query_args isn't something crazy
3449
+		$query_args = is_array($query_args) ? $query_args : [];
3450
+		/**
3451
+		 * Allow injecting actions before the query_args are modified for possible different
3452
+		 * redirections on save and close actions
3453
+		 *
3454
+		 * @param array $query_args       The original query_args array coming into the
3455
+		 *                                method.
3456
+		 * @since 4.2.0
3457
+		 */
3458
+		do_action(
3459
+			"AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3460
+			$query_args
3461
+		);
3462
+		// set redirect url.
3463
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3464
+		// otherwise we go with whatever is set as the _admin_base_url
3465
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3466
+		// calculate where we're going (if we have a "save and close" button pushed)
3467
+		if (
3468
+			$this->request->requestParamIsSet('save_and_close')
3469
+			&& $this->request->requestParamIsSet('save_and_close_referrer')
3470
+		) {
3471
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3472
+			$parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3473
+			// regenerate query args array from referrer URL
3474
+			parse_str($parsed_url['query'], $query_args);
3475
+			// correct page and action will be in the query args now
3476
+			$redirect_url = admin_url('admin.php');
3477
+		}
3478
+		// merge any default query_args set in _default_route_query_args property
3479
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3480
+			$args_to_merge = [];
3481
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3482
+				// is there a wp_referer array in our _default_route_query_args property?
3483
+				if ($query_param === 'wp_referer') {
3484
+					$query_value = (array) $query_value;
3485
+					foreach ($query_value as $reference => $value) {
3486
+						if (strpos($reference, 'nonce') !== false) {
3487
+							continue;
3488
+						}
3489
+						// finally we will override any arguments in the referer with
3490
+						// what might be set on the _default_route_query_args array.
3491
+						if (isset($this->_default_route_query_args[ $reference ])) {
3492
+							$args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3493
+						} else {
3494
+							$args_to_merge[ $reference ] = urlencode($value);
3495
+						}
3496
+					}
3497
+					continue;
3498
+				}
3499
+				$args_to_merge[ $query_param ] = $query_value;
3500
+			}
3501
+			// now let's merge these arguments but override with what was specifically sent in to the
3502
+			// redirect.
3503
+			$query_args = array_merge($args_to_merge, $query_args);
3504
+		}
3505
+		$this->_process_notices($query_args);
3506
+		// generate redirect url
3507
+		// if redirecting to anything other than the main page, add a nonce
3508
+		if (isset($query_args['action'])) {
3509
+			// manually generate wp_nonce and merge that with the query vars
3510
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3511
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3512
+		}
3513
+		// we're adding some hooks and filters in here for processing any things just before redirects
3514
+		// (example: an admin page has done an insert or update and we want to run something after that).
3515
+		do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3516
+		$redirect_url = apply_filters(
3517
+			'FHEE_redirect_' . $this->class_name . $this->_req_action,
3518
+			EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3519
+			$query_args
3520
+		);
3521
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3522
+		if ($this->request->isAjax()) {
3523
+			$default_data                    = [
3524
+				'close'        => true,
3525
+				'redirect_url' => $redirect_url,
3526
+				'where'        => 'main',
3527
+				'what'         => 'append',
3528
+			];
3529
+			$this->_template_args['success'] = $success;
3530
+			$this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3531
+				$default_data,
3532
+				$this->_template_args['data']
3533
+			) : $default_data;
3534
+			$this->_return_json();
3535
+		}
3536
+		wp_safe_redirect($redirect_url);
3537
+		exit();
3538
+	}
3539
+
3540
+
3541
+	/**
3542
+	 * process any notices before redirecting (or returning ajax request)
3543
+	 * This method sets the $this->_template_args['notices'] attribute;
3544
+	 *
3545
+	 * @param array $query_args         any query args that need to be used for notice transient ('action')
3546
+	 * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3547
+	 *                                  page_routes haven't been defined yet.
3548
+	 * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3549
+	 *                                  still save a transient for the notice.
3550
+	 * @return void
3551
+	 * @throws EE_Error
3552
+	 * @throws InvalidArgumentException
3553
+	 * @throws InvalidDataTypeException
3554
+	 * @throws InvalidInterfaceException
3555
+	 */
3556
+	protected function _process_notices(
3557
+		array $query_args = [],
3558
+		bool $skip_route_verify = false,
3559
+		bool $sticky_notices = true
3560
+	) {
3561
+		// first let's set individual error properties if doing_ajax and the properties aren't already set.
3562
+		if ($this->request->isAjax()) {
3563
+			$notices = EE_Error::get_notices(false);
3564
+			if (empty($this->_template_args['success'])) {
3565
+				$this->_template_args['success'] = $notices['success'] ?? false;
3566
+			}
3567
+			if (empty($this->_template_args['errors'])) {
3568
+				$this->_template_args['errors'] = $notices['errors'] ?? false;
3569
+			}
3570
+			if (empty($this->_template_args['attention'])) {
3571
+				$this->_template_args['attention'] = $notices['attention'] ?? false;
3572
+			}
3573
+		}
3574
+		$this->_template_args['notices'] = EE_Error::get_notices();
3575
+		// IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3576
+		if (! $this->request->isAjax() || $sticky_notices) {
3577
+			$route = $query_args['action'] ?? 'default';
3578
+			$this->_add_transient(
3579
+				$route,
3580
+				(array) $this->_template_args['notices'],
3581
+				true,
3582
+				$skip_route_verify
3583
+			);
3584
+		}
3585
+	}
3586
+
3587
+
3588
+	/**
3589
+	 * get_action_link_or_button
3590
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3591
+	 *
3592
+	 * @param string $action        use this to indicate which action the url is generated with.
3593
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3594
+	 *                              property.
3595
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3596
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3597
+	 * @param string $base_url      If this is not provided
3598
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3599
+	 *                              Otherwise this value will be used.
3600
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3601
+	 * @return string
3602
+	 * @throws InvalidArgumentException
3603
+	 * @throws InvalidInterfaceException
3604
+	 * @throws InvalidDataTypeException
3605
+	 * @throws EE_Error
3606
+	 */
3607
+	public function get_action_link_or_button(
3608
+		string $action,
3609
+		string $type = 'add',
3610
+		array $extra_request = [],
3611
+		string $class = 'button button--primary',
3612
+		string $base_url = '',
3613
+		bool $exclude_nonce = false
3614
+	): string {
3615
+		// first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3616
+		if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3617
+			throw new EE_Error(
3618
+				sprintf(
3619
+					esc_html__(
3620
+						'There is no page route for given action for the button.  This action was given: %s',
3621
+						'event_espresso'
3622
+					),
3623
+					$action
3624
+				)
3625
+			);
3626
+		}
3627
+		if (! isset($this->_labels['buttons'][ $type ])) {
3628
+			throw new EE_Error(
3629
+				sprintf(
3630
+					esc_html__(
3631
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3632
+						'event_espresso'
3633
+					),
3634
+					$type
3635
+				)
3636
+			);
3637
+		}
3638
+		// finally check user access for this button.
3639
+		$has_access = $this->check_user_access($action, true);
3640
+		if (! $has_access) {
3641
+			return '';
3642
+		}
3643
+		$_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3644
+		$query_args = [
3645
+			'action' => $action,
3646
+		];
3647
+		// merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3648
+		if (! empty($extra_request)) {
3649
+			$query_args = array_merge($extra_request, $query_args);
3650
+		}
3651
+		$url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3652
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3653
+	}
3654
+
3655
+
3656
+	/**
3657
+	 * _per_page_screen_option
3658
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3659
+	 *
3660
+	 * @return void
3661
+	 * @throws InvalidArgumentException
3662
+	 * @throws InvalidInterfaceException
3663
+	 * @throws InvalidDataTypeException
3664
+	 */
3665
+	protected function _per_page_screen_option()
3666
+	{
3667
+		$option = 'per_page';
3668
+		$args   = [
3669
+			'label'   => apply_filters(
3670
+				'FHEE__EE_Admin_Page___per_page_screen_options___label',
3671
+				$this->_admin_page_title,
3672
+				$this
3673
+			),
3674
+			'default' => (int) apply_filters(
3675
+				'FHEE__EE_Admin_Page___per_page_screen_options__default',
3676
+				20
3677
+			),
3678
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3679
+		];
3680
+		// ONLY add the screen option if the user has access to it.
3681
+		if ($this->check_user_access($this->_current_view, true)) {
3682
+			add_screen_option($option, $args);
3683
+		}
3684
+	}
3685
+
3686
+
3687
+	/**
3688
+	 * set_per_page_screen_option
3689
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3690
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3691
+	 * admin_menu.
3692
+	 *
3693
+	 * @return void
3694
+	 */
3695
+	private function _set_per_page_screen_options()
3696
+	{
3697
+		if ($this->request->requestParamIsSet('wp_screen_options')) {
3698
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3699
+			if (! $user = wp_get_current_user()) {
3700
+				return;
3701
+			}
3702
+			$option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3703
+			if (! $option) {
3704
+				return;
3705
+			}
3706
+			$value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3707
+			$map_option = $option;
3708
+			$option     = str_replace('-', '_', $option);
3709
+			switch ($map_option) {
3710
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3711
+					$max_value = apply_filters(
3712
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3713
+						999,
3714
+						$this->_current_page,
3715
+						$this->_current_view
3716
+					);
3717
+					if ($value < 1) {
3718
+						return;
3719
+					}
3720
+					$value = min($value, $max_value);
3721
+					break;
3722
+				default:
3723
+					$value = apply_filters(
3724
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3725
+						false,
3726
+						$option,
3727
+						$value
3728
+					);
3729
+					if (false === $value) {
3730
+						return;
3731
+					}
3732
+					break;
3733
+			}
3734
+			update_user_meta($user->ID, $option, $value);
3735
+			wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3736
+			exit;
3737
+		}
3738
+	}
3739
+
3740
+
3741
+	/**
3742
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3743
+	 *
3744
+	 * @param array $data array that will be assigned to template args.
3745
+	 */
3746
+	public function set_template_args(array $data)
3747
+	{
3748
+		$this->_template_args = array_merge($this->_template_args, $data);
3749
+	}
3750
+
3751
+
3752
+	public function setAdminPageTitle(string $title)
3753
+	{
3754
+		$this->_admin_page_title = sanitize_text_field($title);
3755
+	}
3756
+
3757
+
3758
+	/**
3759
+	 * This makes available the WP transient system for temporarily moving data between routes
3760
+	 *
3761
+	 * @param string $route             the route that should receive the transient
3762
+	 * @param array  $data              the data that gets sent
3763
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3764
+	 *                                  normal route transient.
3765
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3766
+	 *                                  when we are adding a transient before page_routes have been defined.
3767
+	 * @return void
3768
+	 * @throws EE_Error
3769
+	 */
3770
+	protected function _add_transient(
3771
+		string $route,
3772
+		array $data,
3773
+		bool $notices = false,
3774
+		bool $skip_route_verify = false
3775
+	) {
3776
+		$user_id = get_current_user_id();
3777
+		if (! $skip_route_verify) {
3778
+			$this->_verify_route($route);
3779
+		}
3780
+		// now let's set the string for what kind of transient we're setting
3781
+		$transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3782
+		$data      = $notices ? ['notices' => $data] : $data;
3783
+		// is there already a transient for this route?  If there is then let's ADD to that transient
3784
+		$existing = is_multisite() && is_network_admin()
3785
+			? get_site_transient($transient)
3786
+			: get_transient($transient);
3787
+		if ($existing) {
3788
+			$data = array_merge($data, (array) $existing);
3789
+		}
3790
+		if (is_multisite() && is_network_admin()) {
3791
+			set_site_transient($transient, $data, 8);
3792
+		} else {
3793
+			set_transient($transient, $data, 8);
3794
+		}
3795
+	}
3796
+
3797
+
3798
+	/**
3799
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3800
+	 *
3801
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3802
+	 * @param string $route
3803
+	 * @return mixed data
3804
+	 */
3805
+	protected function _get_transient(bool $notices = false, string $route = '')
3806
+	{
3807
+		$user_id   = get_current_user_id();
3808
+		$route     = ! $route ? $this->_req_action : $route;
3809
+		$transient = $notices
3810
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3811
+			: 'rte_tx_' . $route . '_' . $user_id;
3812
+		$data      = is_multisite() && is_network_admin()
3813
+			? get_site_transient($transient)
3814
+			: get_transient($transient);
3815
+		// delete transient after retrieval (just in case it hasn't expired);
3816
+		if (is_multisite() && is_network_admin()) {
3817
+			delete_site_transient($transient);
3818
+		} else {
3819
+			delete_transient($transient);
3820
+		}
3821
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3822
+	}
3823
+
3824
+
3825
+	/**
3826
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3827
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3828
+	 * default route callback on the EE_Admin page you want it run.)
3829
+	 *
3830
+	 * @return void
3831
+	 */
3832
+	protected function _transient_garbage_collection()
3833
+	{
3834
+		global $wpdb;
3835
+		// retrieve all existing transients
3836
+		$query =
3837
+			"SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3838
+		if ($results = $wpdb->get_results($query)) {
3839
+			foreach ($results as $result) {
3840
+				$transient = str_replace('_transient_', '', $result->option_name);
3841
+				get_transient($transient);
3842
+				if (is_multisite() && is_network_admin()) {
3843
+					get_site_transient($transient);
3844
+				}
3845
+			}
3846
+		}
3847
+	}
3848
+
3849
+
3850
+	/**
3851
+	 * get_view
3852
+	 *
3853
+	 * @return string content of _view property
3854
+	 */
3855
+	public function get_view(): string
3856
+	{
3857
+		return $this->_view;
3858
+	}
3859
+
3860
+
3861
+	/**
3862
+	 * getter for the protected $_views property
3863
+	 *
3864
+	 * @return array
3865
+	 */
3866
+	public function get_views(): array
3867
+	{
3868
+		return $this->_views;
3869
+	}
3870
+
3871
+
3872
+	/**
3873
+	 * @param array $views
3874
+	 * @return void
3875
+	 * @since 5.0.13.p
3876
+	 */
3877
+	public function updateViews(array $views)
3878
+	{
3879
+		$this->_views = array_merge($this->_views, $views);
3880
+	}
3881
+
3882
+
3883
+	/**
3884
+    /**
3885
+	 * get_current_page
3886
+	 *
3887
+	 * @return string _current_page property value
3888
+	 */
3889
+	public function get_current_page(): string
3890
+	{
3891
+		return $this->_current_page;
3892
+	}
3893
+
3894
+
3895
+	/**
3896
+	 * get_current_view
3897
+	 *
3898
+	 * @return string _current_view property value
3899
+	 */
3900
+	public function get_current_view(): string
3901
+	{
3902
+		return $this->_current_view;
3903
+	}
3904
+
3905
+
3906
+	/**
3907
+	 * get_current_screen
3908
+	 *
3909
+	 * @return object The current WP_Screen object
3910
+	 */
3911
+	public function get_current_screen()
3912
+	{
3913
+		return $this->_current_screen;
3914
+	}
3915
+
3916
+
3917
+	/**
3918
+	 * get_current_page_view_url
3919
+	 *
3920
+	 * @return string This returns the url for the current_page_view.
3921
+	 */
3922
+	public function get_current_page_view_url(): string
3923
+	{
3924
+		return $this->_current_page_view_url;
3925
+	}
3926
+
3927
+
3928
+	/**
3929
+	 * just returns the Request
3930
+	 *
3931
+	 * @return RequestInterface
3932
+	 */
3933
+	public function get_request(): ?RequestInterface
3934
+	{
3935
+		return $this->request;
3936
+	}
3937
+
3938
+
3939
+	/**
3940
+	 * just returns the _req_data property
3941
+	 *
3942
+	 * @return array
3943
+	 */
3944
+	public function get_request_data(): array
3945
+	{
3946
+		return $this->request->requestParams();
3947
+	}
3948
+
3949
+
3950
+	/**
3951
+	 * returns the _req_data protected property
3952
+	 *
3953
+	 * @return string
3954
+	 */
3955
+	public function get_req_action(): string
3956
+	{
3957
+		return $this->_req_action;
3958
+	}
3959
+
3960
+
3961
+	/**
3962
+	 * @return bool  value of $_is_caf property
3963
+	 */
3964
+	public function is_caf(): bool
3965
+	{
3966
+		return $this->_is_caf;
3967
+	}
3968
+
3969
+
3970
+	/**
3971
+	 * @return array
3972
+	 */
3973
+	public function default_espresso_metaboxes(): array
3974
+	{
3975
+		return $this->_default_espresso_metaboxes;
3976
+	}
3977
+
3978
+
3979
+	/**
3980
+	 * @return string
3981
+	 */
3982
+	public function admin_base_url(): string
3983
+	{
3984
+		return $this->_admin_base_url;
3985
+	}
3986
+
3987
+
3988
+	/**
3989
+	 * @return string
3990
+	 */
3991
+	public function wp_page_slug(): string
3992
+	{
3993
+		return $this->_wp_page_slug;
3994
+	}
3995
+
3996
+
3997
+	/**
3998
+	 * updates  espresso configuration settings
3999
+	 *
4000
+	 * @param string                   $tab
4001
+	 * @param EE_Config_Base|EE_Config $config
4002
+	 * @param string                   $file file where error occurred
4003
+	 * @param string                   $func function  where error occurred
4004
+	 * @param string                   $line line no where error occurred
4005
+	 * @return bool
4006
+	 */
4007
+	protected function _update_espresso_configuration(
4008
+		string $tab,
4009
+		$config,
4010
+		string $file = '',
4011
+		string $func = '',
4012
+		string $line = ''
4013
+	): bool {
4014
+		// remove any options that are NOT going to be saved with the config settings.
4015
+		if (isset($config->core->ee_ueip_optin)) {
4016
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4017
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4018
+			update_option('ee_ueip_has_notified', true);
4019
+		}
4020
+		// and save it (note we're also doing the network save here)
4021
+		$net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4022
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4023
+		if ($config_saved && $net_saved) {
4024
+			EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4025
+			return true;
4026
+		}
4027
+		EE_Error::add_error(
4028
+			sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4029
+			$file,
4030
+			$func,
4031
+			$line
4032
+		);
4033
+		return false;
4034
+	}
4035
+
4036
+
4037
+	/**
4038
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4039
+	 *
4040
+	 * @return array
4041
+	 */
4042
+	public function get_yes_no_values(): array
4043
+	{
4044
+		return $this->_yes_no_values;
4045
+	}
4046
+
4047
+
4048
+	/**
4049
+	 * @return string
4050
+	 * @throws ReflectionException
4051
+	 * @since 5.0.0.p
4052
+	 */
4053
+	protected function _get_dir(): string
4054
+	{
4055
+		$reflector = new ReflectionClass($this->class_name);
4056
+		return dirname($reflector->getFileName());
4057
+	}
4058
+
4059
+
4060
+	/**
4061
+	 * A helper for getting a "next link".
4062
+	 *
4063
+	 * @param string $url   The url to link to
4064
+	 * @param string $class The class to use.
4065
+	 * @return string
4066
+	 */
4067
+	protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4068
+	{
4069
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4070
+	}
4071
+
4072
+
4073
+	/**
4074
+	 * A helper for getting a "previous link".
4075
+	 *
4076
+	 * @param string $url   The url to link to
4077
+	 * @param string $class The class to use.
4078
+	 * @return string
4079
+	 */
4080
+	protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4081
+	{
4082
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4083
+	}
4084
+
4085
+
4086
+
4087
+
4088
+
4089
+
4090
+
4091
+	// below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4092
+
4093
+
4094
+	/**
4095
+	 * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4096
+	 * 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
4097
+	 * _req_data array.
4098
+	 *
4099
+	 * @return bool success/fail
4100
+	 * @throws EE_Error
4101
+	 * @throws InvalidArgumentException
4102
+	 * @throws ReflectionException
4103
+	 * @throws InvalidDataTypeException
4104
+	 * @throws InvalidInterfaceException
4105
+	 */
4106
+	protected function _process_resend_registration(): bool
4107
+	{
4108
+		$this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4109
+		do_action(
4110
+			'AHEE__EE_Admin_Page___process_resend_registration',
4111
+			$this->_template_args['success'],
4112
+			$this->request->requestParams()
4113
+		);
4114
+		return $this->_template_args['success'];
4115
+	}
4116
+
4117
+
4118
+	/**
4119
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4120
+	 *
4121
+	 * @param EE_Payment $payment
4122
+	 * @return bool success/fail
4123
+	 */
4124
+	protected function _process_payment_notification(EE_Payment $payment): bool
4125
+	{
4126
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4127
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4128
+		$this->_template_args['success'] = apply_filters(
4129
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4130
+			false,
4131
+			$payment
4132
+		);
4133
+		return $this->_template_args['success'];
4134
+	}
4135
+
4136
+
4137
+	/**
4138
+	 * @param EEM_Base      $entity_model
4139
+	 * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4140
+	 * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4141
+	 * @param string        $delete_column  name of the field that denotes whether entity is trashed
4142
+	 * @param callable|null $callback       called after entity is trashed, restored, or deleted
4143
+	 * @return int|float
4144
+	 * @throws EE_Error
4145
+	 */
4146
+	protected function trashRestoreDeleteEntities(
4147
+		EEM_Base $entity_model,
4148
+		string $entity_PK_name,
4149
+		string $action = EE_Admin_List_Table::ACTION_DELETE,
4150
+		string $delete_column = '',
4151
+		?callable $callback = null
4152
+	) {
4153
+		$entity_PK      = $entity_model->get_primary_key_field();
4154
+		$entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4155
+		$entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4156
+		// grab ID if deleting a single entity
4157
+		if ($this->request->requestParamIsSet($entity_PK_name)) {
4158
+			$ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4159
+			return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4160
+		}
4161
+		// or grab checkbox array if bulk deleting
4162
+		$checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4163
+		if (empty($checkboxes)) {
4164
+			return 0;
4165
+		}
4166
+		$success = 0;
4167
+		$IDs     = array_keys($checkboxes);
4168
+		// cycle thru bulk action checkboxes
4169
+		foreach ($IDs as $ID) {
4170
+			// increment $success
4171
+			if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4172
+				$success++;
4173
+			}
4174
+		}
4175
+		$count = (int) count($checkboxes);
4176
+		// if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4177
+		// otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4178
+		return $success === $count ? $count : $success / $count;
4179
+	}
4180
+
4181
+
4182
+	/**
4183
+	 * @param EE_Primary_Key_Field_Base $entity_PK
4184
+	 * @return string
4185
+	 * @throws EE_Error
4186
+	 * @since   4.10.30.p
4187
+	 */
4188
+	private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4189
+	{
4190
+		$entity_PK_type = $entity_PK->getSchemaType();
4191
+		switch ($entity_PK_type) {
4192
+			case 'boolean':
4193
+				return DataType::BOOL;
4194
+			case 'integer':
4195
+				return DataType::INT;
4196
+			case 'number':
4197
+				return DataType::FLOAT;
4198
+			case 'string':
4199
+				return DataType::STRING;
4200
+		}
4201
+		throw new RuntimeException(
4202
+			sprintf(
4203
+				esc_html__(
4204
+					'"%1$s" is an invalid schema type for the %2$s primary key.',
4205
+					'event_espresso'
4206
+				),
4207
+				$entity_PK_type,
4208
+				$entity_PK->get_name()
4209
+			)
4210
+		);
4211
+	}
4212
+
4213
+
4214
+	/**
4215
+	 * @param EEM_Base      $entity_model
4216
+	 * @param int|string    $entity_ID
4217
+	 * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4218
+	 * @param string        $delete_column name of the field that denotes whether entity is trashed
4219
+	 * @param callable|null $callback      called after entity is trashed, restored, or deleted
4220
+	 * @return bool
4221
+	 */
4222
+	protected function trashRestoreDeleteEntity(
4223
+		EEM_Base $entity_model,
4224
+		$entity_ID,
4225
+		string $action,
4226
+		string $delete_column,
4227
+		?callable $callback = null
4228
+	): bool {
4229
+		$entity_ID = absint($entity_ID);
4230
+		if (! $entity_ID) {
4231
+			$this->trashRestoreDeleteError($action, $entity_model);
4232
+		}
4233
+		$result = 0;
4234
+		try {
4235
+			$entity = $entity_model->get_one_by_ID($entity_ID);
4236
+			if (! $entity instanceof EE_Base_Class) {
4237
+				throw new DomainException(
4238
+					sprintf(
4239
+						esc_html__(
4240
+							'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4241
+							'event_espresso'
4242
+						),
4243
+						str_replace('EEM_', '', $entity_model->get_this_model_name()),
4244
+						$entity_ID
4245
+					)
4246
+				);
4247
+			}
4248
+			switch ($action) {
4249
+				case EE_Admin_List_Table::ACTION_DELETE:
4250
+					$result = (bool) $entity->delete_permanently();
4251
+					break;
4252
+				case EE_Admin_List_Table::ACTION_RESTORE:
4253
+					$result = $entity->delete_or_restore(false);
4254
+					break;
4255
+				case EE_Admin_List_Table::ACTION_TRASH:
4256
+					$result = $entity->delete_or_restore();
4257
+					break;
4258
+			}
4259
+		} catch (Exception $exception) {
4260
+			$this->trashRestoreDeleteError($action, $entity_model, $exception);
4261
+		}
4262
+		if (is_callable($callback)) {
4263
+			call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4264
+		}
4265
+		return $result;
4266
+	}
4267
+
4268
+
4269
+	/**
4270
+	 * @param EEM_Base $entity_model
4271
+	 * @param string   $delete_column
4272
+	 * @since 4.10.30.p
4273
+	 */
4274
+	private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4275
+	{
4276
+		if (empty($delete_column)) {
4277
+			throw new DomainException(
4278
+				sprintf(
4279
+					esc_html__(
4280
+						'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4281
+						'event_espresso'
4282
+					),
4283
+					$entity_model->get_this_model_name()
4284
+				)
4285
+			);
4286
+		}
4287
+		if (! $entity_model->has_field($delete_column)) {
4288
+			throw new DomainException(
4289
+				sprintf(
4290
+					esc_html__(
4291
+						'The %1$s field does not exist on the %2$s model.',
4292
+						'event_espresso'
4293
+					),
4294
+					$delete_column,
4295
+					$entity_model->get_this_model_name()
4296
+				)
4297
+			);
4298
+		}
4299
+	}
4300
+
4301
+
4302
+	/**
4303
+	 * @param EEM_Base       $entity_model
4304
+	 * @param Exception|null $exception
4305
+	 * @param string         $action
4306
+	 * @since 4.10.30.p
4307
+	 */
4308
+	private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4309
+	{
4310
+		if ($exception instanceof Exception) {
4311
+			throw new RuntimeException(
4312
+				sprintf(
4313
+					esc_html__(
4314
+						'Could not %1$s the %2$s because the following error occurred: %3$s',
4315
+						'event_espresso'
4316
+					),
4317
+					$action,
4318
+					$entity_model->get_this_model_name(),
4319
+					$exception->getMessage()
4320
+				)
4321
+			);
4322
+		}
4323
+		throw new RuntimeException(
4324
+			sprintf(
4325
+				esc_html__(
4326
+					'Could not %1$s the %2$s because an invalid ID was received.',
4327
+					'event_espresso'
4328
+				),
4329
+				$action,
4330
+				$entity_model->get_this_model_name()
4331
+			)
4332
+		);
4333
+	}
4334 4334
 }
Please login to merge, or discard this patch.
Spacing   +173 added lines, -173 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
      */
103 103
     protected ?bool $_is_UI_request = null;
104 104
 
105
-    protected bool  $_is_caf        = false;                                                                                                                                                                                                                                  // This is just a property that flags whether the given route is a caffeinated route or not.
105
+    protected bool  $_is_caf        = false; // This is just a property that flags whether the given route is a caffeinated route or not.
106 106
 
107 107
     protected bool  $_routing       = false;
108 108
 
@@ -597,7 +597,7 @@  discard block
 block discarded – undo
597 597
         $ee_menu_slugs = (array) $ee_menu_slugs;
598 598
         if (
599 599
             ! $this->request->isAjax()
600
-            && (! $this->_current_page || ! isset($ee_menu_slugs[ $this->_current_page ]))
600
+            && ( ! $this->_current_page || ! isset($ee_menu_slugs[$this->_current_page]))
601 601
         ) {
602 602
             return;
603 603
         }
@@ -616,7 +616,7 @@  discard block
 block discarded – undo
616 616
             ? $route
617 617
             : $req_action;
618 618
         $this->_current_view = $this->_req_action;
619
-        $this->_req_nonce    = $this->_req_action . '_nonce';
619
+        $this->_req_nonce    = $this->_req_action.'_nonce';
620 620
         $this->_define_page_props();
621 621
         $this->_current_page_view_url = add_query_arg(
622 622
             ['page' => $this->_current_page, 'action' => $this->_current_view],
@@ -640,33 +640,33 @@  discard block
 block discarded – undo
640 640
         }
641 641
         // filter routes and page_config so addons can add their stuff. Filtering done per class
642 642
         $this->_page_routes = apply_filters(
643
-            'FHEE__' . $this->class_name . '__page_setup__page_routes',
643
+            'FHEE__'.$this->class_name.'__page_setup__page_routes',
644 644
             $this->_page_routes,
645 645
             $this
646 646
         );
647 647
         $this->_page_config = apply_filters(
648
-            'FHEE__' . $this->class_name . '__page_setup__page_config',
648
+            'FHEE__'.$this->class_name.'__page_setup__page_config',
649 649
             $this->_page_config,
650 650
             $this
651 651
         );
652 652
         if ($this->base_class_name !== '') {
653 653
             $this->_page_routes = apply_filters(
654
-                'FHEE__' . $this->base_class_name . '__page_setup__page_routes',
654
+                'FHEE__'.$this->base_class_name.'__page_setup__page_routes',
655 655
                 $this->_page_routes,
656 656
                 $this
657 657
             );
658 658
             $this->_page_config = apply_filters(
659
-                'FHEE__' . $this->base_class_name . '__page_setup__page_config',
659
+                'FHEE__'.$this->base_class_name.'__page_setup__page_config',
660 660
                 $this->_page_config,
661 661
                 $this
662 662
             );
663 663
         }
664 664
         // if AHEE__EE_Admin_Page__route_admin_request_$this->_current_view method is present
665 665
         // then we call it hooked into the AHEE__EE_Admin_Page__route_admin_request action
666
-        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view)) {
666
+        if (method_exists($this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view)) {
667 667
             add_action(
668 668
                 'AHEE__EE_Admin_Page__route_admin_request',
669
-                [$this, 'AHEE__EE_Admin_Page__route_admin_request_' . $this->_current_view],
669
+                [$this, 'AHEE__EE_Admin_Page__route_admin_request_'.$this->_current_view],
670 670
                 10,
671 671
                 2
672 672
             );
@@ -679,8 +679,8 @@  discard block
 block discarded – undo
679 679
             if ($this->_is_UI_request) {
680 680
                 // admin_init stuff - global, all views for this page class, specific view
681 681
                 add_action('admin_init', [$this, 'admin_init']);
682
-                if (method_exists($this, 'admin_init_' . $this->_current_view)) {
683
-                    add_action('admin_init', [$this, 'admin_init_' . $this->_current_view], 15);
682
+                if (method_exists($this, 'admin_init_'.$this->_current_view)) {
683
+                    add_action('admin_init', [$this, 'admin_init_'.$this->_current_view], 15);
684 684
                 }
685 685
             } else {
686 686
                 // hijack regular WP loading and route admin request immediately
@@ -699,12 +699,12 @@  discard block
 block discarded – undo
699 699
      */
700 700
     private function _do_other_page_hooks()
701 701
     {
702
-        $registered_pages = apply_filters('FHEE_do_other_page_hooks_' . $this->page_slug, []);
702
+        $registered_pages = apply_filters('FHEE_do_other_page_hooks_'.$this->page_slug, []);
703 703
         foreach ($registered_pages as $page) {
704 704
             // now let's setup the file name and class that should be present
705 705
             $classname = str_replace('.class.php', '', $page);
706 706
             // autoloaders should take care of loading file
707
-            if (! class_exists($classname)) {
707
+            if ( ! class_exists($classname)) {
708 708
                 $error_msg[] = sprintf(
709 709
                     esc_html__(
710 710
                         'Something went wrong with loading the %s admin hooks page.',
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
                                    ),
722 722
                                    $page,
723 723
                                    '<br />',
724
-                                   '<strong>' . $classname . '</strong>'
724
+                                   '<strong>'.$classname.'</strong>'
725 725
                                );
726 726
                 throw new EE_Error(implode('||', $error_msg));
727 727
             }
@@ -770,13 +770,13 @@  discard block
 block discarded – undo
770 770
         // load admin_notices - global, page class, and view specific
771 771
         add_action('admin_notices', [$this, 'admin_notices_global'], 5);
772 772
         add_action('admin_notices', [$this, 'admin_notices']);
773
-        if (method_exists($this, 'admin_notices_' . $this->_current_view)) {
774
-            add_action('admin_notices', [$this, 'admin_notices_' . $this->_current_view], 15);
773
+        if (method_exists($this, 'admin_notices_'.$this->_current_view)) {
774
+            add_action('admin_notices', [$this, 'admin_notices_'.$this->_current_view], 15);
775 775
         }
776 776
         // load network admin_notices - global, page class, and view specific
777 777
         add_action('network_admin_notices', [$this, 'network_admin_notices_global'], 5);
778
-        if (method_exists($this, 'network_admin_notices_' . $this->_current_view)) {
779
-            add_action('network_admin_notices', [$this, 'network_admin_notices_' . $this->_current_view]);
778
+        if (method_exists($this, 'network_admin_notices_'.$this->_current_view)) {
779
+            add_action('network_admin_notices', [$this, 'network_admin_notices_'.$this->_current_view]);
780 780
         }
781 781
         // this will save any per_page screen options if they are present
782 782
         $this->_set_per_page_screen_options();
@@ -902,7 +902,7 @@  discard block
 block discarded – undo
902 902
      */
903 903
     protected function _verify_routes(): bool
904 904
     {
905
-        if (! $this->_current_page && ! $this->request->isAjax()) {
905
+        if ( ! $this->_current_page && ! $this->request->isAjax()) {
906 906
             return false;
907 907
         }
908 908
         // check that the page_routes array is not empty
@@ -913,7 +913,7 @@  discard block
 block discarded – undo
913 913
                 $this->_admin_page_title
914 914
             );
915 915
             // developer error msg
916
-            $error_msg .= '||' . $error_msg
916
+            $error_msg .= '||'.$error_msg
917 917
                           . esc_html__(
918 918
                               ' Make sure the "set_page_routes()" method exists, and is setting the "_page_routes" array properly.',
919 919
                               'event_espresso'
@@ -931,8 +931,8 @@  discard block
 block discarded – undo
931 931
         }
932 932
         // and that the requested page route exists
933 933
         if (array_key_exists($this->_req_action, $this->_page_routes)) {
934
-            $this->_route        = $this->_page_routes[ $this->_req_action ];
935
-            $this->_route_config = $this->_page_config[ $this->_req_action ] ?? [];
934
+            $this->_route        = $this->_page_routes[$this->_req_action];
935
+            $this->_route_config = $this->_page_config[$this->_req_action] ?? [];
936 936
         } else {
937 937
             // user error msg
938 938
             $error_msg = sprintf(
@@ -943,7 +943,7 @@  discard block
 block discarded – undo
943 943
                 $this->_admin_page_title
944 944
             );
945 945
             // developer error msg
946
-            $error_msg .= '||' . $error_msg
946
+            $error_msg .= '||'.$error_msg
947 947
                           . sprintf(
948 948
                               esc_html__(
949 949
                                   ' Create a key in the "_page_routes" array named "%s" and set its value to the appropriate method.',
@@ -954,7 +954,7 @@  discard block
 block discarded – undo
954 954
             throw new EE_Error($error_msg);
955 955
         }
956 956
         // and that a default route exists
957
-        if (! array_key_exists('default', $this->_page_routes)) {
957
+        if ( ! array_key_exists('default', $this->_page_routes)) {
958 958
             // user error msg
959 959
             $error_msg = sprintf(
960 960
                 esc_html__(
@@ -964,7 +964,7 @@  discard block
 block discarded – undo
964 964
                 $this->_admin_page_title
965 965
             );
966 966
             // developer error msg
967
-            $error_msg .= '||' . $error_msg
967
+            $error_msg .= '||'.$error_msg
968 968
                           . esc_html__(
969 969
                               ' Create a key in the "_page_routes" array named "default" and set its value to your default page method.',
970 970
                               'event_espresso'
@@ -1004,7 +1004,7 @@  discard block
 block discarded – undo
1004 1004
             $this->_admin_page_title
1005 1005
         );
1006 1006
         // developer error msg
1007
-        $error_msg .= '||' . $error_msg
1007
+        $error_msg .= '||'.$error_msg
1008 1008
                       . sprintf(
1009 1009
                           esc_html__(
1010 1010
                               ' Check the route you are using in your method (%s) and make sure it matches a route set in your "_page_routes" array property',
@@ -1032,7 +1032,7 @@  discard block
 block discarded – undo
1032 1032
     protected function _verify_nonce(string $nonce, string $nonce_ref)
1033 1033
     {
1034 1034
         // verify nonce against expected value
1035
-        if (! wp_verify_nonce($nonce, $nonce_ref)) {
1035
+        if ( ! wp_verify_nonce($nonce, $nonce_ref)) {
1036 1036
             // these are not the droids you are looking for !!!
1037 1037
             $msg = sprintf(
1038 1038
                 esc_html__('%sNonce Fail.%s', 'event_espresso'),
@@ -1049,7 +1049,7 @@  discard block
 block discarded – undo
1049 1049
                     __CLASS__
1050 1050
                 );
1051 1051
             }
1052
-            if (! $this->request->isAjax()) {
1052
+            if ( ! $this->request->isAjax()) {
1053 1053
                 wp_die($msg);
1054 1054
             }
1055 1055
             EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
@@ -1074,7 +1074,7 @@  discard block
 block discarded – undo
1074 1074
      */
1075 1075
     protected function _route_admin_request()
1076 1076
     {
1077
-        if (! $this->_is_UI_request) {
1077
+        if ( ! $this->_is_UI_request) {
1078 1078
             $this->_verify_routes();
1079 1079
         }
1080 1080
         $nonce_check = ! isset($this->_route_config['require_nonce']) || $this->_route_config['require_nonce'];
@@ -1094,7 +1094,7 @@  discard block
 block discarded – undo
1094 1094
 
1095 1095
         // action right before calling route
1096 1096
         // (hook is something like 'AHEE__Registrations_Admin_Page__route_admin_request')
1097
-        if (! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1097
+        if ( ! did_action('AHEE__EE_Admin_Page__route_admin_request')) {
1098 1098
             do_action('AHEE__EE_Admin_Page__route_admin_request', $this->_current_view, $this);
1099 1099
         }
1100 1100
         // strip _wp_http_referer from the server REQUEST_URI
@@ -1109,7 +1109,7 @@  discard block
 block discarded – undo
1109 1109
         $this->request->setRequestParam('_wp_http_referer', $cleaner_request_uri, true);
1110 1110
         $this->request->setServerParam('REQUEST_URI', $cleaner_request_uri, true);
1111 1111
         $route_callback = [];
1112
-        if (! empty($func)) {
1112
+        if ( ! empty($func)) {
1113 1113
             if (is_array($func) && is_callable($func)) {
1114 1114
                 $route_callback = $func;
1115 1115
             } elseif (is_string($func)) {
@@ -1123,7 +1123,7 @@  discard block
 block discarded – undo
1123 1123
             }
1124 1124
             [$class, $method] = $route_callback;
1125 1125
             // is it neither a class method NOR a standalone function?
1126
-            if (! is_callable($route_callback)) {
1126
+            if ( ! is_callable($route_callback)) {
1127 1127
                 // user error msg
1128 1128
                 $error_msg = esc_html__(
1129 1129
                     'An error occurred. The  requested page route could not be found.',
@@ -1232,7 +1232,7 @@  discard block
 block discarded – undo
1232 1232
                 if (strpos($key, 'nonce') !== false) {
1233 1233
                     continue;
1234 1234
                 }
1235
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1235
+                $args['wp_referer['.$key.']'] = is_string($value) ? htmlspecialchars($value) : $value;
1236 1236
             }
1237 1237
         }
1238 1238
         return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
@@ -1272,12 +1272,12 @@  discard block
 block discarded – undo
1272 1272
      */
1273 1273
     protected function _add_help_tabs()
1274 1274
     {
1275
-        if (isset($this->_page_config[ $this->_req_action ])) {
1276
-            $config = $this->_page_config[ $this->_req_action ];
1275
+        if (isset($this->_page_config[$this->_req_action])) {
1276
+            $config = $this->_page_config[$this->_req_action];
1277 1277
             // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1278 1278
             if (is_array($config) && isset($config['help_sidebar'])) {
1279 1279
                 // check that the callback given is valid
1280
-                if (! method_exists($this, $config['help_sidebar'])) {
1280
+                if ( ! method_exists($this, $config['help_sidebar'])) {
1281 1281
                     throw new EE_Error(
1282 1282
                         sprintf(
1283 1283
                             esc_html__(
@@ -1290,18 +1290,18 @@  discard block
 block discarded – undo
1290 1290
                     );
1291 1291
                 }
1292 1292
                 $content = apply_filters(
1293
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1293
+                    'FHEE__'.$this->class_name.'__add_help_tabs__help_sidebar',
1294 1294
                     $this->{$config['help_sidebar']}()
1295 1295
                 );
1296 1296
                 $this->_current_screen->set_help_sidebar($content);
1297 1297
             }
1298
-            if (! isset($config['help_tabs'])) {
1298
+            if ( ! isset($config['help_tabs'])) {
1299 1299
                 return;
1300 1300
             } //no help tabs for this route
1301 1301
             foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1302 1302
                 // we're here so there ARE help tabs!
1303 1303
                 // make sure we've got what we need
1304
-                if (! isset($cfg['title'])) {
1304
+                if ( ! isset($cfg['title'])) {
1305 1305
                     throw new EE_Error(
1306 1306
                         esc_html__(
1307 1307
                             'The _page_config array is not set up properly for help tabs.  It is missing a title',
@@ -1309,7 +1309,7 @@  discard block
 block discarded – undo
1309 1309
                         )
1310 1310
                     );
1311 1311
                 }
1312
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1312
+                if ( ! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1313 1313
                     throw new EE_Error(
1314 1314
                         esc_html__(
1315 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',
@@ -1318,11 +1318,11 @@  discard block
 block discarded – undo
1318 1318
                     );
1319 1319
                 }
1320 1320
                 // first priority goes to content.
1321
-                if (! empty($cfg['content'])) {
1321
+                if ( ! empty($cfg['content'])) {
1322 1322
                     $content = $cfg['content'];
1323 1323
                     // second priority goes to filename
1324
-                } elseif (! empty($cfg['filename'])) {
1325
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1324
+                } elseif ( ! empty($cfg['filename'])) {
1325
+                    $file_path = $this->_get_dir().'/help_tabs/'.$cfg['filename'].'.help_tab.php';
1326 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 1327
                     $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1328 1328
                                                              . basename($this->_get_dir())
@@ -1330,7 +1330,7 @@  discard block
 block discarded – undo
1330 1330
                                                              . $cfg['filename']
1331 1331
                                                              . '.help_tab.php' : $file_path;
1332 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)) {
1333
+                    if ( ! isset($cfg['callback']) && ! is_readable($file_path)) {
1334 1334
                         EE_Error::add_error(
1335 1335
                             sprintf(
1336 1336
                                 esc_html__(
@@ -1378,7 +1378,7 @@  discard block
 block discarded – undo
1378 1378
                     return;
1379 1379
                 }
1380 1380
                 // setup config array for help tab method
1381
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1381
+                $id  = $this->page_slug.'-'.$this->_req_action.'-'.$tab_id;
1382 1382
                 $_ht = [
1383 1383
                     'id'       => $id,
1384 1384
                     'title'    => $cfg['title'],
@@ -1404,8 +1404,8 @@  discard block
 block discarded – undo
1404 1404
             $qtips = (array) $this->_route_config['qtips'];
1405 1405
             // load qtip loader
1406 1406
             $path = [
1407
-                $this->_get_dir() . '/qtips/',
1408
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1407
+                $this->_get_dir().'/qtips/',
1408
+                EE_ADMIN_PAGES.basename($this->_get_dir()).'/qtips/',
1409 1409
             ];
1410 1410
             EEH_Qtip_Loader::instance()->register($qtips, $path);
1411 1411
         }
@@ -1427,7 +1427,7 @@  discard block
 block discarded – undo
1427 1427
         $i        = 0;
1428 1428
         $only_tab = count($this->_page_config) < 2;
1429 1429
         foreach ($this->_page_config as $slug => $config) {
1430
-            if (! is_array($config) || empty($config['nav'])) {
1430
+            if ( ! is_array($config) || empty($config['nav'])) {
1431 1431
                 continue;
1432 1432
             }
1433 1433
             // no nav tab for this config
@@ -1436,7 +1436,7 @@  discard block
 block discarded – undo
1436 1436
                 // nav tab is only to appear when route requested.
1437 1437
                 continue;
1438 1438
             }
1439
-            if (! $this->check_user_access($slug, true)) {
1439
+            if ( ! $this->check_user_access($slug, true)) {
1440 1440
                 // no nav tab because current user does not have access.
1441 1441
                 continue;
1442 1442
             }
@@ -1444,20 +1444,20 @@  discard block
 block discarded – undo
1444 1444
             $css_class .= $only_tab ? ' ee-only-tab' : '';
1445 1445
             $css_class .= " ee-nav-tab__$slug";
1446 1446
 
1447
-            $this->_nav_tabs[ $slug ] = [
1447
+            $this->_nav_tabs[$slug] = [
1448 1448
                 'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1449 1449
                         ['action' => $slug],
1450 1450
                         $this->_admin_base_url
1451 1451
                     ),
1452 1452
                 'link_text' => $this->navTabLabel($config['nav'], $slug),
1453
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1453
+                'css_class' => $this->_req_action === $slug ? $css_class.' nav-tab-active' : $css_class,
1454 1454
                 'order'     => $config['nav']['order'] ?? $i,
1455 1455
             ];
1456 1456
             $i++;
1457 1457
         }
1458 1458
         // if $this->_nav_tabs is empty then lets set the default
1459 1459
         if (empty($this->_nav_tabs)) {
1460
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1460
+            $this->_nav_tabs[$this->_default_nav_tab_name] = [
1461 1461
                 'url'       => $this->_admin_base_url,
1462 1462
                 'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1463 1463
                 'css_class' => 'nav-tab-active',
@@ -1473,11 +1473,11 @@  discard block
 block discarded – undo
1473 1473
     {
1474 1474
         $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1475 1475
         $icon  = $nav_tab['icon'] ?? null;
1476
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1476
+        $icon  = $icon ? '<span class="dashicons '.$icon.'"></span>' : '';
1477 1477
         return '
1478 1478
             <span class="ee-admin-screen-tab__label">
1479
-                ' . $icon . '
1480
-                <span class="ee-nav-label__text">' . $label . '</span>
1479
+                ' . $icon.'
1480
+                <span class="ee-nav-label__text">' . $label.'</span>
1481 1481
             </span>';
1482 1482
     }
1483 1483
 
@@ -1495,10 +1495,10 @@  discard block
 block discarded – undo
1495 1495
             foreach ($this->_route_config['labels'] as $label => $text) {
1496 1496
                 if (is_array($text)) {
1497 1497
                     foreach ($text as $sublabel => $subtext) {
1498
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1498
+                        $this->_labels[$label][$sublabel] = $subtext;
1499 1499
                     }
1500 1500
                 } else {
1501
-                    $this->_labels[ $label ] = $text;
1501
+                    $this->_labels[$label] = $text;
1502 1502
                 }
1503 1503
             }
1504 1504
         }
@@ -1520,8 +1520,8 @@  discard block
 block discarded – undo
1520 1520
     {
1521 1521
         // if no route_to_check is passed in then use the current route set via _req_action
1522 1522
         $action = $route_to_check ?: $this->_req_action;
1523
-        $capability = ! empty($this->_page_routes[ $action ]['capability'])
1524
-            ? $this->_page_routes[ $action ]['capability']
1523
+        $capability = ! empty($this->_page_routes[$action]['capability'])
1524
+            ? $this->_page_routes[$action]['capability']
1525 1525
             : null;
1526 1526
 
1527 1527
         if (empty($capability)) {
@@ -1571,14 +1571,14 @@  discard block
 block discarded – undo
1571 1571
         string $priority = 'default',
1572 1572
         ?array $callback_args = null
1573 1573
     ) {
1574
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1574
+        if ( ! (is_callable($callback) || ! function_exists($callback))) {
1575 1575
             return;
1576 1576
         }
1577 1577
 
1578 1578
         add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1579 1579
         add_filter(
1580 1580
             "postbox_classes_{$this->_wp_page_slug}_$box_id",
1581
-            function ($classes) {
1581
+            function($classes) {
1582 1582
                 $classes[] = 'ee-admin-container';
1583 1583
                 return $classes;
1584 1584
             }
@@ -1669,8 +1669,8 @@  discard block
 block discarded – undo
1669 1669
             <div class="ee-notices"></div>
1670 1670
             <div class="ee-admin-dialog-container-inner-content"></div>
1671 1671
         </div>
1672
-        <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>
1673
-        <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page) . '"/>';
1672
+        <span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()).'</span>
1673
+        <input type="hidden" id="espresso_admin_current_page" value="' . esc_attr($this->_current_page).'"/>';
1674 1674
     }
1675 1675
 
1676 1676
 
@@ -1704,7 +1704,7 @@  discard block
 block discarded – undo
1704 1704
         // loop through the array and setup content
1705 1705
         foreach ($help_array as $trigger => $help) {
1706 1706
             // make sure the array is setup properly
1707
-            if (! isset($help['title'], $help['content'])) {
1707
+            if ( ! isset($help['title'], $help['content'])) {
1708 1708
                 throw new EE_Error(
1709 1709
                     esc_html__(
1710 1710
                         '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',
@@ -1718,8 +1718,8 @@  discard block
 block discarded – undo
1718 1718
                 'help_popup_title'   => $help['title'],
1719 1719
                 'help_popup_content' => $help['content'],
1720 1720
             ];
1721
-            $content       .= EEH_Template::display_template(
1722
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1721
+            $content .= EEH_Template::display_template(
1722
+                EE_ADMIN_TEMPLATE.'admin_help_popup.template.php',
1723 1723
                 $template_args,
1724 1724
                 true
1725 1725
             );
@@ -1741,15 +1741,15 @@  discard block
 block discarded – undo
1741 1741
     private function _get_help_content(): array
1742 1742
     {
1743 1743
         // what is the method we're looking for?
1744
-        $method_name = '_help_popup_content_' . $this->_req_action;
1744
+        $method_name = '_help_popup_content_'.$this->_req_action;
1745 1745
         // if method doesn't exist let's get out.
1746
-        if (! method_exists($this, $method_name)) {
1746
+        if ( ! method_exists($this, $method_name)) {
1747 1747
             return [];
1748 1748
         }
1749 1749
         // k we're good to go let's retrieve the help array
1750 1750
         $help_array = $this->{$method_name}();
1751 1751
         // make sure we've got an array!
1752
-        if (! is_array($help_array)) {
1752
+        if ( ! is_array($help_array)) {
1753 1753
             throw new EE_Error(
1754 1754
                 esc_html__(
1755 1755
                     'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
@@ -1781,15 +1781,15 @@  discard block
 block discarded – undo
1781 1781
         // 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
1782 1782
         $help_array   = $this->_get_help_content();
1783 1783
         $help_content = '';
1784
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1785
-            $help_array[ $trigger_id ] = [
1784
+        if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1785
+            $help_array[$trigger_id] = [
1786 1786
                 'title'   => esc_html__('Missing Content', 'event_espresso'),
1787 1787
                 'content' => esc_html__(
1788 1788
                     '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.)',
1789 1789
                     'event_espresso'
1790 1790
                 ),
1791 1791
             ];
1792
-            $help_content              = $this->_set_help_popup_content($help_array);
1792
+            $help_content = $this->_set_help_popup_content($help_array);
1793 1793
         }
1794 1794
         $height   = esc_attr($dimensions[0]) ?? 400;
1795 1795
         $width    = esc_attr($dimensions[1]) ?? 640;
@@ -1877,7 +1877,7 @@  discard block
 block discarded – undo
1877 1877
 
1878 1878
         add_filter(
1879 1879
             'admin_body_class',
1880
-            function ($classes) {
1880
+            function($classes) {
1881 1881
                 if (strpos($classes, 'espresso-admin') === false) {
1882 1882
                     $classes .= ' espresso-admin';
1883 1883
                 }
@@ -1968,12 +1968,12 @@  discard block
 block discarded – undo
1968 1968
     protected function _set_list_table()
1969 1969
     {
1970 1970
         // first is this a list_table view?
1971
-        if (! isset($this->_route_config['list_table'])) {
1971
+        if ( ! isset($this->_route_config['list_table'])) {
1972 1972
             return;
1973 1973
         } //not a list_table view so get out.
1974 1974
         // list table functions are per view specific (because some admin pages might have more than one list table!)
1975
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
1976
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
1975
+        $list_table_view = '_set_list_table_views_'.$this->_req_action;
1976
+        if ( ! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
1977 1977
             // user error msg
1978 1978
             $error_msg = esc_html__(
1979 1979
                 'An error occurred. The requested list table views could not be found.',
@@ -1993,10 +1993,10 @@  discard block
 block discarded – undo
1993 1993
         }
1994 1994
         // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
1995 1995
         $this->_views = apply_filters(
1996
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
1996
+            'FHEE_list_table_views_'.$this->page_slug.'_'.$this->_req_action,
1997 1997
             $this->_views
1998 1998
         );
1999
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
1999
+        $this->_views = apply_filters('FHEE_list_table_views_'.$this->page_slug, $this->_views);
2000 2000
         $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2001 2001
         $this->_set_list_table_view();
2002 2002
         $this->_set_list_table_object();
@@ -2031,7 +2031,7 @@  discard block
 block discarded – undo
2031 2031
     protected function _set_list_table_object()
2032 2032
     {
2033 2033
         if (isset($this->_route_config['list_table'])) {
2034
-            if (! class_exists($this->_route_config['list_table'])) {
2034
+            if ( ! class_exists($this->_route_config['list_table'])) {
2035 2035
                 throw new EE_Error(
2036 2036
                     sprintf(
2037 2037
                         esc_html__(
@@ -2073,16 +2073,16 @@  discard block
 block discarded – undo
2073 2073
         foreach ($this->_views as $key => $view) {
2074 2074
             $query_args = [];
2075 2075
             // check for current view
2076
-            $this->_views[ $key ]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2076
+            $this->_views[$key]['class'] = $this->_view === $view['slug'] ? 'current' : '';
2077 2077
             $query_args['action']          = $this->_req_action;
2078 2078
             $action_nonce                  = "{$this->_req_action}_nonce";
2079
-            $query_args[ $action_nonce ]   = wp_create_nonce($action_nonce);
2079
+            $query_args[$action_nonce]   = wp_create_nonce($action_nonce);
2080 2080
             $query_args['status']          = $view['slug'];
2081 2081
             // merge any other arguments sent in.
2082
-            if (isset($extra_query_args[ $view['slug'] ])) {
2083
-                $query_args = array_merge($query_args, $extra_query_args[ $view['slug'] ]);
2082
+            if (isset($extra_query_args[$view['slug']])) {
2083
+                $query_args = array_merge($query_args, $extra_query_args[$view['slug']]);
2084 2084
             }
2085
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2085
+            $this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2086 2086
         }
2087 2087
         return $this->_views;
2088 2088
     }
@@ -2111,14 +2111,14 @@  discard block
 block discarded – undo
2111 2111
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2112 2112
         foreach ($values as $value) {
2113 2113
             if ($value < $max_entries) {
2114
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2114
+                $selected = $value === $per_page ? ' selected="'.$per_page.'"' : '';
2115 2115
                 $entries_per_page_dropdown .= '
2116
-						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2116
+						<option value="' . $value.'"'.$selected.'>'.$value.'&nbsp;&nbsp;</option>';
2117 2117
             }
2118 2118
         }
2119
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2119
+        $selected = $max_entries === $per_page ? ' selected="'.$per_page.'"' : '';
2120 2120
         $entries_per_page_dropdown .= '
2121
-						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2121
+						<option value="' . $max_entries.'"'.$selected.'>All&nbsp;&nbsp;</option>';
2122 2122
         $entries_per_page_dropdown .= '
2123 2123
 					</select>
2124 2124
 					entries
@@ -2142,7 +2142,7 @@  discard block
 block discarded – undo
2142 2142
             empty($this->_search_btn_label) ? $this->page_label
2143 2143
                 : $this->_search_btn_label
2144 2144
         );
2145
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2145
+        $this->_template_args['search']['callback'] = 'search_'.$this->page_slug;
2146 2146
     }
2147 2147
 
2148 2148
 
@@ -2203,7 +2203,7 @@  discard block
 block discarded – undo
2203 2203
                                   );
2204 2204
                     throw new EE_Error($error_msg);
2205 2205
                 }
2206
-                unset($this->_route_config['metaboxes'][ $key ]);
2206
+                unset($this->_route_config['metaboxes'][$key]);
2207 2207
             }
2208 2208
         }
2209 2209
     }
@@ -2236,7 +2236,7 @@  discard block
 block discarded – undo
2236 2236
             $total_columns                                       = ! empty($screen_columns)
2237 2237
                 ? $screen_columns
2238 2238
                 : $this->_route_config['columns'][1];
2239
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2239
+            $this->_template_args['current_screen_widget_class'] = 'columns-'.$total_columns;
2240 2240
             $this->_template_args['current_page']                = $this->_wp_page_slug;
2241 2241
             $this->_template_args['screen']                      = $this->_current_screen;
2242 2242
             $this->_column_template_path                         = EE_ADMIN_TEMPLATE
@@ -2282,7 +2282,7 @@  discard block
 block discarded – undo
2282 2282
      */
2283 2283
     protected function _espresso_ratings_request()
2284 2284
     {
2285
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2285
+        if ( ! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2286 2286
             return;
2287 2287
         }
2288 2288
         $ratings_box_title = apply_filters(
@@ -2309,28 +2309,28 @@  discard block
 block discarded – undo
2309 2309
      */
2310 2310
     public function espresso_ratings_request()
2311 2311
     {
2312
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2312
+        EEH_Template::display_template(EE_ADMIN_TEMPLATE.'espresso_ratings_request_content.template.php');
2313 2313
     }
2314 2314
 
2315 2315
 
2316 2316
     public static function cached_rss_display(string $rss_id, string $url): bool
2317 2317
     {
2318
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2318
+        $loading = '<p class="widget-loading hide-if-no-js">'
2319 2319
                      . esc_html__('Loading&#8230;', 'event_espresso')
2320 2320
                      . '</p><p class="hide-if-js">'
2321 2321
                      . esc_html__('This widget requires JavaScript.', 'event_espresso')
2322 2322
                      . '</p>';
2323
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2324
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2325
-        $post      = '</div>' . "\n";
2326
-        $cache_key = 'ee_rss_' . md5($rss_id);
2323
+        $pre       = '<div class="espresso-rss-display">'."\n\t";
2324
+        $pre .= '<span id="'.esc_attr($rss_id).'_url" class="hidden">'.esc_url_raw($url).'</span>';
2325
+        $post      = '</div>'."\n";
2326
+        $cache_key = 'ee_rss_'.md5($rss_id);
2327 2327
         $output    = get_transient($cache_key);
2328 2328
         if ($output !== false) {
2329
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2329
+            echo wp_kses($pre.$output.$post, AllowedTags::getWithFormTags());
2330 2330
             return true;
2331 2331
         }
2332
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2333
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2332
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
2333
+            echo wp_kses($pre.$loading.$post, AllowedTags::getWithFormTags());
2334 2334
             return false;
2335 2335
         }
2336 2336
         ob_start();
@@ -2397,7 +2397,7 @@  discard block
 block discarded – undo
2397 2397
     public function espresso_sponsors_post_box()
2398 2398
     {
2399 2399
         EEH_Template::display_template(
2400
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2400
+            EE_ADMIN_TEMPLATE.'admin_general_metabox_contents_espresso_sponsors.template.php'
2401 2401
         );
2402 2402
     }
2403 2403
 
@@ -2414,9 +2414,9 @@  discard block
 block discarded – undo
2414 2414
     protected function getPublishBoxTitle(): string
2415 2415
     {
2416 2416
         $publish_box_title = esc_html__('Publish', 'event_espresso');
2417
-        if (! empty($this->_labels['publishbox'])) {
2417
+        if ( ! empty($this->_labels['publishbox'])) {
2418 2418
             if (is_array($this->_labels['publishbox'])) {
2419
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2419
+                $publish_box_title = $this->_labels['publishbox'][$this->_req_action] ?? $publish_box_title;
2420 2420
             } else {
2421 2421
                 $publish_box_title = $this->_labels['publishbox'];
2422 2422
             }
@@ -2466,7 +2466,7 @@  discard block
 block discarded – undo
2466 2466
         // if we have extra content set let's add it in if not make sure its empty
2467 2467
         $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2468 2468
         echo EEH_Template::display_template(
2469
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2469
+            EE_ADMIN_TEMPLATE.'admin_details_publish_metabox.template.php',
2470 2470
             $this->_template_args,
2471 2471
             true
2472 2472
         );
@@ -2519,10 +2519,10 @@  discard block
 block discarded – undo
2519 2519
                 'submitdelete deletion button button--outline button--caution'
2520 2520
             );
2521 2521
         }
2522
-        if (! isset($this->_template_args['publish_delete_link'])) {
2522
+        if ( ! isset($this->_template_args['publish_delete_link'])) {
2523 2523
             $this->_template_args['publish_delete_link'] = '';
2524 2524
         }
2525
-        if (! empty($name) && ! empty($id)) {
2525
+        if ( ! empty($name) && ! empty($id)) {
2526 2526
             $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2527 2527
         }
2528 2528
         $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
@@ -2555,7 +2555,7 @@  discard block
 block discarded – undo
2555 2555
 
2556 2556
     protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2557 2557
     {
2558
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2558
+        $this->publish_post_meta_box_hidden_fields[$field_name] = $field_attributes;
2559 2559
     }
2560 2560
 
2561 2561
 
@@ -2657,7 +2657,7 @@  discard block
 block discarded – undo
2657 2657
         }
2658 2658
         // 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)
2659 2659
         $call_back_func = $create_func
2660
-            ? static function ($post, $metabox) {
2660
+            ? static function($post, $metabox) {
2661 2661
                 echo EEH_Template::display_template(
2662 2662
                     $metabox['args']['template_path'],
2663 2663
                     $metabox['args']['template_args'],
@@ -2666,7 +2666,7 @@  discard block
 block discarded – undo
2666 2666
             }
2667 2667
             : $callback;
2668 2668
         $this->addMetaBox(
2669
-            str_replace('_', '-', $action) . '-mbox',
2669
+            str_replace('_', '-', $action).'-mbox',
2670 2670
             $title,
2671 2671
             $call_back_func,
2672 2672
             $this->_wp_page_slug,
@@ -2782,15 +2782,15 @@  discard block
 block discarded – undo
2782 2782
                                                                     'event-espresso_page_espresso_',
2783 2783
                                                                     '',
2784 2784
                                                                     $this->_wp_page_slug
2785
-                                                                ) . ' ' . $this->_req_action . '-route';
2785
+                                                                ).' '.$this->_req_action.'-route';
2786 2786
 
2787 2787
         $template_path = $sidebar
2788 2788
             ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2789
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2789
+            : EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar.template.php';
2790 2790
 
2791 2791
         $this->_template_args['is_ajax'] = $this->request->isAjax();
2792 2792
         if ($this->request->isAjax()) {
2793
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2793
+            $template_path = EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar_ajax.template.php';
2794 2794
         }
2795 2795
         $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2796 2796
 
@@ -2802,10 +2802,10 @@  discard block
 block discarded – undo
2802 2802
         // to prevent WooCommerce from blowing things up if not using CPT
2803 2803
         global $post_type, $post;
2804 2804
         $this->_template_args['post_type'] = $post_type ?? '';
2805
-        $this->_template_args['post']  = $post ?? new WP_Post( (object) [ 'ID' => 0, 'filter' => 'raw' ] );
2805
+        $this->_template_args['post'] = $post ?? new WP_Post((object) ['ID' => 0, 'filter' => 'raw']);
2806 2806
 
2807 2807
         $this->_template_args['post_body_content'] = EEH_Template::display_template(
2808
-            EE_ADMIN_TEMPLATE . 'admin_details_wrapper_post_body_content.template.php',
2808
+            EE_ADMIN_TEMPLATE.'admin_details_wrapper_post_body_content.template.php',
2809 2809
             $this->_template_args,
2810 2810
             true
2811 2811
         );
@@ -2837,11 +2837,11 @@  discard block
 block discarded – undo
2837 2837
     public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2838 2838
     {
2839 2839
         // let's generate a default preview action button if there isn't one already present.
2840
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2840
+        $this->_labels['buttons']['buy_now'] = esc_html__(
2841 2841
             'Upgrade to Event Espresso 4 Right Now',
2842 2842
             'event_espresso'
2843 2843
         );
2844
-        $buy_now_url                                   = add_query_arg(
2844
+        $buy_now_url = add_query_arg(
2845 2845
             [
2846 2846
                 'ee_ver'       => 'ee4',
2847 2847
                 'utm_source'   => 'ee4_plugin_admin',
@@ -2861,8 +2861,8 @@  discard block
 block discarded – undo
2861 2861
                 true
2862 2862
             )
2863 2863
             : $this->_template_args['preview_action_button'];
2864
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2865
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2864
+        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2865
+            EE_ADMIN_TEMPLATE.'admin_caf_full_page_preview.template.php',
2866 2866
             $this->_template_args,
2867 2867
             true
2868 2868
         );
@@ -2920,7 +2920,7 @@  discard block
 block discarded – undo
2920 2920
         // setup search attributes
2921 2921
         $this->_set_search_attributes();
2922 2922
         $this->_template_args['current_page']     = $this->_wp_page_slug;
2923
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2923
+        $template_path                            = EE_ADMIN_TEMPLATE.'admin_list_wrapper.template.php';
2924 2924
         $this->_template_args['table_url']        = $this->request->isAjax()
2925 2925
             ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2926 2926
             : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
@@ -2928,10 +2928,10 @@  discard block
 block discarded – undo
2928 2928
         $this->_template_args['current_route']    = $this->_req_action;
2929 2929
         $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2930 2930
         $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2931
-        if (! empty($ajax_sorting_callback)) {
2931
+        if ( ! empty($ajax_sorting_callback)) {
2932 2932
             $sortable_list_table_form_fields = wp_nonce_field(
2933
-                $ajax_sorting_callback . '_nonce',
2934
-                $ajax_sorting_callback . '_nonce',
2933
+                $ajax_sorting_callback.'_nonce',
2934
+                $ajax_sorting_callback.'_nonce',
2935 2935
                 false,
2936 2936
                 false
2937 2937
             );
@@ -2948,18 +2948,18 @@  discard block
 block discarded – undo
2948 2948
 
2949 2949
         $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2950 2950
 
2951
-        $nonce_ref          = $this->_req_action . '_nonce';
2951
+        $nonce_ref          = $this->_req_action.'_nonce';
2952 2952
         $hidden_form_fields .= '
2953
-            <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2953
+            <input type="hidden" name="' . $nonce_ref.'" value="'.wp_create_nonce($nonce_ref).'">';
2954 2954
 
2955 2955
         $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2956 2956
         // display message about search results?
2957
-        $search                                    = $this->request->getRequestParam('s');
2957
+        $search = $this->request->getRequestParam('s');
2958 2958
         $this->_template_args['before_list_table'] .= ! empty($search)
2959
-            ? '<p class="ee-search-results">' . sprintf(
2959
+            ? '<p class="ee-search-results">'.sprintf(
2960 2960
                 esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2961 2961
                 trim($search, '%')
2962
-            ) . '</p>'
2962
+            ).'</p>'
2963 2963
             : '';
2964 2964
         // filter before_list_table template arg
2965 2965
         $this->_template_args['before_list_table'] = apply_filters(
@@ -2993,7 +2993,7 @@  discard block
 block discarded – undo
2993 2993
         // convert to array and filter again
2994 2994
         // arrays are easier to inject new items in a specific location,
2995 2995
         // but would not be backwards compatible, so we have to add a new filter
2996
-        $this->_template_args['after_list_table']   = implode(
2996
+        $this->_template_args['after_list_table'] = implode(
2997 2997
             " \n",
2998 2998
             (array) apply_filters(
2999 2999
                 'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
@@ -3048,7 +3048,7 @@  discard block
 block discarded – undo
3048 3048
             $this->page_slug
3049 3049
         );
3050 3050
         return EEH_Template::display_template(
3051
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3051
+            EE_ADMIN_TEMPLATE.'admin_details_legend.template.php',
3052 3052
             $this->_template_args,
3053 3053
             true
3054 3054
         );
@@ -3171,7 +3171,7 @@  discard block
 block discarded – undo
3171 3171
         if ($this->request->isAjax()) {
3172 3172
             $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3173 3173
             // $template_path,
3174
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3174
+                EE_ADMIN_TEMPLATE.'admin_wrapper_ajax.template.php',
3175 3175
                 $this->_template_args,
3176 3176
                 true
3177 3177
             );
@@ -3180,7 +3180,7 @@  discard block
 block discarded – undo
3180 3180
         // load settings page wrapper template
3181 3181
         $template_path = $about
3182 3182
             ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3183
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3183
+            : EE_ADMIN_TEMPLATE.'admin_wrapper.template.php';
3184 3184
 
3185 3185
         EEH_Template::display_template($template_path, $this->_template_args);
3186 3186
     }
@@ -3264,12 +3264,12 @@  discard block
 block discarded – undo
3264 3264
         $default_names = ['save', 'save_and_close'];
3265 3265
         $buttons       = '';
3266 3266
         foreach ($button_text as $key => $button) {
3267
-            $ref     = $default_names[ $key ];
3268
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3269
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3270
-                        . 'value="' . $button . '" name="' . $name . '" '
3271
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3272
-            if (! $both) {
3267
+            $ref     = $default_names[$key];
3268
+            $name    = ! empty($actions) ? $actions[$key] : $ref;
3269
+            $buttons .= '<input type="submit" class="button button--primary '.$ref.'" '
3270
+                        . 'value="'.$button.'" name="'.$name.'" '
3271
+                        . 'id="'.$this->_current_view.'_'.$ref.'" />';
3272
+            if ( ! $both) {
3273 3273
                 break;
3274 3274
             }
3275 3275
         }
@@ -3310,13 +3310,13 @@  discard block
 block discarded – undo
3310 3310
                 'An error occurred. No action was set for this page\'s form.',
3311 3311
                 'event_espresso'
3312 3312
             );
3313
-            $dev_msg  = $user_msg . "\n"
3313
+            $dev_msg = $user_msg."\n"
3314 3314
                         . sprintf(
3315 3315
                             esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3316 3316
                             __FUNCTION__,
3317 3317
                             __CLASS__
3318 3318
                         );
3319
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3319
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
3320 3320
         }
3321 3321
         // open form
3322 3322
         $action                                            = $this->_admin_base_url;
@@ -3324,9 +3324,9 @@  discard block
 block discarded – undo
3324 3324
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3325 3325
             ";
3326 3326
         // add nonce
3327
-        $nonce                                             =
3328
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3329
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3327
+        $nonce =
3328
+            wp_nonce_field($route.'_nonce', $route.'_nonce', false, false);
3329
+        $this->_template_args['before_admin_page_content'] .= "\n\t".$nonce;
3330 3330
         // add REQUIRED form action
3331 3331
         $hidden_fields = [
3332 3332
             'action' => ['type' => 'hidden', 'value' => $route],
@@ -3339,7 +3339,7 @@  discard block
 block discarded – undo
3339 3339
         $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3340 3340
         // add fields to form
3341 3341
         foreach ((array) $form_fields as $form_field) {
3342
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3342
+            $this->_template_args['before_admin_page_content'] .= "\n\t".$form_field['field'];
3343 3343
         }
3344 3344
         // close form
3345 3345
         $this->_template_args['after_admin_page_content'] = '</form>';
@@ -3422,10 +3422,10 @@  discard block
 block discarded – undo
3422 3422
     ) {
3423 3423
         $notices = EE_Error::get_notices(false);
3424 3424
         // overwrite default success messages //BUT ONLY if overwrite not overridden
3425
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3425
+        if ( ! $override_overwrite || ! empty($notices['errors'])) {
3426 3426
             EE_Error::overwrite_success();
3427 3427
         }
3428
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3428
+        if ( ! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3429 3429
             // how many records affected ? more than one record ? or just one ?
3430 3430
             EE_Error::add_success(
3431 3431
                 sprintf(
@@ -3476,7 +3476,7 @@  discard block
 block discarded – undo
3476 3476
             $redirect_url = admin_url('admin.php');
3477 3477
         }
3478 3478
         // merge any default query_args set in _default_route_query_args property
3479
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3479
+        if ( ! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3480 3480
             $args_to_merge = [];
3481 3481
             foreach ($this->_default_route_query_args as $query_param => $query_value) {
3482 3482
                 // is there a wp_referer array in our _default_route_query_args property?
@@ -3488,15 +3488,15 @@  discard block
 block discarded – undo
3488 3488
                         }
3489 3489
                         // finally we will override any arguments in the referer with
3490 3490
                         // what might be set on the _default_route_query_args array.
3491
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3492
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3491
+                        if (isset($this->_default_route_query_args[$reference])) {
3492
+                            $args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3493 3493
                         } else {
3494
-                            $args_to_merge[ $reference ] = urlencode($value);
3494
+                            $args_to_merge[$reference] = urlencode($value);
3495 3495
                         }
3496 3496
                     }
3497 3497
                     continue;
3498 3498
                 }
3499
-                $args_to_merge[ $query_param ] = $query_value;
3499
+                $args_to_merge[$query_param] = $query_value;
3500 3500
             }
3501 3501
             // now let's merge these arguments but override with what was specifically sent in to the
3502 3502
             // redirect.
@@ -3508,19 +3508,19 @@  discard block
 block discarded – undo
3508 3508
         if (isset($query_args['action'])) {
3509 3509
             // manually generate wp_nonce and merge that with the query vars
3510 3510
             // becuz the wp_nonce_url function wrecks havoc on some vars
3511
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3511
+            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'].'_nonce');
3512 3512
         }
3513 3513
         // we're adding some hooks and filters in here for processing any things just before redirects
3514 3514
         // (example: an admin page has done an insert or update and we want to run something after that).
3515
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3515
+        do_action('AHEE_redirect_'.$this->class_name.$this->_req_action, $query_args);
3516 3516
         $redirect_url = apply_filters(
3517
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3517
+            'FHEE_redirect_'.$this->class_name.$this->_req_action,
3518 3518
             EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3519 3519
             $query_args
3520 3520
         );
3521 3521
         // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3522 3522
         if ($this->request->isAjax()) {
3523
-            $default_data                    = [
3523
+            $default_data = [
3524 3524
                 'close'        => true,
3525 3525
                 'redirect_url' => $redirect_url,
3526 3526
                 'where'        => 'main',
@@ -3573,7 +3573,7 @@  discard block
 block discarded – undo
3573 3573
         }
3574 3574
         $this->_template_args['notices'] = EE_Error::get_notices();
3575 3575
         // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3576
-        if (! $this->request->isAjax() || $sticky_notices) {
3576
+        if ( ! $this->request->isAjax() || $sticky_notices) {
3577 3577
             $route = $query_args['action'] ?? 'default';
3578 3578
             $this->_add_transient(
3579 3579
                 $route,
@@ -3613,7 +3613,7 @@  discard block
 block discarded – undo
3613 3613
         bool $exclude_nonce = false
3614 3614
     ): string {
3615 3615
         // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3616
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3616
+        if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3617 3617
             throw new EE_Error(
3618 3618
                 sprintf(
3619 3619
                     esc_html__(
@@ -3624,7 +3624,7 @@  discard block
 block discarded – undo
3624 3624
                 )
3625 3625
             );
3626 3626
         }
3627
-        if (! isset($this->_labels['buttons'][ $type ])) {
3627
+        if ( ! isset($this->_labels['buttons'][$type])) {
3628 3628
             throw new EE_Error(
3629 3629
                 sprintf(
3630 3630
                     esc_html__(
@@ -3637,7 +3637,7 @@  discard block
 block discarded – undo
3637 3637
         }
3638 3638
         // finally check user access for this button.
3639 3639
         $has_access = $this->check_user_access($action, true);
3640
-        if (! $has_access) {
3640
+        if ( ! $has_access) {
3641 3641
             return '';
3642 3642
         }
3643 3643
         $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
@@ -3645,11 +3645,11 @@  discard block
 block discarded – undo
3645 3645
             'action' => $action,
3646 3646
         ];
3647 3647
         // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3648
-        if (! empty($extra_request)) {
3648
+        if ( ! empty($extra_request)) {
3649 3649
             $query_args = array_merge($extra_request, $query_args);
3650 3650
         }
3651 3651
         $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3652
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3652
+        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3653 3653
     }
3654 3654
 
3655 3655
 
@@ -3675,7 +3675,7 @@  discard block
 block discarded – undo
3675 3675
                 'FHEE__EE_Admin_Page___per_page_screen_options__default',
3676 3676
                 20
3677 3677
             ),
3678
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3678
+            'option'  => $this->_current_page.'_'.$this->_current_view.'_per_page',
3679 3679
         ];
3680 3680
         // ONLY add the screen option if the user has access to it.
3681 3681
         if ($this->check_user_access($this->_current_view, true)) {
@@ -3696,18 +3696,18 @@  discard block
 block discarded – undo
3696 3696
     {
3697 3697
         if ($this->request->requestParamIsSet('wp_screen_options')) {
3698 3698
             check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3699
-            if (! $user = wp_get_current_user()) {
3699
+            if ( ! $user = wp_get_current_user()) {
3700 3700
                 return;
3701 3701
             }
3702 3702
             $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3703
-            if (! $option) {
3703
+            if ( ! $option) {
3704 3704
                 return;
3705 3705
             }
3706 3706
             $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3707 3707
             $map_option = $option;
3708 3708
             $option     = str_replace('-', '_', $option);
3709 3709
             switch ($map_option) {
3710
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3710
+                case $this->_current_page.'_'.$this->_current_view.'_per_page':
3711 3711
                     $max_value = apply_filters(
3712 3712
                         'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3713 3713
                         999,
@@ -3774,7 +3774,7 @@  discard block
 block discarded – undo
3774 3774
         bool $skip_route_verify = false
3775 3775
     ) {
3776 3776
         $user_id = get_current_user_id();
3777
-        if (! $skip_route_verify) {
3777
+        if ( ! $skip_route_verify) {
3778 3778
             $this->_verify_route($route);
3779 3779
         }
3780 3780
         // now let's set the string for what kind of transient we're setting
@@ -3807,8 +3807,8 @@  discard block
 block discarded – undo
3807 3807
         $user_id   = get_current_user_id();
3808 3808
         $route     = ! $route ? $this->_req_action : $route;
3809 3809
         $transient = $notices
3810
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3811
-            : 'rte_tx_' . $route . '_' . $user_id;
3810
+            ? 'ee_rte_n_tx_'.$route.'_'.$user_id
3811
+            : 'rte_tx_'.$route.'_'.$user_id;
3812 3812
         $data      = is_multisite() && is_network_admin()
3813 3813
             ? get_site_transient($transient)
3814 3814
             : get_transient($transient);
@@ -4066,7 +4066,7 @@  discard block
 block discarded – undo
4066 4066
      */
4067 4067
     protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4068 4068
     {
4069
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4069
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4070 4070
     }
4071 4071
 
4072 4072
 
@@ -4079,7 +4079,7 @@  discard block
 block discarded – undo
4079 4079
      */
4080 4080
     protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4081 4081
     {
4082
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4082
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4083 4083
     }
4084 4084
 
4085 4085
 
@@ -4227,13 +4227,13 @@  discard block
 block discarded – undo
4227 4227
         ?callable $callback = null
4228 4228
     ): bool {
4229 4229
         $entity_ID = absint($entity_ID);
4230
-        if (! $entity_ID) {
4230
+        if ( ! $entity_ID) {
4231 4231
             $this->trashRestoreDeleteError($action, $entity_model);
4232 4232
         }
4233 4233
         $result = 0;
4234 4234
         try {
4235 4235
             $entity = $entity_model->get_one_by_ID($entity_ID);
4236
-            if (! $entity instanceof EE_Base_Class) {
4236
+            if ( ! $entity instanceof EE_Base_Class) {
4237 4237
                 throw new DomainException(
4238 4238
                     sprintf(
4239 4239
                         esc_html__(
@@ -4284,7 +4284,7 @@  discard block
 block discarded – undo
4284 4284
                 )
4285 4285
             );
4286 4286
         }
4287
-        if (! $entity_model->has_field($delete_column)) {
4287
+        if ( ! $entity_model->has_field($delete_column)) {
4288 4288
             throw new DomainException(
4289 4289
                 sprintf(
4290 4290
                     esc_html__(
Please login to merge, or discard this patch.
core/db_models/EEM_Payment_Method.model.php 1 patch
Indentation   +450 added lines, -450 removed lines patch added patch discarded remove patch
@@ -16,454 +16,454 @@
 block discarded – undo
16 16
  */
17 17
 class EEM_Payment_Method extends EEM_Base
18 18
 {
19
-    const scope_cart  = 'CART';
20
-
21
-    const scope_admin = 'ADMIN';
22
-
23
-    const scope_api   = 'API';
24
-
25
-
26
-    protected static ?EEM_Payment_Method $_instance = null;
27
-
28
-
29
-    /**
30
-     * private constructor to prevent direct creation
31
-     *
32
-     * @param string|null $timezone
33
-     * @throws EE_Error
34
-     */
35
-    protected function __construct(?string $timezone = '')
36
-    {
37
-        $this->singular_item    = esc_html__('Payment Method', 'event_espresso');
38
-        $this->plural_item      = esc_html__('Payment Methods', 'event_espresso');
39
-        $this->_tables          = [
40
-            'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID'),
41
-        ];
42
-        $this->_fields          = [
43
-            'Payment_Method' => [
44
-                'PMD_ID'              => new EE_Primary_Key_Int_Field(
45
-                    'PMD_ID',
46
-                    esc_html__('ID', 'event_espresso')
47
-                ),
48
-                'PMD_type'            => new EE_Plain_Text_Field(
49
-                    'PMD_type',
50
-                    esc_html__('Payment Method Type', 'event_espresso'),
51
-                    false,
52
-                    'Admin_Only'
53
-                ),
54
-                'PMD_name'            => new EE_Plain_Text_Field(
55
-                    'PMD_name',
56
-                    esc_html__('Name', 'event_espresso'),
57
-                    false
58
-                ),
59
-                'PMD_desc'            => new EE_Post_Content_Field(
60
-                    'PMD_desc',
61
-                    esc_html__('Description', 'event_espresso'),
62
-                    false,
63
-                    ''
64
-                ),
65
-                'PMD_admin_name'      => new EE_Plain_Text_Field(
66
-                    'PMD_admin_name',
67
-                    esc_html__('Admin-Only Name', 'event_espresso'),
68
-                    true
69
-                ),
70
-                'PMD_admin_desc'      => new EE_Post_Content_Field(
71
-                    'PMD_admin_desc',
72
-                    esc_html__('Admin-Only Description', 'event_espresso'),
73
-                    true
74
-                ),
75
-                'PMD_slug'            => new EE_Slug_Field(
76
-                    'PMD_slug',
77
-                    esc_html__('Slug', 'event_espresso'),
78
-                    false
79
-                ),
80
-                'PMD_order'           => new EE_Integer_Field(
81
-                    'PMD_order',
82
-                    esc_html__('Order', 'event_espresso'),
83
-                    false,
84
-                    0
85
-                ),
86
-                'PMD_debug_mode'      => new EE_Boolean_Field(
87
-                    'PMD_debug_mode',
88
-                    esc_html__('Sandbox Mode On? (AKA: debug mode)', 'event_espresso'),
89
-                    false,
90
-                    false
91
-                ),
92
-                'PMD_wp_user'         => new EE_WP_User_Field(
93
-                    'PMD_wp_user',
94
-                    esc_html__('Payment Method Creator ID', 'event_espresso'),
95
-                    false
96
-                ),
97
-                'PMD_open_by_default' => new EE_Boolean_Field(
98
-                    'PMD_open_by_default',
99
-                    esc_html__('Open by Default?', 'event_espresso'),
100
-                    false,
101
-                    false
102
-                ),
103
-                'PMD_button_url'      => new EE_Plain_Text_Field(
104
-                    'PMD_button_url',
105
-                    esc_html__('Button URL', 'event_espresso'),
106
-                    true,
107
-                    ''
108
-                ),
109
-                'PMD_scope'           => new EE_Serialized_Text_Field(
110
-                    'PMD_scope',
111
-                    esc_html__('Usable From?', 'event_espresso'),
112
-                    false,
113
-                    []// possible values currently are 'CART','ADMIN','API'
114
-                ),
115
-            ],
116
-        ];
117
-        $this->_model_relations = [
118
-            'Currency'    => new EE_HABTM_Relation('Currency_Payment_Method'),
119
-            'Payment'     => new EE_Has_Many_Relation(),
120
-            'Transaction' => new EE_Has_Many_Relation(),
121
-            'WP_User'     => new EE_Belongs_To_Relation(),
122
-        ];
123
-        parent::__construct($timezone);
124
-    }
125
-
126
-
127
-    /**
128
-     * Gets one by the slug provided
129
-     *
130
-     * @param string $slug
131
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
132
-     * @throws EE_Error
133
-     */
134
-    public function get_one_by_slug($slug)
135
-    {
136
-        return $this->get_one([['PMD_slug' => $slug]]);
137
-    }
138
-
139
-
140
-    /**
141
-     * Gets all the acceptable scopes for payment methods.
142
-     * Keys are their names as store din the DB, and values are nice names for displaying them
143
-     *
144
-     * @return array
145
-     */
146
-    public function scopes()
147
-    {
148
-        return apply_filters(
149
-            'FHEE__EEM_Payment_Method__scopes',
150
-            [
151
-                EEM_Payment_Method::scope_cart  => esc_html__('Front-end Registration Page', 'event_espresso'),
152
-                EEM_Payment_Method::scope_admin => esc_html__(
153
-                    'Admin Registration Page (no online processing)',
154
-                    'event_espresso'
155
-                ),
156
-            ]
157
-        );
158
-    }
159
-
160
-
161
-    /**
162
-     * Determines if this is an valid scope
163
-     *
164
-     * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
165
-     * @return boolean
166
-     */
167
-    public function is_valid_scope($scope)
168
-    {
169
-        $scopes = $this->scopes();
170
-        if (isset($scopes[ $scope ])) {
171
-            return true;
172
-        }
173
-        return false;
174
-    }
175
-
176
-
177
-    /**
178
-     * Gets all active payment methods
179
-     *
180
-     * @param string $scope one of
181
-     * @param array  $query_params
182
-     * @return EE_Base_Class[]|EE_Payment_Method[]
183
-     * @throws EE_Error
184
-     */
185
-    public function get_all_active($scope = null, $query_params = [])
186
-    {
187
-        if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
188
-            $query_params['order_by'] = ['PMD_order' => 'ASC', 'PMD_ID' => 'ASC'];
189
-        }
190
-        return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
191
-    }
192
-
193
-
194
-    /**
195
-     * Counts all active gateways in the specified scope
196
-     *
197
-     * @param string $scope one of EEM_Payment_Method::scope_*
198
-     * @param array  $query_params
199
-     * @return int
200
-     * @throws EE_Error
201
-     */
202
-    public function count_active($scope = null, $query_params = [])
203
-    {
204
-        return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
205
-    }
206
-
207
-
208
-    /**
209
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
210
-     * argument to get all active for a given scope
211
-     *
212
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
213
-     * @param array  $query_params
214
-     * @return array
215
-     * @throws EE_Error
216
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
217
-     */
218
-    protected function _get_query_params_for_all_active($scope = null, $query_params = [])
219
-    {
220
-        if ($scope) {
221
-            if ($this->is_valid_scope($scope)) {
222
-                return array_replace_recursive([['PMD_scope' => ['LIKE', "%$scope%"]]], $query_params);
223
-            }
224
-            throw new EE_Error(
225
-                sprintf(
226
-                    esc_html__("'%s' is not a valid scope for a payment method", 'event_espresso'),
227
-                    $scope
228
-                )
229
-            );
230
-        }
231
-        $acceptable_scopes = [];
232
-        $count             = 0;
233
-        foreach ($this->scopes() as $scope_name => $desc) {
234
-            $count++;
235
-            $acceptable_scopes[ 'PMD_scope*' . $count ] = ['LIKE', '%' . $scope_name . '%'];
236
-        }
237
-        return array_replace_recursive([['OR*active_scope' => $acceptable_scopes]], $query_params);
238
-    }
239
-
240
-
241
-    /**
242
-     * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
243
-     * argument to get all active for a given scope
244
-     *
245
-     * @param string $scope one of the constants EEM_Payment_Method::scope_*
246
-     * @param array  $query_params
247
-     * @return array
248
-     * @throws EE_Error
249
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
250
-     */
251
-    public function get_query_params_for_all_active($scope = null, $query_params = [])
252
-    {
253
-        return $this->_get_query_params_for_all_active($scope, $query_params);
254
-    }
255
-
256
-
257
-    /**
258
-     * Gets one active payment method. see @get_all_active for documentation
259
-     *
260
-     * @param string $scope
261
-     * @param array  $query_params
262
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
263
-     * @throws EE_Error
264
-     */
265
-    public function get_one_active($scope = null, $query_params = [])
266
-    {
267
-        return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
268
-    }
269
-
270
-
271
-    /**
272
-     * Gets one payment method of that type, regardless of whether its active or not
273
-     *
274
-     * @param string $type
275
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
276
-     * @throws EE_Error
277
-     */
278
-    public function get_one_of_type($type)
279
-    {
280
-        return $this->get_one([['PMD_type' => $type]]);
281
-    }
282
-
283
-
284
-    /**
285
-     * Overrides parent ot also check by the slug
286
-     *
287
-     * @param string|int|EE_Payment_Method $base_class_obj_or_id
288
-     * @param boolean                      $ensure_is_in_db
289
-     * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|int|string
290
-     * @throws EE_Error
291
-     * @see EEM_Base::ensure_is_obj()
292
-     */
293
-    public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
294
-    {
295
-        // first: check if it's a slug
296
-        if (is_string($base_class_obj_or_id)) {
297
-            $obj = $this->get_one_by_slug($base_class_obj_or_id);
298
-            if ($obj) {
299
-                return $obj;
300
-            }
301
-        }
302
-        // ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
303
-        try {
304
-            return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
305
-        } catch (EE_Error $e) {
306
-            // handle it outside the catch
307
-        }
308
-        throw new EE_Error(
309
-            sprintf(
310
-                esc_html__("'%s' is neither a Payment Method ID, slug, nor object.", 'event_espresso'),
311
-                $base_class_obj_or_id
312
-            )
313
-        );
314
-    }
315
-
316
-
317
-    /**
318
-     * Gets the ID of this object, or if its a string finds the object's id
319
-     * associated with that slug
320
-     *
321
-     * @param mixed $base_obj_or_id_or_slug
322
-     * @return int
323
-     * @throws EE_Error
324
-     */
325
-    public function ensure_is_ID($base_obj_or_id_or_slug)
326
-    {
327
-        if (is_string($base_obj_or_id_or_slug)) {
328
-            // assume it's a slug
329
-            $base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
330
-        }
331
-        return parent::ensure_is_ID($base_obj_or_id_or_slug);
332
-    }
333
-
334
-
335
-    /**
336
-     * Verifies the button urls on all the passed payment methods have a valid button url.
337
-     * If not, resets them to their default.
338
-     *
339
-     * @param EE_Payment_Method[] $payment_methods if NULL, defaults to all payment methods active in the cart
340
-     * @throws EE_Error
341
-     * @throws ReflectionException
342
-     */
343
-    public function verify_button_urls($payment_methods = null)
344
-    {
345
-        $payment_methods = is_array($payment_methods)
346
-            ? $payment_methods
347
-            : $this->get_all_active(EEM_Payment_Method::scope_cart);
348
-        foreach ($payment_methods as $payment_method) {
349
-            try {
350
-                // If there is really no button URL at all, or if the button URLs still point to decaf folder even
351
-                // though this is a caffeinated install, reset it to the default.
352
-                $current_button_url = $payment_method->button_url();
353
-                if (
354
-                    empty($current_button_url)
355
-                    || (
356
-                        strpos($current_button_url, 'decaf') !== false
357
-                        && strpos($payment_method->type_obj()->default_button_url(), 'decaf') === false
358
-                    )
359
-                ) {
360
-                    $payment_method->save(
361
-                        [
362
-                            'PMD_button_url' => $payment_method->type_obj()->default_button_url(),
363
-                        ]
364
-                    );
365
-                }
366
-            } catch (EE_Error $e) {
367
-                $payment_method->deactivate();
368
-            }
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
375
-     * but also verifies the payment method type of each is a usable object. If not,
376
-     * deactivate it, sets a notification, and deactivates it
377
-     *
378
-     * @param array $rows
379
-     * @return EE_Payment_Method[]
380
-     * @throws EE_Error
381
-     * @throws InvalidDataTypeException
382
-     * @throws ReflectionException
383
-     */
384
-    protected function _create_objects($rows = [])
385
-    {
386
-        EE_Registry::instance()->load_lib('Payment_Method_Manager');
387
-        $payment_methods = parent::_create_objects($rows);
388
-        /* @var $payment_methods EE_Payment_Method[] */
389
-        $usable_payment_methods = [];
390
-        foreach ($payment_methods as $key => $payment_method) {
391
-            if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
392
-                $usable_payment_methods[ $key ] = $payment_method;
393
-                // some payment methods enqueue their scripts in EE_PMT_*::__construct
394
-                // which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
395
-                // its scripts). but for backwards-compat we should continue to do that
396
-                $payment_method->type_obj();
397
-            } elseif ($payment_method->active()) {
398
-                // only deactivate and notify the admin if the payment is active somewhere
399
-                $payment_method->deactivate();
400
-                $payment_method->save();
401
-                do_action(
402
-                    'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
403
-                    $payment_method
404
-                );
405
-                new PersistentAdminNotice(
406
-                    'auto-deactivated-' . $payment_method->type(),
407
-                    sprintf(
408
-                        esc_html__(
409
-                            'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
410
-                            'event_espresso'
411
-                        ),
412
-                        $payment_method->admin_name(),
413
-                        '<br />',
414
-                        '<a href="' . admin_url('plugins.php') . '">',
415
-                        '</a>'
416
-                    ),
417
-                    true
418
-                );
419
-            }
420
-        }
421
-        return $usable_payment_methods;
422
-    }
423
-
424
-
425
-    /**
426
-     * Gets all the payment methods which can be used for transaction
427
-     * (according to the relations between payment methods and events, and
428
-     * the currencies used for the transaction and their relation to payment methods)
429
-     *
430
-     * @param EE_Transaction $transaction
431
-     * @param string         $scope @see EEM_Payment_Method::get_all_for_events
432
-     * @return EE_Payment_Method[]
433
-     * @throws EE_Error
434
-     */
435
-    public function get_all_for_transaction($transaction, $scope)
436
-    {
437
-        // give addons a chance to override what payment methods are chosen based on the transaction
438
-        return apply_filters(
439
-            'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
440
-            $this->get_all_active($scope, ['group_by' => 'PMD_type']),
441
-            $transaction,
442
-            $scope
443
-        );
444
-    }
445
-
446
-
447
-    /**
448
-     * Returns the payment method used for the last payment made for a registration.
449
-     * Note: if an offline payment method was selected on the related transaction then this will have no payment
450
-     * methods returned. It will ONLY return a payment method for a PAYMENT recorded against the registration.
451
-     *
452
-     * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the
453
-     *                                                    registration.
454
-     * @return EE_Payment|null
455
-     * @throws EE_Error
456
-     */
457
-    public function get_last_used_for_registration($registration_or_reg_id)
458
-    {
459
-        $registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
460
-
461
-        $query_params = [
462
-            0          => [
463
-                'Payment.Registration.REG_ID' => $registration_id,
464
-            ],
465
-            'order_by' => ['Payment.PAY_ID' => 'DESC'],
466
-        ];
467
-        return $this->get_one($query_params);
468
-    }
19
+	const scope_cart  = 'CART';
20
+
21
+	const scope_admin = 'ADMIN';
22
+
23
+	const scope_api   = 'API';
24
+
25
+
26
+	protected static ?EEM_Payment_Method $_instance = null;
27
+
28
+
29
+	/**
30
+	 * private constructor to prevent direct creation
31
+	 *
32
+	 * @param string|null $timezone
33
+	 * @throws EE_Error
34
+	 */
35
+	protected function __construct(?string $timezone = '')
36
+	{
37
+		$this->singular_item    = esc_html__('Payment Method', 'event_espresso');
38
+		$this->plural_item      = esc_html__('Payment Methods', 'event_espresso');
39
+		$this->_tables          = [
40
+			'Payment_Method' => new EE_Primary_Table('esp_payment_method', 'PMD_ID'),
41
+		];
42
+		$this->_fields          = [
43
+			'Payment_Method' => [
44
+				'PMD_ID'              => new EE_Primary_Key_Int_Field(
45
+					'PMD_ID',
46
+					esc_html__('ID', 'event_espresso')
47
+				),
48
+				'PMD_type'            => new EE_Plain_Text_Field(
49
+					'PMD_type',
50
+					esc_html__('Payment Method Type', 'event_espresso'),
51
+					false,
52
+					'Admin_Only'
53
+				),
54
+				'PMD_name'            => new EE_Plain_Text_Field(
55
+					'PMD_name',
56
+					esc_html__('Name', 'event_espresso'),
57
+					false
58
+				),
59
+				'PMD_desc'            => new EE_Post_Content_Field(
60
+					'PMD_desc',
61
+					esc_html__('Description', 'event_espresso'),
62
+					false,
63
+					''
64
+				),
65
+				'PMD_admin_name'      => new EE_Plain_Text_Field(
66
+					'PMD_admin_name',
67
+					esc_html__('Admin-Only Name', 'event_espresso'),
68
+					true
69
+				),
70
+				'PMD_admin_desc'      => new EE_Post_Content_Field(
71
+					'PMD_admin_desc',
72
+					esc_html__('Admin-Only Description', 'event_espresso'),
73
+					true
74
+				),
75
+				'PMD_slug'            => new EE_Slug_Field(
76
+					'PMD_slug',
77
+					esc_html__('Slug', 'event_espresso'),
78
+					false
79
+				),
80
+				'PMD_order'           => new EE_Integer_Field(
81
+					'PMD_order',
82
+					esc_html__('Order', 'event_espresso'),
83
+					false,
84
+					0
85
+				),
86
+				'PMD_debug_mode'      => new EE_Boolean_Field(
87
+					'PMD_debug_mode',
88
+					esc_html__('Sandbox Mode On? (AKA: debug mode)', 'event_espresso'),
89
+					false,
90
+					false
91
+				),
92
+				'PMD_wp_user'         => new EE_WP_User_Field(
93
+					'PMD_wp_user',
94
+					esc_html__('Payment Method Creator ID', 'event_espresso'),
95
+					false
96
+				),
97
+				'PMD_open_by_default' => new EE_Boolean_Field(
98
+					'PMD_open_by_default',
99
+					esc_html__('Open by Default?', 'event_espresso'),
100
+					false,
101
+					false
102
+				),
103
+				'PMD_button_url'      => new EE_Plain_Text_Field(
104
+					'PMD_button_url',
105
+					esc_html__('Button URL', 'event_espresso'),
106
+					true,
107
+					''
108
+				),
109
+				'PMD_scope'           => new EE_Serialized_Text_Field(
110
+					'PMD_scope',
111
+					esc_html__('Usable From?', 'event_espresso'),
112
+					false,
113
+					[]// possible values currently are 'CART','ADMIN','API'
114
+				),
115
+			],
116
+		];
117
+		$this->_model_relations = [
118
+			'Currency'    => new EE_HABTM_Relation('Currency_Payment_Method'),
119
+			'Payment'     => new EE_Has_Many_Relation(),
120
+			'Transaction' => new EE_Has_Many_Relation(),
121
+			'WP_User'     => new EE_Belongs_To_Relation(),
122
+		];
123
+		parent::__construct($timezone);
124
+	}
125
+
126
+
127
+	/**
128
+	 * Gets one by the slug provided
129
+	 *
130
+	 * @param string $slug
131
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
132
+	 * @throws EE_Error
133
+	 */
134
+	public function get_one_by_slug($slug)
135
+	{
136
+		return $this->get_one([['PMD_slug' => $slug]]);
137
+	}
138
+
139
+
140
+	/**
141
+	 * Gets all the acceptable scopes for payment methods.
142
+	 * Keys are their names as store din the DB, and values are nice names for displaying them
143
+	 *
144
+	 * @return array
145
+	 */
146
+	public function scopes()
147
+	{
148
+		return apply_filters(
149
+			'FHEE__EEM_Payment_Method__scopes',
150
+			[
151
+				EEM_Payment_Method::scope_cart  => esc_html__('Front-end Registration Page', 'event_espresso'),
152
+				EEM_Payment_Method::scope_admin => esc_html__(
153
+					'Admin Registration Page (no online processing)',
154
+					'event_espresso'
155
+				),
156
+			]
157
+		);
158
+	}
159
+
160
+
161
+	/**
162
+	 * Determines if this is an valid scope
163
+	 *
164
+	 * @param string $scope like one of EEM_Payment_Method::instance()->scopes()
165
+	 * @return boolean
166
+	 */
167
+	public function is_valid_scope($scope)
168
+	{
169
+		$scopes = $this->scopes();
170
+		if (isset($scopes[ $scope ])) {
171
+			return true;
172
+		}
173
+		return false;
174
+	}
175
+
176
+
177
+	/**
178
+	 * Gets all active payment methods
179
+	 *
180
+	 * @param string $scope one of
181
+	 * @param array  $query_params
182
+	 * @return EE_Base_Class[]|EE_Payment_Method[]
183
+	 * @throws EE_Error
184
+	 */
185
+	public function get_all_active($scope = null, $query_params = [])
186
+	{
187
+		if (! isset($query_params['order_by']) && ! isset($query_params['order'])) {
188
+			$query_params['order_by'] = ['PMD_order' => 'ASC', 'PMD_ID' => 'ASC'];
189
+		}
190
+		return $this->get_all($this->_get_query_params_for_all_active($scope, $query_params));
191
+	}
192
+
193
+
194
+	/**
195
+	 * Counts all active gateways in the specified scope
196
+	 *
197
+	 * @param string $scope one of EEM_Payment_Method::scope_*
198
+	 * @param array  $query_params
199
+	 * @return int
200
+	 * @throws EE_Error
201
+	 */
202
+	public function count_active($scope = null, $query_params = [])
203
+	{
204
+		return $this->count($this->_get_query_params_for_all_active($scope, $query_params));
205
+	}
206
+
207
+
208
+	/**
209
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
210
+	 * argument to get all active for a given scope
211
+	 *
212
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
213
+	 * @param array  $query_params
214
+	 * @return array
215
+	 * @throws EE_Error
216
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
217
+	 */
218
+	protected function _get_query_params_for_all_active($scope = null, $query_params = [])
219
+	{
220
+		if ($scope) {
221
+			if ($this->is_valid_scope($scope)) {
222
+				return array_replace_recursive([['PMD_scope' => ['LIKE', "%$scope%"]]], $query_params);
223
+			}
224
+			throw new EE_Error(
225
+				sprintf(
226
+					esc_html__("'%s' is not a valid scope for a payment method", 'event_espresso'),
227
+					$scope
228
+				)
229
+			);
230
+		}
231
+		$acceptable_scopes = [];
232
+		$count             = 0;
233
+		foreach ($this->scopes() as $scope_name => $desc) {
234
+			$count++;
235
+			$acceptable_scopes[ 'PMD_scope*' . $count ] = ['LIKE', '%' . $scope_name . '%'];
236
+		}
237
+		return array_replace_recursive([['OR*active_scope' => $acceptable_scopes]], $query_params);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Creates the $query_params that can be passed into any EEM_Payment_Method as their $query_params
243
+	 * argument to get all active for a given scope
244
+	 *
245
+	 * @param string $scope one of the constants EEM_Payment_Method::scope_*
246
+	 * @param array  $query_params
247
+	 * @return array
248
+	 * @throws EE_Error
249
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
250
+	 */
251
+	public function get_query_params_for_all_active($scope = null, $query_params = [])
252
+	{
253
+		return $this->_get_query_params_for_all_active($scope, $query_params);
254
+	}
255
+
256
+
257
+	/**
258
+	 * Gets one active payment method. see @get_all_active for documentation
259
+	 *
260
+	 * @param string $scope
261
+	 * @param array  $query_params
262
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
263
+	 * @throws EE_Error
264
+	 */
265
+	public function get_one_active($scope = null, $query_params = [])
266
+	{
267
+		return $this->get_one($this->_get_query_params_for_all_active($scope, $query_params));
268
+	}
269
+
270
+
271
+	/**
272
+	 * Gets one payment method of that type, regardless of whether its active or not
273
+	 *
274
+	 * @param string $type
275
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|NULL
276
+	 * @throws EE_Error
277
+	 */
278
+	public function get_one_of_type($type)
279
+	{
280
+		return $this->get_one([['PMD_type' => $type]]);
281
+	}
282
+
283
+
284
+	/**
285
+	 * Overrides parent ot also check by the slug
286
+	 *
287
+	 * @param string|int|EE_Payment_Method $base_class_obj_or_id
288
+	 * @param boolean                      $ensure_is_in_db
289
+	 * @return EE_Base_Class|EE_Payment_Method|EE_Soft_Delete_Base_Class|int|string
290
+	 * @throws EE_Error
291
+	 * @see EEM_Base::ensure_is_obj()
292
+	 */
293
+	public function ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db = false)
294
+	{
295
+		// first: check if it's a slug
296
+		if (is_string($base_class_obj_or_id)) {
297
+			$obj = $this->get_one_by_slug($base_class_obj_or_id);
298
+			if ($obj) {
299
+				return $obj;
300
+			}
301
+		}
302
+		// ok so it wasn't a slug we were passed. try the usual then (ie, it's an object or an ID)
303
+		try {
304
+			return parent::ensure_is_obj($base_class_obj_or_id, $ensure_is_in_db);
305
+		} catch (EE_Error $e) {
306
+			// handle it outside the catch
307
+		}
308
+		throw new EE_Error(
309
+			sprintf(
310
+				esc_html__("'%s' is neither a Payment Method ID, slug, nor object.", 'event_espresso'),
311
+				$base_class_obj_or_id
312
+			)
313
+		);
314
+	}
315
+
316
+
317
+	/**
318
+	 * Gets the ID of this object, or if its a string finds the object's id
319
+	 * associated with that slug
320
+	 *
321
+	 * @param mixed $base_obj_or_id_or_slug
322
+	 * @return int
323
+	 * @throws EE_Error
324
+	 */
325
+	public function ensure_is_ID($base_obj_or_id_or_slug)
326
+	{
327
+		if (is_string($base_obj_or_id_or_slug)) {
328
+			// assume it's a slug
329
+			$base_obj_or_id_or_slug = $this->get_one_by_slug($base_obj_or_id_or_slug);
330
+		}
331
+		return parent::ensure_is_ID($base_obj_or_id_or_slug);
332
+	}
333
+
334
+
335
+	/**
336
+	 * Verifies the button urls on all the passed payment methods have a valid button url.
337
+	 * If not, resets them to their default.
338
+	 *
339
+	 * @param EE_Payment_Method[] $payment_methods if NULL, defaults to all payment methods active in the cart
340
+	 * @throws EE_Error
341
+	 * @throws ReflectionException
342
+	 */
343
+	public function verify_button_urls($payment_methods = null)
344
+	{
345
+		$payment_methods = is_array($payment_methods)
346
+			? $payment_methods
347
+			: $this->get_all_active(EEM_Payment_Method::scope_cart);
348
+		foreach ($payment_methods as $payment_method) {
349
+			try {
350
+				// If there is really no button URL at all, or if the button URLs still point to decaf folder even
351
+				// though this is a caffeinated install, reset it to the default.
352
+				$current_button_url = $payment_method->button_url();
353
+				if (
354
+					empty($current_button_url)
355
+					|| (
356
+						strpos($current_button_url, 'decaf') !== false
357
+						&& strpos($payment_method->type_obj()->default_button_url(), 'decaf') === false
358
+					)
359
+				) {
360
+					$payment_method->save(
361
+						[
362
+							'PMD_button_url' => $payment_method->type_obj()->default_button_url(),
363
+						]
364
+					);
365
+				}
366
+			} catch (EE_Error $e) {
367
+				$payment_method->deactivate();
368
+			}
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * Overrides parent to not only turn wpdb results into EE_Payment_Method objects,
375
+	 * but also verifies the payment method type of each is a usable object. If not,
376
+	 * deactivate it, sets a notification, and deactivates it
377
+	 *
378
+	 * @param array $rows
379
+	 * @return EE_Payment_Method[]
380
+	 * @throws EE_Error
381
+	 * @throws InvalidDataTypeException
382
+	 * @throws ReflectionException
383
+	 */
384
+	protected function _create_objects($rows = [])
385
+	{
386
+		EE_Registry::instance()->load_lib('Payment_Method_Manager');
387
+		$payment_methods = parent::_create_objects($rows);
388
+		/* @var $payment_methods EE_Payment_Method[] */
389
+		$usable_payment_methods = [];
390
+		foreach ($payment_methods as $key => $payment_method) {
391
+			if (EE_Payment_Method_Manager::instance()->payment_method_type_exists($payment_method->type())) {
392
+				$usable_payment_methods[ $key ] = $payment_method;
393
+				// some payment methods enqueue their scripts in EE_PMT_*::__construct
394
+				// which is kinda a no-no (just because it's being constructed doesn't mean we need to enqueue
395
+				// its scripts). but for backwards-compat we should continue to do that
396
+				$payment_method->type_obj();
397
+			} elseif ($payment_method->active()) {
398
+				// only deactivate and notify the admin if the payment is active somewhere
399
+				$payment_method->deactivate();
400
+				$payment_method->save();
401
+				do_action(
402
+					'AHEE__EEM_Payment_Method___create_objects_auto_deactivated_payment_method',
403
+					$payment_method
404
+				);
405
+				new PersistentAdminNotice(
406
+					'auto-deactivated-' . $payment_method->type(),
407
+					sprintf(
408
+						esc_html__(
409
+							'The payment method %1$s was automatically deactivated because it appears its associated Event Espresso Addon was recently deactivated.%2$sIt can be reactivated on the %3$sPlugins admin page%4$s, then you can reactivate the payment method.',
410
+							'event_espresso'
411
+						),
412
+						$payment_method->admin_name(),
413
+						'<br />',
414
+						'<a href="' . admin_url('plugins.php') . '">',
415
+						'</a>'
416
+					),
417
+					true
418
+				);
419
+			}
420
+		}
421
+		return $usable_payment_methods;
422
+	}
423
+
424
+
425
+	/**
426
+	 * Gets all the payment methods which can be used for transaction
427
+	 * (according to the relations between payment methods and events, and
428
+	 * the currencies used for the transaction and their relation to payment methods)
429
+	 *
430
+	 * @param EE_Transaction $transaction
431
+	 * @param string         $scope @see EEM_Payment_Method::get_all_for_events
432
+	 * @return EE_Payment_Method[]
433
+	 * @throws EE_Error
434
+	 */
435
+	public function get_all_for_transaction($transaction, $scope)
436
+	{
437
+		// give addons a chance to override what payment methods are chosen based on the transaction
438
+		return apply_filters(
439
+			'FHEE__EEM_Payment_Method__get_all_for_transaction__payment_methods',
440
+			$this->get_all_active($scope, ['group_by' => 'PMD_type']),
441
+			$transaction,
442
+			$scope
443
+		);
444
+	}
445
+
446
+
447
+	/**
448
+	 * Returns the payment method used for the last payment made for a registration.
449
+	 * Note: if an offline payment method was selected on the related transaction then this will have no payment
450
+	 * methods returned. It will ONLY return a payment method for a PAYMENT recorded against the registration.
451
+	 *
452
+	 * @param EE_Registration|int $registration_or_reg_id Either the EE_Registration object or the id for the
453
+	 *                                                    registration.
454
+	 * @return EE_Payment|null
455
+	 * @throws EE_Error
456
+	 */
457
+	public function get_last_used_for_registration($registration_or_reg_id)
458
+	{
459
+		$registration_id = EEM_Registration::instance()->ensure_is_ID($registration_or_reg_id);
460
+
461
+		$query_params = [
462
+			0          => [
463
+				'Payment.Registration.REG_ID' => $registration_id,
464
+			],
465
+			'order_by' => ['Payment.PAY_ID' => 'DESC'],
466
+		];
467
+		return $this->get_one($query_params);
468
+	}
469 469
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Price.model.php 1 patch
Indentation   +349 added lines, -349 removed lines patch added patch discarded remove patch
@@ -12,380 +12,380 @@
 block discarded – undo
12 12
  */
13 13
 class EEM_Price extends EEM_Soft_Delete_Base
14 14
 {
15
-    protected static ?EEM_Price $_instance = null;
15
+	protected static ?EEM_Price $_instance = null;
16 16
 
17 17
 
18
-    /**
19
-     * private constructor to prevent direct creation
20
-     *
21
-     * @Constructor
22
-     * @param string|null $timezone string representing the timezone we want to set for returned Date Time Strings
23
-     *                              (and any incoming timezone data that gets saved).
24
-     *                              Note this just sends the timezone info to the date time model field objects.
25
-     *                              Default is NULL
26
-     *                              (and will be assumed using the set timezone in the 'timezone_string' wp option)
27
-     * @throws EE_Error
28
-     * @throws ReflectionException
29
-     */
30
-    protected function __construct(?string $timezone = '')
31
-    {
32
-        $this->singular_item = esc_html__('Price', 'event_espresso');
33
-        $this->plural_item   = esc_html__('Prices', 'event_espresso');
18
+	/**
19
+	 * private constructor to prevent direct creation
20
+	 *
21
+	 * @Constructor
22
+	 * @param string|null $timezone string representing the timezone we want to set for returned Date Time Strings
23
+	 *                              (and any incoming timezone data that gets saved).
24
+	 *                              Note this just sends the timezone info to the date time model field objects.
25
+	 *                              Default is NULL
26
+	 *                              (and will be assumed using the set timezone in the 'timezone_string' wp option)
27
+	 * @throws EE_Error
28
+	 * @throws ReflectionException
29
+	 */
30
+	protected function __construct(?string $timezone = '')
31
+	{
32
+		$this->singular_item = esc_html__('Price', 'event_espresso');
33
+		$this->plural_item   = esc_html__('Prices', 'event_espresso');
34 34
 
35
-        $this->_tables          = [
36
-            'Price' => new EE_Primary_Table('esp_price', 'PRC_ID'),
37
-        ];
38
-        $this->_fields          = [
39
-            'Price' => [
40
-                'PRC_ID'         => new EE_Primary_Key_Int_Field(
41
-                    'PRC_ID',
42
-                    'Price ID'
43
-                ),
44
-                'PRT_ID'         => new EE_Foreign_Key_Int_Field(
45
-                    'PRT_ID',
46
-                    esc_html__('Price type Id', 'event_espresso'),
47
-                    false,
48
-                    null,
49
-                    'Price_Type'
50
-                ),
51
-                'PRC_amount'     => new EE_Money_Field(
52
-                    'PRC_amount',
53
-                    esc_html__('Price Amount', 'event_espresso'),
54
-                    false,
55
-                    0
56
-                ),
57
-                'PRC_name'       => new EE_Plain_Text_Field(
58
-                    'PRC_name',
59
-                    esc_html__('Name of Price', 'event_espresso'),
60
-                    false,
61
-                    ''
62
-                ),
63
-                'PRC_desc'       => new EE_Post_Content_Field(
64
-                    'PRC_desc',
65
-                    esc_html__('Price Description', 'event_espresso'),
66
-                    false,
67
-                    ''
68
-                ),
69
-                'PRC_is_default' => new EE_Boolean_Field(
70
-                    'PRC_is_default',
71
-                    esc_html__('Flag indicating whether price is a default price', 'event_espresso'),
72
-                    false,
73
-                    false
74
-                ),
75
-                'PRC_overrides'  => new EE_Integer_Field(
76
-                    'PRC_overrides',
77
-                    esc_html__(
78
-                        'Price ID for a global Price that will be overridden by this Price  ( for replacing default prices )',
79
-                        'event_espresso'
80
-                    ),
81
-                    true,
82
-                    0
83
-                ),
84
-                'PRC_order'      => new EE_Integer_Field(
85
-                    'PRC_order',
86
-                    esc_html__(
87
-                        'Order of Application of Price (lower numbers apply first?)',
88
-                        'event_espresso'
89
-                    ),
90
-                    false,
91
-                    1
92
-                ),
93
-                'PRC_deleted'    => new EE_Trashed_Flag_Field(
94
-                    'PRC_deleted',
95
-                    esc_html__('Flag Indicating if this has been deleted or not', 'event_espresso'),
96
-                    false,
97
-                    false
98
-                ),
99
-                'PRC_parent'     => new EE_Integer_Field(
100
-                    'PRC_parent',
101
-                    esc_html__('Indicates what PRC_ID is the parent of this PRC_ID', 'event_espresso'),
102
-                    true,
103
-                    0
104
-                ),
105
-                'PRC_wp_user'    => new EE_WP_User_Field(
106
-                    'PRC_wp_user',
107
-                    esc_html__('Price Creator ID', 'event_espresso'),
108
-                    false
109
-                ),
110
-            ],
111
-        ];
112
-        $this->_model_relations = [
113
-            'Ticket'     => new EE_HABTM_Relation('Ticket_Price'),
114
-            'Price_Type' => new EE_Belongs_To_Relation(),
115
-            'WP_User'    => new EE_Belongs_To_Relation(),
116
-        ];
117
-        // this model is generally available for reading
118
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] =
119
-            new EE_Restriction_Generator_Default_Public(
120
-                'PRC_is_default',
121
-                'Ticket.Datetime.Event'
122
-            );
123
-        // account for default tickets in the caps
124
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
125
-            new EE_Restriction_Generator_Default_Protected(
126
-                'PRC_is_default',
127
-                'Ticket.Datetime.Event'
128
-            );
129
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
130
-            new EE_Restriction_Generator_Default_Protected(
131
-                'PRC_is_default',
132
-                'Ticket.Datetime.Event'
133
-            );
134
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
135
-            new EE_Restriction_Generator_Default_Protected(
136
-                'PRC_is_default',
137
-                'Ticket.Datetime.Event'
138
-            );
139
-        parent::__construct($timezone);
140
-    }
35
+		$this->_tables          = [
36
+			'Price' => new EE_Primary_Table('esp_price', 'PRC_ID'),
37
+		];
38
+		$this->_fields          = [
39
+			'Price' => [
40
+				'PRC_ID'         => new EE_Primary_Key_Int_Field(
41
+					'PRC_ID',
42
+					'Price ID'
43
+				),
44
+				'PRT_ID'         => new EE_Foreign_Key_Int_Field(
45
+					'PRT_ID',
46
+					esc_html__('Price type Id', 'event_espresso'),
47
+					false,
48
+					null,
49
+					'Price_Type'
50
+				),
51
+				'PRC_amount'     => new EE_Money_Field(
52
+					'PRC_amount',
53
+					esc_html__('Price Amount', 'event_espresso'),
54
+					false,
55
+					0
56
+				),
57
+				'PRC_name'       => new EE_Plain_Text_Field(
58
+					'PRC_name',
59
+					esc_html__('Name of Price', 'event_espresso'),
60
+					false,
61
+					''
62
+				),
63
+				'PRC_desc'       => new EE_Post_Content_Field(
64
+					'PRC_desc',
65
+					esc_html__('Price Description', 'event_espresso'),
66
+					false,
67
+					''
68
+				),
69
+				'PRC_is_default' => new EE_Boolean_Field(
70
+					'PRC_is_default',
71
+					esc_html__('Flag indicating whether price is a default price', 'event_espresso'),
72
+					false,
73
+					false
74
+				),
75
+				'PRC_overrides'  => new EE_Integer_Field(
76
+					'PRC_overrides',
77
+					esc_html__(
78
+						'Price ID for a global Price that will be overridden by this Price  ( for replacing default prices )',
79
+						'event_espresso'
80
+					),
81
+					true,
82
+					0
83
+				),
84
+				'PRC_order'      => new EE_Integer_Field(
85
+					'PRC_order',
86
+					esc_html__(
87
+						'Order of Application of Price (lower numbers apply first?)',
88
+						'event_espresso'
89
+					),
90
+					false,
91
+					1
92
+				),
93
+				'PRC_deleted'    => new EE_Trashed_Flag_Field(
94
+					'PRC_deleted',
95
+					esc_html__('Flag Indicating if this has been deleted or not', 'event_espresso'),
96
+					false,
97
+					false
98
+				),
99
+				'PRC_parent'     => new EE_Integer_Field(
100
+					'PRC_parent',
101
+					esc_html__('Indicates what PRC_ID is the parent of this PRC_ID', 'event_espresso'),
102
+					true,
103
+					0
104
+				),
105
+				'PRC_wp_user'    => new EE_WP_User_Field(
106
+					'PRC_wp_user',
107
+					esc_html__('Price Creator ID', 'event_espresso'),
108
+					false
109
+				),
110
+			],
111
+		];
112
+		$this->_model_relations = [
113
+			'Ticket'     => new EE_HABTM_Relation('Ticket_Price'),
114
+			'Price_Type' => new EE_Belongs_To_Relation(),
115
+			'WP_User'    => new EE_Belongs_To_Relation(),
116
+		];
117
+		// this model is generally available for reading
118
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] =
119
+			new EE_Restriction_Generator_Default_Public(
120
+				'PRC_is_default',
121
+				'Ticket.Datetime.Event'
122
+			);
123
+		// account for default tickets in the caps
124
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
125
+			new EE_Restriction_Generator_Default_Protected(
126
+				'PRC_is_default',
127
+				'Ticket.Datetime.Event'
128
+			);
129
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
130
+			new EE_Restriction_Generator_Default_Protected(
131
+				'PRC_is_default',
132
+				'Ticket.Datetime.Event'
133
+			);
134
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
135
+			new EE_Restriction_Generator_Default_Protected(
136
+				'PRC_is_default',
137
+				'Ticket.Datetime.Event'
138
+			);
139
+		parent::__construct($timezone);
140
+	}
141 141
 
142 142
 
143
-    /**
144
-     * instantiate a new price object with blank/empty properties
145
-     *
146
-     * @return EE_Price
147
-     * @throws EE_Error
148
-     * @throws ReflectionException
149
-     */
150
-    public function get_new_price(): EE_Price
151
-    {
152
-        return $this->create_default_object();
153
-    }
143
+	/**
144
+	 * instantiate a new price object with blank/empty properties
145
+	 *
146
+	 * @return EE_Price
147
+	 * @throws EE_Error
148
+	 * @throws ReflectionException
149
+	 */
150
+	public function get_new_price(): EE_Price
151
+	{
152
+		return $this->create_default_object();
153
+	}
154 154
 
155 155
 
156
-    /**
157
-     * retrieve  ALL prices from db
158
-     *
159
-     * @return EE_Price[]
160
-     * @throws EE_Error
161
-     * @throws ReflectionException
162
-     */
163
-    public function get_all_prices(): array
164
-    {
165
-        // retrieve all prices
166
-        return $this->get_all(['order_by' => ['PRC_amount' => 'ASC']]);
167
-    }
156
+	/**
157
+	 * retrieve  ALL prices from db
158
+	 *
159
+	 * @return EE_Price[]
160
+	 * @throws EE_Error
161
+	 * @throws ReflectionException
162
+	 */
163
+	public function get_all_prices(): array
164
+	{
165
+		// retrieve all prices
166
+		return $this->get_all(['order_by' => ['PRC_amount' => 'ASC']]);
167
+	}
168 168
 
169 169
 
170
-    /**
171
-     * retrieve all active prices for a particular event
172
-     *
173
-     * @param int $EVT_ID
174
-     * @return array on success
175
-     * @throws EE_Error
176
-     * @throws ReflectionException
177
-     */
178
-    public function get_all_event_prices(int $EVT_ID = 0): array
179
-    {
180
-        return $this->get_all(
181
-            [
182
-                [
183
-                    'EVT_ID'            => $EVT_ID,
184
-                    'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax],
185
-                ],
186
-                'order_by' => $this->_order_by_array_for_get_all_method(),
187
-            ]
188
-        );
189
-    }
170
+	/**
171
+	 * retrieve all active prices for a particular event
172
+	 *
173
+	 * @param int $EVT_ID
174
+	 * @return array on success
175
+	 * @throws EE_Error
176
+	 * @throws ReflectionException
177
+	 */
178
+	public function get_all_event_prices(int $EVT_ID = 0): array
179
+	{
180
+		return $this->get_all(
181
+			[
182
+				[
183
+					'EVT_ID'            => $EVT_ID,
184
+					'Price_Type.PBT_ID' => ['!=', EEM_Price_Type::base_type_tax],
185
+				],
186
+				'order_by' => $this->_order_by_array_for_get_all_method(),
187
+			]
188
+		);
189
+	}
190 190
 
191 191
 
192
-    /**
193
-     * retrieve all active global prices (that are not taxes (PBT_ID=4)) for a particular event
194
-     *
195
-     * @param bool $count return count
196
-     * @param bool $include_taxes
197
-     * @return int|EE_Price[]
198
-     * @throws EE_Error
199
-     * @throws ReflectionException
200
-     * @throws ReflectionException
201
-     */
202
-    public function get_all_default_prices(bool $count = false, bool $include_taxes = false)
203
-    {
204
-        $_where = [
205
-            'PRC_deleted'    => 0,
206
-            'PRC_is_default' => 1,
207
-        ];
208
-        if (! $include_taxes) {
209
-            $_where['Price_Type.PBT_ID'] = ['!=', 4];
210
-        }
211
-        $_query_params = [
212
-            $_where,
213
-            'order_by' => $this->_order_by_array_for_get_all_method(),
214
-        ];
215
-        return $count ? $this->count([$_where]) : $this->get_all($_query_params);
216
-    }
192
+	/**
193
+	 * retrieve all active global prices (that are not taxes (PBT_ID=4)) for a particular event
194
+	 *
195
+	 * @param bool $count return count
196
+	 * @param bool $include_taxes
197
+	 * @return int|EE_Price[]
198
+	 * @throws EE_Error
199
+	 * @throws ReflectionException
200
+	 * @throws ReflectionException
201
+	 */
202
+	public function get_all_default_prices(bool $count = false, bool $include_taxes = false)
203
+	{
204
+		$_where = [
205
+			'PRC_deleted'    => 0,
206
+			'PRC_is_default' => 1,
207
+		];
208
+		if (! $include_taxes) {
209
+			$_where['Price_Type.PBT_ID'] = ['!=', 4];
210
+		}
211
+		$_query_params = [
212
+			$_where,
213
+			'order_by' => $this->_order_by_array_for_get_all_method(),
214
+		];
215
+		return $count ? $this->count([$_where]) : $this->get_all($_query_params);
216
+	}
217 217
 
218 218
 
219
-    /**
220
-     * retrieve all active global prices that are taxes
221
-     *
222
-     * @return EE_Price[]
223
-     * @throws EE_Error
224
-     * @throws ReflectionException
225
-     * @since   5.0.0.p
226
-     */
227
-    public function getAllDefaultTaxes(): array
228
-    {
229
-        return $this->get_all(
230
-            [
231
-                [
232
-                    'PRC_deleted'       => 0,
233
-                    'PRC_is_default'    => 1,
234
-                    'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax,
235
-                ],
236
-                'order_by' => [
237
-                    'Price_Type.PRT_order' => 'ASC',
238
-                    'PRC_order'            => 'ASC',
239
-                ],
240
-            ]
241
-        );
242
-    }
219
+	/**
220
+	 * retrieve all active global prices that are taxes
221
+	 *
222
+	 * @return EE_Price[]
223
+	 * @throws EE_Error
224
+	 * @throws ReflectionException
225
+	 * @since   5.0.0.p
226
+	 */
227
+	public function getAllDefaultTaxes(): array
228
+	{
229
+		return $this->get_all(
230
+			[
231
+				[
232
+					'PRC_deleted'       => 0,
233
+					'PRC_is_default'    => 1,
234
+					'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax,
235
+				],
236
+				'order_by' => [
237
+					'Price_Type.PRT_order' => 'ASC',
238
+					'PRC_order'            => 'ASC',
239
+				],
240
+			]
241
+		);
242
+	}
243 243
 
244 244
 
245
-    /**
246
-     * retrieve all prices that are taxes
247
-     *
248
-     * @return EE_Price[]
249
-     * @throws EE_Error
250
-     * @throws InvalidArgumentException
251
-     * @throws ReflectionException
252
-     * @throws InvalidDataTypeException
253
-     * @throws InvalidInterfaceException
254
-     */
255
-    public function get_all_prices_that_are_taxes(): array
256
-    {
257
-        $taxes     = [];
258
-        $all_taxes = $this->get_all(
259
-            [
260
-                ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax, 'PRC_is_default' => 1],
261
-                'order_by' => ['Price_Type.PRT_order' => 'ASC', 'PRC_order' => 'ASC'],
262
-            ]
263
-        );
264
-        foreach ($all_taxes as $tax) {
265
-            if ($tax instanceof EE_Price) {
266
-                $taxes[ $tax->order() ][ $tax->ID() ] = $tax;
267
-            }
268
-        }
269
-        return $taxes;
270
-    }
245
+	/**
246
+	 * retrieve all prices that are taxes
247
+	 *
248
+	 * @return EE_Price[]
249
+	 * @throws EE_Error
250
+	 * @throws InvalidArgumentException
251
+	 * @throws ReflectionException
252
+	 * @throws InvalidDataTypeException
253
+	 * @throws InvalidInterfaceException
254
+	 */
255
+	public function get_all_prices_that_are_taxes(): array
256
+	{
257
+		$taxes     = [];
258
+		$all_taxes = $this->get_all(
259
+			[
260
+				['Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax, 'PRC_is_default' => 1],
261
+				'order_by' => ['Price_Type.PRT_order' => 'ASC', 'PRC_order' => 'ASC'],
262
+			]
263
+		);
264
+		foreach ($all_taxes as $tax) {
265
+			if ($tax instanceof EE_Price) {
266
+				$taxes[ $tax->order() ][ $tax->ID() ] = $tax;
267
+			}
268
+		}
269
+		return $taxes;
270
+	}
271 271
 
272 272
 
273
-    /**
274
-     * retrieve all prices for an ticket plus default global prices, but not taxes
275
-     *
276
-     * @param int $TKT_ID the id of the event.  If not included then we assume that this is a new ticket.
277
-     * @return EE_Price[]
278
-     * @throws EE_Error
279
-     * @throws ReflectionException
280
-     * @throws ReflectionException
281
-     * @throws ReflectionException
282
-     */
283
-    public function get_all_ticket_prices_for_admin(int $TKT_ID = 0): array
284
-    {
285
-        $array_of_price_objects = [];
286
-        if (empty($TKT_ID)) {
287
-            // if there is no tkt, get prices with no tkt ID, are global, are not a tax, and are active
288
-            // return that list
289
-            $default_prices = $this->get_all_default_prices();
273
+	/**
274
+	 * retrieve all prices for an ticket plus default global prices, but not taxes
275
+	 *
276
+	 * @param int $TKT_ID the id of the event.  If not included then we assume that this is a new ticket.
277
+	 * @return EE_Price[]
278
+	 * @throws EE_Error
279
+	 * @throws ReflectionException
280
+	 * @throws ReflectionException
281
+	 * @throws ReflectionException
282
+	 */
283
+	public function get_all_ticket_prices_for_admin(int $TKT_ID = 0): array
284
+	{
285
+		$array_of_price_objects = [];
286
+		if (empty($TKT_ID)) {
287
+			// if there is no tkt, get prices with no tkt ID, are global, are not a tax, and are active
288
+			// return that list
289
+			$default_prices = $this->get_all_default_prices();
290 290
 
291
-            if ($default_prices) {
292
-                foreach ($default_prices as $price) {
293
-                    if ($price instanceof EE_Price) {
294
-                        $array_of_price_objects[ $price->type() ][] = $price;
295
-                    }
296
-                }
297
-                return $array_of_price_objects;
298
-            }
299
-            return [];
300
-        }
301
-        $ticket_prices = $this->get_all(
302
-            [
303
-                [
304
-                    'TKT_ID'      => $TKT_ID,
305
-                    'PRC_deleted' => 0,
306
-                ],
307
-                'order_by' => ['PRC_order' => 'ASC'],
308
-            ]
309
-        );
291
+			if ($default_prices) {
292
+				foreach ($default_prices as $price) {
293
+					if ($price instanceof EE_Price) {
294
+						$array_of_price_objects[ $price->type() ][] = $price;
295
+					}
296
+				}
297
+				return $array_of_price_objects;
298
+			}
299
+			return [];
300
+		}
301
+		$ticket_prices = $this->get_all(
302
+			[
303
+				[
304
+					'TKT_ID'      => $TKT_ID,
305
+					'PRC_deleted' => 0,
306
+				],
307
+				'order_by' => ['PRC_order' => 'ASC'],
308
+			]
309
+		);
310 310
 
311
-        if (! empty($ticket_prices)) {
312
-            foreach ($ticket_prices as $price) {
313
-                if ($price instanceof EE_Price) {
314
-                    $array_of_price_objects[ $price->type() ][] = $price;
315
-                }
316
-            }
317
-            return $array_of_price_objects;
318
-        }
319
-        return [];
320
-    }
311
+		if (! empty($ticket_prices)) {
312
+			foreach ($ticket_prices as $price) {
313
+				if ($price instanceof EE_Price) {
314
+					$array_of_price_objects[ $price->type() ][] = $price;
315
+				}
316
+			}
317
+			return $array_of_price_objects;
318
+		}
319
+		return [];
320
+	}
321 321
 
322 322
 
323
-    /**
324
-     * @param EE_Price $price_a
325
-     * @param EE_Price $price_b
326
-     * @return int
327
-     * @throws EE_Error
328
-     * @throws ReflectionException
329
-     */
330
-    public function _sort_event_prices_by_type(EE_Price $price_a, EE_Price $price_b): int
331
-    {
332
-        if ($price_a->type_obj()->order() === $price_b->type_obj()->order()) {
333
-            return $this->_sort_event_prices_by_order($price_a, $price_b);
334
-        }
335
-        return $price_a->type_obj()->order() < $price_b->type_obj()->order() ? -1 : 1;
336
-    }
323
+	/**
324
+	 * @param EE_Price $price_a
325
+	 * @param EE_Price $price_b
326
+	 * @return int
327
+	 * @throws EE_Error
328
+	 * @throws ReflectionException
329
+	 */
330
+	public function _sort_event_prices_by_type(EE_Price $price_a, EE_Price $price_b): int
331
+	{
332
+		if ($price_a->type_obj()->order() === $price_b->type_obj()->order()) {
333
+			return $this->_sort_event_prices_by_order($price_a, $price_b);
334
+		}
335
+		return $price_a->type_obj()->order() < $price_b->type_obj()->order() ? -1 : 1;
336
+	}
337 337
 
338 338
 
339
-    /**
340
-     * @param EE_Price $price_a
341
-     * @param EE_Price $price_b
342
-     * @return int
343
-     * @throws EE_Error
344
-     * @throws ReflectionException
345
-     */
346
-    public function _sort_event_prices_by_order(EE_Price $price_a, EE_Price $price_b): int
347
-    {
348
-        if ($price_a->order() === $price_b->order()) {
349
-            return 0;
350
-        }
351
-        return $price_a->order() < $price_b->order() ? -1 : 1;
352
-    }
339
+	/**
340
+	 * @param EE_Price $price_a
341
+	 * @param EE_Price $price_b
342
+	 * @return int
343
+	 * @throws EE_Error
344
+	 * @throws ReflectionException
345
+	 */
346
+	public function _sort_event_prices_by_order(EE_Price $price_a, EE_Price $price_b): int
347
+	{
348
+		if ($price_a->order() === $price_b->order()) {
349
+			return 0;
350
+		}
351
+		return $price_a->order() < $price_b->order() ? -1 : 1;
352
+	}
353 353
 
354 354
 
355
-    /**
356
-     * get all prices of a specific type
357
-     *
358
-     * @param int $type - PRT_ID
359
-     * @return EE_Price[]
360
-     * @throws EE_Error
361
-     * @throws ReflectionException
362
-     */
363
-    public function get_all_prices_that_are_type(int $type = 0): array
364
-    {
365
-        return $this->get_all(
366
-            [
367
-                [
368
-                    'PRT_ID' => $type,
369
-                ],
370
-                'order_by' => $this->_order_by_array_for_get_all_method(),
371
-            ]
372
-        );
373
-    }
355
+	/**
356
+	 * get all prices of a specific type
357
+	 *
358
+	 * @param int $type - PRT_ID
359
+	 * @return EE_Price[]
360
+	 * @throws EE_Error
361
+	 * @throws ReflectionException
362
+	 */
363
+	public function get_all_prices_that_are_type(int $type = 0): array
364
+	{
365
+		return $this->get_all(
366
+			[
367
+				[
368
+					'PRT_ID' => $type,
369
+				],
370
+				'order_by' => $this->_order_by_array_for_get_all_method(),
371
+			]
372
+		);
373
+	}
374 374
 
375 375
 
376
-    /**
377
-     * Returns an array of the normal 'order_by' query parameter provided to the get_all query.
378
-     * Of course you don't have to use it, but this is the order we usually want to sort prices by
379
-     *
380
-     * @return array which can be used like so: $this->get_all(array(array(...where
381
-     *               stuff...),'order_by'=>$this->_order_by_array_for_get_all_method()));
382
-     */
383
-    public function _order_by_array_for_get_all_method(): array
384
-    {
385
-        return [
386
-            'PRC_order'            => 'ASC',
387
-            'Price_Type.PRT_order' => 'ASC',
388
-            'PRC_ID'               => 'ASC',
389
-        ];
390
-    }
376
+	/**
377
+	 * Returns an array of the normal 'order_by' query parameter provided to the get_all query.
378
+	 * Of course you don't have to use it, but this is the order we usually want to sort prices by
379
+	 *
380
+	 * @return array which can be used like so: $this->get_all(array(array(...where
381
+	 *               stuff...),'order_by'=>$this->_order_by_array_for_get_all_method()));
382
+	 */
383
+	public function _order_by_array_for_get_all_method(): array
384
+	{
385
+		return [
386
+			'PRC_order'            => 'ASC',
387
+			'Price_Type.PRT_order' => 'ASC',
388
+			'PRC_ID'               => 'ASC',
389
+		];
390
+	}
391 391
 }
Please login to merge, or discard this patch.
core/db_models/EEM_System_Status.model.php 1 patch
Indentation   +377 added lines, -377 removed lines patch added patch discarded remove patch
@@ -5,382 +5,382 @@
 block discarded – undo
5 5
  */
6 6
 class EEM_System_Status
7 7
 {
8
-    protected static ?EEM_System_Status $_instance = null;
9
-
10
-
11
-    /**
12
-     * This function is a singleton method used to instantiate the EEM_Attendee object
13
-     *
14
-     * @return EEM_System_Status
15
-     */
16
-    public static function instance()
17
-    {
18
-        // check if instance of EEM_System_Status already exists
19
-        if (self::$_instance === null) {
20
-            // instantiate EEM_System_Status
21
-            self::$_instance = new self();
22
-        }
23
-        return self::$_instance;
24
-    }
25
-
26
-
27
-    private function __construct()
28
-    {
29
-    }
30
-
31
-
32
-    /**
33
-     * @return array where each key is a function name on this class, and each value is SOMETHING--
34
-     * it might be a value, an array, or an object
35
-     */
36
-    public function get_system_stati()
37
-    {
38
-        return apply_filters(
39
-            'FHEE__EEM_System_Status__get_system_stati',
40
-            [
41
-                'ee_version'            => $this->get_ee_version(),
42
-                'ee_activation_history' => $this->get_ee_activation_history(),
43
-                'ee_config'             => $this->get_ee_config(),
44
-                'ee_migration_history'  => $this->get_ee_migration_history(),
45
-                'active_plugins'        => $this->get_active_plugins(),
46
-                'wp_settings'           => $this->get_wp_settings(),
47
-                'wp_maintenance_mode'   => $this->get_wp_maintenance_mode(),
48
-                'https_enabled'         => $this->get_https_enabled(),
49
-                'logging_enabled'       => $this->get_logging_enabled(),
50
-                'remote_posting'        => $this->get_remote_posting(),
51
-                'php_version'           => $this->php_version(),
52
-                'php.ini_settings'      => $this->get_php_ini_all(),
53
-                'php_info'              => $this->get_php_info(),
54
-            ],
55
-            $this
56
-        );
57
-    }
58
-
59
-
60
-    /**
61
-     * @return string
62
-     */
63
-    public function get_ee_version()
64
-    {
65
-        return espresso_version();
66
-    }
67
-
68
-
69
-    /**
70
-     * @return string
71
-     */
72
-    public function php_version()
73
-    {
74
-        return phpversion();
75
-    }
76
-
77
-
78
-    /**
79
-     * @return array, where each key is a plugin name (lower-cased), values are sub-arrays.
80
-     * Sub-arrays like described in wp function get_plugin_data. Ie,     *
81
-     *  'Name' => 'Plugin Name',
82
-     * 'PluginURI' => 'Plugin URI',
83
-     * 'Version' => 'Version',
84
-     * 'Description' => 'Description',
85
-     * 'Author' => 'Author',
86
-     * 'AuthorURI' => 'Author URI',
87
-     * 'TextDomain' => 'Text Domain',
88
-     * 'DomainPath' => 'Domain Path',
89
-     * 'Network' => 'Network',
90
-     */
91
-    public function get_active_plugins()
92
-    {
93
-        $active_plugins = (array) get_option('active_plugins', []);
94
-        if (is_multisite()) {
95
-            $active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', []));
96
-        }
97
-        $active_plugins = array_map('strtolower', $active_plugins);
98
-        $plugin_info    = [];
99
-        foreach ($active_plugins as $plugin) {
100
-            $plugin_data = @get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
101
-
102
-            $plugin_info[ $plugin ] = $plugin_data;
103
-        }
104
-        return $plugin_info;
105
-    }
106
-
107
-
108
-    /**
109
-     * @return array with keys 'home_url' and 'site_url'
110
-     */
111
-    public function get_wp_settings()
112
-    {
113
-        $wp_memory_int = $this->let_to_num(WP_MEMORY_LIMIT);
114
-        if ($wp_memory_int < 67108864) {
115
-            $wp_memory_to_display = '<mark class="error">';
116
-            $wp_memory_to_display .= sprintf(
117
-                esc_html__(
118
-                    '%s - We recommend setting memory to at least 64MB. See: %s Increasing memory allocated to PHP %s',
119
-                    'event_espresso'
120
-                ),
121
-                WP_MEMORY_LIMIT,
122
-                '<a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">',
123
-                '</a>"'
124
-            );
125
-            $wp_memory_to_display .= '</mark>';
126
-        } else {
127
-            $wp_memory_to_display = '<mark class="yes">' . size_format($wp_memory_int) . '</mark>';
128
-        }
129
-        return [
130
-            'name'                => get_bloginfo('name', 'display'),
131
-            'is_multisite'        => is_multisite(),
132
-            'version'             => get_bloginfo('version', 'display'),
133
-            'home_url'            => home_url(),
134
-            'site_url'            => site_url(),
135
-            'WP_DEBUG'            => WP_DEBUG,
136
-            'permalink_structure' => get_option('permalink_structure'),
137
-            'theme'               => wp_get_theme(),
138
-            'gmt_offset'          => get_option('gmt_offset'),
139
-            'timezone_string'     => get_option('timezone_string'),
140
-            'admin_email'         => get_bloginfo('admin_email', 'display'),
141
-            'language'            => get_bloginfo('language', 'display'),
142
-            'wp_max_upload_size'  => size_format(wp_max_upload_size()),
143
-            'wp_memory'           => $wp_memory_to_display,
144
-        ];
145
-    }
146
-
147
-
148
-    /**
149
-     * Gets an array of information about the history of ee versions installed
150
-     *
151
-     * @return array
152
-     */
153
-    public function get_ee_activation_history()
154
-    {
155
-        return get_option('espresso_db_update');
156
-    }
157
-
158
-
159
-    /**
160
-     * Gets an array where keys are ee versions, and their values are arrays indicating all the different times that
161
-     * version was installed
162
-     *
163
-     * @return EE_Data_Migration_Script_Base[]
164
-     */
165
-    public function get_ee_migration_history()
166
-    {
167
-        $options                       = EE_Data_Migration_Manager::instance()->get_all_migration_script_options();
168
-        $presentable_migration_scripts = [];
169
-        foreach ($options as $option_array) {
170
-            $presentable_migration_scripts[ str_replace(
171
-                EE_Data_Migration_Manager::data_migration_script_option_prefix,
172
-                "",
173
-                $option_array['option_name']
174
-            ) ] = maybe_unserialize($option_array['option_value']);
175
-        }
176
-        return $presentable_migration_scripts;
8
+	protected static ?EEM_System_Status $_instance = null;
9
+
10
+
11
+	/**
12
+	 * This function is a singleton method used to instantiate the EEM_Attendee object
13
+	 *
14
+	 * @return EEM_System_Status
15
+	 */
16
+	public static function instance()
17
+	{
18
+		// check if instance of EEM_System_Status already exists
19
+		if (self::$_instance === null) {
20
+			// instantiate EEM_System_Status
21
+			self::$_instance = new self();
22
+		}
23
+		return self::$_instance;
24
+	}
25
+
26
+
27
+	private function __construct()
28
+	{
29
+	}
30
+
31
+
32
+	/**
33
+	 * @return array where each key is a function name on this class, and each value is SOMETHING--
34
+	 * it might be a value, an array, or an object
35
+	 */
36
+	public function get_system_stati()
37
+	{
38
+		return apply_filters(
39
+			'FHEE__EEM_System_Status__get_system_stati',
40
+			[
41
+				'ee_version'            => $this->get_ee_version(),
42
+				'ee_activation_history' => $this->get_ee_activation_history(),
43
+				'ee_config'             => $this->get_ee_config(),
44
+				'ee_migration_history'  => $this->get_ee_migration_history(),
45
+				'active_plugins'        => $this->get_active_plugins(),
46
+				'wp_settings'           => $this->get_wp_settings(),
47
+				'wp_maintenance_mode'   => $this->get_wp_maintenance_mode(),
48
+				'https_enabled'         => $this->get_https_enabled(),
49
+				'logging_enabled'       => $this->get_logging_enabled(),
50
+				'remote_posting'        => $this->get_remote_posting(),
51
+				'php_version'           => $this->php_version(),
52
+				'php.ini_settings'      => $this->get_php_ini_all(),
53
+				'php_info'              => $this->get_php_info(),
54
+			],
55
+			$this
56
+		);
57
+	}
58
+
59
+
60
+	/**
61
+	 * @return string
62
+	 */
63
+	public function get_ee_version()
64
+	{
65
+		return espresso_version();
66
+	}
67
+
68
+
69
+	/**
70
+	 * @return string
71
+	 */
72
+	public function php_version()
73
+	{
74
+		return phpversion();
75
+	}
76
+
77
+
78
+	/**
79
+	 * @return array, where each key is a plugin name (lower-cased), values are sub-arrays.
80
+	 * Sub-arrays like described in wp function get_plugin_data. Ie,     *
81
+	 *  'Name' => 'Plugin Name',
82
+	 * 'PluginURI' => 'Plugin URI',
83
+	 * 'Version' => 'Version',
84
+	 * 'Description' => 'Description',
85
+	 * 'Author' => 'Author',
86
+	 * 'AuthorURI' => 'Author URI',
87
+	 * 'TextDomain' => 'Text Domain',
88
+	 * 'DomainPath' => 'Domain Path',
89
+	 * 'Network' => 'Network',
90
+	 */
91
+	public function get_active_plugins()
92
+	{
93
+		$active_plugins = (array) get_option('active_plugins', []);
94
+		if (is_multisite()) {
95
+			$active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', []));
96
+		}
97
+		$active_plugins = array_map('strtolower', $active_plugins);
98
+		$plugin_info    = [];
99
+		foreach ($active_plugins as $plugin) {
100
+			$plugin_data = @get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin);
101
+
102
+			$plugin_info[ $plugin ] = $plugin_data;
103
+		}
104
+		return $plugin_info;
105
+	}
106
+
107
+
108
+	/**
109
+	 * @return array with keys 'home_url' and 'site_url'
110
+	 */
111
+	public function get_wp_settings()
112
+	{
113
+		$wp_memory_int = $this->let_to_num(WP_MEMORY_LIMIT);
114
+		if ($wp_memory_int < 67108864) {
115
+			$wp_memory_to_display = '<mark class="error">';
116
+			$wp_memory_to_display .= sprintf(
117
+				esc_html__(
118
+					'%s - We recommend setting memory to at least 64MB. See: %s Increasing memory allocated to PHP %s',
119
+					'event_espresso'
120
+				),
121
+				WP_MEMORY_LIMIT,
122
+				'<a href="http://codex.wordpress.org/Editing_wp-config.php#Increasing_memory_allocated_to_PHP">',
123
+				'</a>"'
124
+			);
125
+			$wp_memory_to_display .= '</mark>';
126
+		} else {
127
+			$wp_memory_to_display = '<mark class="yes">' . size_format($wp_memory_int) . '</mark>';
128
+		}
129
+		return [
130
+			'name'                => get_bloginfo('name', 'display'),
131
+			'is_multisite'        => is_multisite(),
132
+			'version'             => get_bloginfo('version', 'display'),
133
+			'home_url'            => home_url(),
134
+			'site_url'            => site_url(),
135
+			'WP_DEBUG'            => WP_DEBUG,
136
+			'permalink_structure' => get_option('permalink_structure'),
137
+			'theme'               => wp_get_theme(),
138
+			'gmt_offset'          => get_option('gmt_offset'),
139
+			'timezone_string'     => get_option('timezone_string'),
140
+			'admin_email'         => get_bloginfo('admin_email', 'display'),
141
+			'language'            => get_bloginfo('language', 'display'),
142
+			'wp_max_upload_size'  => size_format(wp_max_upload_size()),
143
+			'wp_memory'           => $wp_memory_to_display,
144
+		];
145
+	}
146
+
147
+
148
+	/**
149
+	 * Gets an array of information about the history of ee versions installed
150
+	 *
151
+	 * @return array
152
+	 */
153
+	public function get_ee_activation_history()
154
+	{
155
+		return get_option('espresso_db_update');
156
+	}
157
+
158
+
159
+	/**
160
+	 * Gets an array where keys are ee versions, and their values are arrays indicating all the different times that
161
+	 * version was installed
162
+	 *
163
+	 * @return EE_Data_Migration_Script_Base[]
164
+	 */
165
+	public function get_ee_migration_history()
166
+	{
167
+		$options                       = EE_Data_Migration_Manager::instance()->get_all_migration_script_options();
168
+		$presentable_migration_scripts = [];
169
+		foreach ($options as $option_array) {
170
+			$presentable_migration_scripts[ str_replace(
171
+				EE_Data_Migration_Manager::data_migration_script_option_prefix,
172
+				"",
173
+				$option_array['option_name']
174
+			) ] = maybe_unserialize($option_array['option_value']);
175
+		}
176
+		return $presentable_migration_scripts;
177 177
 //      return get_option(EE_Data_Migration_Manager::data_migrations_option_name);//EE_Data_Migration_Manager::instance()->get_data_migrations_ran();
178
-    }
179
-
180
-
181
-    /**
182
-     * @return array like EE_Config class
183
-     */
184
-    public function get_ee_config()
185
-    {
186
-        return EE_Config::instance();
187
-    }
188
-
189
-
190
-    /**
191
-     * Gets an array of php setup info, pilfered from http://www.php.net/manual/en/function.phpinfo.php#87463
192
-     *
193
-     * @return array like the output of phpinfo(), but in an array
194
-     */
195
-    public function get_php_info()
196
-    {
197
-        ob_start();
198
-        phpinfo(-1);
199
-
200
-        $pi = preg_replace(
201
-            [
202
-                '#^.*<body>(.*)</body>.*$#ms',
203
-                '#<h2>PHP License</h2>.*$#ms',
204
-                '#<h1>Configuration</h1>#',
205
-                "#\r?\n#",
206
-                "#</(h1|h2|h3|tr)>#",
207
-                '# +<#',
208
-                "#[ \t]+#",
209
-                '#&nbsp;#',
210
-                '#  +#',
211
-                '# class=".*?"#',
212
-                '%&#039;%',
213
-                '#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>'
214
-                . '<h1>PHP Version (.*?)</h1>(?:\n+?)</td></tr>#',
215
-                '#<h1><a href="(?:.*?)\?=(.*?)">PHP Credits</a></h1>#',
216
-                '#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#',
217
-                "# +#",
218
-                '#<tr>#',
219
-                '#</tr>#',
220
-            ],
221
-            [
222
-                '$1',
223
-                '',
224
-                '',
225
-                '',
226
-                '</$1>' . "\n",
227
-                '<',
228
-                ' ',
229
-                ' ',
230
-                ' ',
231
-                '',
232
-                ' ',
233
-                '<h2>PHP Configuration</h2>' . "\n" . '<tr><td>PHP Version</td><td>$2</td></tr>' .
234
-                "\n" . '<tr><td>PHP Egg</td><td>$1</td></tr>',
235
-                '<tr><td>PHP Credits Egg</td><td>$1</td></tr>',
236
-                '<tr><td>Zend Engine</td><td>$2</td></tr>' . "\n" .
237
-                '<tr><td>Zend Egg</td><td>$1</td></tr>',
238
-                ' ',
239
-                '%S%',
240
-                '%E%',
241
-            ],
242
-            ob_get_clean()
243
-        );
244
-
245
-        $sections = explode('<h2>', strip_tags((string) $pi, '<h2><th><td>'));
246
-        unset($sections[0]);
247
-
248
-        $pi = [];
249
-        foreach ($sections as $section) {
250
-            $n = substr($section, 0, strpos($section, '</h2>'));
251
-            preg_match_all(
252
-                '#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#',
253
-                $section,
254
-                $askapache,
255
-                PREG_SET_ORDER
256
-            );
257
-            foreach ($askapache as $m) {
258
-                $m2 = isset($m[2]) ? $m[2] : null;
259
-            }
260
-            $pi[ $n ][ $m[1] ] = (! isset($m[3]) || $m2 == $m[3]) ? $m2 : array_slice($m, 2);
261
-        }
262
-
263
-        return $pi;
264
-    }
265
-
266
-
267
-    /**
268
-     * Checks if site responds ot HTTPS
269
-     *
270
-     * @return boolean
271
-     */
272
-    public function get_https_enabled()
273
-    {
274
-        $home     = str_replace("http://", "https://", home_url());
275
-        $response = wp_remote_get($home);
276
-        if ($response instanceof WP_Error) {
277
-            $error_string = '';
278
-            foreach ($response->errors as $short_name => $description_array) {
279
-                $error_string .= "<b>$short_name</b>: " . implode(", ", $description_array);
280
-            }
281
-            return $error_string;
282
-        }
283
-        return "ok!";
284
-    }
285
-
286
-
287
-    /**
288
-     * Whether or not a .maintenance file is detected
289
-     *
290
-     * @return string descripting wp_maintenance_mode status
291
-     */
292
-    public function get_wp_maintenance_mode()
293
-    {
294
-        $opened = file_exists(ABSPATH . '.maintenance');
295
-        return $opened ? sprintf(
296
-            esc_html__(
297
-                '%s.maintenance file detected.%s Wordpress may have a failed auto-update which could prevent Event Espresso from updating the database correctly.',
298
-                'event_espresso'
299
-            ),
300
-            '<strong>',
301
-            '</strong>'
302
-        ) : esc_html__('.maintenance file not detected. WordPress is not in maintenance mode.', 'event_espresso');
303
-    }
304
-
305
-
306
-    /**
307
-     * Whether or not logging is enabled
308
-     *
309
-     * @return string descripting logging's status
310
-     */
311
-    public function get_logging_enabled()
312
-    {
313
-        $opened = @fopen(EVENT_ESPRESSO_UPLOAD_DIR . '/logs/espresso_log.txt', 'a');
314
-        return $opened
315
-            ? esc_html__('Log Directory is writable', 'event_espresso')
316
-            : sprintf(
317
-                esc_html__('%sLog directory is NOT writable%s', 'event_espresso'),
318
-                '<mark class="error"',
319
-                '</mark>'
320
-            );
321
-    }
322
-
323
-
324
-    /**
325
-     *  Whether curl ro fsock works
326
-     *
327
-     * @return string describing posting's status
328
-     */
329
-    public function get_remote_posting()
330
-    {
331
-        $fsock_works = function_exists('fsockopen');
332
-        $curl_works  = function_exists('curl_init');
333
-        if ($fsock_works && $curl_works) {
334
-            $status = esc_html__('Your server has fsockopen and cURL enabled.', 'event_espresso');
335
-        } elseif ($fsock_works) {
336
-            $status = esc_html__('Your server has fsockopen enabled, cURL is disabled.', 'event_espresso');
337
-        } elseif ($curl_works) {
338
-            $status = esc_html__('Your server has cURL enabled, fsockopen is disabled.', 'event_espresso');
339
-        } else {
340
-            $status = esc_html__(
341
-                          'Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.',
342
-                          'event_espresso'
343
-                      ) . '</mark>';
344
-        }
345
-        return $status;
346
-    }
347
-
348
-
349
-    /**
350
-     * Gets all the php.ini settings
351
-     *
352
-     * @return array
353
-     */
354
-    public function get_php_ini_all()
355
-    {
356
-        return ini_get_all();
357
-    }
358
-
359
-
360
-    /**
361
-     * Transforms the php.ini notation for numbers (like '2M') to an integer.
362
-     *
363
-     * @param type $size
364
-     * @return int
365
-     */
366
-    public function let_to_num($size)
367
-    {
368
-        $l   = substr($size, -1);
369
-        $ret = substr($size, 0, -1);
370
-        // phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
371
-        switch (strtoupper($l)) {
372
-            case 'P':
373
-                $ret *= 1024;
374
-            case 'T':
375
-                $ret *= 1024;
376
-            case 'G':
377
-                $ret *= 1024;
378
-            case 'M':
379
-                $ret *= 1024;
380
-            case 'K':
381
-                $ret *= 1024;
382
-        }
383
-        // phpcs:enable
384
-        return $ret;
385
-    }
178
+	}
179
+
180
+
181
+	/**
182
+	 * @return array like EE_Config class
183
+	 */
184
+	public function get_ee_config()
185
+	{
186
+		return EE_Config::instance();
187
+	}
188
+
189
+
190
+	/**
191
+	 * Gets an array of php setup info, pilfered from http://www.php.net/manual/en/function.phpinfo.php#87463
192
+	 *
193
+	 * @return array like the output of phpinfo(), but in an array
194
+	 */
195
+	public function get_php_info()
196
+	{
197
+		ob_start();
198
+		phpinfo(-1);
199
+
200
+		$pi = preg_replace(
201
+			[
202
+				'#^.*<body>(.*)</body>.*$#ms',
203
+				'#<h2>PHP License</h2>.*$#ms',
204
+				'#<h1>Configuration</h1>#',
205
+				"#\r?\n#",
206
+				"#</(h1|h2|h3|tr)>#",
207
+				'# +<#',
208
+				"#[ \t]+#",
209
+				'#&nbsp;#',
210
+				'#  +#',
211
+				'# class=".*?"#',
212
+				'%&#039;%',
213
+				'#<tr>(?:.*?)" src="(?:.*?)=(.*?)" alt="PHP Logo" /></a>'
214
+				. '<h1>PHP Version (.*?)</h1>(?:\n+?)</td></tr>#',
215
+				'#<h1><a href="(?:.*?)\?=(.*?)">PHP Credits</a></h1>#',
216
+				'#<tr>(?:.*?)" src="(?:.*?)=(.*?)"(?:.*?)Zend Engine (.*?),(?:.*?)</tr>#',
217
+				"# +#",
218
+				'#<tr>#',
219
+				'#</tr>#',
220
+			],
221
+			[
222
+				'$1',
223
+				'',
224
+				'',
225
+				'',
226
+				'</$1>' . "\n",
227
+				'<',
228
+				' ',
229
+				' ',
230
+				' ',
231
+				'',
232
+				' ',
233
+				'<h2>PHP Configuration</h2>' . "\n" . '<tr><td>PHP Version</td><td>$2</td></tr>' .
234
+				"\n" . '<tr><td>PHP Egg</td><td>$1</td></tr>',
235
+				'<tr><td>PHP Credits Egg</td><td>$1</td></tr>',
236
+				'<tr><td>Zend Engine</td><td>$2</td></tr>' . "\n" .
237
+				'<tr><td>Zend Egg</td><td>$1</td></tr>',
238
+				' ',
239
+				'%S%',
240
+				'%E%',
241
+			],
242
+			ob_get_clean()
243
+		);
244
+
245
+		$sections = explode('<h2>', strip_tags((string) $pi, '<h2><th><td>'));
246
+		unset($sections[0]);
247
+
248
+		$pi = [];
249
+		foreach ($sections as $section) {
250
+			$n = substr($section, 0, strpos($section, '</h2>'));
251
+			preg_match_all(
252
+				'#%S%(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?(?:<td>(.*?)</td>)?%E%#',
253
+				$section,
254
+				$askapache,
255
+				PREG_SET_ORDER
256
+			);
257
+			foreach ($askapache as $m) {
258
+				$m2 = isset($m[2]) ? $m[2] : null;
259
+			}
260
+			$pi[ $n ][ $m[1] ] = (! isset($m[3]) || $m2 == $m[3]) ? $m2 : array_slice($m, 2);
261
+		}
262
+
263
+		return $pi;
264
+	}
265
+
266
+
267
+	/**
268
+	 * Checks if site responds ot HTTPS
269
+	 *
270
+	 * @return boolean
271
+	 */
272
+	public function get_https_enabled()
273
+	{
274
+		$home     = str_replace("http://", "https://", home_url());
275
+		$response = wp_remote_get($home);
276
+		if ($response instanceof WP_Error) {
277
+			$error_string = '';
278
+			foreach ($response->errors as $short_name => $description_array) {
279
+				$error_string .= "<b>$short_name</b>: " . implode(", ", $description_array);
280
+			}
281
+			return $error_string;
282
+		}
283
+		return "ok!";
284
+	}
285
+
286
+
287
+	/**
288
+	 * Whether or not a .maintenance file is detected
289
+	 *
290
+	 * @return string descripting wp_maintenance_mode status
291
+	 */
292
+	public function get_wp_maintenance_mode()
293
+	{
294
+		$opened = file_exists(ABSPATH . '.maintenance');
295
+		return $opened ? sprintf(
296
+			esc_html__(
297
+				'%s.maintenance file detected.%s Wordpress may have a failed auto-update which could prevent Event Espresso from updating the database correctly.',
298
+				'event_espresso'
299
+			),
300
+			'<strong>',
301
+			'</strong>'
302
+		) : esc_html__('.maintenance file not detected. WordPress is not in maintenance mode.', 'event_espresso');
303
+	}
304
+
305
+
306
+	/**
307
+	 * Whether or not logging is enabled
308
+	 *
309
+	 * @return string descripting logging's status
310
+	 */
311
+	public function get_logging_enabled()
312
+	{
313
+		$opened = @fopen(EVENT_ESPRESSO_UPLOAD_DIR . '/logs/espresso_log.txt', 'a');
314
+		return $opened
315
+			? esc_html__('Log Directory is writable', 'event_espresso')
316
+			: sprintf(
317
+				esc_html__('%sLog directory is NOT writable%s', 'event_espresso'),
318
+				'<mark class="error"',
319
+				'</mark>'
320
+			);
321
+	}
322
+
323
+
324
+	/**
325
+	 *  Whether curl ro fsock works
326
+	 *
327
+	 * @return string describing posting's status
328
+	 */
329
+	public function get_remote_posting()
330
+	{
331
+		$fsock_works = function_exists('fsockopen');
332
+		$curl_works  = function_exists('curl_init');
333
+		if ($fsock_works && $curl_works) {
334
+			$status = esc_html__('Your server has fsockopen and cURL enabled.', 'event_espresso');
335
+		} elseif ($fsock_works) {
336
+			$status = esc_html__('Your server has fsockopen enabled, cURL is disabled.', 'event_espresso');
337
+		} elseif ($curl_works) {
338
+			$status = esc_html__('Your server has cURL enabled, fsockopen is disabled.', 'event_espresso');
339
+		} else {
340
+			$status = esc_html__(
341
+						  'Your server does not have fsockopen or cURL enabled - PayPal IPN and other scripts which communicate with other servers will not work. Contact your hosting provider.',
342
+						  'event_espresso'
343
+					  ) . '</mark>';
344
+		}
345
+		return $status;
346
+	}
347
+
348
+
349
+	/**
350
+	 * Gets all the php.ini settings
351
+	 *
352
+	 * @return array
353
+	 */
354
+	public function get_php_ini_all()
355
+	{
356
+		return ini_get_all();
357
+	}
358
+
359
+
360
+	/**
361
+	 * Transforms the php.ini notation for numbers (like '2M') to an integer.
362
+	 *
363
+	 * @param type $size
364
+	 * @return int
365
+	 */
366
+	public function let_to_num($size)
367
+	{
368
+		$l   = substr($size, -1);
369
+		$ret = substr($size, 0, -1);
370
+		// phpcs:disable PSR2.ControlStructures.SwitchDeclaration.TerminatingComment
371
+		switch (strtoupper($l)) {
372
+			case 'P':
373
+				$ret *= 1024;
374
+			case 'T':
375
+				$ret *= 1024;
376
+			case 'G':
377
+				$ret *= 1024;
378
+			case 'M':
379
+				$ret *= 1024;
380
+			case 'K':
381
+				$ret *= 1024;
382
+		}
383
+		// phpcs:enable
384
+		return $ret;
385
+	}
386 386
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Extra_Join.model.php 1 patch
Indentation   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -19,72 +19,72 @@
 block discarded – undo
19 19
  */
20 20
 class EEM_Extra_Join extends EEM_Base
21 21
 {
22
-    protected static ?EEM_Extra_Join $_instance = null;
22
+	protected static ?EEM_Extra_Join $_instance = null;
23 23
 
24 24
 
25
-    /**
26
-     * @param string|null $timezone
27
-     * @throws EE_Error
28
-     */
29
-    public function __construct(?string $timezone = '')
30
-    {
31
-        $models_this_can_join = array_keys(EE_Registry::instance()->non_abstract_db_models);
32
-        $this->_tables        = [
33
-            'Extra_Join' => new EE_Primary_Table('esp_extra_join', 'EXJ_ID'),
34
-        ];
35
-        $this->_fields        = [
36
-            'Extra_Join' => [
37
-                'EXJ_ID'                => new EE_Primary_Key_Int_Field(
38
-                    'EXJ_ID',
39
-                    esc_html__('Extra Join ID', 'event_espresso')
40
-                ),
41
-                'EXJ_first_model_ID'    => new EE_Foreign_Key_String_Field(
42
-                    'EXJ_first_model_ID',
43
-                    esc_html__('First Model ID', 'event_espresso'),
44
-                    true,
45
-                    0,
46
-                    $models_this_can_join
47
-                ),
48
-                'EXJ_first_model_name'  => new EE_Any_Foreign_Model_Name_Field(
49
-                    'EXJ_first_model_name',
50
-                    esc_html__(
51
-                        'First Model Name',
52
-                        'event_espresso'
53
-                    ),
54
-                    true,
55
-                    '',
56
-                    $models_this_can_join
57
-                ),
58
-                'EXJ_second_model_ID'   => new EE_Foreign_Key_String_Field(
59
-                    'EXJ_second_model_ID',
60
-                    esc_html__(
61
-                        'Second Model ID',
62
-                        'event_espresso'
63
-                    ),
64
-                    true,
65
-                    0,
66
-                    $models_this_can_join
67
-                ),
68
-                'EXJ_second_model_name' => new EE_Any_Foreign_Model_Name_Field(
69
-                    'EXJ_second_model_name',
70
-                    esc_html__(
71
-                        'Second Model Name',
72
-                        'event_espresso'
73
-                    ),
74
-                    true,
75
-                    '',
76
-                    $models_this_can_join
77
-                ),
25
+	/**
26
+	 * @param string|null $timezone
27
+	 * @throws EE_Error
28
+	 */
29
+	public function __construct(?string $timezone = '')
30
+	{
31
+		$models_this_can_join = array_keys(EE_Registry::instance()->non_abstract_db_models);
32
+		$this->_tables        = [
33
+			'Extra_Join' => new EE_Primary_Table('esp_extra_join', 'EXJ_ID'),
34
+		];
35
+		$this->_fields        = [
36
+			'Extra_Join' => [
37
+				'EXJ_ID'                => new EE_Primary_Key_Int_Field(
38
+					'EXJ_ID',
39
+					esc_html__('Extra Join ID', 'event_espresso')
40
+				),
41
+				'EXJ_first_model_ID'    => new EE_Foreign_Key_String_Field(
42
+					'EXJ_first_model_ID',
43
+					esc_html__('First Model ID', 'event_espresso'),
44
+					true,
45
+					0,
46
+					$models_this_can_join
47
+				),
48
+				'EXJ_first_model_name'  => new EE_Any_Foreign_Model_Name_Field(
49
+					'EXJ_first_model_name',
50
+					esc_html__(
51
+						'First Model Name',
52
+						'event_espresso'
53
+					),
54
+					true,
55
+					'',
56
+					$models_this_can_join
57
+				),
58
+				'EXJ_second_model_ID'   => new EE_Foreign_Key_String_Field(
59
+					'EXJ_second_model_ID',
60
+					esc_html__(
61
+						'Second Model ID',
62
+						'event_espresso'
63
+					),
64
+					true,
65
+					0,
66
+					$models_this_can_join
67
+				),
68
+				'EXJ_second_model_name' => new EE_Any_Foreign_Model_Name_Field(
69
+					'EXJ_second_model_name',
70
+					esc_html__(
71
+						'Second Model Name',
72
+						'event_espresso'
73
+					),
74
+					true,
75
+					'',
76
+					$models_this_can_join
77
+				),
78 78
 
79
-            ],
80
-        ];
81
-        // this model is weird in that it has two foreign key columns which can point to any model/table.
82
-        // eg a foreign key to event will be in "EXJ_first_model_ID", provided the other
83
-        // model linked to is alphabetically greater than event (eg venue).
84
-        // but if the model linked to is alphabetically lower (eg attendee),
85
-        // the foreign key to the event will be in "EXJ_second_model_ID"
86
-        // so normal usage of foreign keys is weird. So don't define any
87
-        // relations to other models because they won't work properly with this model
88
-        parent::__construct($timezone);
89
-    }
79
+			],
80
+		];
81
+		// this model is weird in that it has two foreign key columns which can point to any model/table.
82
+		// eg a foreign key to event will be in "EXJ_first_model_ID", provided the other
83
+		// model linked to is alphabetically greater than event (eg venue).
84
+		// but if the model linked to is alphabetically lower (eg attendee),
85
+		// the foreign key to the event will be in "EXJ_second_model_ID"
86
+		// so normal usage of foreign keys is weird. So don't define any
87
+		// relations to other models because they won't work properly with this model
88
+		parent::__construct($timezone);
89
+	}
90 90
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Event_Message_Template.model.php 1 patch
Indentation   +122 added lines, -122 removed lines patch added patch discarded remove patch
@@ -11,138 +11,138 @@
 block discarded – undo
11 11
  */
12 12
 class EEM_Event_Message_Template extends EEM_Base
13 13
 {
14
-    protected static ?EEM_Event_Message_Template $_instance = null;
14
+	protected static ?EEM_Event_Message_Template $_instance = null;
15 15
 
16 16
 
17 17
 
18
-    /**
19
-     * protected constructor to prevent direct creation
20
-     *
21
-     * @param string|null $timezone
22
-     * @throws EE_Error
23
-     */
24
-    protected function __construct(?string $timezone = '')
25
-    {
26
-        $this->singular_item = esc_html__('Event Message Template', 'event_espresso');
27
-        $this->plural_item   = esc_html__('Event Message Templates', 'event_espresso');
18
+	/**
19
+	 * protected constructor to prevent direct creation
20
+	 *
21
+	 * @param string|null $timezone
22
+	 * @throws EE_Error
23
+	 */
24
+	protected function __construct(?string $timezone = '')
25
+	{
26
+		$this->singular_item = esc_html__('Event Message Template', 'event_espresso');
27
+		$this->plural_item   = esc_html__('Event Message Templates', 'event_espresso');
28 28
 
29
-        $this->_tables                                                  = [
30
-            'Event_Message_Template' => new EE_Primary_Table('esp_event_message_template', 'EMT_ID'),
31
-        ];
32
-        $this->_fields                                                  = [
33
-            'Event_Message_Template' => [
34
-                'EMT_ID' => new EE_Primary_Key_Int_Field(
35
-                    'EMT_ID',
36
-                    esc_html__('Event Message Template ID', 'event_espresso')
37
-                ),
38
-                'EVT_ID' => new EE_Foreign_Key_Int_Field(
39
-                    'EVT_ID',
40
-                    esc_html__('The ID to the Event', 'event_espresso'),
41
-                    false,
42
-                    0,
43
-                    'Event'
44
-                ),
45
-                'GRP_ID' => new EE_Foreign_Key_Int_Field(
46
-                    'GRP_ID',
47
-                    esc_html__('The ID to the Message Template Group', 'event_espresso'),
48
-                    false,
49
-                    0,
50
-                    'Message_Template_Group'
51
-                ),
52
-            ],
53
-        ];
54
-        $this->_model_relations                                         = [
55
-            'Event'                  => new EE_Belongs_To_Relation(),
56
-            'Message_Template_Group' => new EE_Belongs_To_Relation(),
57
-        ];
58
-        $path_to_event                                                  = 'Event';
59
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
60
-            new EE_Restriction_Generator_Event_Related_Public(
61
-                $path_to_event
62
-            );
63
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
64
-            new EE_Restriction_Generator_Event_Related_Protected(
65
-                $path_to_event
66
-            );
67
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
68
-            new EE_Restriction_Generator_Event_Related_Protected(
69
-                $path_to_event
70
-            );
71
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
72
-            new EE_Restriction_Generator_Event_Related_Protected(
73
-                $path_to_event,
74
-                EEM_Base::caps_edit
75
-            );
76
-        parent::__construct($timezone);
77
-    }
29
+		$this->_tables                                                  = [
30
+			'Event_Message_Template' => new EE_Primary_Table('esp_event_message_template', 'EMT_ID'),
31
+		];
32
+		$this->_fields                                                  = [
33
+			'Event_Message_Template' => [
34
+				'EMT_ID' => new EE_Primary_Key_Int_Field(
35
+					'EMT_ID',
36
+					esc_html__('Event Message Template ID', 'event_espresso')
37
+				),
38
+				'EVT_ID' => new EE_Foreign_Key_Int_Field(
39
+					'EVT_ID',
40
+					esc_html__('The ID to the Event', 'event_espresso'),
41
+					false,
42
+					0,
43
+					'Event'
44
+				),
45
+				'GRP_ID' => new EE_Foreign_Key_Int_Field(
46
+					'GRP_ID',
47
+					esc_html__('The ID to the Message Template Group', 'event_espresso'),
48
+					false,
49
+					0,
50
+					'Message_Template_Group'
51
+				),
52
+			],
53
+		];
54
+		$this->_model_relations                                         = [
55
+			'Event'                  => new EE_Belongs_To_Relation(),
56
+			'Message_Template_Group' => new EE_Belongs_To_Relation(),
57
+		];
58
+		$path_to_event                                                  = 'Event';
59
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ]       =
60
+			new EE_Restriction_Generator_Event_Related_Public(
61
+				$path_to_event
62
+			);
63
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] =
64
+			new EE_Restriction_Generator_Event_Related_Protected(
65
+				$path_to_event
66
+			);
67
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ]       =
68
+			new EE_Restriction_Generator_Event_Related_Protected(
69
+				$path_to_event
70
+			);
71
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ]     =
72
+			new EE_Restriction_Generator_Event_Related_Protected(
73
+				$path_to_event,
74
+				EEM_Base::caps_edit
75
+			);
76
+		parent::__construct($timezone);
77
+	}
78 78
 
79 79
 
80
-    /**
81
-     * helper method to simply return an array of event ids for events attached to the given
82
-     * message template group.
83
-     *
84
-     * @param int $GRP_ID The MTP group we want attached events for.
85
-     * @return  array               An array of event ids.
86
-     * @throws EE_Error
87
-     * @since 4.3.0
88
-     */
89
-    public function get_attached_event_ids($GRP_ID)
90
-    {
91
-        $event_ids = $this->_get_all_wpdb_results([['GRP_ID' => $GRP_ID]], ARRAY_N, 'EVT_ID');
92
-        $event_ids = call_user_func_array('array_merge', $event_ids);
93
-        return $event_ids;
94
-    }
80
+	/**
81
+	 * helper method to simply return an array of event ids for events attached to the given
82
+	 * message template group.
83
+	 *
84
+	 * @param int $GRP_ID The MTP group we want attached events for.
85
+	 * @return  array               An array of event ids.
86
+	 * @throws EE_Error
87
+	 * @since 4.3.0
88
+	 */
89
+	public function get_attached_event_ids($GRP_ID)
90
+	{
91
+		$event_ids = $this->_get_all_wpdb_results([['GRP_ID' => $GRP_ID]], ARRAY_N, 'EVT_ID');
92
+		$event_ids = call_user_func_array('array_merge', $event_ids);
93
+		return $event_ids;
94
+	}
95 95
 
96 96
 
97
-    /**
98
-     * helper method for clearing event/group relations for the given event ids and grp ids.
99
-     *
100
-     * @param array $GRP_IDs An array of GRP_IDs. Optional. If empty then there must be EVT IDs.
101
-     * @param array $EVT_IDs An array of EVT_IDs.  Optional. If empty then there must be GRP IDs.
102
-     * @return int             How many rows were deleted.
103
-     * @throws EE_Error
104
-     * @throws EE_Error
105
-     */
106
-    public function delete_event_group_relations($GRP_IDs = [], $EVT_IDs = [])
107
-    {
108
-        if (empty($GRP_IDs) && empty($EVT_IDs)) {
109
-            throw new EE_Error(
110
-                sprintf(
111
-                    esc_html__(
112
-                        '%s requires either an array of GRP_IDs or EVT_IDs or both, but both cannot be empty.',
113
-                        'event_espresso'
114
-                    ),
115
-                    __METHOD__
116
-                )
117
-            );
118
-        }
97
+	/**
98
+	 * helper method for clearing event/group relations for the given event ids and grp ids.
99
+	 *
100
+	 * @param array $GRP_IDs An array of GRP_IDs. Optional. If empty then there must be EVT IDs.
101
+	 * @param array $EVT_IDs An array of EVT_IDs.  Optional. If empty then there must be GRP IDs.
102
+	 * @return int             How many rows were deleted.
103
+	 * @throws EE_Error
104
+	 * @throws EE_Error
105
+	 */
106
+	public function delete_event_group_relations($GRP_IDs = [], $EVT_IDs = [])
107
+	{
108
+		if (empty($GRP_IDs) && empty($EVT_IDs)) {
109
+			throw new EE_Error(
110
+				sprintf(
111
+					esc_html__(
112
+						'%s requires either an array of GRP_IDs or EVT_IDs or both, but both cannot be empty.',
113
+						'event_espresso'
114
+					),
115
+					__METHOD__
116
+				)
117
+			);
118
+		}
119 119
 
120
-        $where = [];
121
-        if (! empty($GRP_IDs)) {
122
-            $where['GRP_ID'] = ['IN', (array) $GRP_IDs];
123
-        }
124
-        if (! empty($EVT_IDs)) {
125
-            $where['EVT_ID'] = ['IN', (array) $EVT_IDs];
126
-        }
120
+		$where = [];
121
+		if (! empty($GRP_IDs)) {
122
+			$where['GRP_ID'] = ['IN', (array) $GRP_IDs];
123
+		}
124
+		if (! empty($EVT_IDs)) {
125
+			$where['EVT_ID'] = ['IN', (array) $EVT_IDs];
126
+		}
127 127
 
128
-        return $this->delete([$where], false);
129
-    }
128
+		return $this->delete([$where], false);
129
+	}
130 130
 
131 131
 
132
-    /**
133
-     * returns a numerically indexed array
134
-     * with values that correspond to the 'GRP_ID' column
135
-     * where the 'EVT_ID' column matches that of the supplied event
136
-     *
137
-     * @param EE_Event $event
138
-     * @return array
139
-     * @throws EE_Error
140
-     * @throws ReflectionException
141
-     * @since   5.0.0.p
142
-     */
143
-    public function messageTemplateGroupIDsForEvent(EE_Event $event): array
144
-    {
145
-        $results = $this->get_col([['EVT_ID' => $event->ID()]], 'GRP_ID');
146
-        return $results !== false ? $results : [];
147
-    }
132
+	/**
133
+	 * returns a numerically indexed array
134
+	 * with values that correspond to the 'GRP_ID' column
135
+	 * where the 'EVT_ID' column matches that of the supplied event
136
+	 *
137
+	 * @param EE_Event $event
138
+	 * @return array
139
+	 * @throws EE_Error
140
+	 * @throws ReflectionException
141
+	 * @since   5.0.0.p
142
+	 */
143
+	public function messageTemplateGroupIDsForEvent(EE_Event $event): array
144
+	{
145
+		$results = $this->get_col([['EVT_ID' => $event->ID()]], 'GRP_ID');
146
+		return $results !== false ? $results : [];
147
+	}
148 148
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Venue.model.php 1 patch
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -12,201 +12,201 @@
 block discarded – undo
12 12
  */
13 13
 class EEM_Venue extends EEM_CPT_Base
14 14
 {
15
-    protected static ?EEM_Venue $_instance = null;
15
+	protected static ?EEM_Venue $_instance = null;
16 16
 
17 17
 
18
-    /**
19
-     * @param string|null $timezone
20
-     * @throws EE_Error
21
-     */
22
-    protected function __construct(?string $timezone = '')
23
-    {
24
-        $this->singular_item    = esc_html__('Venue', 'event_espresso');
25
-        $this->plural_item      = esc_html__('Venues', 'event_espresso');
26
-        $this->_tables          = [
27
-            'Venue_CPT'  => new EE_Primary_Table('posts', 'ID'),
28
-            'Venue_Meta' => new EE_Secondary_Table('esp_venue_meta', 'VNUM_ID', 'VNU_ID'),
29
-        ];
30
-        $this->_fields          = [
31
-            'Venue_CPT'  => [
32
-                'VNU_ID'         => new EE_Primary_Key_Int_Field('ID', esc_html__("Venue ID", "event_espresso")),
33
-                'VNU_name'       => new EE_Plain_Text_Field(
34
-                    'post_title',
35
-                    esc_html__("Venue Name", "event_espresso"),
36
-                    false,
37
-                    ''
38
-                ),
39
-                'VNU_desc'       => new EE_Post_Content_Field(
40
-                    'post_content',
41
-                    esc_html__("Venue Description", "event_espresso"),
42
-                    false,
43
-                    ''
44
-                ),
45
-                'VNU_identifier' => new EE_Slug_Field(
46
-                    'post_name',
47
-                    esc_html__("Venue Identifier", "event_espresso"),
48
-                    false,
49
-                    ''
50
-                ),
51
-                'VNU_created'    => new EE_Datetime_Field(
52
-                    'post_date',
53
-                    esc_html__("Date Venue Created", "event_espresso"),
54
-                    false,
55
-                    EE_Datetime_Field::now
56
-                ),
57
-                'VNU_short_desc' => new EE_Plain_Text_Field(
58
-                    'post_excerpt',
59
-                    esc_html__("Short Description of Venue", "event_espresso"),
60
-                    true,
61
-                    ''
62
-                ),
63
-                'VNU_modified'   => new EE_Datetime_Field(
64
-                    'post_modified',
65
-                    esc_html__("Venue Modified Date", "event_espresso"),
66
-                    false,
67
-                    EE_Datetime_Field::now
68
-                ),
69
-                'VNU_wp_user'    => new EE_WP_User_Field(
70
-                    'post_author',
71
-                    esc_html__("Venue Creator ID", "event_espresso"),
72
-                    false
73
-                ),
74
-                'parent'         => new EE_Integer_Field(
75
-                    'post_parent',
76
-                    esc_html__("Venue Parent ID", "event_espresso"),
77
-                    false,
78
-                    0
79
-                ),
80
-                'VNU_order'      => new EE_Integer_Field(
81
-                    'menu_order',
82
-                    esc_html__("Venue order", "event_espresso"),
83
-                    false,
84
-                    1
85
-                ),
86
-                'post_type'      => new EE_WP_Post_Type_Field(EspressoPostType::VENUES),
87
-                'password'       => new EE_Password_Field(
88
-                    'post_password',
89
-                    esc_html__('Password', 'event_espresso'),
90
-                    false,
91
-                    '',
92
-                    [
93
-                        'VNU_desc',
94
-                        'VNU_short_desc',
95
-                        'VNU_address',
96
-                        'VNU_address2',
97
-                        'VNU_city',
98
-                        'STA_ID',
99
-                        'CNT_ISO',
100
-                        'VNU_zip',
101
-                        'VNU_phone',
102
-                        'VNU_capacity',
103
-                        'VNU_url',
104
-                        'VNU_virtual_phone',
105
-                        'VNU_virtual_url',
106
-                        'VNU_google_map_link',
107
-                        'VNU_enable_for_gmap',
108
-                    ]
109
-                ),
110
-            ],
111
-            'Venue_Meta' => [
112
-                'VNUM_ID'             => new EE_DB_Only_Int_Field(
113
-                    'VNUM_ID',
114
-                    esc_html__("ID of Venue Meta Row", "event_espresso"),
115
-                    false
116
-                ),
117
-                'VNU_ID_fk'           => new EE_DB_Only_Int_Field(
118
-                    'VNU_ID',
119
-                    esc_html__("Foreign Key to Venue Post ", "event_espresso"),
120
-                    false
121
-                ),
122
-                'VNU_address'         => new EE_Plain_Text_Field(
123
-                    'VNU_address',
124
-                    esc_html__("Venue Address line 1", "event_espresso"),
125
-                    true,
126
-                    ''
127
-                ),
128
-                'VNU_address2'        => new EE_Plain_Text_Field(
129
-                    'VNU_address2',
130
-                    esc_html__("Venue Address line 2", "event_espresso"),
131
-                    true,
132
-                    ''
133
-                ),
134
-                'VNU_city'            => new EE_Plain_Text_Field(
135
-                    'VNU_city',
136
-                    esc_html__("Venue City", "event_espresso"),
137
-                    true,
138
-                    ''
139
-                ),
140
-                'STA_ID'              => new EE_Foreign_Key_Int_Field(
141
-                    'STA_ID',
142
-                    esc_html__("State ID", "event_espresso"),
143
-                    true,
144
-                    null,
145
-                    'State'
146
-                ),
147
-                'CNT_ISO'             => new EE_Foreign_Key_String_Field(
148
-                    'CNT_ISO',
149
-                    esc_html__("Country Code", "event_espresso"),
150
-                    true,
151
-                    null,
152
-                    'Country'
153
-                ),
154
-                'VNU_zip'             => new EE_Plain_Text_Field(
155
-                    'VNU_zip',
156
-                    esc_html__("Venue Zip/Postal Code", "event_espresso"),
157
-                    true
158
-                ),
159
-                'VNU_phone'           => new EE_Plain_Text_Field(
160
-                    'VNU_phone',
161
-                    esc_html__("Venue Phone", "event_espresso"),
162
-                    true
163
-                ),
164
-                'VNU_capacity'        => new EE_Infinite_Integer_Field(
165
-                    'VNU_capacity',
166
-                    esc_html__("Venue Capacity", "event_espresso"),
167
-                    true,
168
-                    EE_INF
169
-                ),
170
-                'VNU_url'             => new EE_Plain_Text_Field(
171
-                    'VNU_url',
172
-                    esc_html__('Venue Website', 'event_espresso'),
173
-                    true
174
-                ),
175
-                'VNU_virtual_phone'   => new EE_Plain_Text_Field(
176
-                    'VNU_virtual_phone',
177
-                    esc_html__('Call in Number', 'event_espresso'),
178
-                    true
179
-                ),
180
-                'VNU_virtual_url'     => new EE_Plain_Text_Field(
181
-                    'VNU_virtual_url',
182
-                    esc_html__('Virtual URL', 'event_espresso'),
183
-                    true
184
-                ),
185
-                'VNU_google_map_link' => new EE_Plain_Text_Field(
186
-                    'VNU_google_map_link',
187
-                    esc_html__('Google Map Link', 'event_espresso'),
188
-                    true
189
-                ),
190
-                'VNU_enable_for_gmap' => new EE_Boolean_Field(
191
-                    'VNU_enable_for_gmap',
192
-                    esc_html__('Show Google Map?', 'event_espresso'),
193
-                    false,
194
-                    false
195
-                ),
196
-            ],
197
-        ];
198
-        $this->_model_relations = [
199
-            'Country'           => new EE_Belongs_To_Relation(),
200
-            'Event'             => new EE_Has_Many_Relation(),
201
-            'Datetime'          => new EE_Has_Many_Relation(),
202
-            'State'             => new EE_Belongs_To_Relation(),
203
-            'Term_Relationship' => new EE_Has_Many_Relation(),
204
-            'Term_Taxonomy'     => new EE_HABTM_Relation('Term_Relationship'),
205
-            'WP_User'           => new EE_Belongs_To_Relation(),
206
-        ];
207
-        // this model is generally available for reading
208
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
209
-        $this->model_chain_to_password                            = '';
210
-        parent::__construct($timezone);
211
-    }
18
+	/**
19
+	 * @param string|null $timezone
20
+	 * @throws EE_Error
21
+	 */
22
+	protected function __construct(?string $timezone = '')
23
+	{
24
+		$this->singular_item    = esc_html__('Venue', 'event_espresso');
25
+		$this->plural_item      = esc_html__('Venues', 'event_espresso');
26
+		$this->_tables          = [
27
+			'Venue_CPT'  => new EE_Primary_Table('posts', 'ID'),
28
+			'Venue_Meta' => new EE_Secondary_Table('esp_venue_meta', 'VNUM_ID', 'VNU_ID'),
29
+		];
30
+		$this->_fields          = [
31
+			'Venue_CPT'  => [
32
+				'VNU_ID'         => new EE_Primary_Key_Int_Field('ID', esc_html__("Venue ID", "event_espresso")),
33
+				'VNU_name'       => new EE_Plain_Text_Field(
34
+					'post_title',
35
+					esc_html__("Venue Name", "event_espresso"),
36
+					false,
37
+					''
38
+				),
39
+				'VNU_desc'       => new EE_Post_Content_Field(
40
+					'post_content',
41
+					esc_html__("Venue Description", "event_espresso"),
42
+					false,
43
+					''
44
+				),
45
+				'VNU_identifier' => new EE_Slug_Field(
46
+					'post_name',
47
+					esc_html__("Venue Identifier", "event_espresso"),
48
+					false,
49
+					''
50
+				),
51
+				'VNU_created'    => new EE_Datetime_Field(
52
+					'post_date',
53
+					esc_html__("Date Venue Created", "event_espresso"),
54
+					false,
55
+					EE_Datetime_Field::now
56
+				),
57
+				'VNU_short_desc' => new EE_Plain_Text_Field(
58
+					'post_excerpt',
59
+					esc_html__("Short Description of Venue", "event_espresso"),
60
+					true,
61
+					''
62
+				),
63
+				'VNU_modified'   => new EE_Datetime_Field(
64
+					'post_modified',
65
+					esc_html__("Venue Modified Date", "event_espresso"),
66
+					false,
67
+					EE_Datetime_Field::now
68
+				),
69
+				'VNU_wp_user'    => new EE_WP_User_Field(
70
+					'post_author',
71
+					esc_html__("Venue Creator ID", "event_espresso"),
72
+					false
73
+				),
74
+				'parent'         => new EE_Integer_Field(
75
+					'post_parent',
76
+					esc_html__("Venue Parent ID", "event_espresso"),
77
+					false,
78
+					0
79
+				),
80
+				'VNU_order'      => new EE_Integer_Field(
81
+					'menu_order',
82
+					esc_html__("Venue order", "event_espresso"),
83
+					false,
84
+					1
85
+				),
86
+				'post_type'      => new EE_WP_Post_Type_Field(EspressoPostType::VENUES),
87
+				'password'       => new EE_Password_Field(
88
+					'post_password',
89
+					esc_html__('Password', 'event_espresso'),
90
+					false,
91
+					'',
92
+					[
93
+						'VNU_desc',
94
+						'VNU_short_desc',
95
+						'VNU_address',
96
+						'VNU_address2',
97
+						'VNU_city',
98
+						'STA_ID',
99
+						'CNT_ISO',
100
+						'VNU_zip',
101
+						'VNU_phone',
102
+						'VNU_capacity',
103
+						'VNU_url',
104
+						'VNU_virtual_phone',
105
+						'VNU_virtual_url',
106
+						'VNU_google_map_link',
107
+						'VNU_enable_for_gmap',
108
+					]
109
+				),
110
+			],
111
+			'Venue_Meta' => [
112
+				'VNUM_ID'             => new EE_DB_Only_Int_Field(
113
+					'VNUM_ID',
114
+					esc_html__("ID of Venue Meta Row", "event_espresso"),
115
+					false
116
+				),
117
+				'VNU_ID_fk'           => new EE_DB_Only_Int_Field(
118
+					'VNU_ID',
119
+					esc_html__("Foreign Key to Venue Post ", "event_espresso"),
120
+					false
121
+				),
122
+				'VNU_address'         => new EE_Plain_Text_Field(
123
+					'VNU_address',
124
+					esc_html__("Venue Address line 1", "event_espresso"),
125
+					true,
126
+					''
127
+				),
128
+				'VNU_address2'        => new EE_Plain_Text_Field(
129
+					'VNU_address2',
130
+					esc_html__("Venue Address line 2", "event_espresso"),
131
+					true,
132
+					''
133
+				),
134
+				'VNU_city'            => new EE_Plain_Text_Field(
135
+					'VNU_city',
136
+					esc_html__("Venue City", "event_espresso"),
137
+					true,
138
+					''
139
+				),
140
+				'STA_ID'              => new EE_Foreign_Key_Int_Field(
141
+					'STA_ID',
142
+					esc_html__("State ID", "event_espresso"),
143
+					true,
144
+					null,
145
+					'State'
146
+				),
147
+				'CNT_ISO'             => new EE_Foreign_Key_String_Field(
148
+					'CNT_ISO',
149
+					esc_html__("Country Code", "event_espresso"),
150
+					true,
151
+					null,
152
+					'Country'
153
+				),
154
+				'VNU_zip'             => new EE_Plain_Text_Field(
155
+					'VNU_zip',
156
+					esc_html__("Venue Zip/Postal Code", "event_espresso"),
157
+					true
158
+				),
159
+				'VNU_phone'           => new EE_Plain_Text_Field(
160
+					'VNU_phone',
161
+					esc_html__("Venue Phone", "event_espresso"),
162
+					true
163
+				),
164
+				'VNU_capacity'        => new EE_Infinite_Integer_Field(
165
+					'VNU_capacity',
166
+					esc_html__("Venue Capacity", "event_espresso"),
167
+					true,
168
+					EE_INF
169
+				),
170
+				'VNU_url'             => new EE_Plain_Text_Field(
171
+					'VNU_url',
172
+					esc_html__('Venue Website', 'event_espresso'),
173
+					true
174
+				),
175
+				'VNU_virtual_phone'   => new EE_Plain_Text_Field(
176
+					'VNU_virtual_phone',
177
+					esc_html__('Call in Number', 'event_espresso'),
178
+					true
179
+				),
180
+				'VNU_virtual_url'     => new EE_Plain_Text_Field(
181
+					'VNU_virtual_url',
182
+					esc_html__('Virtual URL', 'event_espresso'),
183
+					true
184
+				),
185
+				'VNU_google_map_link' => new EE_Plain_Text_Field(
186
+					'VNU_google_map_link',
187
+					esc_html__('Google Map Link', 'event_espresso'),
188
+					true
189
+				),
190
+				'VNU_enable_for_gmap' => new EE_Boolean_Field(
191
+					'VNU_enable_for_gmap',
192
+					esc_html__('Show Google Map?', 'event_espresso'),
193
+					false,
194
+					false
195
+				),
196
+			],
197
+		];
198
+		$this->_model_relations = [
199
+			'Country'           => new EE_Belongs_To_Relation(),
200
+			'Event'             => new EE_Has_Many_Relation(),
201
+			'Datetime'          => new EE_Has_Many_Relation(),
202
+			'State'             => new EE_Belongs_To_Relation(),
203
+			'Term_Relationship' => new EE_Has_Many_Relation(),
204
+			'Term_Taxonomy'     => new EE_HABTM_Relation('Term_Relationship'),
205
+			'WP_User'           => new EE_Belongs_To_Relation(),
206
+		];
207
+		// this model is generally available for reading
208
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
209
+		$this->model_chain_to_password                            = '';
210
+		parent::__construct($timezone);
211
+	}
212 212
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Price_Type.model.php 2 patches
Indentation   +199 added lines, -199 removed lines patch added patch discarded remove patch
@@ -9,203 +9,203 @@
 block discarded – undo
9 9
  */
10 10
 class EEM_Price_Type extends EEM_Soft_Delete_Base
11 11
 {
12
-    /**
13
-     * constants for price base types. In the DB, we decided to store the price base type
14
-     * as an integer. So, to avoid just having magic numbers everwhere (eg, querying for
15
-     * all price types with PBT_ID = 2), we define these constants, to make code more understandable.
16
-     * So, as an example, to query for all price types that are a tax, we'd do
17
-     * EEM_PRice_Type::instance()->get_all(array(array('PBT_ID'=>EEM_Price_Type::base_type_tax)))
18
-     * instead of
19
-     * EEM_Price_Type::instance()->get_all(array(array('PBT_ID'=>2)))
20
-     * Although the 2nd is shorter, it's much less obvious what it's doing. Also, should these magic IDs ever
21
-     * change, we can continue to use the constant, by simply change its value.
22
-     */
23
-    const base_type_base_price = 1;
24
-
25
-    const base_type_discount   = 2;
26
-
27
-    const base_type_surcharge  = 3;
28
-
29
-    const base_type_tax        = 4;
30
-
31
-
32
-    protected static ?EEM_Price_Type $_instance = null;
33
-
34
-    /**
35
-     * keys are one of the base_type_* constants above, and values are the text-representation of the base type.
36
-     *
37
-     * @var string[]
38
-     */
39
-    public array $base_types;
40
-
41
-    /**
42
-     * An array of the price type objects
43
-     */
44
-    public ?array $type = null;
45
-
46
-
47
-    /**
48
-     * return an array of Base types. Keys are INTs which are used in the database,
49
-     * values are text-representations of the base type.
50
-     *
51
-     * @return array
52
-     */
53
-    public function get_base_types(): array
54
-    {
55
-        return $this->base_types;
56
-    }
57
-
58
-
59
-    /**
60
-     * Gets the name of the base
61
-     *
62
-     * @param int $base_type_int
63
-     * @return string
64
-     */
65
-    public function get_base_type_name(int $base_type_int): string
66
-    {
67
-        return $this->base_types[ $base_type_int ];
68
-    }
69
-
70
-
71
-    /**
72
-     * private constructor to prevent direct creation
73
-     *
74
-     * @param string|null $timezone
75
-     * @return void
76
-     * @throws EE_Error
77
-     */
78
-    protected function __construct(?string $timezone = '')
79
-    {
80
-        $this->base_types    = [
81
-            EEM_Price_Type::base_type_base_price => esc_html__('Price', 'event_espresso'),
82
-            EEM_Price_Type::base_type_discount   => esc_html__('Discount', 'event_espresso'),
83
-            EEM_Price_Type::base_type_surcharge  => esc_html__('Surcharge', 'event_espresso'),
84
-            EEM_Price_Type::base_type_tax        => esc_html__('Tax', 'event_espresso'),
85
-        ];
86
-        $this->singular_item = esc_html__('Price Type', 'event_espresso');
87
-        $this->plural_item   = esc_html__('Price Types', 'event_espresso');
88
-
89
-        $this->_tables          = [
90
-            'Price_Type' => new EE_Primary_Table('esp_price_type', 'PRT_ID'),
91
-        ];
92
-        $this->_fields          = [
93
-            'Price_Type' => [
94
-                'PRT_ID'         => new EE_Primary_Key_Int_Field(
95
-                    'PRT_ID', esc_html__('Price Type ID', 'event_espresso')
96
-                ),
97
-                'PRT_name'       => new EE_Plain_Text_Field(
98
-                    'PRT_name',
99
-                    esc_html__('Price Type Name', 'event_espresso'),
100
-                    false,
101
-                    ''
102
-                ),
103
-                'PBT_ID'         => new EE_Enum_Integer_Field(
104
-                    'PBT_ID',
105
-                    esc_html__(
106
-                        'Price Base type ID, 1 = Price , 2 = Discount , 3 = Surcharge , 4 = Tax',
107
-                        'event_espresso'
108
-                    ),
109
-                    false,
110
-                    EEM_Price_Type::base_type_base_price,
111
-                    $this->base_types
112
-                ),
113
-                'PRT_is_percent' => new EE_Boolean_Field(
114
-                    'PRT_is_percent',
115
-                    esc_html__(
116
-                        'Flag indicating price is a percentage',
117
-                        'event_espresso'
118
-                    ),
119
-                    false,
120
-                    false
121
-                ),
122
-                'PRT_order'      => new EE_Integer_Field(
123
-                    'PRT_order',
124
-                    esc_html__(
125
-                        'Order in which price should be applied. ',
126
-                        'event_espresso'
127
-                    ),
128
-                    false,
129
-                    0
130
-                ),
131
-                'PRT_deleted'    => new EE_Trashed_Flag_Field(
132
-                    'PRT_deleted',
133
-                    esc_html__(
134
-                        'Flag indicating price type has been trashed',
135
-                        'event_espresso'
136
-                    ),
137
-                    false,
138
-                    false
139
-                ),
140
-                'PRT_wp_user'    => new EE_WP_User_Field(
141
-                    'PRT_wp_user',
142
-                    esc_html__('Price Type Creator ID', 'event_espresso'),
143
-                    false
144
-                ),
145
-            ],
146
-        ];
147
-        $this->_model_relations = [
148
-            'Price'   => new EE_Has_Many_Relation(),
149
-            'WP_User' => new EE_Belongs_To_Relation(),
150
-        ];
151
-        // this model is generally available for reading
152
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
153
-        // all price types are "default" in terms of capability names
154
-        $this->_caps_slug = 'default_price_types';
155
-        parent::__construct($timezone);
156
-    }
157
-
158
-
159
-    /**
160
-     * instantiate a new price type object with blank/empty properties
161
-     *
162
-     * @return EE_Price_Type
163
-     * @throws EE_Error
164
-     * @throws ReflectionException
165
-     */
166
-    public function get_new_price_type(): EE_Price_Type
167
-    {
168
-        return EE_Price_Type::new_instance();
169
-    }
170
-
171
-
172
-    /**
173
-     * @param array $query_params
174
-     * @param bool  $allow_blocking   if TRUE, matched objects will only be deleted if there is no related model info
175
-     *                                that blocks it (ie, there' sno other data that depends on this data);
176
-     *                                if false, deletes regardless of other objects which may depend on it.
177
-     *                                Its generally advisable to always leave this as TRUE,
178
-     *                                otherwise you could easily corrupt your DB
179
-     * @return bool
180
-     * @throws EE_Error
181
-     * @throws ReflectionException
182
-     */
183
-    public function delete_permanently($query_params = [], $allow_blocking = true)
184
-    {
185
-        $would_be_deleted_price_types    = $this->get_all_deleted_and_undeleted($query_params);
186
-        $would_be_deleted_price_type_ids = array_keys($would_be_deleted_price_types);
187
-
188
-        $ID = $query_params[0][ $this->get_primary_key_field()->get_name() ];
189
-
190
-        // check if any prices use this price type
191
-        $prc_query_params = [['PRT_ID' => ['IN', $would_be_deleted_price_type_ids]]];
192
-        if ($prices = $this->get_all_related($ID, 'Price', $prc_query_params)) {
193
-            $prices_names_and_ids = [];
194
-            foreach ($prices as $price) {
195
-                /* @var $price EE_Price */
196
-                $prices_names_and_ids[] = $price->name() . "(" . $price->ID() . ")";
197
-            }
198
-            $msg = sprintf(
199
-                esc_html__(
200
-                    'The Price Type(s) could not be deleted because there are existing Prices that currently use this Price Type.  If you still wish to delete this Price Type, then either delete those Prices or change them to use other Price Types.The prices are: %s',
201
-                    'event_espresso'
202
-                ),
203
-                implode(",", $prices_names_and_ids)
204
-            );
205
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
206
-            return false;
207
-        }
208
-
209
-        return parent::delete_permanently($query_params);
210
-    }
12
+	/**
13
+	 * constants for price base types. In the DB, we decided to store the price base type
14
+	 * as an integer. So, to avoid just having magic numbers everwhere (eg, querying for
15
+	 * all price types with PBT_ID = 2), we define these constants, to make code more understandable.
16
+	 * So, as an example, to query for all price types that are a tax, we'd do
17
+	 * EEM_PRice_Type::instance()->get_all(array(array('PBT_ID'=>EEM_Price_Type::base_type_tax)))
18
+	 * instead of
19
+	 * EEM_Price_Type::instance()->get_all(array(array('PBT_ID'=>2)))
20
+	 * Although the 2nd is shorter, it's much less obvious what it's doing. Also, should these magic IDs ever
21
+	 * change, we can continue to use the constant, by simply change its value.
22
+	 */
23
+	const base_type_base_price = 1;
24
+
25
+	const base_type_discount   = 2;
26
+
27
+	const base_type_surcharge  = 3;
28
+
29
+	const base_type_tax        = 4;
30
+
31
+
32
+	protected static ?EEM_Price_Type $_instance = null;
33
+
34
+	/**
35
+	 * keys are one of the base_type_* constants above, and values are the text-representation of the base type.
36
+	 *
37
+	 * @var string[]
38
+	 */
39
+	public array $base_types;
40
+
41
+	/**
42
+	 * An array of the price type objects
43
+	 */
44
+	public ?array $type = null;
45
+
46
+
47
+	/**
48
+	 * return an array of Base types. Keys are INTs which are used in the database,
49
+	 * values are text-representations of the base type.
50
+	 *
51
+	 * @return array
52
+	 */
53
+	public function get_base_types(): array
54
+	{
55
+		return $this->base_types;
56
+	}
57
+
58
+
59
+	/**
60
+	 * Gets the name of the base
61
+	 *
62
+	 * @param int $base_type_int
63
+	 * @return string
64
+	 */
65
+	public function get_base_type_name(int $base_type_int): string
66
+	{
67
+		return $this->base_types[ $base_type_int ];
68
+	}
69
+
70
+
71
+	/**
72
+	 * private constructor to prevent direct creation
73
+	 *
74
+	 * @param string|null $timezone
75
+	 * @return void
76
+	 * @throws EE_Error
77
+	 */
78
+	protected function __construct(?string $timezone = '')
79
+	{
80
+		$this->base_types    = [
81
+			EEM_Price_Type::base_type_base_price => esc_html__('Price', 'event_espresso'),
82
+			EEM_Price_Type::base_type_discount   => esc_html__('Discount', 'event_espresso'),
83
+			EEM_Price_Type::base_type_surcharge  => esc_html__('Surcharge', 'event_espresso'),
84
+			EEM_Price_Type::base_type_tax        => esc_html__('Tax', 'event_espresso'),
85
+		];
86
+		$this->singular_item = esc_html__('Price Type', 'event_espresso');
87
+		$this->plural_item   = esc_html__('Price Types', 'event_espresso');
88
+
89
+		$this->_tables          = [
90
+			'Price_Type' => new EE_Primary_Table('esp_price_type', 'PRT_ID'),
91
+		];
92
+		$this->_fields          = [
93
+			'Price_Type' => [
94
+				'PRT_ID'         => new EE_Primary_Key_Int_Field(
95
+					'PRT_ID', esc_html__('Price Type ID', 'event_espresso')
96
+				),
97
+				'PRT_name'       => new EE_Plain_Text_Field(
98
+					'PRT_name',
99
+					esc_html__('Price Type Name', 'event_espresso'),
100
+					false,
101
+					''
102
+				),
103
+				'PBT_ID'         => new EE_Enum_Integer_Field(
104
+					'PBT_ID',
105
+					esc_html__(
106
+						'Price Base type ID, 1 = Price , 2 = Discount , 3 = Surcharge , 4 = Tax',
107
+						'event_espresso'
108
+					),
109
+					false,
110
+					EEM_Price_Type::base_type_base_price,
111
+					$this->base_types
112
+				),
113
+				'PRT_is_percent' => new EE_Boolean_Field(
114
+					'PRT_is_percent',
115
+					esc_html__(
116
+						'Flag indicating price is a percentage',
117
+						'event_espresso'
118
+					),
119
+					false,
120
+					false
121
+				),
122
+				'PRT_order'      => new EE_Integer_Field(
123
+					'PRT_order',
124
+					esc_html__(
125
+						'Order in which price should be applied. ',
126
+						'event_espresso'
127
+					),
128
+					false,
129
+					0
130
+				),
131
+				'PRT_deleted'    => new EE_Trashed_Flag_Field(
132
+					'PRT_deleted',
133
+					esc_html__(
134
+						'Flag indicating price type has been trashed',
135
+						'event_espresso'
136
+					),
137
+					false,
138
+					false
139
+				),
140
+				'PRT_wp_user'    => new EE_WP_User_Field(
141
+					'PRT_wp_user',
142
+					esc_html__('Price Type Creator ID', 'event_espresso'),
143
+					false
144
+				),
145
+			],
146
+		];
147
+		$this->_model_relations = [
148
+			'Price'   => new EE_Has_Many_Relation(),
149
+			'WP_User' => new EE_Belongs_To_Relation(),
150
+		];
151
+		// this model is generally available for reading
152
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
153
+		// all price types are "default" in terms of capability names
154
+		$this->_caps_slug = 'default_price_types';
155
+		parent::__construct($timezone);
156
+	}
157
+
158
+
159
+	/**
160
+	 * instantiate a new price type object with blank/empty properties
161
+	 *
162
+	 * @return EE_Price_Type
163
+	 * @throws EE_Error
164
+	 * @throws ReflectionException
165
+	 */
166
+	public function get_new_price_type(): EE_Price_Type
167
+	{
168
+		return EE_Price_Type::new_instance();
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param array $query_params
174
+	 * @param bool  $allow_blocking   if TRUE, matched objects will only be deleted if there is no related model info
175
+	 *                                that blocks it (ie, there' sno other data that depends on this data);
176
+	 *                                if false, deletes regardless of other objects which may depend on it.
177
+	 *                                Its generally advisable to always leave this as TRUE,
178
+	 *                                otherwise you could easily corrupt your DB
179
+	 * @return bool
180
+	 * @throws EE_Error
181
+	 * @throws ReflectionException
182
+	 */
183
+	public function delete_permanently($query_params = [], $allow_blocking = true)
184
+	{
185
+		$would_be_deleted_price_types    = $this->get_all_deleted_and_undeleted($query_params);
186
+		$would_be_deleted_price_type_ids = array_keys($would_be_deleted_price_types);
187
+
188
+		$ID = $query_params[0][ $this->get_primary_key_field()->get_name() ];
189
+
190
+		// check if any prices use this price type
191
+		$prc_query_params = [['PRT_ID' => ['IN', $would_be_deleted_price_type_ids]]];
192
+		if ($prices = $this->get_all_related($ID, 'Price', $prc_query_params)) {
193
+			$prices_names_and_ids = [];
194
+			foreach ($prices as $price) {
195
+				/* @var $price EE_Price */
196
+				$prices_names_and_ids[] = $price->name() . "(" . $price->ID() . ")";
197
+			}
198
+			$msg = sprintf(
199
+				esc_html__(
200
+					'The Price Type(s) could not be deleted because there are existing Prices that currently use this Price Type.  If you still wish to delete this Price Type, then either delete those Prices or change them to use other Price Types.The prices are: %s',
201
+					'event_espresso'
202
+				),
203
+				implode(",", $prices_names_and_ids)
204
+			);
205
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
206
+			return false;
207
+		}
208
+
209
+		return parent::delete_permanently($query_params);
210
+	}
211 211
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
      */
65 65
     public function get_base_type_name(int $base_type_int): string
66 66
     {
67
-        return $this->base_types[ $base_type_int ];
67
+        return $this->base_types[$base_type_int];
68 68
     }
69 69
 
70 70
 
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
      */
78 78
     protected function __construct(?string $timezone = '')
79 79
     {
80
-        $this->base_types    = [
80
+        $this->base_types = [
81 81
             EEM_Price_Type::base_type_base_price => esc_html__('Price', 'event_espresso'),
82 82
             EEM_Price_Type::base_type_discount   => esc_html__('Discount', 'event_espresso'),
83 83
             EEM_Price_Type::base_type_surcharge  => esc_html__('Surcharge', 'event_espresso'),
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
             'WP_User' => new EE_Belongs_To_Relation(),
150 150
         ];
151 151
         // this model is generally available for reading
152
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Public();
152
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Public();
153 153
         // all price types are "default" in terms of capability names
154 154
         $this->_caps_slug = 'default_price_types';
155 155
         parent::__construct($timezone);
@@ -185,7 +185,7 @@  discard block
 block discarded – undo
185 185
         $would_be_deleted_price_types    = $this->get_all_deleted_and_undeleted($query_params);
186 186
         $would_be_deleted_price_type_ids = array_keys($would_be_deleted_price_types);
187 187
 
188
-        $ID = $query_params[0][ $this->get_primary_key_field()->get_name() ];
188
+        $ID = $query_params[0][$this->get_primary_key_field()->get_name()];
189 189
 
190 190
         // check if any prices use this price type
191 191
         $prc_query_params = [['PRT_ID' => ['IN', $would_be_deleted_price_type_ids]]];
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
             $prices_names_and_ids = [];
194 194
             foreach ($prices as $price) {
195 195
                 /* @var $price EE_Price */
196
-                $prices_names_and_ids[] = $price->name() . "(" . $price->ID() . ")";
196
+                $prices_names_and_ids[] = $price->name()."(".$price->ID().")";
197 197
             }
198 198
             $msg = sprintf(
199 199
                 esc_html__(
Please login to merge, or discard this patch.