Completed
Branch master (44537d)
by
unknown
14:30 queued 10:03
created
core/business/EE_Transaction_Processor.class.php 2 patches
Indentation   +964 added lines, -964 removed lines patch added patch discarded remove patch
@@ -16,968 +16,968 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Transaction_Processor extends EE_Processor_Base
18 18
 {
19
-    /**
20
-     * @var EE_Registration_Processor $_instance
21
-     * @access    private
22
-     */
23
-    private static $_instance;
24
-
25
-    /**
26
-     * array of query WHERE params to use when retrieving cached registrations from a transaction
27
-     *
28
-     * @var array $registration_query_params
29
-     * @access private
30
-     */
31
-    private $_registration_query_params = [];
32
-
33
-    /**
34
-     * @deprecated
35
-     * @var string
36
-     */
37
-    protected $_old_txn_status;
38
-
39
-    /**
40
-     * @deprecated
41
-     * @var string
42
-     */
43
-    protected $_new_txn_status;
44
-
45
-
46
-    /**
47
-     * @singleton method used to instantiate class object
48
-     * @access    public
49
-     * @param array $registration_query_params
50
-     * @return EE_Transaction_Processor instance
51
-     */
52
-    public static function instance($registration_query_params = [])
53
-    {
54
-        // check if class object is instantiated
55
-        if (! self::$_instance instanceof EE_Transaction_Processor) {
56
-            self::$_instance = new self($registration_query_params);
57
-        }
58
-        return self::$_instance;
59
-    }
60
-
61
-
62
-    /**
63
-     * @param array $registration_query_params
64
-     */
65
-    private function __construct($registration_query_params = [])
66
-    {
67
-        // make sure some query params are set for retrieving registrations
68
-        $this->_set_registration_query_params($registration_query_params);
69
-    }
70
-
71
-
72
-    /**
73
-     * @access private
74
-     * @param array $registration_query_params
75
-     */
76
-    private function _set_registration_query_params($registration_query_params)
77
-    {
78
-        $this->_registration_query_params = ! empty($registration_query_params)
79
-            ? $registration_query_params
80
-            : ['order_by' => ['REG_count' => 'ASC']];
81
-    }
82
-
83
-
84
-    /**
85
-     * manually_update_registration_statuses
86
-     *
87
-     * @access public
88
-     * @param EE_Transaction $transaction
89
-     * @param string         $new_reg_status
90
-     * @param array          $registration_query_params array of query WHERE params to use
91
-     *                                                  when retrieving cached registrations from a transaction
92
-     * @return    boolean
93
-     * @throws \EE_Error
94
-     */
95
-    public function manually_update_registration_statuses(
96
-        EE_Transaction $transaction,
97
-        $new_reg_status = '',
98
-        $registration_query_params = []
99
-    ) {
100
-        $status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
101
-            'manually_update_registration_status',
102
-            $transaction,
103
-            $registration_query_params,
104
-            $new_reg_status
105
-        );
106
-        // send messages
107
-        /** @type EE_Registration_Processor $registration_processor */
108
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
109
-        $registration_processor->trigger_registration_update_notifications(
110
-            $transaction->primary_registration(),
111
-            ['manually_updated' => true]
112
-        );
113
-        do_action(
114
-            'AHEE__EE_Transaction_Processor__manually_update_registration_statuses',
115
-            $transaction,
116
-            $status_updates
117
-        );
118
-        return $status_updates;
119
-    }
120
-
121
-
122
-    /**
123
-     * toggle_registration_statuses_for_default_approved_events
124
-     *
125
-     * @access public
126
-     * @param EE_Transaction $transaction
127
-     * @param array          $registration_query_params array of query WHERE params to use
128
-     *                                                  when retrieving cached registrations from a transaction
129
-     * @return    boolean
130
-     * @throws \EE_Error
131
-     */
132
-    public function toggle_registration_statuses_for_default_approved_events(
133
-        EE_Transaction $transaction,
134
-        $registration_query_params = []
135
-    ) {
136
-        $status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
137
-            'toggle_registration_status_for_default_approved_events',
138
-            $transaction,
139
-            $registration_query_params
140
-        );
141
-        do_action(
142
-            'AHEE__EE_Transaction_Processor__toggle_registration_statuses_for_default_approved_events',
143
-            $transaction,
144
-            $status_updates
145
-        );
146
-        return $status_updates;
147
-    }
148
-
149
-
150
-    /**
151
-     * toggle_registration_statuses_if_no_monies_owing
152
-     *
153
-     * @access public
154
-     * @param EE_Transaction $transaction
155
-     * @param array          $registration_query_params array of query WHERE params to use
156
-     *                                                  when retrieving cached registrations from a transaction
157
-     * @return    boolean
158
-     * @throws \EE_Error
159
-     */
160
-    public function toggle_registration_statuses_if_no_monies_owing(
161
-        EE_Transaction $transaction,
162
-        $registration_query_params = []
163
-    ) {
164
-        $status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
165
-            'toggle_registration_status_if_no_monies_owing',
166
-            $transaction,
167
-            $registration_query_params
168
-        );
169
-        do_action(
170
-            'AHEE__EE_Transaction_Processor__toggle_registration_statuses_if_no_monies_owing',
171
-            $transaction,
172
-            $status_updates
173
-        );
174
-        return $status_updates;
175
-    }
176
-
177
-
178
-    /**
179
-     * update_transaction_and_registrations_after_checkout_or_payment
180
-     * cycles thru related registrations and calls update_registration_after_checkout_or_payment() on each
181
-     *
182
-     * @param EE_Transaction     $transaction
183
-     * @param \EE_Payment | NULL $payment
184
-     * @param array              $registration_query_params    array of query WHERE params to use
185
-     *                                                         when retrieving cached registrations from a transaction
186
-     * @param bool               $trigger_notifications        whether or not to call
187
-     *                                                         \EE_Registration_Processor::trigger_registration_update_notifications()
188
-     * @return array
189
-     * @throws \EE_Error
190
-     */
191
-    public function update_transaction_and_registrations_after_checkout_or_payment(
192
-        EE_Transaction $transaction,
193
-        $payment = null,
194
-        $registration_query_params = [],
195
-        $trigger_notifications = true
196
-    ) {
197
-        // make sure some query params are set for retrieving registrations
198
-        $this->_set_registration_query_params($registration_query_params);
199
-        // get final reg step status
200
-        $finalized = $transaction->final_reg_step_completed();
201
-        // if the 'finalize_registration' step has been initiated (has a timestamp)
202
-        // but has not yet been fully completed (TRUE)
203
-        if (is_int($finalized) && $finalized !== false && $finalized !== true) {
204
-            $transaction->set_reg_step_completed('finalize_registration');
205
-            $finalized = true;
206
-        }
207
-        $transaction->save();
208
-        // array of details to aid in decision making by systems
209
-        $update_params = [
210
-            'old_txn_status'  => $transaction->old_txn_status(),
211
-            'new_txn_status'  => $transaction->status_ID(),
212
-            'finalized'       => $finalized,
213
-            'revisit'         => $this->_revisit,
214
-            'payment_updates' => $payment instanceof EE_Payment
215
-                ? true
216
-                : false,
217
-            'last_payment'    => $payment,
218
-        ];
219
-        // now update the registrations and add the results to our $update_params
220
-        $update_params['status_updates'] = $this->_call_method_on_registrations_via_Registration_Processor(
221
-            'update_registration_after_checkout_or_payment',
222
-            $transaction,
223
-            $this->_registration_query_params,
224
-            $update_params
225
-        );
226
-        if ($trigger_notifications) {
227
-            // send messages
228
-            /** @type EE_Registration_Processor $registration_processor */
229
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
230
-            $registration_processor->trigger_registration_update_notifications(
231
-                $transaction->primary_registration(),
232
-                $update_params
233
-            );
234
-        }
235
-        do_action(
236
-            'AHEE__EE_Transaction_Processor__update_transaction_and_registrations_after_checkout_or_payment',
237
-            $transaction,
238
-            $update_params
239
-        );
240
-        return $update_params;
241
-    }
242
-
243
-
244
-    /**
245
-     * update_transaction_after_registration_reopened
246
-     * readjusts TXN and Line Item totals after a registration is changed from
247
-     * cancelled or declined to another reg status such as pending payment or approved
248
-     *
249
-     * @param \EE_Registration $registration
250
-     * @param array            $closed_reg_statuses
251
-     * @param bool             $update_txn
252
-     * @return bool
253
-     * @throws \EE_Error
254
-     */
255
-    public function update_transaction_after_reinstating_canceled_registration(
256
-        EE_Registration $registration,
257
-        $closed_reg_statuses = [],
258
-        $update_txn = true
259
-    ) {
260
-        // these reg statuses should not be considered in any calculations involving monies owing
261
-        $closed_reg_statuses = ! empty($closed_reg_statuses)
262
-            ? $closed_reg_statuses
263
-            : EEM_Registration::closed_reg_statuses();
264
-        if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
265
-            return false;
266
-        }
267
-        try {
268
-            $transaction      = $this->get_transaction_for_registration($registration);
269
-            $ticket_line_item = $this->get_ticket_line_item_for_transaction_registration(
270
-                $transaction,
271
-                $registration
272
-            );
273
-            // un-cancel the ticket
274
-            $success = EEH_Line_Item::reinstate_canceled_ticket_line_item($ticket_line_item);
275
-        } catch (EE_Error $e) {
276
-            EE_Error::add_error(
277
-                sprintf(
278
-                    esc_html__(
279
-                        'The Ticket Line Item for Registration %1$d could not be reinstated because :%2$s%3$s',
280
-                        'event_espresso'
281
-                    ),
282
-                    $registration->ID(),
283
-                    '<br />',
284
-                    $e->getMessage()
285
-                ),
286
-                __FILE__,
287
-                __FUNCTION__,
288
-                __LINE__
289
-            );
290
-            return false;
291
-        }
292
-        if ($update_txn) {
293
-            return $transaction->save()
294
-                ? $success
295
-                : false;
296
-        }
297
-        return $success;
298
-    }
299
-
300
-
301
-    /**
302
-     * update_transaction_after_canceled_or_declined_registration
303
-     * readjusts TXN and Line Item totals after a registration is cancelled or declined
304
-     *
305
-     * @param \EE_Registration $registration
306
-     * @param array            $closed_reg_statuses
307
-     * @param bool             $update_txn
308
-     * @return bool
309
-     * @throws \EE_Error
310
-     */
311
-    public function update_transaction_after_canceled_or_declined_registration(
312
-        EE_Registration $registration,
313
-        $closed_reg_statuses = [],
314
-        $update_txn = true
315
-    ) {
316
-        // these reg statuses should not be considered in any calculations involving monies owing
317
-        $closed_reg_statuses = ! empty($closed_reg_statuses)
318
-            ? $closed_reg_statuses
319
-            : EEM_Registration::closed_reg_statuses();
320
-        if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
321
-            return false;
322
-        }
323
-        try {
324
-            $transaction = $this->get_transaction_for_registration($registration);
325
-            if (
326
-                apply_filters(
327
-                    'FHEE__EE_Transaction_Processor__update_transaction_after_canceled_or_declined_registration__cancel_ticket_line_item',
328
-                    true,
329
-                    $registration,
330
-                    $transaction
331
-                )
332
-            ) {
333
-                $ticket_line_item = $this->get_ticket_line_item_for_transaction_registration(
334
-                    $transaction,
335
-                    $registration
336
-                );
337
-                EEH_Line_Item::cancel_ticket_line_item($ticket_line_item);
338
-            }
339
-        } catch (EE_Error $e) {
340
-            EE_Error::add_error(
341
-                sprintf(
342
-                    esc_html__(
343
-                        'The Ticket Line Item for Registration %1$d could not be cancelled because :%2$s%3$s',
344
-                        'event_espresso'
345
-                    ),
346
-                    $registration->ID(),
347
-                    '<br />',
348
-                    $e->getMessage()
349
-                ),
350
-                __FILE__,
351
-                __FUNCTION__,
352
-                __LINE__
353
-            );
354
-            return false;
355
-        }
356
-        if ($update_txn) {
357
-            return $transaction->save()
358
-                ? true
359
-                : false;
360
-        }
361
-        return true;
362
-    }
363
-
364
-
365
-    /**
366
-     * get_transaction_for_registration
367
-     *
368
-     * @access    public
369
-     * @param EE_Registration $registration
370
-     * @return    EE_Transaction
371
-     * @throws    EE_Error
372
-     */
373
-    public function get_transaction_for_registration(EE_Registration $registration)
374
-    {
375
-        $transaction = $registration->transaction();
376
-        if (! $transaction instanceof EE_Transaction) {
377
-            throw new EE_Error(
378
-                sprintf(
379
-                    esc_html__('The Transaction for Registration %1$d was not found or is invalid.', 'event_espresso'),
380
-                    $registration->ID()
381
-                )
382
-            );
383
-        }
384
-        return $transaction;
385
-    }
386
-
387
-
388
-    /**
389
-     * get_ticket_line_item_for_transaction_registration
390
-     *
391
-     * @access    public
392
-     * @param EE_Transaction  $transaction
393
-     * @param EE_Registration $registration
394
-     * @return    EE_Line_Item
395
-     * @throws    EE_Error
396
-     */
397
-    public function get_ticket_line_item_for_transaction_registration(
398
-        EE_Transaction $transaction,
399
-        EE_Registration $registration
400
-    ) {
401
-        EE_Registry::instance()->load_helper('Line_Item');
402
-        $ticket_line_item = EEM_Line_Item::instance()->get_ticket_line_item_for_transaction(
403
-            $transaction->ID(),
404
-            $registration->ticket_ID()
405
-        );
406
-        if (! $ticket_line_item instanceof EE_Line_Item) {
407
-            throw new EE_Error(
408
-                sprintf(
409
-                    esc_html__(
410
-                        'The Line Item for Transaction %1$d and Ticket %2$d was not found or is invalid.',
411
-                        'event_espresso'
412
-                    ),
413
-                    $transaction->ID(),
414
-                    $registration->ticket_ID()
415
-                )
416
-            );
417
-        }
418
-        return $ticket_line_item;
419
-    }
420
-
421
-
422
-    /**
423
-     * cancel_transaction_if_all_registrations_canceled
424
-     * cycles thru related registrations and checks their statuses
425
-     * if ALL registrations are Cancelled or Declined, then this sets the TXN status to
426
-     *
427
-     * @access    public
428
-     * @param EE_Transaction $transaction
429
-     * @param string         $new_TXN_status
430
-     * @param array          $registration_query_params    - array of query WHERE params to use when
431
-     *                                                     retrieving cached registrations from a transaction
432
-     * @param array          $closed_reg_statuses
433
-     * @param bool           $update_txn
434
-     * @return    bool            true if TXN status was updated, false if not
435
-     */
436
-    public function toggle_transaction_status_if_all_registrations_canceled_or_declined(
437
-        EE_Transaction $transaction,
438
-        $new_TXN_status = '',
439
-        $registration_query_params = [],
440
-        $closed_reg_statuses = [],
441
-        $update_txn = true
442
-    ) {
443
-        // make sure some query params are set for retrieving registrations
444
-        $this->_set_registration_query_params($registration_query_params);
445
-        // these reg statuses should not be considered in any calculations involving monies owing
446
-        $closed_reg_statuses = ! empty($closed_reg_statuses)
447
-            ? $closed_reg_statuses
448
-            : EEM_Registration::closed_reg_statuses();
449
-        // loop through cached registrations
450
-        foreach ($transaction->registrations($this->_registration_query_params) as $registration) {
451
-            if (
452
-                $registration instanceof EE_Registration
453
-                && ! in_array($registration->status_ID(), $closed_reg_statuses)
454
-            ) {
455
-                return false;
456
-            }
457
-        }
458
-        if (in_array($new_TXN_status, EEM_Transaction::txn_status_array())) {
459
-            $transaction->set_status($new_TXN_status);
460
-        }
461
-        if ($update_txn) {
462
-            return $transaction->save()
463
-                ? true
464
-                : false;
465
-        }
466
-        return true;
467
-    }
468
-
469
-
470
-    /**
471
-     * _call_method_on_registrations_via_Registration_Processor
472
-     * cycles thru related registrations and calls the requested method on each
473
-     *
474
-     * @access private
475
-     * @param string         $method_name
476
-     * @param EE_Transaction $transaction
477
-     * @param array          $registration_query_params array of query WHERE params to use
478
-     *                                                  when retrieving cached registrations from a transaction
479
-     * @param string         $additional_param
480
-     * @return boolean
481
-     * @throws \EE_Error
482
-     */
483
-    private function _call_method_on_registrations_via_Registration_Processor(
484
-        $method_name,
485
-        EE_Transaction $transaction,
486
-        $registration_query_params = [],
487
-        $additional_param = null
488
-    ) {
489
-        $response = false;
490
-        /** @type EE_Registration_Processor $registration_processor */
491
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
492
-        // check that method exists
493
-        if (! method_exists($registration_processor, $method_name)) {
494
-            throw new EE_Error(esc_html__('Method does not exist.', 'event_espresso'));
495
-        }
496
-        // make sure some query params are set for retrieving registrations
497
-        $this->_set_registration_query_params($registration_query_params);
498
-        // loop through cached registrations
499
-        foreach ($transaction->registrations($this->_registration_query_params) as $registration) {
500
-            if ($registration instanceof EE_Registration) {
501
-                if ($additional_param) {
502
-                    $response = $registration_processor->{$method_name}($registration, $additional_param)
503
-                        ? true
504
-                        : $response;
505
-                } else {
506
-                    $response = $registration_processor->{$method_name}($registration)
507
-                        ? true
508
-                        : $response;
509
-                }
510
-            }
511
-        }
512
-        return $response;
513
-    }
514
-
515
-
516
-    /**
517
-     * set_transaction_payment_method_based_on_registration_statuses
518
-     * sets or unsets the PMD_ID field on the TXN based on the related REG statuses
519
-     * basically if ALL Registrations are "Not Approved", then the EE_Transaction.PMD_ID is set to null,
520
-     * but if any Registration has a different status, then EE_Transaction.PMD_ID is set to either:
521
-     *        the first "default" Payment Method
522
-     *        the first active Payment Method
523
-     *    whichever is found first.
524
-     *
525
-     * @param EE_Registration $edited_registration
526
-     * @return void
527
-     * @throws \EE_Error
528
-     */
529
-    public function set_transaction_payment_method_based_on_registration_statuses(
530
-        EE_Registration $edited_registration
531
-    ) {
532
-        if ($edited_registration instanceof EE_Registration) {
533
-            $transaction = $edited_registration->transaction();
534
-            if ($transaction instanceof EE_Transaction) {
535
-                $all_not_approved = true;
536
-                foreach ($transaction->registrations() as $registration) {
537
-                    if ($registration instanceof EE_Registration) {
538
-                        // if any REG != "Not Approved" then toggle to false
539
-                        $all_not_approved = $registration->is_not_approved()
540
-                            ? $all_not_approved
541
-                            : false;
542
-                    }
543
-                }
544
-                // if ALL Registrations are "Not Approved"
545
-                if ($all_not_approved) {
546
-                    $transaction->set_payment_method_ID(null);
547
-                    $transaction->save();
548
-                } else {
549
-                    $available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
550
-                        $transaction,
551
-                        EEM_Payment_Method::scope_cart
552
-                    );
553
-                    if (! empty($available_payment_methods)) {
554
-                        $PMD_ID = 0;
555
-                        foreach ($available_payment_methods as $available_payment_method) {
556
-                            if (
557
-                                $available_payment_method instanceof EE_Payment_Method
558
-                                && $available_payment_method->open_by_default()
559
-                            ) {
560
-                                $PMD_ID = $available_payment_method->ID();
561
-                                break;
562
-                            }
563
-                        }
564
-                        if (! $PMD_ID) {
565
-                            $first_payment_method = reset($available_payment_methods);
566
-                            if ($first_payment_method instanceof EE_Payment_Method) {
567
-                                $PMD_ID = $first_payment_method->ID();
568
-                            } else {
569
-                                EE_Error::add_error(
570
-                                    esc_html__(
571
-                                        'A valid Payment Method could not be determined. Please ensure that at least one Payment Method is activated.',
572
-                                        'event_espresso'
573
-                                    ),
574
-                                    __FILE__,
575
-                                    __LINE__,
576
-                                    __FUNCTION__
577
-                                );
578
-                            }
579
-                        }
580
-                        $transaction->set_payment_method_ID($PMD_ID);
581
-                        $transaction->save();
582
-                    } else {
583
-                        EE_Error::add_error(
584
-                            esc_html__(
585
-                                'Please activate at least one Payment Method in order for things to operate correctly.',
586
-                                'event_espresso'
587
-                            ),
588
-                            __FILE__,
589
-                            __LINE__,
590
-                            __FUNCTION__
591
-                        );
592
-                    }
593
-                }
594
-            }
595
-        }
596
-    }
597
-
598
-
599
-
600
-    /********************************** DEPRECATED METHODS **********************************/
601
-
602
-
603
-    /**
604
-     * @return string
605
-     * @deprecated 4.9.12
606
-     */
607
-    public function old_txn_status()
608
-    {
609
-        EE_Error::doing_it_wrong(
610
-            __METHOD__,
611
-            esc_html__(
612
-                'This logic has been moved into \EE_Transaction::old_txn_status(), please use that method instead.',
613
-                'event_espresso'
614
-            ),
615
-            '4.9.12'
616
-        );
617
-        return $this->_old_txn_status;
618
-    }
619
-
620
-
621
-    /**
622
-     * @param string $old_txn_status
623
-     * @deprecated 4.9.12
624
-     */
625
-    public function set_old_txn_status($old_txn_status)
626
-    {
627
-        EE_Error::doing_it_wrong(
628
-            __METHOD__,
629
-            esc_html__(
630
-                'This logic has been moved into \EE_Transaction::set_old_txn_status(), please use that method instead.',
631
-                'event_espresso'
632
-            ),
633
-            '4.9.12'
634
-        );
635
-        // only set the first time
636
-        if ($this->_old_txn_status === null) {
637
-            $this->_old_txn_status = $old_txn_status;
638
-        }
639
-    }
640
-
641
-
642
-    /**
643
-     * @return string
644
-     * @deprecated 4.9.12
645
-     */
646
-    public function new_txn_status()
647
-    {
648
-        EE_Error::doing_it_wrong(
649
-            __METHOD__,
650
-            esc_html__(
651
-                'This logic has been removed. Please just use \EE_Transaction::status_ID() instead.',
652
-                'event_espresso'
653
-            ),
654
-            '4.9.12'
655
-        );
656
-        return $this->_new_txn_status;
657
-    }
658
-
659
-
660
-    /**
661
-     * @param string $new_txn_status
662
-     * @deprecated 4.9.12
663
-     */
664
-    public function set_new_txn_status($new_txn_status)
665
-    {
666
-        EE_Error::doing_it_wrong(
667
-            __METHOD__,
668
-            esc_html__(
669
-                'This logic has been removed. Please just use \EE_Transaction::set_status() instead.',
670
-                'event_espresso'
671
-            ),
672
-            '4.9.12'
673
-        );
674
-        $this->_new_txn_status = $new_txn_status;
675
-    }
676
-
677
-
678
-    /**
679
-     * reg_status_updated
680
-     *
681
-     * @return bool
682
-     * @deprecated 4.9.12
683
-     */
684
-    public function txn_status_updated()
685
-    {
686
-        EE_Error::doing_it_wrong(
687
-            __METHOD__,
688
-            esc_html__(
689
-                'This logic has been moved into \EE_Transaction::txn_status_updated(), please use that method instead.',
690
-                'event_espresso'
691
-            ),
692
-            '4.9.12'
693
-        );
694
-        return $this->_new_txn_status !== $this->_old_txn_status && $this->_old_txn_status !== null
695
-            ? true
696
-            : false;
697
-    }
698
-
699
-
700
-    /**
701
-     * all_reg_steps_completed
702
-     * returns:
703
-     *    true if ALL reg steps have been marked as completed
704
-     *        or false if any step is not completed
705
-     *
706
-     * @param EE_Transaction $transaction
707
-     * @return boolean
708
-     * @deprecated 4.9.12
709
-     */
710
-    public function all_reg_steps_completed(EE_Transaction $transaction)
711
-    {
712
-        EE_Error::doing_it_wrong(
713
-            __METHOD__,
714
-            esc_html__(
715
-                'This logic has been moved into \EE_Transaction::all_reg_steps_completed(), please use that method instead.',
716
-                'event_espresso'
717
-            ),
718
-            '4.9.12',
719
-            '5.0.0'
720
-        );
721
-        return $transaction->all_reg_steps_completed();
722
-    }
723
-
724
-
725
-    /**
726
-     * all_reg_steps_completed_except
727
-     * returns:
728
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
729
-     *        or false if any other step is not completed
730
-     *        or false if ALL steps are completed including the exception you are testing !!!
731
-     *
732
-     * @param EE_Transaction $transaction
733
-     * @param string         $exception
734
-     * @return boolean
735
-     * @deprecated 4.9.12
736
-     */
737
-    public function all_reg_steps_completed_except(EE_Transaction $transaction, $exception = '')
738
-    {
739
-        EE_Error::doing_it_wrong(
740
-            __METHOD__,
741
-            esc_html__(
742
-                'This logic has been moved into \EE_Transaction::all_reg_steps_completed_except(), please use that method instead.',
743
-                'event_espresso'
744
-            ),
745
-            '4.9.12',
746
-            '5.0.0'
747
-        );
748
-        return $transaction->all_reg_steps_completed_except($exception);
749
-    }
750
-
751
-
752
-    /**
753
-     * all_reg_steps_completed_except
754
-     * returns:
755
-     *        true if ALL reg steps, except the final step, have been marked as completed
756
-     *        or false if any step is not completed
757
-     *    or false if ALL steps are completed including the final step !!!
758
-     *
759
-     * @param EE_Transaction $transaction
760
-     * @return boolean
761
-     * @deprecated 4.9.12
762
-     */
763
-    public function all_reg_steps_completed_except_final_step(EE_Transaction $transaction)
764
-    {
765
-        EE_Error::doing_it_wrong(
766
-            __METHOD__,
767
-            esc_html__(
768
-                'This logic has been moved into \EE_Transaction::all_reg_steps_completed_except_final_step(), please use that method instead.',
769
-                'event_espresso'
770
-            ),
771
-            '4.9.12',
772
-            '5.0.0'
773
-        );
774
-        return $transaction->all_reg_steps_completed_except_final_step();
775
-    }
776
-
777
-
778
-    /**
779
-     * reg_step_completed
780
-     * returns:
781
-     *    true if a specific reg step has been marked as completed
782
-     *    a Unix timestamp if it has been initialized but not yet completed,
783
-     *    or false if it has not yet been initialized
784
-     *
785
-     * @param EE_Transaction $transaction
786
-     * @param string         $reg_step_slug
787
-     * @return boolean | int
788
-     * @deprecated 4.9.12
789
-     */
790
-    public function reg_step_completed(EE_Transaction $transaction, $reg_step_slug)
791
-    {
792
-        EE_Error::doing_it_wrong(
793
-            __METHOD__,
794
-            esc_html__(
795
-                'This logic has been moved into \EE_Transaction::reg_step_completed(), please use that method instead.',
796
-                'event_espresso'
797
-            ),
798
-            '4.9.12',
799
-            '5.0.0'
800
-        );
801
-        return $transaction->reg_step_completed($reg_step_slug);
802
-    }
803
-
804
-
805
-    /**
806
-     * completed_final_reg_step
807
-     * returns:
808
-     *    true if the finalize_registration reg step has been marked as completed
809
-     *    a Unix timestamp if it has been initialized but not yet completed,
810
-     *    or false if it has not yet been initialized
811
-     *
812
-     * @param EE_Transaction $transaction
813
-     * @return boolean | int
814
-     * @deprecated 4.9.12
815
-     */
816
-    public function final_reg_step_completed(EE_Transaction $transaction)
817
-    {
818
-        EE_Error::doing_it_wrong(
819
-            __METHOD__,
820
-            esc_html__(
821
-                'This logic has been moved into \EE_Transaction::final_reg_step_completed(), please use that method instead.',
822
-                'event_espresso'
823
-            ),
824
-            '4.9.12',
825
-            '5.0.0'
826
-        );
827
-        return $transaction->final_reg_step_completed();
828
-    }
829
-
830
-
831
-    /**
832
-     * set_reg_step_initiated
833
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
834
-     *
835
-     * @param \EE_Transaction $transaction
836
-     * @param string          $reg_step_slug
837
-     * @return boolean
838
-     * @throws \EE_Error
839
-     * @deprecated 4.9.12
840
-     * @access     public
841
-     */
842
-    public function set_reg_step_initiated(EE_Transaction $transaction, $reg_step_slug)
843
-    {
844
-        EE_Error::doing_it_wrong(
845
-            __METHOD__,
846
-            esc_html__(
847
-                'This logic has been moved into \EE_Transaction::set_reg_step_initiated(), please use that method instead.',
848
-                'event_espresso'
849
-            ),
850
-            '4.9.12',
851
-            '5.0.0'
852
-        );
853
-        return $transaction->set_reg_step_initiated($reg_step_slug);
854
-    }
855
-
856
-
857
-    /**
858
-     * set_reg_step_completed
859
-     * given a valid TXN_reg_step, this sets the step as completed
860
-     *
861
-     * @param \EE_Transaction $transaction
862
-     * @param string          $reg_step_slug
863
-     * @return boolean
864
-     * @throws \EE_Error
865
-     * @deprecated 4.9.12
866
-     * @access     public
867
-     */
868
-    public function set_reg_step_completed(EE_Transaction $transaction, $reg_step_slug)
869
-    {
870
-        EE_Error::doing_it_wrong(
871
-            __METHOD__,
872
-            esc_html__(
873
-                'This logic has been moved into \EE_Transaction::set_reg_step_completed(), please use that method instead.',
874
-                'event_espresso'
875
-            ),
876
-            '4.9.12',
877
-            '5.0.0'
878
-        );
879
-        return $transaction->set_reg_step_completed($reg_step_slug);
880
-    }
881
-
882
-
883
-    /**
884
-     * set_reg_step_completed
885
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
886
-     *
887
-     * @param \EE_Transaction $transaction
888
-     * @param string          $reg_step_slug
889
-     * @return boolean
890
-     * @throws \EE_Error
891
-     * @deprecated 4.9.12
892
-     * @access     public
893
-     */
894
-    public function set_reg_step_not_completed(EE_Transaction $transaction, $reg_step_slug)
895
-    {
896
-        EE_Error::doing_it_wrong(
897
-            __METHOD__,
898
-            esc_html__(
899
-                'This logic has been moved into \EE_Transaction::set_reg_step_not_completed(), please use that method instead.',
900
-                'event_espresso'
901
-            ),
902
-            '4.9.12',
903
-            '5.0.0'
904
-        );
905
-        return $transaction->set_reg_step_not_completed($reg_step_slug);
906
-    }
907
-
908
-
909
-    /**
910
-     * remove_reg_step
911
-     * given a valid TXN_reg_step slug, this will remove (unset)
912
-     * the reg step from the TXN reg step array
913
-     *
914
-     * @param \EE_Transaction $transaction
915
-     * @param string          $reg_step_slug
916
-     * @return void
917
-     * @deprecated 4.9.12
918
-     * @access     public
919
-     */
920
-    public function remove_reg_step(EE_Transaction $transaction, $reg_step_slug)
921
-    {
922
-        EE_Error::doing_it_wrong(
923
-            __METHOD__,
924
-            esc_html__(
925
-                'This logic has been moved into \EE_Transaction::remove_reg_step(), please use that method instead.',
926
-                'event_espresso'
927
-            ),
928
-            '4.9.12',
929
-            '5.0.0'
930
-        );
931
-        $transaction->remove_reg_step($reg_step_slug);
932
-    }
933
-
934
-
935
-    /**
936
-     *    toggle_failed_transaction_status
937
-     * upgrades a TXNs status from failed to abandoned,
938
-     * meaning that contact information has been captured for at least one registrant
939
-     *
940
-     * @param EE_Transaction $transaction
941
-     * @return    boolean
942
-     * @throws \EE_Error
943
-     * @deprecated 4.9.12
944
-     * @access     public
945
-     */
946
-    public function toggle_failed_transaction_status(EE_Transaction $transaction)
947
-    {
948
-        EE_Error::doing_it_wrong(
949
-            __METHOD__,
950
-            esc_html__(
951
-                'This logic has been moved into \EE_Transaction::toggle_failed_transaction_status(), please use that method instead.',
952
-                'event_espresso'
953
-            ),
954
-            '4.9.12',
955
-            '5.0.0'
956
-        );
957
-        return $transaction->toggle_failed_transaction_status();
958
-    }
959
-
960
-
961
-    /**
962
-     * toggle_abandoned_transaction_status
963
-     * upgrades a TXNs status from failed or abandoned to incomplete
964
-     *
965
-     * @param EE_Transaction $transaction
966
-     * @return boolean
967
-     * @deprecated 4.9.12
968
-     * @access     public
969
-     */
970
-    public function toggle_abandoned_transaction_status(EE_Transaction $transaction)
971
-    {
972
-        EE_Error::doing_it_wrong(
973
-            __METHOD__,
974
-            esc_html__(
975
-                'This logic has been moved into \EE_Transaction::toggle_abandoned_transaction_status(), please use that method instead.',
976
-                'event_espresso'
977
-            ),
978
-            '4.9.12',
979
-            '5.0.0'
980
-        );
981
-        return $transaction->toggle_abandoned_transaction_status();
982
-    }
19
+	/**
20
+	 * @var EE_Registration_Processor $_instance
21
+	 * @access    private
22
+	 */
23
+	private static $_instance;
24
+
25
+	/**
26
+	 * array of query WHERE params to use when retrieving cached registrations from a transaction
27
+	 *
28
+	 * @var array $registration_query_params
29
+	 * @access private
30
+	 */
31
+	private $_registration_query_params = [];
32
+
33
+	/**
34
+	 * @deprecated
35
+	 * @var string
36
+	 */
37
+	protected $_old_txn_status;
38
+
39
+	/**
40
+	 * @deprecated
41
+	 * @var string
42
+	 */
43
+	protected $_new_txn_status;
44
+
45
+
46
+	/**
47
+	 * @singleton method used to instantiate class object
48
+	 * @access    public
49
+	 * @param array $registration_query_params
50
+	 * @return EE_Transaction_Processor instance
51
+	 */
52
+	public static function instance($registration_query_params = [])
53
+	{
54
+		// check if class object is instantiated
55
+		if (! self::$_instance instanceof EE_Transaction_Processor) {
56
+			self::$_instance = new self($registration_query_params);
57
+		}
58
+		return self::$_instance;
59
+	}
60
+
61
+
62
+	/**
63
+	 * @param array $registration_query_params
64
+	 */
65
+	private function __construct($registration_query_params = [])
66
+	{
67
+		// make sure some query params are set for retrieving registrations
68
+		$this->_set_registration_query_params($registration_query_params);
69
+	}
70
+
71
+
72
+	/**
73
+	 * @access private
74
+	 * @param array $registration_query_params
75
+	 */
76
+	private function _set_registration_query_params($registration_query_params)
77
+	{
78
+		$this->_registration_query_params = ! empty($registration_query_params)
79
+			? $registration_query_params
80
+			: ['order_by' => ['REG_count' => 'ASC']];
81
+	}
82
+
83
+
84
+	/**
85
+	 * manually_update_registration_statuses
86
+	 *
87
+	 * @access public
88
+	 * @param EE_Transaction $transaction
89
+	 * @param string         $new_reg_status
90
+	 * @param array          $registration_query_params array of query WHERE params to use
91
+	 *                                                  when retrieving cached registrations from a transaction
92
+	 * @return    boolean
93
+	 * @throws \EE_Error
94
+	 */
95
+	public function manually_update_registration_statuses(
96
+		EE_Transaction $transaction,
97
+		$new_reg_status = '',
98
+		$registration_query_params = []
99
+	) {
100
+		$status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
101
+			'manually_update_registration_status',
102
+			$transaction,
103
+			$registration_query_params,
104
+			$new_reg_status
105
+		);
106
+		// send messages
107
+		/** @type EE_Registration_Processor $registration_processor */
108
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
109
+		$registration_processor->trigger_registration_update_notifications(
110
+			$transaction->primary_registration(),
111
+			['manually_updated' => true]
112
+		);
113
+		do_action(
114
+			'AHEE__EE_Transaction_Processor__manually_update_registration_statuses',
115
+			$transaction,
116
+			$status_updates
117
+		);
118
+		return $status_updates;
119
+	}
120
+
121
+
122
+	/**
123
+	 * toggle_registration_statuses_for_default_approved_events
124
+	 *
125
+	 * @access public
126
+	 * @param EE_Transaction $transaction
127
+	 * @param array          $registration_query_params array of query WHERE params to use
128
+	 *                                                  when retrieving cached registrations from a transaction
129
+	 * @return    boolean
130
+	 * @throws \EE_Error
131
+	 */
132
+	public function toggle_registration_statuses_for_default_approved_events(
133
+		EE_Transaction $transaction,
134
+		$registration_query_params = []
135
+	) {
136
+		$status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
137
+			'toggle_registration_status_for_default_approved_events',
138
+			$transaction,
139
+			$registration_query_params
140
+		);
141
+		do_action(
142
+			'AHEE__EE_Transaction_Processor__toggle_registration_statuses_for_default_approved_events',
143
+			$transaction,
144
+			$status_updates
145
+		);
146
+		return $status_updates;
147
+	}
148
+
149
+
150
+	/**
151
+	 * toggle_registration_statuses_if_no_monies_owing
152
+	 *
153
+	 * @access public
154
+	 * @param EE_Transaction $transaction
155
+	 * @param array          $registration_query_params array of query WHERE params to use
156
+	 *                                                  when retrieving cached registrations from a transaction
157
+	 * @return    boolean
158
+	 * @throws \EE_Error
159
+	 */
160
+	public function toggle_registration_statuses_if_no_monies_owing(
161
+		EE_Transaction $transaction,
162
+		$registration_query_params = []
163
+	) {
164
+		$status_updates = $this->_call_method_on_registrations_via_Registration_Processor(
165
+			'toggle_registration_status_if_no_monies_owing',
166
+			$transaction,
167
+			$registration_query_params
168
+		);
169
+		do_action(
170
+			'AHEE__EE_Transaction_Processor__toggle_registration_statuses_if_no_monies_owing',
171
+			$transaction,
172
+			$status_updates
173
+		);
174
+		return $status_updates;
175
+	}
176
+
177
+
178
+	/**
179
+	 * update_transaction_and_registrations_after_checkout_or_payment
180
+	 * cycles thru related registrations and calls update_registration_after_checkout_or_payment() on each
181
+	 *
182
+	 * @param EE_Transaction     $transaction
183
+	 * @param \EE_Payment | NULL $payment
184
+	 * @param array              $registration_query_params    array of query WHERE params to use
185
+	 *                                                         when retrieving cached registrations from a transaction
186
+	 * @param bool               $trigger_notifications        whether or not to call
187
+	 *                                                         \EE_Registration_Processor::trigger_registration_update_notifications()
188
+	 * @return array
189
+	 * @throws \EE_Error
190
+	 */
191
+	public function update_transaction_and_registrations_after_checkout_or_payment(
192
+		EE_Transaction $transaction,
193
+		$payment = null,
194
+		$registration_query_params = [],
195
+		$trigger_notifications = true
196
+	) {
197
+		// make sure some query params are set for retrieving registrations
198
+		$this->_set_registration_query_params($registration_query_params);
199
+		// get final reg step status
200
+		$finalized = $transaction->final_reg_step_completed();
201
+		// if the 'finalize_registration' step has been initiated (has a timestamp)
202
+		// but has not yet been fully completed (TRUE)
203
+		if (is_int($finalized) && $finalized !== false && $finalized !== true) {
204
+			$transaction->set_reg_step_completed('finalize_registration');
205
+			$finalized = true;
206
+		}
207
+		$transaction->save();
208
+		// array of details to aid in decision making by systems
209
+		$update_params = [
210
+			'old_txn_status'  => $transaction->old_txn_status(),
211
+			'new_txn_status'  => $transaction->status_ID(),
212
+			'finalized'       => $finalized,
213
+			'revisit'         => $this->_revisit,
214
+			'payment_updates' => $payment instanceof EE_Payment
215
+				? true
216
+				: false,
217
+			'last_payment'    => $payment,
218
+		];
219
+		// now update the registrations and add the results to our $update_params
220
+		$update_params['status_updates'] = $this->_call_method_on_registrations_via_Registration_Processor(
221
+			'update_registration_after_checkout_or_payment',
222
+			$transaction,
223
+			$this->_registration_query_params,
224
+			$update_params
225
+		);
226
+		if ($trigger_notifications) {
227
+			// send messages
228
+			/** @type EE_Registration_Processor $registration_processor */
229
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
230
+			$registration_processor->trigger_registration_update_notifications(
231
+				$transaction->primary_registration(),
232
+				$update_params
233
+			);
234
+		}
235
+		do_action(
236
+			'AHEE__EE_Transaction_Processor__update_transaction_and_registrations_after_checkout_or_payment',
237
+			$transaction,
238
+			$update_params
239
+		);
240
+		return $update_params;
241
+	}
242
+
243
+
244
+	/**
245
+	 * update_transaction_after_registration_reopened
246
+	 * readjusts TXN and Line Item totals after a registration is changed from
247
+	 * cancelled or declined to another reg status such as pending payment or approved
248
+	 *
249
+	 * @param \EE_Registration $registration
250
+	 * @param array            $closed_reg_statuses
251
+	 * @param bool             $update_txn
252
+	 * @return bool
253
+	 * @throws \EE_Error
254
+	 */
255
+	public function update_transaction_after_reinstating_canceled_registration(
256
+		EE_Registration $registration,
257
+		$closed_reg_statuses = [],
258
+		$update_txn = true
259
+	) {
260
+		// these reg statuses should not be considered in any calculations involving monies owing
261
+		$closed_reg_statuses = ! empty($closed_reg_statuses)
262
+			? $closed_reg_statuses
263
+			: EEM_Registration::closed_reg_statuses();
264
+		if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
265
+			return false;
266
+		}
267
+		try {
268
+			$transaction      = $this->get_transaction_for_registration($registration);
269
+			$ticket_line_item = $this->get_ticket_line_item_for_transaction_registration(
270
+				$transaction,
271
+				$registration
272
+			);
273
+			// un-cancel the ticket
274
+			$success = EEH_Line_Item::reinstate_canceled_ticket_line_item($ticket_line_item);
275
+		} catch (EE_Error $e) {
276
+			EE_Error::add_error(
277
+				sprintf(
278
+					esc_html__(
279
+						'The Ticket Line Item for Registration %1$d could not be reinstated because :%2$s%3$s',
280
+						'event_espresso'
281
+					),
282
+					$registration->ID(),
283
+					'<br />',
284
+					$e->getMessage()
285
+				),
286
+				__FILE__,
287
+				__FUNCTION__,
288
+				__LINE__
289
+			);
290
+			return false;
291
+		}
292
+		if ($update_txn) {
293
+			return $transaction->save()
294
+				? $success
295
+				: false;
296
+		}
297
+		return $success;
298
+	}
299
+
300
+
301
+	/**
302
+	 * update_transaction_after_canceled_or_declined_registration
303
+	 * readjusts TXN and Line Item totals after a registration is cancelled or declined
304
+	 *
305
+	 * @param \EE_Registration $registration
306
+	 * @param array            $closed_reg_statuses
307
+	 * @param bool             $update_txn
308
+	 * @return bool
309
+	 * @throws \EE_Error
310
+	 */
311
+	public function update_transaction_after_canceled_or_declined_registration(
312
+		EE_Registration $registration,
313
+		$closed_reg_statuses = [],
314
+		$update_txn = true
315
+	) {
316
+		// these reg statuses should not be considered in any calculations involving monies owing
317
+		$closed_reg_statuses = ! empty($closed_reg_statuses)
318
+			? $closed_reg_statuses
319
+			: EEM_Registration::closed_reg_statuses();
320
+		if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
321
+			return false;
322
+		}
323
+		try {
324
+			$transaction = $this->get_transaction_for_registration($registration);
325
+			if (
326
+				apply_filters(
327
+					'FHEE__EE_Transaction_Processor__update_transaction_after_canceled_or_declined_registration__cancel_ticket_line_item',
328
+					true,
329
+					$registration,
330
+					$transaction
331
+				)
332
+			) {
333
+				$ticket_line_item = $this->get_ticket_line_item_for_transaction_registration(
334
+					$transaction,
335
+					$registration
336
+				);
337
+				EEH_Line_Item::cancel_ticket_line_item($ticket_line_item);
338
+			}
339
+		} catch (EE_Error $e) {
340
+			EE_Error::add_error(
341
+				sprintf(
342
+					esc_html__(
343
+						'The Ticket Line Item for Registration %1$d could not be cancelled because :%2$s%3$s',
344
+						'event_espresso'
345
+					),
346
+					$registration->ID(),
347
+					'<br />',
348
+					$e->getMessage()
349
+				),
350
+				__FILE__,
351
+				__FUNCTION__,
352
+				__LINE__
353
+			);
354
+			return false;
355
+		}
356
+		if ($update_txn) {
357
+			return $transaction->save()
358
+				? true
359
+				: false;
360
+		}
361
+		return true;
362
+	}
363
+
364
+
365
+	/**
366
+	 * get_transaction_for_registration
367
+	 *
368
+	 * @access    public
369
+	 * @param EE_Registration $registration
370
+	 * @return    EE_Transaction
371
+	 * @throws    EE_Error
372
+	 */
373
+	public function get_transaction_for_registration(EE_Registration $registration)
374
+	{
375
+		$transaction = $registration->transaction();
376
+		if (! $transaction instanceof EE_Transaction) {
377
+			throw new EE_Error(
378
+				sprintf(
379
+					esc_html__('The Transaction for Registration %1$d was not found or is invalid.', 'event_espresso'),
380
+					$registration->ID()
381
+				)
382
+			);
383
+		}
384
+		return $transaction;
385
+	}
386
+
387
+
388
+	/**
389
+	 * get_ticket_line_item_for_transaction_registration
390
+	 *
391
+	 * @access    public
392
+	 * @param EE_Transaction  $transaction
393
+	 * @param EE_Registration $registration
394
+	 * @return    EE_Line_Item
395
+	 * @throws    EE_Error
396
+	 */
397
+	public function get_ticket_line_item_for_transaction_registration(
398
+		EE_Transaction $transaction,
399
+		EE_Registration $registration
400
+	) {
401
+		EE_Registry::instance()->load_helper('Line_Item');
402
+		$ticket_line_item = EEM_Line_Item::instance()->get_ticket_line_item_for_transaction(
403
+			$transaction->ID(),
404
+			$registration->ticket_ID()
405
+		);
406
+		if (! $ticket_line_item instanceof EE_Line_Item) {
407
+			throw new EE_Error(
408
+				sprintf(
409
+					esc_html__(
410
+						'The Line Item for Transaction %1$d and Ticket %2$d was not found or is invalid.',
411
+						'event_espresso'
412
+					),
413
+					$transaction->ID(),
414
+					$registration->ticket_ID()
415
+				)
416
+			);
417
+		}
418
+		return $ticket_line_item;
419
+	}
420
+
421
+
422
+	/**
423
+	 * cancel_transaction_if_all_registrations_canceled
424
+	 * cycles thru related registrations and checks their statuses
425
+	 * if ALL registrations are Cancelled or Declined, then this sets the TXN status to
426
+	 *
427
+	 * @access    public
428
+	 * @param EE_Transaction $transaction
429
+	 * @param string         $new_TXN_status
430
+	 * @param array          $registration_query_params    - array of query WHERE params to use when
431
+	 *                                                     retrieving cached registrations from a transaction
432
+	 * @param array          $closed_reg_statuses
433
+	 * @param bool           $update_txn
434
+	 * @return    bool            true if TXN status was updated, false if not
435
+	 */
436
+	public function toggle_transaction_status_if_all_registrations_canceled_or_declined(
437
+		EE_Transaction $transaction,
438
+		$new_TXN_status = '',
439
+		$registration_query_params = [],
440
+		$closed_reg_statuses = [],
441
+		$update_txn = true
442
+	) {
443
+		// make sure some query params are set for retrieving registrations
444
+		$this->_set_registration_query_params($registration_query_params);
445
+		// these reg statuses should not be considered in any calculations involving monies owing
446
+		$closed_reg_statuses = ! empty($closed_reg_statuses)
447
+			? $closed_reg_statuses
448
+			: EEM_Registration::closed_reg_statuses();
449
+		// loop through cached registrations
450
+		foreach ($transaction->registrations($this->_registration_query_params) as $registration) {
451
+			if (
452
+				$registration instanceof EE_Registration
453
+				&& ! in_array($registration->status_ID(), $closed_reg_statuses)
454
+			) {
455
+				return false;
456
+			}
457
+		}
458
+		if (in_array($new_TXN_status, EEM_Transaction::txn_status_array())) {
459
+			$transaction->set_status($new_TXN_status);
460
+		}
461
+		if ($update_txn) {
462
+			return $transaction->save()
463
+				? true
464
+				: false;
465
+		}
466
+		return true;
467
+	}
468
+
469
+
470
+	/**
471
+	 * _call_method_on_registrations_via_Registration_Processor
472
+	 * cycles thru related registrations and calls the requested method on each
473
+	 *
474
+	 * @access private
475
+	 * @param string         $method_name
476
+	 * @param EE_Transaction $transaction
477
+	 * @param array          $registration_query_params array of query WHERE params to use
478
+	 *                                                  when retrieving cached registrations from a transaction
479
+	 * @param string         $additional_param
480
+	 * @return boolean
481
+	 * @throws \EE_Error
482
+	 */
483
+	private function _call_method_on_registrations_via_Registration_Processor(
484
+		$method_name,
485
+		EE_Transaction $transaction,
486
+		$registration_query_params = [],
487
+		$additional_param = null
488
+	) {
489
+		$response = false;
490
+		/** @type EE_Registration_Processor $registration_processor */
491
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
492
+		// check that method exists
493
+		if (! method_exists($registration_processor, $method_name)) {
494
+			throw new EE_Error(esc_html__('Method does not exist.', 'event_espresso'));
495
+		}
496
+		// make sure some query params are set for retrieving registrations
497
+		$this->_set_registration_query_params($registration_query_params);
498
+		// loop through cached registrations
499
+		foreach ($transaction->registrations($this->_registration_query_params) as $registration) {
500
+			if ($registration instanceof EE_Registration) {
501
+				if ($additional_param) {
502
+					$response = $registration_processor->{$method_name}($registration, $additional_param)
503
+						? true
504
+						: $response;
505
+				} else {
506
+					$response = $registration_processor->{$method_name}($registration)
507
+						? true
508
+						: $response;
509
+				}
510
+			}
511
+		}
512
+		return $response;
513
+	}
514
+
515
+
516
+	/**
517
+	 * set_transaction_payment_method_based_on_registration_statuses
518
+	 * sets or unsets the PMD_ID field on the TXN based on the related REG statuses
519
+	 * basically if ALL Registrations are "Not Approved", then the EE_Transaction.PMD_ID is set to null,
520
+	 * but if any Registration has a different status, then EE_Transaction.PMD_ID is set to either:
521
+	 *        the first "default" Payment Method
522
+	 *        the first active Payment Method
523
+	 *    whichever is found first.
524
+	 *
525
+	 * @param EE_Registration $edited_registration
526
+	 * @return void
527
+	 * @throws \EE_Error
528
+	 */
529
+	public function set_transaction_payment_method_based_on_registration_statuses(
530
+		EE_Registration $edited_registration
531
+	) {
532
+		if ($edited_registration instanceof EE_Registration) {
533
+			$transaction = $edited_registration->transaction();
534
+			if ($transaction instanceof EE_Transaction) {
535
+				$all_not_approved = true;
536
+				foreach ($transaction->registrations() as $registration) {
537
+					if ($registration instanceof EE_Registration) {
538
+						// if any REG != "Not Approved" then toggle to false
539
+						$all_not_approved = $registration->is_not_approved()
540
+							? $all_not_approved
541
+							: false;
542
+					}
543
+				}
544
+				// if ALL Registrations are "Not Approved"
545
+				if ($all_not_approved) {
546
+					$transaction->set_payment_method_ID(null);
547
+					$transaction->save();
548
+				} else {
549
+					$available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
550
+						$transaction,
551
+						EEM_Payment_Method::scope_cart
552
+					);
553
+					if (! empty($available_payment_methods)) {
554
+						$PMD_ID = 0;
555
+						foreach ($available_payment_methods as $available_payment_method) {
556
+							if (
557
+								$available_payment_method instanceof EE_Payment_Method
558
+								&& $available_payment_method->open_by_default()
559
+							) {
560
+								$PMD_ID = $available_payment_method->ID();
561
+								break;
562
+							}
563
+						}
564
+						if (! $PMD_ID) {
565
+							$first_payment_method = reset($available_payment_methods);
566
+							if ($first_payment_method instanceof EE_Payment_Method) {
567
+								$PMD_ID = $first_payment_method->ID();
568
+							} else {
569
+								EE_Error::add_error(
570
+									esc_html__(
571
+										'A valid Payment Method could not be determined. Please ensure that at least one Payment Method is activated.',
572
+										'event_espresso'
573
+									),
574
+									__FILE__,
575
+									__LINE__,
576
+									__FUNCTION__
577
+								);
578
+							}
579
+						}
580
+						$transaction->set_payment_method_ID($PMD_ID);
581
+						$transaction->save();
582
+					} else {
583
+						EE_Error::add_error(
584
+							esc_html__(
585
+								'Please activate at least one Payment Method in order for things to operate correctly.',
586
+								'event_espresso'
587
+							),
588
+							__FILE__,
589
+							__LINE__,
590
+							__FUNCTION__
591
+						);
592
+					}
593
+				}
594
+			}
595
+		}
596
+	}
597
+
598
+
599
+
600
+	/********************************** DEPRECATED METHODS **********************************/
601
+
602
+
603
+	/**
604
+	 * @return string
605
+	 * @deprecated 4.9.12
606
+	 */
607
+	public function old_txn_status()
608
+	{
609
+		EE_Error::doing_it_wrong(
610
+			__METHOD__,
611
+			esc_html__(
612
+				'This logic has been moved into \EE_Transaction::old_txn_status(), please use that method instead.',
613
+				'event_espresso'
614
+			),
615
+			'4.9.12'
616
+		);
617
+		return $this->_old_txn_status;
618
+	}
619
+
620
+
621
+	/**
622
+	 * @param string $old_txn_status
623
+	 * @deprecated 4.9.12
624
+	 */
625
+	public function set_old_txn_status($old_txn_status)
626
+	{
627
+		EE_Error::doing_it_wrong(
628
+			__METHOD__,
629
+			esc_html__(
630
+				'This logic has been moved into \EE_Transaction::set_old_txn_status(), please use that method instead.',
631
+				'event_espresso'
632
+			),
633
+			'4.9.12'
634
+		);
635
+		// only set the first time
636
+		if ($this->_old_txn_status === null) {
637
+			$this->_old_txn_status = $old_txn_status;
638
+		}
639
+	}
640
+
641
+
642
+	/**
643
+	 * @return string
644
+	 * @deprecated 4.9.12
645
+	 */
646
+	public function new_txn_status()
647
+	{
648
+		EE_Error::doing_it_wrong(
649
+			__METHOD__,
650
+			esc_html__(
651
+				'This logic has been removed. Please just use \EE_Transaction::status_ID() instead.',
652
+				'event_espresso'
653
+			),
654
+			'4.9.12'
655
+		);
656
+		return $this->_new_txn_status;
657
+	}
658
+
659
+
660
+	/**
661
+	 * @param string $new_txn_status
662
+	 * @deprecated 4.9.12
663
+	 */
664
+	public function set_new_txn_status($new_txn_status)
665
+	{
666
+		EE_Error::doing_it_wrong(
667
+			__METHOD__,
668
+			esc_html__(
669
+				'This logic has been removed. Please just use \EE_Transaction::set_status() instead.',
670
+				'event_espresso'
671
+			),
672
+			'4.9.12'
673
+		);
674
+		$this->_new_txn_status = $new_txn_status;
675
+	}
676
+
677
+
678
+	/**
679
+	 * reg_status_updated
680
+	 *
681
+	 * @return bool
682
+	 * @deprecated 4.9.12
683
+	 */
684
+	public function txn_status_updated()
685
+	{
686
+		EE_Error::doing_it_wrong(
687
+			__METHOD__,
688
+			esc_html__(
689
+				'This logic has been moved into \EE_Transaction::txn_status_updated(), please use that method instead.',
690
+				'event_espresso'
691
+			),
692
+			'4.9.12'
693
+		);
694
+		return $this->_new_txn_status !== $this->_old_txn_status && $this->_old_txn_status !== null
695
+			? true
696
+			: false;
697
+	}
698
+
699
+
700
+	/**
701
+	 * all_reg_steps_completed
702
+	 * returns:
703
+	 *    true if ALL reg steps have been marked as completed
704
+	 *        or false if any step is not completed
705
+	 *
706
+	 * @param EE_Transaction $transaction
707
+	 * @return boolean
708
+	 * @deprecated 4.9.12
709
+	 */
710
+	public function all_reg_steps_completed(EE_Transaction $transaction)
711
+	{
712
+		EE_Error::doing_it_wrong(
713
+			__METHOD__,
714
+			esc_html__(
715
+				'This logic has been moved into \EE_Transaction::all_reg_steps_completed(), please use that method instead.',
716
+				'event_espresso'
717
+			),
718
+			'4.9.12',
719
+			'5.0.0'
720
+		);
721
+		return $transaction->all_reg_steps_completed();
722
+	}
723
+
724
+
725
+	/**
726
+	 * all_reg_steps_completed_except
727
+	 * returns:
728
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
729
+	 *        or false if any other step is not completed
730
+	 *        or false if ALL steps are completed including the exception you are testing !!!
731
+	 *
732
+	 * @param EE_Transaction $transaction
733
+	 * @param string         $exception
734
+	 * @return boolean
735
+	 * @deprecated 4.9.12
736
+	 */
737
+	public function all_reg_steps_completed_except(EE_Transaction $transaction, $exception = '')
738
+	{
739
+		EE_Error::doing_it_wrong(
740
+			__METHOD__,
741
+			esc_html__(
742
+				'This logic has been moved into \EE_Transaction::all_reg_steps_completed_except(), please use that method instead.',
743
+				'event_espresso'
744
+			),
745
+			'4.9.12',
746
+			'5.0.0'
747
+		);
748
+		return $transaction->all_reg_steps_completed_except($exception);
749
+	}
750
+
751
+
752
+	/**
753
+	 * all_reg_steps_completed_except
754
+	 * returns:
755
+	 *        true if ALL reg steps, except the final step, have been marked as completed
756
+	 *        or false if any step is not completed
757
+	 *    or false if ALL steps are completed including the final step !!!
758
+	 *
759
+	 * @param EE_Transaction $transaction
760
+	 * @return boolean
761
+	 * @deprecated 4.9.12
762
+	 */
763
+	public function all_reg_steps_completed_except_final_step(EE_Transaction $transaction)
764
+	{
765
+		EE_Error::doing_it_wrong(
766
+			__METHOD__,
767
+			esc_html__(
768
+				'This logic has been moved into \EE_Transaction::all_reg_steps_completed_except_final_step(), please use that method instead.',
769
+				'event_espresso'
770
+			),
771
+			'4.9.12',
772
+			'5.0.0'
773
+		);
774
+		return $transaction->all_reg_steps_completed_except_final_step();
775
+	}
776
+
777
+
778
+	/**
779
+	 * reg_step_completed
780
+	 * returns:
781
+	 *    true if a specific reg step has been marked as completed
782
+	 *    a Unix timestamp if it has been initialized but not yet completed,
783
+	 *    or false if it has not yet been initialized
784
+	 *
785
+	 * @param EE_Transaction $transaction
786
+	 * @param string         $reg_step_slug
787
+	 * @return boolean | int
788
+	 * @deprecated 4.9.12
789
+	 */
790
+	public function reg_step_completed(EE_Transaction $transaction, $reg_step_slug)
791
+	{
792
+		EE_Error::doing_it_wrong(
793
+			__METHOD__,
794
+			esc_html__(
795
+				'This logic has been moved into \EE_Transaction::reg_step_completed(), please use that method instead.',
796
+				'event_espresso'
797
+			),
798
+			'4.9.12',
799
+			'5.0.0'
800
+		);
801
+		return $transaction->reg_step_completed($reg_step_slug);
802
+	}
803
+
804
+
805
+	/**
806
+	 * completed_final_reg_step
807
+	 * returns:
808
+	 *    true if the finalize_registration reg step has been marked as completed
809
+	 *    a Unix timestamp if it has been initialized but not yet completed,
810
+	 *    or false if it has not yet been initialized
811
+	 *
812
+	 * @param EE_Transaction $transaction
813
+	 * @return boolean | int
814
+	 * @deprecated 4.9.12
815
+	 */
816
+	public function final_reg_step_completed(EE_Transaction $transaction)
817
+	{
818
+		EE_Error::doing_it_wrong(
819
+			__METHOD__,
820
+			esc_html__(
821
+				'This logic has been moved into \EE_Transaction::final_reg_step_completed(), please use that method instead.',
822
+				'event_espresso'
823
+			),
824
+			'4.9.12',
825
+			'5.0.0'
826
+		);
827
+		return $transaction->final_reg_step_completed();
828
+	}
829
+
830
+
831
+	/**
832
+	 * set_reg_step_initiated
833
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
834
+	 *
835
+	 * @param \EE_Transaction $transaction
836
+	 * @param string          $reg_step_slug
837
+	 * @return boolean
838
+	 * @throws \EE_Error
839
+	 * @deprecated 4.9.12
840
+	 * @access     public
841
+	 */
842
+	public function set_reg_step_initiated(EE_Transaction $transaction, $reg_step_slug)
843
+	{
844
+		EE_Error::doing_it_wrong(
845
+			__METHOD__,
846
+			esc_html__(
847
+				'This logic has been moved into \EE_Transaction::set_reg_step_initiated(), please use that method instead.',
848
+				'event_espresso'
849
+			),
850
+			'4.9.12',
851
+			'5.0.0'
852
+		);
853
+		return $transaction->set_reg_step_initiated($reg_step_slug);
854
+	}
855
+
856
+
857
+	/**
858
+	 * set_reg_step_completed
859
+	 * given a valid TXN_reg_step, this sets the step as completed
860
+	 *
861
+	 * @param \EE_Transaction $transaction
862
+	 * @param string          $reg_step_slug
863
+	 * @return boolean
864
+	 * @throws \EE_Error
865
+	 * @deprecated 4.9.12
866
+	 * @access     public
867
+	 */
868
+	public function set_reg_step_completed(EE_Transaction $transaction, $reg_step_slug)
869
+	{
870
+		EE_Error::doing_it_wrong(
871
+			__METHOD__,
872
+			esc_html__(
873
+				'This logic has been moved into \EE_Transaction::set_reg_step_completed(), please use that method instead.',
874
+				'event_espresso'
875
+			),
876
+			'4.9.12',
877
+			'5.0.0'
878
+		);
879
+		return $transaction->set_reg_step_completed($reg_step_slug);
880
+	}
881
+
882
+
883
+	/**
884
+	 * set_reg_step_completed
885
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
886
+	 *
887
+	 * @param \EE_Transaction $transaction
888
+	 * @param string          $reg_step_slug
889
+	 * @return boolean
890
+	 * @throws \EE_Error
891
+	 * @deprecated 4.9.12
892
+	 * @access     public
893
+	 */
894
+	public function set_reg_step_not_completed(EE_Transaction $transaction, $reg_step_slug)
895
+	{
896
+		EE_Error::doing_it_wrong(
897
+			__METHOD__,
898
+			esc_html__(
899
+				'This logic has been moved into \EE_Transaction::set_reg_step_not_completed(), please use that method instead.',
900
+				'event_espresso'
901
+			),
902
+			'4.9.12',
903
+			'5.0.0'
904
+		);
905
+		return $transaction->set_reg_step_not_completed($reg_step_slug);
906
+	}
907
+
908
+
909
+	/**
910
+	 * remove_reg_step
911
+	 * given a valid TXN_reg_step slug, this will remove (unset)
912
+	 * the reg step from the TXN reg step array
913
+	 *
914
+	 * @param \EE_Transaction $transaction
915
+	 * @param string          $reg_step_slug
916
+	 * @return void
917
+	 * @deprecated 4.9.12
918
+	 * @access     public
919
+	 */
920
+	public function remove_reg_step(EE_Transaction $transaction, $reg_step_slug)
921
+	{
922
+		EE_Error::doing_it_wrong(
923
+			__METHOD__,
924
+			esc_html__(
925
+				'This logic has been moved into \EE_Transaction::remove_reg_step(), please use that method instead.',
926
+				'event_espresso'
927
+			),
928
+			'4.9.12',
929
+			'5.0.0'
930
+		);
931
+		$transaction->remove_reg_step($reg_step_slug);
932
+	}
933
+
934
+
935
+	/**
936
+	 *    toggle_failed_transaction_status
937
+	 * upgrades a TXNs status from failed to abandoned,
938
+	 * meaning that contact information has been captured for at least one registrant
939
+	 *
940
+	 * @param EE_Transaction $transaction
941
+	 * @return    boolean
942
+	 * @throws \EE_Error
943
+	 * @deprecated 4.9.12
944
+	 * @access     public
945
+	 */
946
+	public function toggle_failed_transaction_status(EE_Transaction $transaction)
947
+	{
948
+		EE_Error::doing_it_wrong(
949
+			__METHOD__,
950
+			esc_html__(
951
+				'This logic has been moved into \EE_Transaction::toggle_failed_transaction_status(), please use that method instead.',
952
+				'event_espresso'
953
+			),
954
+			'4.9.12',
955
+			'5.0.0'
956
+		);
957
+		return $transaction->toggle_failed_transaction_status();
958
+	}
959
+
960
+
961
+	/**
962
+	 * toggle_abandoned_transaction_status
963
+	 * upgrades a TXNs status from failed or abandoned to incomplete
964
+	 *
965
+	 * @param EE_Transaction $transaction
966
+	 * @return boolean
967
+	 * @deprecated 4.9.12
968
+	 * @access     public
969
+	 */
970
+	public function toggle_abandoned_transaction_status(EE_Transaction $transaction)
971
+	{
972
+		EE_Error::doing_it_wrong(
973
+			__METHOD__,
974
+			esc_html__(
975
+				'This logic has been moved into \EE_Transaction::toggle_abandoned_transaction_status(), please use that method instead.',
976
+				'event_espresso'
977
+			),
978
+			'4.9.12',
979
+			'5.0.0'
980
+		);
981
+		return $transaction->toggle_abandoned_transaction_status();
982
+	}
983 983
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
     public static function instance($registration_query_params = [])
53 53
     {
54 54
         // check if class object is instantiated
55
-        if (! self::$_instance instanceof EE_Transaction_Processor) {
55
+        if ( ! self::$_instance instanceof EE_Transaction_Processor) {
56 56
             self::$_instance = new self($registration_query_params);
57 57
         }
58 58
         return self::$_instance;
@@ -317,7 +317,7 @@  discard block
 block discarded – undo
317 317
         $closed_reg_statuses = ! empty($closed_reg_statuses)
318 318
             ? $closed_reg_statuses
319 319
             : EEM_Registration::closed_reg_statuses();
320
-        if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
320
+        if ( ! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
321 321
             return false;
322 322
         }
323 323
         try {
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
     public function get_transaction_for_registration(EE_Registration $registration)
374 374
     {
375 375
         $transaction = $registration->transaction();
376
-        if (! $transaction instanceof EE_Transaction) {
376
+        if ( ! $transaction instanceof EE_Transaction) {
377 377
             throw new EE_Error(
378 378
                 sprintf(
379 379
                     esc_html__('The Transaction for Registration %1$d was not found or is invalid.', 'event_espresso'),
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
             $transaction->ID(),
404 404
             $registration->ticket_ID()
405 405
         );
406
-        if (! $ticket_line_item instanceof EE_Line_Item) {
406
+        if ( ! $ticket_line_item instanceof EE_Line_Item) {
407 407
             throw new EE_Error(
408 408
                 sprintf(
409 409
                     esc_html__(
@@ -490,7 +490,7 @@  discard block
 block discarded – undo
490 490
         /** @type EE_Registration_Processor $registration_processor */
491 491
         $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
492 492
         // check that method exists
493
-        if (! method_exists($registration_processor, $method_name)) {
493
+        if ( ! method_exists($registration_processor, $method_name)) {
494 494
             throw new EE_Error(esc_html__('Method does not exist.', 'event_espresso'));
495 495
         }
496 496
         // make sure some query params are set for retrieving registrations
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
                         $transaction,
551 551
                         EEM_Payment_Method::scope_cart
552 552
                     );
553
-                    if (! empty($available_payment_methods)) {
553
+                    if ( ! empty($available_payment_methods)) {
554 554
                         $PMD_ID = 0;
555 555
                         foreach ($available_payment_methods as $available_payment_method) {
556 556
                             if (
@@ -561,7 +561,7 @@  discard block
 block discarded – undo
561 561
                                 break;
562 562
                             }
563 563
                         }
564
-                        if (! $PMD_ID) {
564
+                        if ( ! $PMD_ID) {
565 565
                             $first_payment_method = reset($available_payment_methods);
566 566
                             if ($first_payment_method instanceof EE_Payment_Method) {
567 567
                                 $PMD_ID = $first_payment_method->ID();
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page.core.php 2 patches
Indentation   +4217 added lines, -4217 removed lines patch added patch discarded remove patch
@@ -25,4309 +25,4309 @@
 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 = [];
46
+	/**
47
+	 * @var array
48
+	 * @since 5.0.0.p
49
+	 */
50
+	private array $publish_post_meta_box_hidden_fields = [];
51 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
-    ];
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 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 = [];
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 71
 
72
-    protected array $_labels                   = [];
72
+	protected array $_labels                   = [];
73 73
 
74
-    protected array $_nav_tabs                 = [];
74
+	protected array $_nav_tabs                 = [];
75 75
 
76
-    protected array $_page_config              = [];
76
+	protected array $_page_config              = [];
77 77
 
78
-    /**
79
-     * action => method pairs used for routing incoming requests
80
-     *
81
-     * @var array
82
-     */
83
-    protected array $_page_routes   = [];
78
+	/**
79
+	 * action => method pairs used for routing incoming requests
80
+	 *
81
+	 * @var array
82
+	 */
83
+	protected array $_page_routes   = [];
84 84
 
85
-    protected array $_req_data      = [];
85
+	protected array $_req_data      = [];
86 86
 
87
-    protected array $_route_config  = [];
87
+	protected array $_route_config  = [];
88 88
 
89
-    protected array $_template_args = [];
89
+	protected array $_template_args = [];
90 90
 
91
-    protected array $_views         = [];
91
+	protected array $_views         = [];
92 92
 
93
-    /**
94
-     * yes / no array for admin form fields
95
-     *
96
-     * @var array|array[]
97
-     */
98
-    protected array $_yes_no_values = [];
93
+	/**
94
+	 * yes / no array for admin form fields
95
+	 *
96
+	 * @var array|array[]
97
+	 */
98
+	protected array $_yes_no_values = [];
99 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;
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 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
-    protected bool  $_routing       = false;
107
+	protected bool  $_routing       = false;
108 108
 
109
-    /**
110
-     * whether or not initializePage() has run
111
-     *
112
-     * @var bool
113
-     */
114
-    protected bool $initialized = false;
109
+	/**
110
+	 * whether or not initializePage() has run
111
+	 *
112
+	 * @var bool
113
+	 */
114
+	protected bool $initialized = false;
115 115
 
116 116
 
117
-    protected string $_admin_base_path      = '';
117
+	protected string $_admin_base_path      = '';
118 118
 
119
-    protected string $_admin_base_url       = '';
119
+	protected string $_admin_base_url       = '';
120 120
 
121
-    protected string $_admin_page_title     = '';
121
+	protected string $_admin_page_title     = '';
122 122
 
123
-    protected string $_column_template_path = '';
123
+	protected string $_column_template_path = '';
124 124
 
125
-    protected bool   $_cpt_route            = false;
125
+	protected bool   $_cpt_route            = false;
126 126
 
127
-    /**
128
-     * set via request page and action args.
129
-     */
130
-    protected string $_current_page          = '';
127
+	/**
128
+	 * set via request page and action args.
129
+	 */
130
+	protected string $_current_page          = '';
131 131
 
132
-    protected string $_current_page_view_url = '';
132
+	protected string $_current_page_view_url = '';
133 133
 
134
-    protected string $_current_view          = '';
134
+	protected string $_current_view          = '';
135 135
 
136
-    protected string $_default_nav_tab_name  = 'overview';
136
+	protected string $_default_nav_tab_name  = 'overview';
137 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();
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)) {
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
-            try {
1149
-                call_user_func_array($route_callback, $args);
1150
-            } catch (Throwable $throwable) {
1151
-                $nice_args = [];
1152
-                foreach ($args as $key => $arg) {
1153
-                    $nice_args[ $key ] = is_object($arg) ? get_class($arg) : $key;
1154
-                }
1155
-                new ExceptionStackTraceDisplay(
1156
-                    new RuntimeException(
1157
-                        sprintf(
1158
-                            esc_html__(
1159
-                                'Page route "%1$s" with the supplied arguments (%2$s) threw the following exception: %3$s',
1160
-                                'event_espresso'
1161
-                            ),
1162
-                            $method,
1163
-                            implode(', ', $nice_args),
1164
-                            $throwable->getMessage()
1165
-                        ),
1166
-                        $throwable->getCode(),
1167
-                        $throwable
1168
-                    )
1169
-                );
1170
-            }
1171
-        }
1172
-        // if we've routed and this route has a no headers route AND a sent_headers_route,
1173
-        // then we need to reset the routing properties to the new route.
1174
-        // 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.
1175
-        if (
1176
-            $this->_is_UI_request === false
1177
-            && is_array($this->_route)
1178
-            && ! empty($this->_route['headers_sent_route'])
1179
-        ) {
1180
-            $this->_reset_routing_properties($this->_route['headers_sent_route']);
1181
-        }
1182
-    }
1183
-
1184
-
1185
-    /**
1186
-     * This method just allows the resetting of page properties in the case where a no headers
1187
-     * route redirects to a headers route in its route config.
1188
-     *
1189
-     * @param string $new_route New (non header) route to redirect to.
1190
-     * @return void
1191
-     * @throws ReflectionException
1192
-     * @throws InvalidArgumentException
1193
-     * @throws InvalidInterfaceException
1194
-     * @throws InvalidDataTypeException
1195
-     * @throws EE_Error
1196
-     * @throws Throwable
1197
-     * @since   4.3.0
1198
-     */
1199
-    protected function _reset_routing_properties(string $new_route)
1200
-    {
1201
-        $this->_is_UI_request = true;
1202
-        // now we set the current route to whatever the headers_sent_route is set at
1203
-        $this->request->setRequestParam('action', $new_route);
1204
-        // rerun page setup
1205
-        $this->_page_setup();
1206
-    }
1207
-
1208
-
1209
-    /**
1210
-     * _add_query_arg
1211
-     * adds nonce to array of arguments then calls WP add_query_arg function
1212
-     *(internally just uses EEH_URL's function with the same name)
1213
-     *
1214
-     * @param array  $args
1215
-     * @param string $url
1216
-     * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1217
-     *                                        generated url in an associative array indexed by the key 'wp_referer';
1218
-     *                                        Example usage: If the current page is:
1219
-     *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1220
-     *                                        &action=default&event_id=20&month_range=March%202015
1221
-     *                                        &_wpnonce=5467821
1222
-     *                                        and you call:
1223
-     *                                        EE_Admin_Page::add_query_args_and_nonce(
1224
-     *                                        array(
1225
-     *                                        'action' => 'resend_something',
1226
-     *                                        'page=>espresso_registrations'
1227
-     *                                        ),
1228
-     *                                        $some_url,
1229
-     *                                        true
1230
-     *                                        );
1231
-     *                                        It will produce a url in this structure:
1232
-     *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1233
-     *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1234
-     *                                        month_range]=March%202015
1235
-     * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1236
-     * @param int    $context
1237
-     * @return string
1238
-     */
1239
-    public static function add_query_args_and_nonce(
1240
-        array $args = [],
1241
-        string $url = '',
1242
-        bool $sticky = false,
1243
-        bool $exclude_nonce = false,
1244
-        int $context = EEH_URL::CONTEXT_NONE
1245
-    ): string {
1246
-        // if there is a _wp_http_referer include the values from the request but only if sticky = true
1247
-        if ($sticky) {
1248
-            /** @var RequestInterface $request */
1249
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1250
-            $request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1251
-            $request->unSetServerParam('_wp_http_referer', true);
1252
-            foreach ($request->requestParams() as $key => $value) {
1253
-                // do not add nonces
1254
-                if (strpos($key, 'nonce') !== false) {
1255
-                    continue;
1256
-                }
1257
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1258
-            }
1259
-        }
1260
-        return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1261
-    }
1262
-
1263
-
1264
-    /**
1265
-     * This returns a generated link that will load the related help tab.
1266
-     *
1267
-     * @param string $help_tab_id the id for the connected help tab
1268
-     * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1269
-     * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1270
-     * @return string              generated link
1271
-     * @uses EEH_Template::get_help_tab_link()
1272
-     */
1273
-    protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1274
-    {
1275
-        return EEH_Template::get_help_tab_link(
1276
-            $help_tab_id,
1277
-            $this->page_slug,
1278
-            $this->_req_action,
1279
-            $icon_style,
1280
-            $help_text
1281
-        );
1282
-    }
1283
-
1284
-
1285
-    /**
1286
-     * _add_help_tabs
1287
-     * Note child classes define their help tabs within the page_config array.
1288
-     *
1289
-     * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1290
-     * @return void
1291
-     * @throws DomainException
1292
-     * @throws EE_Error
1293
-     * @throws ReflectionException
1294
-     */
1295
-    protected function _add_help_tabs()
1296
-    {
1297
-        if (isset($this->_page_config[ $this->_req_action ])) {
1298
-            $config = $this->_page_config[ $this->_req_action ];
1299
-            // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1300
-            if (is_array($config) && isset($config['help_sidebar'])) {
1301
-                // check that the callback given is valid
1302
-                if (! method_exists($this, $config['help_sidebar'])) {
1303
-                    throw new EE_Error(
1304
-                        sprintf(
1305
-                            esc_html__(
1306
-                                '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',
1307
-                                'event_espresso'
1308
-                            ),
1309
-                            $config['help_sidebar'],
1310
-                            $this->class_name
1311
-                        )
1312
-                    );
1313
-                }
1314
-                $content = apply_filters(
1315
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1316
-                    $this->{$config['help_sidebar']}()
1317
-                );
1318
-                $this->_current_screen->set_help_sidebar($content);
1319
-            }
1320
-            if (! isset($config['help_tabs'])) {
1321
-                return;
1322
-            } //no help tabs for this route
1323
-            foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1324
-                // we're here so there ARE help tabs!
1325
-                // make sure we've got what we need
1326
-                if (! isset($cfg['title'])) {
1327
-                    throw new EE_Error(
1328
-                        esc_html__(
1329
-                            'The _page_config array is not set up properly for help tabs.  It is missing a title',
1330
-                            'event_espresso'
1331
-                        )
1332
-                    );
1333
-                }
1334
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1335
-                    throw new EE_Error(
1336
-                        esc_html__(
1337
-                            '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',
1338
-                            'event_espresso'
1339
-                        )
1340
-                    );
1341
-                }
1342
-                // first priority goes to content.
1343
-                if (! empty($cfg['content'])) {
1344
-                    $content = $cfg['content'];
1345
-                    // second priority goes to filename
1346
-                } elseif (! empty($cfg['filename'])) {
1347
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1348
-                    // 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)
1349
-                    $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1350
-                                                             . basename($this->_get_dir())
1351
-                                                             . '/help_tabs/'
1352
-                                                             . $cfg['filename']
1353
-                                                             . '.help_tab.php' : $file_path;
1354
-                    // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1355
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1356
-                        EE_Error::add_error(
1357
-                            sprintf(
1358
-                                esc_html__(
1359
-                                    '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',
1360
-                                    'event_espresso'
1361
-                                ),
1362
-                                $tab_id,
1363
-                                key($config),
1364
-                                $file_path
1365
-                            ),
1366
-                            __FILE__,
1367
-                            __FUNCTION__,
1368
-                            __LINE__
1369
-                        );
1370
-                        return;
1371
-                    }
1372
-                    $template_args['admin_page_obj'] = $this;
1373
-                    $content                         = EEH_Template::display_template(
1374
-                        $file_path,
1375
-                        $template_args,
1376
-                        true
1377
-                    );
1378
-                } else {
1379
-                    $content = '';
1380
-                }
1381
-                // check if callback is valid
1382
-                if (
1383
-                    empty($content)
1384
-                    && (
1385
-                        ! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1386
-                    )
1387
-                ) {
1388
-                    EE_Error::add_error(
1389
-                        sprintf(
1390
-                            esc_html__(
1391
-                                '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.',
1392
-                                'event_espresso'
1393
-                            ),
1394
-                            $cfg['title']
1395
-                        ),
1396
-                        __FILE__,
1397
-                        __FUNCTION__,
1398
-                        __LINE__
1399
-                    );
1400
-                    return;
1401
-                }
1402
-                // setup config array for help tab method
1403
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1404
-                $_ht = [
1405
-                    'id'       => $id,
1406
-                    'title'    => $cfg['title'],
1407
-                    'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1408
-                    'content'  => $content,
1409
-                ];
1410
-                $this->_current_screen->add_help_tab($_ht);
1411
-            }
1412
-        }
1413
-    }
1414
-
1415
-
1416
-    /**
1417
-     * This simply sets up any qtips that have been defined in the page config
1418
-     *
1419
-     * @return void
1420
-     * @throws ReflectionException
1421
-     * @throws EE_Error
1422
-     */
1423
-    protected function _add_qtips()
1424
-    {
1425
-        if (isset($this->_route_config['qtips'])) {
1426
-            $qtips = (array) $this->_route_config['qtips'];
1427
-            // load qtip loader
1428
-            $path = [
1429
-                $this->_get_dir() . '/qtips/',
1430
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1431
-            ];
1432
-            EEH_Qtip_Loader::instance()->register($qtips, $path);
1433
-        }
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * _set_nav_tabs
1439
-     * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1440
-     * wish to add additional tabs or modify accordingly.
1441
-     *
1442
-     * @return void
1443
-     * @throws InvalidArgumentException
1444
-     * @throws InvalidInterfaceException
1445
-     * @throws InvalidDataTypeException
1446
-     */
1447
-    protected function _set_nav_tabs()
1448
-    {
1449
-        $i        = 0;
1450
-        $only_tab = count($this->_page_config) < 2;
1451
-        foreach ($this->_page_config as $slug => $config) {
1452
-            if (! is_array($config) || empty($config['nav'])) {
1453
-                continue;
1454
-            }
1455
-            // no nav tab for this config
1456
-            // check for persistent flag
1457
-            if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1458
-                // nav tab is only to appear when route requested.
1459
-                continue;
1460
-            }
1461
-            if (! $this->check_user_access($slug, true)) {
1462
-                // no nav tab because current user does not have access.
1463
-                continue;
1464
-            }
1465
-            $css_class = $config['css_class'] ?? '';
1466
-            $css_class .= $only_tab ? ' ee-only-tab' : '';
1467
-            $css_class .= " ee-nav-tab__$slug";
1468
-
1469
-            $this->_nav_tabs[ $slug ] = [
1470
-                'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1471
-                        ['action' => $slug],
1472
-                        $this->_admin_base_url
1473
-                    ),
1474
-                'link_text' => $this->navTabLabel($config['nav'], $slug),
1475
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1476
-                'order'     => $config['nav']['order'] ?? $i,
1477
-            ];
1478
-            $i++;
1479
-        }
1480
-        // if $this->_nav_tabs is empty then lets set the default
1481
-        if (empty($this->_nav_tabs)) {
1482
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1483
-                'url'       => $this->_admin_base_url,
1484
-                'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1485
-                'css_class' => 'nav-tab-active',
1486
-                'order'     => 10,
1487
-            ];
1488
-        }
1489
-        // now let's sort the tabs according to order
1490
-        usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1491
-    }
1492
-
1493
-
1494
-    private function navTabLabel(array $nav_tab, string $slug): string
1495
-    {
1496
-        $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1497
-        $icon  = $nav_tab['icon'] ?? null;
1498
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1499
-        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)) {
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
+			try {
1149
+				call_user_func_array($route_callback, $args);
1150
+			} catch (Throwable $throwable) {
1151
+				$nice_args = [];
1152
+				foreach ($args as $key => $arg) {
1153
+					$nice_args[ $key ] = is_object($arg) ? get_class($arg) : $key;
1154
+				}
1155
+				new ExceptionStackTraceDisplay(
1156
+					new RuntimeException(
1157
+						sprintf(
1158
+							esc_html__(
1159
+								'Page route "%1$s" with the supplied arguments (%2$s) threw the following exception: %3$s',
1160
+								'event_espresso'
1161
+							),
1162
+							$method,
1163
+							implode(', ', $nice_args),
1164
+							$throwable->getMessage()
1165
+						),
1166
+						$throwable->getCode(),
1167
+						$throwable
1168
+					)
1169
+				);
1170
+			}
1171
+		}
1172
+		// if we've routed and this route has a no headers route AND a sent_headers_route,
1173
+		// then we need to reset the routing properties to the new route.
1174
+		// 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.
1175
+		if (
1176
+			$this->_is_UI_request === false
1177
+			&& is_array($this->_route)
1178
+			&& ! empty($this->_route['headers_sent_route'])
1179
+		) {
1180
+			$this->_reset_routing_properties($this->_route['headers_sent_route']);
1181
+		}
1182
+	}
1183
+
1184
+
1185
+	/**
1186
+	 * This method just allows the resetting of page properties in the case where a no headers
1187
+	 * route redirects to a headers route in its route config.
1188
+	 *
1189
+	 * @param string $new_route New (non header) route to redirect to.
1190
+	 * @return void
1191
+	 * @throws ReflectionException
1192
+	 * @throws InvalidArgumentException
1193
+	 * @throws InvalidInterfaceException
1194
+	 * @throws InvalidDataTypeException
1195
+	 * @throws EE_Error
1196
+	 * @throws Throwable
1197
+	 * @since   4.3.0
1198
+	 */
1199
+	protected function _reset_routing_properties(string $new_route)
1200
+	{
1201
+		$this->_is_UI_request = true;
1202
+		// now we set the current route to whatever the headers_sent_route is set at
1203
+		$this->request->setRequestParam('action', $new_route);
1204
+		// rerun page setup
1205
+		$this->_page_setup();
1206
+	}
1207
+
1208
+
1209
+	/**
1210
+	 * _add_query_arg
1211
+	 * adds nonce to array of arguments then calls WP add_query_arg function
1212
+	 *(internally just uses EEH_URL's function with the same name)
1213
+	 *
1214
+	 * @param array  $args
1215
+	 * @param string $url
1216
+	 * @param bool   $sticky                  if true, then the existing Request params will be appended to the
1217
+	 *                                        generated url in an associative array indexed by the key 'wp_referer';
1218
+	 *                                        Example usage: If the current page is:
1219
+	 *                                        http://mydomain.com/wp-admin/admin.php?page=espresso_registrations
1220
+	 *                                        &action=default&event_id=20&month_range=March%202015
1221
+	 *                                        &_wpnonce=5467821
1222
+	 *                                        and you call:
1223
+	 *                                        EE_Admin_Page::add_query_args_and_nonce(
1224
+	 *                                        array(
1225
+	 *                                        'action' => 'resend_something',
1226
+	 *                                        'page=>espresso_registrations'
1227
+	 *                                        ),
1228
+	 *                                        $some_url,
1229
+	 *                                        true
1230
+	 *                                        );
1231
+	 *                                        It will produce a url in this structure:
1232
+	 *                                        http://{$some_url}/?page=espresso_registrations&action=resend_something
1233
+	 *                                        &wp_referer[action]=default&wp_referer[event_id]=20&wpreferer[
1234
+	 *                                        month_range]=March%202015
1235
+	 * @param bool   $exclude_nonce           If true, the the nonce will be excluded from the generated nonce.
1236
+	 * @param int    $context
1237
+	 * @return string
1238
+	 */
1239
+	public static function add_query_args_and_nonce(
1240
+		array $args = [],
1241
+		string $url = '',
1242
+		bool $sticky = false,
1243
+		bool $exclude_nonce = false,
1244
+		int $context = EEH_URL::CONTEXT_NONE
1245
+	): string {
1246
+		// if there is a _wp_http_referer include the values from the request but only if sticky = true
1247
+		if ($sticky) {
1248
+			/** @var RequestInterface $request */
1249
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
1250
+			$request->unSetRequestParams(['_wp_http_referer', 'wp_referer'], true);
1251
+			$request->unSetServerParam('_wp_http_referer', true);
1252
+			foreach ($request->requestParams() as $key => $value) {
1253
+				// do not add nonces
1254
+				if (strpos($key, 'nonce') !== false) {
1255
+					continue;
1256
+				}
1257
+				$args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1258
+			}
1259
+		}
1260
+		return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
1261
+	}
1262
+
1263
+
1264
+	/**
1265
+	 * This returns a generated link that will load the related help tab.
1266
+	 *
1267
+	 * @param string $help_tab_id the id for the connected help tab
1268
+	 * @param string $icon_style  (optional) include css class for the style you want to use for the help icon.
1269
+	 * @param string $help_text   (optional) send help text you want to use for the link if default not to be used
1270
+	 * @return string              generated link
1271
+	 * @uses EEH_Template::get_help_tab_link()
1272
+	 */
1273
+	protected function _get_help_tab_link(string $help_tab_id, string $icon_style = '', string $help_text = ''): string
1274
+	{
1275
+		return EEH_Template::get_help_tab_link(
1276
+			$help_tab_id,
1277
+			$this->page_slug,
1278
+			$this->_req_action,
1279
+			$icon_style,
1280
+			$help_text
1281
+		);
1282
+	}
1283
+
1284
+
1285
+	/**
1286
+	 * _add_help_tabs
1287
+	 * Note child classes define their help tabs within the page_config array.
1288
+	 *
1289
+	 * @link   http://codex.wordpress.org/Function_Reference/add_help_tab
1290
+	 * @return void
1291
+	 * @throws DomainException
1292
+	 * @throws EE_Error
1293
+	 * @throws ReflectionException
1294
+	 */
1295
+	protected function _add_help_tabs()
1296
+	{
1297
+		if (isset($this->_page_config[ $this->_req_action ])) {
1298
+			$config = $this->_page_config[ $this->_req_action ];
1299
+			// let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1300
+			if (is_array($config) && isset($config['help_sidebar'])) {
1301
+				// check that the callback given is valid
1302
+				if (! method_exists($this, $config['help_sidebar'])) {
1303
+					throw new EE_Error(
1304
+						sprintf(
1305
+							esc_html__(
1306
+								'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',
1307
+								'event_espresso'
1308
+							),
1309
+							$config['help_sidebar'],
1310
+							$this->class_name
1311
+						)
1312
+					);
1313
+				}
1314
+				$content = apply_filters(
1315
+					'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1316
+					$this->{$config['help_sidebar']}()
1317
+				);
1318
+				$this->_current_screen->set_help_sidebar($content);
1319
+			}
1320
+			if (! isset($config['help_tabs'])) {
1321
+				return;
1322
+			} //no help tabs for this route
1323
+			foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1324
+				// we're here so there ARE help tabs!
1325
+				// make sure we've got what we need
1326
+				if (! isset($cfg['title'])) {
1327
+					throw new EE_Error(
1328
+						esc_html__(
1329
+							'The _page_config array is not set up properly for help tabs.  It is missing a title',
1330
+							'event_espresso'
1331
+						)
1332
+					);
1333
+				}
1334
+				if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1335
+					throw new EE_Error(
1336
+						esc_html__(
1337
+							'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',
1338
+							'event_espresso'
1339
+						)
1340
+					);
1341
+				}
1342
+				// first priority goes to content.
1343
+				if (! empty($cfg['content'])) {
1344
+					$content = $cfg['content'];
1345
+					// second priority goes to filename
1346
+				} elseif (! empty($cfg['filename'])) {
1347
+					$file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1348
+					// 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)
1349
+					$file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1350
+															 . basename($this->_get_dir())
1351
+															 . '/help_tabs/'
1352
+															 . $cfg['filename']
1353
+															 . '.help_tab.php' : $file_path;
1354
+					// if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1355
+					if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1356
+						EE_Error::add_error(
1357
+							sprintf(
1358
+								esc_html__(
1359
+									'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',
1360
+									'event_espresso'
1361
+								),
1362
+								$tab_id,
1363
+								key($config),
1364
+								$file_path
1365
+							),
1366
+							__FILE__,
1367
+							__FUNCTION__,
1368
+							__LINE__
1369
+						);
1370
+						return;
1371
+					}
1372
+					$template_args['admin_page_obj'] = $this;
1373
+					$content                         = EEH_Template::display_template(
1374
+						$file_path,
1375
+						$template_args,
1376
+						true
1377
+					);
1378
+				} else {
1379
+					$content = '';
1380
+				}
1381
+				// check if callback is valid
1382
+				if (
1383
+					empty($content)
1384
+					&& (
1385
+						! isset($cfg['callback']) || ! method_exists($this, $cfg['callback'])
1386
+					)
1387
+				) {
1388
+					EE_Error::add_error(
1389
+						sprintf(
1390
+							esc_html__(
1391
+								'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.',
1392
+								'event_espresso'
1393
+							),
1394
+							$cfg['title']
1395
+						),
1396
+						__FILE__,
1397
+						__FUNCTION__,
1398
+						__LINE__
1399
+					);
1400
+					return;
1401
+				}
1402
+				// setup config array for help tab method
1403
+				$id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1404
+				$_ht = [
1405
+					'id'       => $id,
1406
+					'title'    => $cfg['title'],
1407
+					'callback' => isset($cfg['callback']) && empty($content) ? [$this, $cfg['callback']] : null,
1408
+					'content'  => $content,
1409
+				];
1410
+				$this->_current_screen->add_help_tab($_ht);
1411
+			}
1412
+		}
1413
+	}
1414
+
1415
+
1416
+	/**
1417
+	 * This simply sets up any qtips that have been defined in the page config
1418
+	 *
1419
+	 * @return void
1420
+	 * @throws ReflectionException
1421
+	 * @throws EE_Error
1422
+	 */
1423
+	protected function _add_qtips()
1424
+	{
1425
+		if (isset($this->_route_config['qtips'])) {
1426
+			$qtips = (array) $this->_route_config['qtips'];
1427
+			// load qtip loader
1428
+			$path = [
1429
+				$this->_get_dir() . '/qtips/',
1430
+				EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1431
+			];
1432
+			EEH_Qtip_Loader::instance()->register($qtips, $path);
1433
+		}
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * _set_nav_tabs
1439
+	 * This sets up the nav tabs from the page_routes array.  This method can be overwritten by child classes if you
1440
+	 * wish to add additional tabs or modify accordingly.
1441
+	 *
1442
+	 * @return void
1443
+	 * @throws InvalidArgumentException
1444
+	 * @throws InvalidInterfaceException
1445
+	 * @throws InvalidDataTypeException
1446
+	 */
1447
+	protected function _set_nav_tabs()
1448
+	{
1449
+		$i        = 0;
1450
+		$only_tab = count($this->_page_config) < 2;
1451
+		foreach ($this->_page_config as $slug => $config) {
1452
+			if (! is_array($config) || empty($config['nav'])) {
1453
+				continue;
1454
+			}
1455
+			// no nav tab for this config
1456
+			// check for persistent flag
1457
+			if ($slug !== $this->_req_action && isset($config['nav']['persistent']) && ! $config['nav']['persistent']) {
1458
+				// nav tab is only to appear when route requested.
1459
+				continue;
1460
+			}
1461
+			if (! $this->check_user_access($slug, true)) {
1462
+				// no nav tab because current user does not have access.
1463
+				continue;
1464
+			}
1465
+			$css_class = $config['css_class'] ?? '';
1466
+			$css_class .= $only_tab ? ' ee-only-tab' : '';
1467
+			$css_class .= " ee-nav-tab__$slug";
1468
+
1469
+			$this->_nav_tabs[ $slug ] = [
1470
+				'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1471
+						['action' => $slug],
1472
+						$this->_admin_base_url
1473
+					),
1474
+				'link_text' => $this->navTabLabel($config['nav'], $slug),
1475
+				'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1476
+				'order'     => $config['nav']['order'] ?? $i,
1477
+			];
1478
+			$i++;
1479
+		}
1480
+		// if $this->_nav_tabs is empty then lets set the default
1481
+		if (empty($this->_nav_tabs)) {
1482
+			$this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1483
+				'url'       => $this->_admin_base_url,
1484
+				'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1485
+				'css_class' => 'nav-tab-active',
1486
+				'order'     => 10,
1487
+			];
1488
+		}
1489
+		// now let's sort the tabs according to order
1490
+		usort($this->_nav_tabs, [$this, '_sort_nav_tabs']);
1491
+	}
1492
+
1493
+
1494
+	private function navTabLabel(array $nav_tab, string $slug): string
1495
+	{
1496
+		$label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1497
+		$icon  = $nav_tab['icon'] ?? null;
1498
+		$icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1499
+		return '
1500 1500
             <span class="ee-admin-screen-tab__label">
1501 1501
                 ' . $icon . '
1502 1502
                 <span class="ee-nav-label__text">' . $label . '</span>
1503 1503
             </span>';
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * _set_current_labels
1509
-     * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1510
-     * property array
1511
-     *
1512
-     * @return void
1513
-     */
1514
-    private function _set_current_labels()
1515
-    {
1516
-        if (isset($this->_route_config['labels'])) {
1517
-            foreach ($this->_route_config['labels'] as $label => $text) {
1518
-                if (is_array($text)) {
1519
-                    foreach ($text as $sublabel => $subtext) {
1520
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1521
-                    }
1522
-                } else {
1523
-                    $this->_labels[ $label ] = $text;
1524
-                }
1525
-            }
1526
-        }
1527
-    }
1528
-
1529
-
1530
-    /**
1531
-     *        verifies user access for this admin page
1532
-     *
1533
-     * @param string $route_to_check if present then the capability for the route matching this string is checked.
1534
-     * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1535
-     *                               return false if verify fail.
1536
-     * @return bool
1537
-     * @throws InvalidArgumentException
1538
-     * @throws InvalidDataTypeException
1539
-     * @throws InvalidInterfaceException
1540
-     */
1541
-    public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1542
-    {
1543
-        // hack to allow editpost capability to be used for edit CPT pages
1544
-        $req_action = $this instanceof EE_Admin_Page_CPT && $this->_req_action === 'edit'
1545
-            ? 'editpost'
1546
-            : $this->_req_action;
1547
-        $route_to_check = ! empty($route_to_check) ? $route_to_check : $req_action;
1548
-        $capability     = ! empty($route_to_check)
1549
-                          && isset($this->_page_routes[ $route_to_check ])
1550
-                          && is_array($this->_page_routes[ $route_to_check ])
1551
-                          && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1552
-            ? $this->_page_routes[ $route_to_check ]['capability']
1553
-            : null;
1554
-
1555
-        if (empty($capability) && empty($route_to_check)) {
1556
-            $capability = ! empty($this->_route['capability']) ? $this->_route['capability'] : 'manage_options';
1557
-        } else {
1558
-            $capability = empty($capability) ? 'manage_options' : $capability;
1559
-        }
1560
-
1561
-        $id = $this->_route['obj_id'] ?? 0;
1562
-
1563
-        if (
1564
-            ! $this->request->isAjax()
1565
-            && (
1566
-                ! function_exists('is_admin')
1567
-                || ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1568
-            )
1569
-        ) {
1570
-            if ($verify_only) {
1571
-                return false;
1572
-            }
1573
-            if (is_user_logged_in()) {
1574
-                wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1575
-            }
1576
-            return false;
1577
-        }
1578
-        return true;
1579
-    }
1580
-
1581
-
1582
-    /**
1583
-     * @param string                 $box_id
1584
-     * @param string                 $title
1585
-     * @param callable|string|null   $callback
1586
-     * @param string|array|WP_Screen $screen
1587
-     * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1588
-     *                                              Comments screen contexts include 'normal' and 'side'.
1589
-     *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1590
-     * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1591
-     * @param array|null             $callback_args
1592
-     */
1593
-    protected function addMetaBox(
1594
-        string $box_id,
1595
-        string $title,
1596
-        $callback,
1597
-        $screen,
1598
-        string $context = 'normal',
1599
-        string $priority = 'default',
1600
-        ?array $callback_args = null
1601
-    ) {
1602
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1603
-            return;
1604
-        }
1605
-
1606
-        add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1607
-        add_filter(
1608
-            "postbox_classes_{$this->_wp_page_slug}_$box_id",
1609
-            function ($classes) {
1610
-                $classes[] = 'ee-admin-container';
1611
-                return $classes;
1612
-            }
1613
-        );
1614
-    }
1615
-
1616
-
1617
-    /**
1618
-     * admin_init_global
1619
-     * This runs all the code that we want executed within the WP admin_init hook.
1620
-     * This method executes for ALL EE Admin pages.
1621
-     *
1622
-     * @return void
1623
-     */
1624
-    public function admin_init_global()
1625
-    {
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * wp_loaded_global
1631
-     * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1632
-     * EE_Admin page and will execute on every EE Admin Page load
1633
-     *
1634
-     * @return void
1635
-     */
1636
-    public function wp_loaded()
1637
-    {
1638
-    }
1639
-
1640
-
1641
-    /**
1642
-     * admin_notices
1643
-     * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1644
-     * ALL EE_Admin pages.
1645
-     *
1646
-     * @return void
1647
-     */
1648
-    public function admin_notices_global()
1649
-    {
1650
-        $this->_display_no_javascript_warning();
1651
-        $this->_display_espresso_notices();
1652
-    }
1653
-
1654
-
1655
-    public function network_admin_notices_global()
1656
-    {
1657
-        $this->_display_no_javascript_warning();
1658
-        $this->_display_espresso_notices();
1659
-    }
1660
-
1661
-
1662
-    /**
1663
-     * admin_footer_scripts_global
1664
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1665
-     * will apply on ALL EE_Admin pages.
1666
-     *
1667
-     * @return void
1668
-     */
1669
-    public function admin_footer_scripts_global()
1670
-    {
1671
-        $this->_add_admin_page_ajax_loading_img();
1672
-        $this->_add_admin_page_overlay();
1673
-        // if metaboxes are present we need to add the nonce field
1674
-        if (
1675
-            isset($this->_route_config['metaboxes'])
1676
-            || isset($this->_route_config['list_table'])
1677
-            || (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1678
-        ) {
1679
-            wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1680
-            wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1681
-        }
1682
-    }
1683
-
1684
-
1685
-    /**
1686
-     * admin_footer_global
1687
-     * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1688
-     * This particular method will apply on ALL EE_Admin Pages.
1689
-     *
1690
-     * @return void
1691
-     */
1692
-    public function admin_footer_global()
1693
-    {
1694
-        // dialog container for dialog helper
1695
-        echo '
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * _set_current_labels
1509
+	 * This method modifies the _labels property with any optional specific labels indicated in the _page_routes
1510
+	 * property array
1511
+	 *
1512
+	 * @return void
1513
+	 */
1514
+	private function _set_current_labels()
1515
+	{
1516
+		if (isset($this->_route_config['labels'])) {
1517
+			foreach ($this->_route_config['labels'] as $label => $text) {
1518
+				if (is_array($text)) {
1519
+					foreach ($text as $sublabel => $subtext) {
1520
+						$this->_labels[ $label ][ $sublabel ] = $subtext;
1521
+					}
1522
+				} else {
1523
+					$this->_labels[ $label ] = $text;
1524
+				}
1525
+			}
1526
+		}
1527
+	}
1528
+
1529
+
1530
+	/**
1531
+	 *        verifies user access for this admin page
1532
+	 *
1533
+	 * @param string $route_to_check if present then the capability for the route matching this string is checked.
1534
+	 * @param bool   $verify_only    Default is FALSE which means if user check fails then wp_die().  Otherwise just
1535
+	 *                               return false if verify fail.
1536
+	 * @return bool
1537
+	 * @throws InvalidArgumentException
1538
+	 * @throws InvalidDataTypeException
1539
+	 * @throws InvalidInterfaceException
1540
+	 */
1541
+	public function check_user_access(string $route_to_check = '', bool $verify_only = false): bool
1542
+	{
1543
+		// hack to allow editpost capability to be used for edit CPT pages
1544
+		$req_action = $this instanceof EE_Admin_Page_CPT && $this->_req_action === 'edit'
1545
+			? 'editpost'
1546
+			: $this->_req_action;
1547
+		$route_to_check = ! empty($route_to_check) ? $route_to_check : $req_action;
1548
+		$capability     = ! empty($route_to_check)
1549
+						  && isset($this->_page_routes[ $route_to_check ])
1550
+						  && is_array($this->_page_routes[ $route_to_check ])
1551
+						  && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1552
+			? $this->_page_routes[ $route_to_check ]['capability']
1553
+			: null;
1554
+
1555
+		if (empty($capability) && empty($route_to_check)) {
1556
+			$capability = ! empty($this->_route['capability']) ? $this->_route['capability'] : 'manage_options';
1557
+		} else {
1558
+			$capability = empty($capability) ? 'manage_options' : $capability;
1559
+		}
1560
+
1561
+		$id = $this->_route['obj_id'] ?? 0;
1562
+
1563
+		if (
1564
+			! $this->request->isAjax()
1565
+			&& (
1566
+				! function_exists('is_admin')
1567
+				|| ! $this->capabilities->current_user_can($capability, "{$this->page_slug}_$route_to_check", $id)
1568
+			)
1569
+		) {
1570
+			if ($verify_only) {
1571
+				return false;
1572
+			}
1573
+			if (is_user_logged_in()) {
1574
+				wp_die(esc_html__('You do not have access to this route.', 'event_espresso'));
1575
+			}
1576
+			return false;
1577
+		}
1578
+		return true;
1579
+	}
1580
+
1581
+
1582
+	/**
1583
+	 * @param string                 $box_id
1584
+	 * @param string                 $title
1585
+	 * @param callable|string|null   $callback
1586
+	 * @param string|array|WP_Screen $screen
1587
+	 * @param string                 $context       Post edit screen contexts include 'normal', 'side', and 'advanced'.
1588
+	 *                                              Comments screen contexts include 'normal' and 'side'.
1589
+	 *                                              Menus meta boxes (accordion sections) all use the 'side' context.
1590
+	 * @param string                 $priority      Accepts 'high', 'core', 'default', or 'low'.
1591
+	 * @param array|null             $callback_args
1592
+	 */
1593
+	protected function addMetaBox(
1594
+		string $box_id,
1595
+		string $title,
1596
+		$callback,
1597
+		$screen,
1598
+		string $context = 'normal',
1599
+		string $priority = 'default',
1600
+		?array $callback_args = null
1601
+	) {
1602
+		if (! (is_callable($callback) || ! function_exists($callback))) {
1603
+			return;
1604
+		}
1605
+
1606
+		add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1607
+		add_filter(
1608
+			"postbox_classes_{$this->_wp_page_slug}_$box_id",
1609
+			function ($classes) {
1610
+				$classes[] = 'ee-admin-container';
1611
+				return $classes;
1612
+			}
1613
+		);
1614
+	}
1615
+
1616
+
1617
+	/**
1618
+	 * admin_init_global
1619
+	 * This runs all the code that we want executed within the WP admin_init hook.
1620
+	 * This method executes for ALL EE Admin pages.
1621
+	 *
1622
+	 * @return void
1623
+	 */
1624
+	public function admin_init_global()
1625
+	{
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * wp_loaded_global
1631
+	 * This runs all the code that we want executed within the WP wp_loaded hook.  This method is optional for an
1632
+	 * EE_Admin page and will execute on every EE Admin Page load
1633
+	 *
1634
+	 * @return void
1635
+	 */
1636
+	public function wp_loaded()
1637
+	{
1638
+	}
1639
+
1640
+
1641
+	/**
1642
+	 * admin_notices
1643
+	 * Anything triggered by the 'admin_notices' WP hook should be put in here.  This particular method will apply on
1644
+	 * ALL EE_Admin pages.
1645
+	 *
1646
+	 * @return void
1647
+	 */
1648
+	public function admin_notices_global()
1649
+	{
1650
+		$this->_display_no_javascript_warning();
1651
+		$this->_display_espresso_notices();
1652
+	}
1653
+
1654
+
1655
+	public function network_admin_notices_global()
1656
+	{
1657
+		$this->_display_no_javascript_warning();
1658
+		$this->_display_espresso_notices();
1659
+	}
1660
+
1661
+
1662
+	/**
1663
+	 * admin_footer_scripts_global
1664
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
1665
+	 * will apply on ALL EE_Admin pages.
1666
+	 *
1667
+	 * @return void
1668
+	 */
1669
+	public function admin_footer_scripts_global()
1670
+	{
1671
+		$this->_add_admin_page_ajax_loading_img();
1672
+		$this->_add_admin_page_overlay();
1673
+		// if metaboxes are present we need to add the nonce field
1674
+		if (
1675
+			isset($this->_route_config['metaboxes'])
1676
+			|| isset($this->_route_config['list_table'])
1677
+			|| (isset($this->_route_config['has_metaboxes']) && $this->_route_config['has_metaboxes'])
1678
+		) {
1679
+			wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false);
1680
+			wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false);
1681
+		}
1682
+	}
1683
+
1684
+
1685
+	/**
1686
+	 * admin_footer_global
1687
+	 * Anything triggered by the wp 'admin_footer' wp hook should be put in here.
1688
+	 * This particular method will apply on ALL EE_Admin Pages.
1689
+	 *
1690
+	 * @return void
1691
+	 */
1692
+	public function admin_footer_global()
1693
+	{
1694
+		// dialog container for dialog helper
1695
+		echo '
1696 1696
         <div class="ee-admin-dialog-container auto-hide hidden">
1697 1697
             <div class="ee-notices"></div>
1698 1698
             <div class="ee-admin-dialog-container-inner-content"></div>
1699 1699
         </div>
1700 1700
         ';
1701 1701
 
1702
-        // current set timezone for timezone js
1703
-        echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1704
-    }
1705
-
1706
-
1707
-    /**
1708
-     * This function sees if there is a method for help popup content existing for the given route.  If there is then
1709
-     * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1710
-     * help popups then in your templates or your content you set "triggers" for the content using the
1711
-     * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1712
-     * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1713
-     * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1714
-     * for the
1715
-     * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1716
-     * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1717
-     *    'help_trigger_id' => array(
1718
-     *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1719
-     *        'content' => esc_html__('localized content for popup', 'event_espresso')
1720
-     *    )
1721
-     * );
1722
-     * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1723
-     *
1724
-     * @param array $help_array
1725
-     * @param bool  $display
1726
-     * @return string content
1727
-     * @throws DomainException
1728
-     * @throws EE_Error
1729
-     */
1730
-    protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1731
-    {
1732
-        $content    = '';
1733
-        $help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1734
-        // loop through the array and setup content
1735
-        foreach ($help_array as $trigger => $help) {
1736
-            // make sure the array is setup properly
1737
-            if (! isset($help['title'], $help['content'])) {
1738
-                throw new EE_Error(
1739
-                    esc_html__(
1740
-                        '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',
1741
-                        'event_espresso'
1742
-                    )
1743
-                );
1744
-            }
1745
-            // we're good so let's setup the template vars and then assign parsed template content to our content.
1746
-            $template_args = [
1747
-                'help_popup_id'      => $trigger,
1748
-                'help_popup_title'   => $help['title'],
1749
-                'help_popup_content' => $help['content'],
1750
-            ];
1751
-            $content       .= EEH_Template::display_template(
1752
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1753
-                $template_args,
1754
-                true
1755
-            );
1756
-        }
1757
-        if ($display) {
1758
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1759
-            return '';
1760
-        }
1761
-        return $content;
1762
-    }
1763
-
1764
-
1765
-    /**
1766
-     * All this does is retrieve the help content array if set by the EE_Admin_Page child
1767
-     *
1768
-     * @return array properly formatted array for help popup content
1769
-     * @throws EE_Error
1770
-     */
1771
-    private function _get_help_content(): array
1772
-    {
1773
-        // what is the method we're looking for?
1774
-        $method_name = '_help_popup_content_' . $this->_req_action;
1775
-        // if method doesn't exist let's get out.
1776
-        if (! method_exists($this, $method_name)) {
1777
-            return [];
1778
-        }
1779
-        // k we're good to go let's retrieve the help array
1780
-        $help_array = $this->{$method_name}();
1781
-        // make sure we've got an array!
1782
-        if (! is_array($help_array)) {
1783
-            throw new EE_Error(
1784
-                esc_html__(
1785
-                    'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1786
-                    'event_espresso'
1787
-                )
1788
-            );
1789
-        }
1790
-        return $help_array;
1791
-    }
1792
-
1793
-
1794
-    /**
1795
-     * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1796
-     * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1797
-     * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1798
-     *
1799
-     * @param string $trigger_id reference for retrieving the trigger content for the popup
1800
-     * @param bool   $display    if false then we return the trigger string
1801
-     * @param array  $dimensions an array of dimensions for the box (array(h,w))
1802
-     * @return string
1803
-     * @throws DomainException
1804
-     * @throws EE_Error
1805
-     */
1806
-    protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1807
-    {
1808
-        if ($this->request->isAjax()) {
1809
-            return '';
1810
-        }
1811
-        // 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
1812
-        $help_array   = $this->_get_help_content();
1813
-        $help_content = '';
1814
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1815
-            $help_array[ $trigger_id ] = [
1816
-                'title'   => esc_html__('Missing Content', 'event_espresso'),
1817
-                'content' => esc_html__(
1818
-                    '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.)',
1819
-                    'event_espresso'
1820
-                ),
1821
-            ];
1822
-            $help_content              = $this->_set_help_popup_content($help_array);
1823
-        }
1824
-        $height   = esc_attr($dimensions[0]) ?? 400;
1825
-        $width    = esc_attr($dimensions[1]) ?? 640;
1826
-        $inlineId = esc_attr($trigger_id);
1827
-        // let's setup the trigger
1828
-        $content = "
1702
+		// current set timezone for timezone js
1703
+		echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1704
+	}
1705
+
1706
+
1707
+	/**
1708
+	 * This function sees if there is a method for help popup content existing for the given route.  If there is then
1709
+	 * we'll use the retrieved array to output the content using the template. For child classes: If you want to have
1710
+	 * help popups then in your templates or your content you set "triggers" for the content using the
1711
+	 * "_set_help_trigger('help_trigger_id')" where "help_trigger_id" is what you will use later in your custom method
1712
+	 * for the help popup content on that page. Then in your Child_Admin_Page class you need to define a help popup
1713
+	 * method for the content in the format "_help_popup_content_{route_name}()"  So if you are setting help content
1714
+	 * for the
1715
+	 * 'edit_event' route you should have a method named "_help_popup_content_edit_route". In your defined
1716
+	 * "help_popup_content_..." method.  You must prepare and return an array in the following format array(
1717
+	 *    'help_trigger_id' => array(
1718
+	 *        'title' => esc_html__('localized title for popup', 'event_espresso'),
1719
+	 *        'content' => esc_html__('localized content for popup', 'event_espresso')
1720
+	 *    )
1721
+	 * );
1722
+	 * Then the EE_Admin_Parent will take care of making sure that is setup properly on the correct route.
1723
+	 *
1724
+	 * @param array $help_array
1725
+	 * @param bool  $display
1726
+	 * @return string content
1727
+	 * @throws DomainException
1728
+	 * @throws EE_Error
1729
+	 */
1730
+	protected function _set_help_popup_content(array $help_array = [], bool $display = false): string
1731
+	{
1732
+		$content    = '';
1733
+		$help_array = empty($help_array) ? $this->_get_help_content() : $help_array;
1734
+		// loop through the array and setup content
1735
+		foreach ($help_array as $trigger => $help) {
1736
+			// make sure the array is setup properly
1737
+			if (! isset($help['title'], $help['content'])) {
1738
+				throw new EE_Error(
1739
+					esc_html__(
1740
+						'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',
1741
+						'event_espresso'
1742
+					)
1743
+				);
1744
+			}
1745
+			// we're good so let's setup the template vars and then assign parsed template content to our content.
1746
+			$template_args = [
1747
+				'help_popup_id'      => $trigger,
1748
+				'help_popup_title'   => $help['title'],
1749
+				'help_popup_content' => $help['content'],
1750
+			];
1751
+			$content       .= EEH_Template::display_template(
1752
+				EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1753
+				$template_args,
1754
+				true
1755
+			);
1756
+		}
1757
+		if ($display) {
1758
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1759
+			return '';
1760
+		}
1761
+		return $content;
1762
+	}
1763
+
1764
+
1765
+	/**
1766
+	 * All this does is retrieve the help content array if set by the EE_Admin_Page child
1767
+	 *
1768
+	 * @return array properly formatted array for help popup content
1769
+	 * @throws EE_Error
1770
+	 */
1771
+	private function _get_help_content(): array
1772
+	{
1773
+		// what is the method we're looking for?
1774
+		$method_name = '_help_popup_content_' . $this->_req_action;
1775
+		// if method doesn't exist let's get out.
1776
+		if (! method_exists($this, $method_name)) {
1777
+			return [];
1778
+		}
1779
+		// k we're good to go let's retrieve the help array
1780
+		$help_array = $this->{$method_name}();
1781
+		// make sure we've got an array!
1782
+		if (! is_array($help_array)) {
1783
+			throw new EE_Error(
1784
+				esc_html__(
1785
+					'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
1786
+					'event_espresso'
1787
+				)
1788
+			);
1789
+		}
1790
+		return $help_array;
1791
+	}
1792
+
1793
+
1794
+	/**
1795
+	 * EE Admin Pages can use this to set a properly formatted trigger for a help popup.
1796
+	 * By default the trigger html is printed.  Otherwise it can be returned if the $display flag is set "false"
1797
+	 * See comments made on the _set_help_content method for understanding other parts to the help popup tool.
1798
+	 *
1799
+	 * @param string $trigger_id reference for retrieving the trigger content for the popup
1800
+	 * @param bool   $display    if false then we return the trigger string
1801
+	 * @param array  $dimensions an array of dimensions for the box (array(h,w))
1802
+	 * @return string
1803
+	 * @throws DomainException
1804
+	 * @throws EE_Error
1805
+	 */
1806
+	protected function _set_help_trigger(string $trigger_id, bool $display = true, array $dimensions = ['400', '640'])
1807
+	{
1808
+		if ($this->request->isAjax()) {
1809
+			return '';
1810
+		}
1811
+		// 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
1812
+		$help_array   = $this->_get_help_content();
1813
+		$help_content = '';
1814
+		if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1815
+			$help_array[ $trigger_id ] = [
1816
+				'title'   => esc_html__('Missing Content', 'event_espresso'),
1817
+				'content' => esc_html__(
1818
+					'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.)',
1819
+					'event_espresso'
1820
+				),
1821
+			];
1822
+			$help_content              = $this->_set_help_popup_content($help_array);
1823
+		}
1824
+		$height   = esc_attr($dimensions[0]) ?? 400;
1825
+		$width    = esc_attr($dimensions[1]) ?? 640;
1826
+		$inlineId = esc_attr($trigger_id);
1827
+		// let's setup the trigger
1828
+		$content = "
1829 1829
         <a class='ee-dialog' href='?height=$height&width=$width&inlineId=$inlineId' target='_blank'>
1830 1830
             <span class='question ee-help-popup-question'></span>
1831 1831
         </a>";
1832
-        $content .= $help_content;
1833
-        if ($display) {
1834
-            echo wp_kses($content, AllowedTags::getWithFormTags());
1835
-            return '';
1836
-        }
1837
-        return $content;
1838
-    }
1839
-
1840
-
1841
-    /**
1842
-     * _add_global_screen_options
1843
-     * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1844
-     * This particular method will add_screen_options on ALL EE_Admin Pages
1845
-     *
1846
-     * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1847
-     *         see also WP_Screen object documents...
1848
-     * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1849
-     * @abstract
1850
-     * @return void
1851
-     */
1852
-    private function _add_global_screen_options()
1853
-    {
1854
-    }
1855
-
1856
-
1857
-    /**
1858
-     * _add_global_feature_pointers
1859
-     * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1860
-     * This particular method will implement feature pointers for ALL EE_Admin pages.
1861
-     * Note: this is just a placeholder for now.  Implementation will come down the road
1862
-     *
1863
-     * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1864
-     *         extended) also see:
1865
-     * @link   http://eamann.com/tech/wordpress-portland/
1866
-     * @abstract
1867
-     * @return void
1868
-     */
1869
-    private function _add_global_feature_pointers()
1870
-    {
1871
-    }
1872
-
1873
-
1874
-    /**
1875
-     * load_global_scripts_styles
1876
-     * The scripts and styles enqueued in here will be loaded on every EE Admin page
1877
-     *
1878
-     * @return void
1879
-     */
1880
-    public function load_global_scripts_styles()
1881
-    {
1882
-        // add debugging styles
1883
-        if (WP_DEBUG) {
1884
-            add_action('admin_head', [$this, 'add_xdebug_style']);
1885
-        }
1886
-        // taking care of metaboxes
1887
-        if (
1888
-            empty($this->_cpt_route)
1889
-            && (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1890
-        ) {
1891
-            wp_enqueue_script('dashboard');
1892
-        }
1893
-
1894
-        wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1895
-        wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1896
-        // LOCALIZED DATA
1897
-        // localize script for ajax lazy loading
1898
-        wp_localize_script(
1899
-            EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1900
-            'eeLazyLoadingContainers',
1901
-            apply_filters(
1902
-                'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1903
-                ['espresso_news_post_box_content']
1904
-            )
1905
-        );
1906
-        StatusChangeNotice::loadAssets();
1907
-
1908
-        add_filter(
1909
-            'admin_body_class',
1910
-            function ($classes) {
1911
-                if (strpos($classes, 'espresso-admin') === false) {
1912
-                    $classes .= ' espresso-admin';
1913
-                }
1914
-                return $classes;
1915
-            }
1916
-        );
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     *        admin_footer_scripts_eei18n_js_strings
1922
-     *
1923
-     * @return        void
1924
-     */
1925
-    public function admin_footer_scripts_eei18n_js_strings()
1926
-    {
1927
-        EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1928
-        EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1929
-            __(
1930
-                '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!!!',
1931
-                'event_espresso'
1932
-            )
1933
-        );
1934
-        EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1935
-        EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1936
-        EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1937
-        EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1938
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1939
-        EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1940
-        EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1941
-        EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1942
-        EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1943
-        EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1944
-        EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1945
-        EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1946
-        EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1947
-        EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1948
-        EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1949
-        EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1950
-        EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1951
-        EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1952
-        EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1953
-        EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1954
-        EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1955
-        EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1956
-        EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1957
-        EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1958
-        EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1959
-        EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1960
-        EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1961
-        EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1962
-        EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1963
-        EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1964
-        EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1965
-        EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1966
-        EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
1967
-        EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
1968
-        EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
1969
-        EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
1970
-        EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
1971
-        EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
1972
-    }
1973
-
1974
-
1975
-    /**
1976
-     *        load enhanced xdebug styles for ppl with failing eyesight
1977
-     *
1978
-     * @return        void
1979
-     */
1980
-    public function add_xdebug_style()
1981
-    {
1982
-        echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1983
-    }
1984
-
1985
-
1986
-    /************************/
1987
-    /** LIST TABLE METHODS **/
1988
-    /************************/
1989
-    /**
1990
-     * this sets up the list table if the current view requires it.
1991
-     *
1992
-     * @return void
1993
-     * @throws EE_Error
1994
-     * @throws InvalidArgumentException
1995
-     * @throws InvalidDataTypeException
1996
-     * @throws InvalidInterfaceException
1997
-     */
1998
-    protected function _set_list_table()
1999
-    {
2000
-        // first is this a list_table view?
2001
-        if (! isset($this->_route_config['list_table'])) {
2002
-            return;
2003
-        } //not a list_table view so get out.
2004
-        // list table functions are per view specific (because some admin pages might have more than one list table!)
2005
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2006
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2007
-            // user error msg
2008
-            $error_msg = esc_html__(
2009
-                'An error occurred. The requested list table views could not be found.',
2010
-                'event_espresso'
2011
-            );
2012
-            // developer error msg
2013
-            $error_msg .= '||'
2014
-                          . sprintf(
2015
-                              esc_html__(
2016
-                                  '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.',
2017
-                                  'event_espresso'
2018
-                              ),
2019
-                              $this->_req_action,
2020
-                              $list_table_view
2021
-                          );
2022
-            throw new EE_Error($error_msg);
2023
-        }
2024
-        // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2025
-        $this->_views = apply_filters(
2026
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2027
-            $this->_views
2028
-        );
2029
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2030
-        $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2031
-        $this->_set_list_table_view();
2032
-        $this->_set_list_table_object();
2033
-    }
2034
-
2035
-
2036
-    /**
2037
-     * set current view for List Table
2038
-     *
2039
-     * @return void
2040
-     */
2041
-    protected function _set_list_table_view()
2042
-    {
2043
-        $this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2044
-        $status      = $this->request->getRequestParam('status', null, DataType::KEY);
2045
-        $this->_view = $status && array_key_exists($status, $this->_views)
2046
-            ? $status
2047
-            : $this->_view;
2048
-    }
2049
-
2050
-
2051
-    /**
2052
-     * _set_list_table_object
2053
-     * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2054
-     *
2055
-     * @throws InvalidInterfaceException
2056
-     * @throws InvalidArgumentException
2057
-     * @throws InvalidDataTypeException
2058
-     * @throws EE_Error
2059
-     * @throws InvalidInterfaceException
2060
-     */
2061
-    protected function _set_list_table_object()
2062
-    {
2063
-        if (isset($this->_route_config['list_table'])) {
2064
-            if (! class_exists($this->_route_config['list_table'])) {
2065
-                throw new EE_Error(
2066
-                    sprintf(
2067
-                        esc_html__(
2068
-                            '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.',
2069
-                            'event_espresso'
2070
-                        ),
2071
-                        $this->_route_config['list_table'],
2072
-                        $this->class_name
2073
-                    )
2074
-                );
2075
-            }
2076
-            $this->_list_table_object = $this->loader->getShared(
2077
-                $this->_route_config['list_table'],
2078
-                [
2079
-                    $this,
2080
-                    LoaderFactory::getShared(AdminListTableFilters::class),
2081
-                ]
2082
-            );
2083
-        }
2084
-    }
2085
-
2086
-
2087
-    /**
2088
-     * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2089
-     *
2090
-     * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2091
-     *                                                    urls.  The array should be indexed by the view it is being
2092
-     *                                                    added to.
2093
-     * @return array
2094
-     */
2095
-    public function get_list_table_view_RLs(array $extra_query_args = []): array
2096
-    {
2097
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2098
-        if (empty($this->_views)) {
2099
-            $this->_views = [];
2100
-        }
2101
-        // cycle thru views
2102
-        foreach ($this->_views as $key => $view) {
2103
-            $query_args = [];
2104
-            // check for current view
2105
-            $this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2106
-            $query_args['action']                        = $this->_req_action;
2107
-            $query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2108
-            $query_args['status']                        = $view['slug'];
2109
-            // merge any other arguments sent in.
2110
-            if (isset($extra_query_args[ $view['slug'] ])) {
2111
-                foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2112
-                    $query_args[] = $extra_query_arg;
2113
-                }
2114
-            }
2115
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2116
-        }
2117
-        return $this->_views;
2118
-    }
2119
-
2120
-
2121
-    /**
2122
-     * generates a dropdown box for selecting the number of visible rows in an admin page list table
2123
-     *
2124
-     * @param int $max_entries total number of rows in the table
2125
-     * @return string
2126
-     * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2127
-     *                         WP does it.
2128
-     */
2129
-    protected function _entries_per_page_dropdown(int $max_entries = 0): string
2130
-    {
2131
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2132
-        $values   = [10, 25, 50, 100];
2133
-        $per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2134
-        if ($max_entries) {
2135
-            $values[] = $max_entries;
2136
-            sort($values);
2137
-        }
2138
-        $entries_per_page_dropdown = '
1832
+		$content .= $help_content;
1833
+		if ($display) {
1834
+			echo wp_kses($content, AllowedTags::getWithFormTags());
1835
+			return '';
1836
+		}
1837
+		return $content;
1838
+	}
1839
+
1840
+
1841
+	/**
1842
+	 * _add_global_screen_options
1843
+	 * Add any extra wp_screen_options within this method using built-in WP functions/methods for doing so.
1844
+	 * This particular method will add_screen_options on ALL EE_Admin Pages
1845
+	 *
1846
+	 * @link   http://chrismarslender.com/wp-tutorials/wordpress-screen-options-tutorial/
1847
+	 *         see also WP_Screen object documents...
1848
+	 * @link   http://codex.wordpress.org/Class_Reference/WP_Screen
1849
+	 * @abstract
1850
+	 * @return void
1851
+	 */
1852
+	private function _add_global_screen_options()
1853
+	{
1854
+	}
1855
+
1856
+
1857
+	/**
1858
+	 * _add_global_feature_pointers
1859
+	 * This method is used for implementing any "feature pointers" (using built-in WP styling js).
1860
+	 * This particular method will implement feature pointers for ALL EE_Admin pages.
1861
+	 * Note: this is just a placeholder for now.  Implementation will come down the road
1862
+	 *
1863
+	 * @see    WP_Internal_Pointers class in wp-admin/includes/template.php for example (its a final class so can't be
1864
+	 *         extended) also see:
1865
+	 * @link   http://eamann.com/tech/wordpress-portland/
1866
+	 * @abstract
1867
+	 * @return void
1868
+	 */
1869
+	private function _add_global_feature_pointers()
1870
+	{
1871
+	}
1872
+
1873
+
1874
+	/**
1875
+	 * load_global_scripts_styles
1876
+	 * The scripts and styles enqueued in here will be loaded on every EE Admin page
1877
+	 *
1878
+	 * @return void
1879
+	 */
1880
+	public function load_global_scripts_styles()
1881
+	{
1882
+		// add debugging styles
1883
+		if (WP_DEBUG) {
1884
+			add_action('admin_head', [$this, 'add_xdebug_style']);
1885
+		}
1886
+		// taking care of metaboxes
1887
+		if (
1888
+			empty($this->_cpt_route)
1889
+			&& (isset($this->_route_config['metaboxes']) || isset($this->_route_config['has_metaboxes']))
1890
+		) {
1891
+			wp_enqueue_script('dashboard');
1892
+		}
1893
+
1894
+		wp_enqueue_script(JqueryAssetManager::JS_HANDLE_JQUERY_UI_TOUCH_PUNCH);
1895
+		wp_enqueue_script(EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN);
1896
+		// LOCALIZED DATA
1897
+		// localize script for ajax lazy loading
1898
+		wp_localize_script(
1899
+			EspressoLegacyAdminAssetManager::JS_HANDLE_EE_ADMIN,
1900
+			'eeLazyLoadingContainers',
1901
+			apply_filters(
1902
+				'FHEE__EE_Admin_Page_Core__load_global_scripts_styles__loader_containers',
1903
+				['espresso_news_post_box_content']
1904
+			)
1905
+		);
1906
+		StatusChangeNotice::loadAssets();
1907
+
1908
+		add_filter(
1909
+			'admin_body_class',
1910
+			function ($classes) {
1911
+				if (strpos($classes, 'espresso-admin') === false) {
1912
+					$classes .= ' espresso-admin';
1913
+				}
1914
+				return $classes;
1915
+			}
1916
+		);
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 *        admin_footer_scripts_eei18n_js_strings
1922
+	 *
1923
+	 * @return        void
1924
+	 */
1925
+	public function admin_footer_scripts_eei18n_js_strings()
1926
+	{
1927
+		EE_Registry::$i18n_js_strings['ajax_url']       = WP_AJAX_URL;
1928
+		EE_Registry::$i18n_js_strings['confirm_delete'] = wp_strip_all_tags(
1929
+			__(
1930
+				'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!!!',
1931
+				'event_espresso'
1932
+			)
1933
+		);
1934
+		EE_Registry::$i18n_js_strings['January']        = wp_strip_all_tags(__('January', 'event_espresso'));
1935
+		EE_Registry::$i18n_js_strings['February']       = wp_strip_all_tags(__('February', 'event_espresso'));
1936
+		EE_Registry::$i18n_js_strings['March']          = wp_strip_all_tags(__('March', 'event_espresso'));
1937
+		EE_Registry::$i18n_js_strings['April']          = wp_strip_all_tags(__('April', 'event_espresso'));
1938
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1939
+		EE_Registry::$i18n_js_strings['June']           = wp_strip_all_tags(__('June', 'event_espresso'));
1940
+		EE_Registry::$i18n_js_strings['July']           = wp_strip_all_tags(__('July', 'event_espresso'));
1941
+		EE_Registry::$i18n_js_strings['August']         = wp_strip_all_tags(__('August', 'event_espresso'));
1942
+		EE_Registry::$i18n_js_strings['September']      = wp_strip_all_tags(__('September', 'event_espresso'));
1943
+		EE_Registry::$i18n_js_strings['October']        = wp_strip_all_tags(__('October', 'event_espresso'));
1944
+		EE_Registry::$i18n_js_strings['November']       = wp_strip_all_tags(__('November', 'event_espresso'));
1945
+		EE_Registry::$i18n_js_strings['December']       = wp_strip_all_tags(__('December', 'event_espresso'));
1946
+		EE_Registry::$i18n_js_strings['Jan']            = wp_strip_all_tags(__('Jan', 'event_espresso'));
1947
+		EE_Registry::$i18n_js_strings['Feb']            = wp_strip_all_tags(__('Feb', 'event_espresso'));
1948
+		EE_Registry::$i18n_js_strings['Mar']            = wp_strip_all_tags(__('Mar', 'event_espresso'));
1949
+		EE_Registry::$i18n_js_strings['Apr']            = wp_strip_all_tags(__('Apr', 'event_espresso'));
1950
+		EE_Registry::$i18n_js_strings['May']            = wp_strip_all_tags(__('May', 'event_espresso'));
1951
+		EE_Registry::$i18n_js_strings['Jun']            = wp_strip_all_tags(__('Jun', 'event_espresso'));
1952
+		EE_Registry::$i18n_js_strings['Jul']            = wp_strip_all_tags(__('Jul', 'event_espresso'));
1953
+		EE_Registry::$i18n_js_strings['Aug']            = wp_strip_all_tags(__('Aug', 'event_espresso'));
1954
+		EE_Registry::$i18n_js_strings['Sep']            = wp_strip_all_tags(__('Sep', 'event_espresso'));
1955
+		EE_Registry::$i18n_js_strings['Oct']            = wp_strip_all_tags(__('Oct', 'event_espresso'));
1956
+		EE_Registry::$i18n_js_strings['Nov']            = wp_strip_all_tags(__('Nov', 'event_espresso'));
1957
+		EE_Registry::$i18n_js_strings['Dec']            = wp_strip_all_tags(__('Dec', 'event_espresso'));
1958
+		EE_Registry::$i18n_js_strings['Sunday']         = wp_strip_all_tags(__('Sunday', 'event_espresso'));
1959
+		EE_Registry::$i18n_js_strings['Monday']         = wp_strip_all_tags(__('Monday', 'event_espresso'));
1960
+		EE_Registry::$i18n_js_strings['Tuesday']        = wp_strip_all_tags(__('Tuesday', 'event_espresso'));
1961
+		EE_Registry::$i18n_js_strings['Wednesday']      = wp_strip_all_tags(__('Wednesday', 'event_espresso'));
1962
+		EE_Registry::$i18n_js_strings['Thursday']       = wp_strip_all_tags(__('Thursday', 'event_espresso'));
1963
+		EE_Registry::$i18n_js_strings['Friday']         = wp_strip_all_tags(__('Friday', 'event_espresso'));
1964
+		EE_Registry::$i18n_js_strings['Saturday']       = wp_strip_all_tags(__('Saturday', 'event_espresso'));
1965
+		EE_Registry::$i18n_js_strings['Sun']            = wp_strip_all_tags(__('Sun', 'event_espresso'));
1966
+		EE_Registry::$i18n_js_strings['Mon']            = wp_strip_all_tags(__('Mon', 'event_espresso'));
1967
+		EE_Registry::$i18n_js_strings['Tue']            = wp_strip_all_tags(__('Tue', 'event_espresso'));
1968
+		EE_Registry::$i18n_js_strings['Wed']            = wp_strip_all_tags(__('Wed', 'event_espresso'));
1969
+		EE_Registry::$i18n_js_strings['Thu']            = wp_strip_all_tags(__('Thu', 'event_espresso'));
1970
+		EE_Registry::$i18n_js_strings['Fri']            = wp_strip_all_tags(__('Fri', 'event_espresso'));
1971
+		EE_Registry::$i18n_js_strings['Sat']            = wp_strip_all_tags(__('Sat', 'event_espresso'));
1972
+	}
1973
+
1974
+
1975
+	/**
1976
+	 *        load enhanced xdebug styles for ppl with failing eyesight
1977
+	 *
1978
+	 * @return        void
1979
+	 */
1980
+	public function add_xdebug_style()
1981
+	{
1982
+		echo '<style>.xdebug-error { font-size:1.5em; }</style>';
1983
+	}
1984
+
1985
+
1986
+	/************************/
1987
+	/** LIST TABLE METHODS **/
1988
+	/************************/
1989
+	/**
1990
+	 * this sets up the list table if the current view requires it.
1991
+	 *
1992
+	 * @return void
1993
+	 * @throws EE_Error
1994
+	 * @throws InvalidArgumentException
1995
+	 * @throws InvalidDataTypeException
1996
+	 * @throws InvalidInterfaceException
1997
+	 */
1998
+	protected function _set_list_table()
1999
+	{
2000
+		// first is this a list_table view?
2001
+		if (! isset($this->_route_config['list_table'])) {
2002
+			return;
2003
+		} //not a list_table view so get out.
2004
+		// list table functions are per view specific (because some admin pages might have more than one list table!)
2005
+		$list_table_view = '_set_list_table_views_' . $this->_req_action;
2006
+		if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2007
+			// user error msg
2008
+			$error_msg = esc_html__(
2009
+				'An error occurred. The requested list table views could not be found.',
2010
+				'event_espresso'
2011
+			);
2012
+			// developer error msg
2013
+			$error_msg .= '||'
2014
+						  . sprintf(
2015
+							  esc_html__(
2016
+								  '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.',
2017
+								  'event_espresso'
2018
+							  ),
2019
+							  $this->_req_action,
2020
+							  $list_table_view
2021
+						  );
2022
+			throw new EE_Error($error_msg);
2023
+		}
2024
+		// let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2025
+		$this->_views = apply_filters(
2026
+			'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2027
+			$this->_views
2028
+		);
2029
+		$this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2030
+		$this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2031
+		$this->_set_list_table_view();
2032
+		$this->_set_list_table_object();
2033
+	}
2034
+
2035
+
2036
+	/**
2037
+	 * set current view for List Table
2038
+	 *
2039
+	 * @return void
2040
+	 */
2041
+	protected function _set_list_table_view()
2042
+	{
2043
+		$this->_view = isset($this->_views['in_use']) ? 'in_use' : 'all';
2044
+		$status      = $this->request->getRequestParam('status', null, DataType::KEY);
2045
+		$this->_view = $status && array_key_exists($status, $this->_views)
2046
+			? $status
2047
+			: $this->_view;
2048
+	}
2049
+
2050
+
2051
+	/**
2052
+	 * _set_list_table_object
2053
+	 * WP_List_Table objects need to be loaded fairly early so automatic stuff WP does is taken care of.
2054
+	 *
2055
+	 * @throws InvalidInterfaceException
2056
+	 * @throws InvalidArgumentException
2057
+	 * @throws InvalidDataTypeException
2058
+	 * @throws EE_Error
2059
+	 * @throws InvalidInterfaceException
2060
+	 */
2061
+	protected function _set_list_table_object()
2062
+	{
2063
+		if (isset($this->_route_config['list_table'])) {
2064
+			if (! class_exists($this->_route_config['list_table'])) {
2065
+				throw new EE_Error(
2066
+					sprintf(
2067
+						esc_html__(
2068
+							'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.',
2069
+							'event_espresso'
2070
+						),
2071
+						$this->_route_config['list_table'],
2072
+						$this->class_name
2073
+					)
2074
+				);
2075
+			}
2076
+			$this->_list_table_object = $this->loader->getShared(
2077
+				$this->_route_config['list_table'],
2078
+				[
2079
+					$this,
2080
+					LoaderFactory::getShared(AdminListTableFilters::class),
2081
+				]
2082
+			);
2083
+		}
2084
+	}
2085
+
2086
+
2087
+	/**
2088
+	 * get_list_table_view_RLs - get it? View RL ?? VU-RL???  URL ??
2089
+	 *
2090
+	 * @param array $extra_query_args                     Optional. An array of extra query args to add to the generated
2091
+	 *                                                    urls.  The array should be indexed by the view it is being
2092
+	 *                                                    added to.
2093
+	 * @return array
2094
+	 */
2095
+	public function get_list_table_view_RLs(array $extra_query_args = []): array
2096
+	{
2097
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2098
+		if (empty($this->_views)) {
2099
+			$this->_views = [];
2100
+		}
2101
+		// cycle thru views
2102
+		foreach ($this->_views as $key => $view) {
2103
+			$query_args = [];
2104
+			// check for current view
2105
+			$this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2106
+			$query_args['action']                        = $this->_req_action;
2107
+			$query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2108
+			$query_args['status']                        = $view['slug'];
2109
+			// merge any other arguments sent in.
2110
+			if (isset($extra_query_args[ $view['slug'] ])) {
2111
+				foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2112
+					$query_args[] = $extra_query_arg;
2113
+				}
2114
+			}
2115
+			$this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2116
+		}
2117
+		return $this->_views;
2118
+	}
2119
+
2120
+
2121
+	/**
2122
+	 * generates a dropdown box for selecting the number of visible rows in an admin page list table
2123
+	 *
2124
+	 * @param int $max_entries total number of rows in the table
2125
+	 * @return string
2126
+	 * @todo   : Note: ideally this should be added to the screen options dropdown as that would be consistent with how
2127
+	 *                         WP does it.
2128
+	 */
2129
+	protected function _entries_per_page_dropdown(int $max_entries = 0): string
2130
+	{
2131
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2132
+		$values   = [10, 25, 50, 100];
2133
+		$per_page = $this->request->getRequestParam('per_page', 10, DataType::INT);
2134
+		if ($max_entries) {
2135
+			$values[] = $max_entries;
2136
+			sort($values);
2137
+		}
2138
+		$entries_per_page_dropdown = '
2139 2139
 			<div id="entries-per-page-dv" class="alignleft actions">
2140 2140
 				<label class="hide-if-no-js">
2141 2141
 					Show
2142 2142
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2143
-        foreach ($values as $value) {
2144
-            if ($value < $max_entries) {
2145
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2146
-                $entries_per_page_dropdown .= '
2143
+		foreach ($values as $value) {
2144
+			if ($value < $max_entries) {
2145
+				$selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2146
+				$entries_per_page_dropdown .= '
2147 2147
 						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2148
-            }
2149
-        }
2150
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2151
-        $entries_per_page_dropdown .= '
2148
+			}
2149
+		}
2150
+		$selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2151
+		$entries_per_page_dropdown .= '
2152 2152
 						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2153
-        $entries_per_page_dropdown .= '
2153
+		$entries_per_page_dropdown .= '
2154 2154
 					</select>
2155 2155
 					entries
2156 2156
 				</label>
2157 2157
 				<input id="entries-per-page-btn" class="button button--secondary" type="submit" value="Go" >
2158 2158
 			</div>
2159 2159
 		';
2160
-        return $entries_per_page_dropdown;
2161
-    }
2162
-
2163
-
2164
-    /**
2165
-     *        _set_search_attributes
2166
-     *
2167
-     * @return        void
2168
-     */
2169
-    public function _set_search_attributes()
2170
-    {
2171
-        $this->_template_args['search']['btn_label'] = sprintf(
2172
-            esc_html__('Search %s', 'event_espresso'),
2173
-            empty($this->_search_btn_label) ? $this->page_label
2174
-                : $this->_search_btn_label
2175
-        );
2176
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2177
-    }
2178
-
2179
-
2180
-
2181
-    /*** END LIST TABLE METHODS **/
2182
-
2183
-    /**
2184
-     * @return void
2185
-     * @throws EE_Error
2186
-     */
2187
-    public function addRegisteredMetaBoxes()
2188
-    {
2189
-        remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2190
-        $this->_add_registered_meta_boxes();
2191
-    }
2192
-
2193
-
2194
-    /**
2195
-     * _add_registered_metaboxes
2196
-     *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2197
-     *
2198
-     * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2199
-     * @return void
2200
-     * @throws EE_Error
2201
-     */
2202
-    private function _add_registered_meta_boxes()
2203
-    {
2204
-        // we only add meta boxes if the page_route calls for it
2205
-        if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2206
-            // this simply loops through the callbacks provided
2207
-            // and checks if there is a corresponding callback registered by the child
2208
-            // if there is then we go ahead and process the metabox loader.
2209
-            foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2210
-                // first check for Closures
2211
-                if ($metabox_callback instanceof Closure) {
2212
-                    $result = $metabox_callback();
2213
-                } elseif (is_callable($metabox_callback)) {
2214
-                    $result = call_user_func($metabox_callback);
2215
-                } elseif (method_exists($this, $metabox_callback)) {
2216
-                    $result = $this->{$metabox_callback}();
2217
-                } else {
2218
-                    $result = false;
2219
-                }
2220
-                if ($result === false) {
2221
-                    // user error msg
2222
-                    $error_msg = esc_html__(
2223
-                        'An error occurred. The  requested metabox could not be found.',
2224
-                        'event_espresso'
2225
-                    );
2226
-                    // developer error msg
2227
-                    $error_msg .= '||'
2228
-                                  . sprintf(
2229
-                                      esc_html__(
2230
-                                          '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.',
2231
-                                          'event_espresso'
2232
-                                      ),
2233
-                                      $metabox_callback
2234
-                                  );
2235
-                    throw new EE_Error($error_msg);
2236
-                }
2237
-                unset($this->_route_config['metaboxes'][ $key ]);
2238
-            }
2239
-        }
2240
-    }
2241
-
2242
-
2243
-    /**
2244
-     * _add_screen_columns
2245
-     * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2246
-     * the dynamic column template and we'll setup the column options for the page.
2247
-     *
2248
-     * @return void
2249
-     */
2250
-    private function _add_screen_columns()
2251
-    {
2252
-        if (
2253
-            isset($this->_route_config['columns'])
2254
-            && is_array($this->_route_config['columns'])
2255
-            && count($this->_route_config['columns']) === 2
2256
-        ) {
2257
-            add_screen_option(
2258
-                'layout_columns',
2259
-                [
2260
-                    'max'     => (int) $this->_route_config['columns'][0],
2261
-                    'default' => (int) $this->_route_config['columns'][1],
2262
-                ]
2263
-            );
2264
-            $this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2265
-            $screen_id                                           = $this->_current_screen->id;
2266
-            $screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2267
-            $total_columns                                       = ! empty($screen_columns)
2268
-                ? $screen_columns
2269
-                : $this->_route_config['columns'][1];
2270
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2271
-            $this->_template_args['current_page']                = $this->_wp_page_slug;
2272
-            $this->_template_args['screen']                      = $this->_current_screen;
2273
-            $this->_column_template_path                         = EE_ADMIN_TEMPLATE
2274
-                                                                   . 'admin_details_metabox_column_wrapper.template.php';
2275
-            // finally if we don't have has_metaboxes set in the route config
2276
-            // let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2277
-            $this->_route_config['has_metaboxes'] = true;
2278
-        }
2279
-    }
2280
-
2281
-
2282
-
2283
-    /** GLOBALLY AVAILABLE METABOXES **/
2284
-
2285
-
2286
-    /**
2287
-     * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2288
-     * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2289
-     * these get loaded on.
2290
-     */
2291
-    private function _espresso_news_post_box()
2292
-    {
2293
-        $news_box_title = apply_filters(
2294
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2295
-            esc_html__('New @ Event Espresso', 'event_espresso')
2296
-        );
2297
-        $this->addMetaBox(
2298
-            'espresso_news_post_box',
2299
-            $news_box_title,
2300
-            [
2301
-                $this,
2302
-                'espresso_news_post_box',
2303
-            ],
2304
-            $this->_wp_page_slug,
2305
-            'side',
2306
-            'low'
2307
-        );
2308
-    }
2309
-
2310
-
2311
-    /**
2312
-     * Code for setting up espresso ratings request metabox.
2313
-     */
2314
-    protected function _espresso_ratings_request()
2315
-    {
2316
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2317
-            return;
2318
-        }
2319
-        $ratings_box_title = apply_filters(
2320
-            'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2321
-            esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2322
-        );
2323
-        $this->addMetaBox(
2324
-            'espresso_ratings_request',
2325
-            $ratings_box_title,
2326
-            [
2327
-                $this,
2328
-                'espresso_ratings_request',
2329
-            ],
2330
-            $this->_wp_page_slug,
2331
-            'side'
2332
-        );
2333
-    }
2334
-
2335
-
2336
-    /**
2337
-     * Code for setting up espresso ratings request metabox content.
2338
-     *
2339
-     * @throws DomainException
2340
-     */
2341
-    public function espresso_ratings_request()
2342
-    {
2343
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2344
-    }
2345
-
2346
-
2347
-    public static function cached_rss_display(string $rss_id, string $url): bool
2348
-    {
2349
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2350
-                     . esc_html__('Loading&#8230;', 'event_espresso')
2351
-                     . '</p><p class="hide-if-js">'
2352
-                     . esc_html__('This widget requires JavaScript.', 'event_espresso')
2353
-                     . '</p>';
2354
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2355
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2356
-        $post      = '</div>' . "\n";
2357
-        $cache_key = 'ee_rss_' . md5($rss_id);
2358
-        $output    = get_transient($cache_key);
2359
-        if ($output !== false) {
2360
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2361
-            return true;
2362
-        }
2363
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2364
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2365
-            return false;
2366
-        }
2367
-        ob_start();
2368
-        wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2369
-        set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2370
-        return true;
2371
-    }
2372
-
2373
-
2374
-    public function espresso_news_post_box()
2375
-    {
2376
-        ?>
2160
+		return $entries_per_page_dropdown;
2161
+	}
2162
+
2163
+
2164
+	/**
2165
+	 *        _set_search_attributes
2166
+	 *
2167
+	 * @return        void
2168
+	 */
2169
+	public function _set_search_attributes()
2170
+	{
2171
+		$this->_template_args['search']['btn_label'] = sprintf(
2172
+			esc_html__('Search %s', 'event_espresso'),
2173
+			empty($this->_search_btn_label) ? $this->page_label
2174
+				: $this->_search_btn_label
2175
+		);
2176
+		$this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2177
+	}
2178
+
2179
+
2180
+
2181
+	/*** END LIST TABLE METHODS **/
2182
+
2183
+	/**
2184
+	 * @return void
2185
+	 * @throws EE_Error
2186
+	 */
2187
+	public function addRegisteredMetaBoxes()
2188
+	{
2189
+		remove_action('add_meta_boxes', [$this, 'addRegisteredMetaBoxes'], 99);
2190
+		$this->_add_registered_meta_boxes();
2191
+	}
2192
+
2193
+
2194
+	/**
2195
+	 * _add_registered_metaboxes
2196
+	 *  this loads any registered metaboxes via the 'metaboxes' index in the _page_config property array.
2197
+	 *
2198
+	 * @link   http://codex.wordpress.org/Function_Reference/add_meta_box
2199
+	 * @return void
2200
+	 * @throws EE_Error
2201
+	 */
2202
+	private function _add_registered_meta_boxes()
2203
+	{
2204
+		// we only add meta boxes if the page_route calls for it
2205
+		if (isset($this->_route_config['metaboxes']) && is_array($this->_route_config['metaboxes'])) {
2206
+			// this simply loops through the callbacks provided
2207
+			// and checks if there is a corresponding callback registered by the child
2208
+			// if there is then we go ahead and process the metabox loader.
2209
+			foreach ($this->_route_config['metaboxes'] as $key => $metabox_callback) {
2210
+				// first check for Closures
2211
+				if ($metabox_callback instanceof Closure) {
2212
+					$result = $metabox_callback();
2213
+				} elseif (is_callable($metabox_callback)) {
2214
+					$result = call_user_func($metabox_callback);
2215
+				} elseif (method_exists($this, $metabox_callback)) {
2216
+					$result = $this->{$metabox_callback}();
2217
+				} else {
2218
+					$result = false;
2219
+				}
2220
+				if ($result === false) {
2221
+					// user error msg
2222
+					$error_msg = esc_html__(
2223
+						'An error occurred. The  requested metabox could not be found.',
2224
+						'event_espresso'
2225
+					);
2226
+					// developer error msg
2227
+					$error_msg .= '||'
2228
+								  . sprintf(
2229
+									  esc_html__(
2230
+										  '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.',
2231
+										  'event_espresso'
2232
+									  ),
2233
+									  $metabox_callback
2234
+								  );
2235
+					throw new EE_Error($error_msg);
2236
+				}
2237
+				unset($this->_route_config['metaboxes'][ $key ]);
2238
+			}
2239
+		}
2240
+	}
2241
+
2242
+
2243
+	/**
2244
+	 * _add_screen_columns
2245
+	 * This will check the _page_config array and if there is "columns" key index indicated, we'll set the template as
2246
+	 * the dynamic column template and we'll setup the column options for the page.
2247
+	 *
2248
+	 * @return void
2249
+	 */
2250
+	private function _add_screen_columns()
2251
+	{
2252
+		if (
2253
+			isset($this->_route_config['columns'])
2254
+			&& is_array($this->_route_config['columns'])
2255
+			&& count($this->_route_config['columns']) === 2
2256
+		) {
2257
+			add_screen_option(
2258
+				'layout_columns',
2259
+				[
2260
+					'max'     => (int) $this->_route_config['columns'][0],
2261
+					'default' => (int) $this->_route_config['columns'][1],
2262
+				]
2263
+			);
2264
+			$this->_template_args['num_columns']                 = $this->_route_config['columns'][0];
2265
+			$screen_id                                           = $this->_current_screen->id;
2266
+			$screen_columns                                      = (int) get_user_option("screen_layout_$screen_id");
2267
+			$total_columns                                       = ! empty($screen_columns)
2268
+				? $screen_columns
2269
+				: $this->_route_config['columns'][1];
2270
+			$this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2271
+			$this->_template_args['current_page']                = $this->_wp_page_slug;
2272
+			$this->_template_args['screen']                      = $this->_current_screen;
2273
+			$this->_column_template_path                         = EE_ADMIN_TEMPLATE
2274
+																   . 'admin_details_metabox_column_wrapper.template.php';
2275
+			// finally if we don't have has_metaboxes set in the route config
2276
+			// let's make sure it IS set other wise the necessary hidden fields for this won't be loaded.
2277
+			$this->_route_config['has_metaboxes'] = true;
2278
+		}
2279
+	}
2280
+
2281
+
2282
+
2283
+	/** GLOBALLY AVAILABLE METABOXES **/
2284
+
2285
+
2286
+	/**
2287
+	 * In this section we put any globally available EE metaboxes for all EE Admin pages.  They are called by simply
2288
+	 * referencing the callback in the _page_config array property.  This way you can be very specific about what pages
2289
+	 * these get loaded on.
2290
+	 */
2291
+	private function _espresso_news_post_box()
2292
+	{
2293
+		$news_box_title = apply_filters(
2294
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2295
+			esc_html__('New @ Event Espresso', 'event_espresso')
2296
+		);
2297
+		$this->addMetaBox(
2298
+			'espresso_news_post_box',
2299
+			$news_box_title,
2300
+			[
2301
+				$this,
2302
+				'espresso_news_post_box',
2303
+			],
2304
+			$this->_wp_page_slug,
2305
+			'side',
2306
+			'low'
2307
+		);
2308
+	}
2309
+
2310
+
2311
+	/**
2312
+	 * Code for setting up espresso ratings request metabox.
2313
+	 */
2314
+	protected function _espresso_ratings_request()
2315
+	{
2316
+		if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2317
+			return;
2318
+		}
2319
+		$ratings_box_title = apply_filters(
2320
+			'FHEE__EE_Admin_Page___espresso_news_post_box__news_box_title',
2321
+			esc_html__('Keep Event Espresso Decaf Free', 'event_espresso')
2322
+		);
2323
+		$this->addMetaBox(
2324
+			'espresso_ratings_request',
2325
+			$ratings_box_title,
2326
+			[
2327
+				$this,
2328
+				'espresso_ratings_request',
2329
+			],
2330
+			$this->_wp_page_slug,
2331
+			'side'
2332
+		);
2333
+	}
2334
+
2335
+
2336
+	/**
2337
+	 * Code for setting up espresso ratings request metabox content.
2338
+	 *
2339
+	 * @throws DomainException
2340
+	 */
2341
+	public function espresso_ratings_request()
2342
+	{
2343
+		EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2344
+	}
2345
+
2346
+
2347
+	public static function cached_rss_display(string $rss_id, string $url): bool
2348
+	{
2349
+		$loading   = '<p class="widget-loading hide-if-no-js">'
2350
+					 . esc_html__('Loading&#8230;', 'event_espresso')
2351
+					 . '</p><p class="hide-if-js">'
2352
+					 . esc_html__('This widget requires JavaScript.', 'event_espresso')
2353
+					 . '</p>';
2354
+		$pre       = '<div class="espresso-rss-display">' . "\n\t";
2355
+		$pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2356
+		$post      = '</div>' . "\n";
2357
+		$cache_key = 'ee_rss_' . md5($rss_id);
2358
+		$output    = get_transient($cache_key);
2359
+		if ($output !== false) {
2360
+			echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2361
+			return true;
2362
+		}
2363
+		if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2364
+			echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2365
+			return false;
2366
+		}
2367
+		ob_start();
2368
+		wp_widget_rss_output($url, ['show_date' => 0, 'items' => 5]);
2369
+		set_transient($cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS);
2370
+		return true;
2371
+	}
2372
+
2373
+
2374
+	public function espresso_news_post_box()
2375
+	{
2376
+		?>
2377 2377
 <div class="padding">
2378 2378
 	<div id="espresso_news_post_box_content" class="infolinks">
2379 2379
 		<?php
2380
-                // Get RSS Feed(s)
2381
-                EE_Admin_Page::cached_rss_display(
2382
-                    'espresso_news_post_box_content',
2383
-                    esc_url_raw(
2384
-                        apply_filters(
2385
-                            'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2386
-                            'https://eventespresso.com/feed/'
2387
-                        )
2388
-                    )
2389
-                );
2390
-                ?>
2380
+				// Get RSS Feed(s)
2381
+				EE_Admin_Page::cached_rss_display(
2382
+					'espresso_news_post_box_content',
2383
+					esc_url_raw(
2384
+						apply_filters(
2385
+							'FHEE__EE_Admin_Page__espresso_news_post_box__feed_url',
2386
+							'https://eventespresso.com/feed/'
2387
+						)
2388
+					)
2389
+				);
2390
+				?>
2391 2391
 	</div>
2392 2392
 	<?php do_action('AHEE__EE_Admin_Page__espresso_news_post_box__after_content'); ?>
2393 2393
 </div>
2394 2394
 <?php
2395
-    }
2396
-
2397
-
2398
-    private function _espresso_links_post_box()
2399
-    {
2400
-        // Hiding until we actually have content to put in here...
2401
-        // $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2402
-    }
2403
-
2404
-
2405
-    public function espresso_links_post_box()
2406
-    {
2407
-        // Hiding until we actually have content to put in here...
2408
-        // EEH_Template::display_template(
2409
-        //     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2410
-        // );
2411
-    }
2412
-
2413
-
2414
-    protected function _espresso_sponsors_post_box()
2415
-    {
2416
-        if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2417
-            $this->addMetaBox(
2418
-                'espresso_sponsors_post_box',
2419
-                esc_html__('Event Espresso Highlights', 'event_espresso'),
2420
-                [$this, 'espresso_sponsors_post_box'],
2421
-                $this->_wp_page_slug,
2422
-                'side'
2423
-            );
2424
-        }
2425
-    }
2426
-
2427
-
2428
-    public function espresso_sponsors_post_box()
2429
-    {
2430
-        EEH_Template::display_template(
2431
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2432
-        );
2433
-    }
2434
-
2435
-
2436
-    /**
2437
-     * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2438
-     * present in the _page_config array, then we'll use that for the metabox label.
2439
-     * Otherwise we'll just use publish
2440
-     * (publishbox itself could be an array of labels indexed by routes)
2441
-     *
2442
-     * @return string
2443
-     * @since   5.0.0.p
2444
-     */
2445
-    protected function getPublishBoxTitle(): string
2446
-    {
2447
-        $publish_box_title = esc_html__('Publish', 'event_espresso');
2448
-        if (! empty($this->_labels['publishbox'])) {
2449
-            if (is_array($this->_labels['publishbox'])) {
2450
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2451
-            } else {
2452
-                $publish_box_title = $this->_labels['publishbox'];
2453
-            }
2454
-        }
2455
-        return apply_filters(
2456
-            'FHEE__EE_Admin_Page___publish_post_box__box_label',
2457
-            $publish_box_title,
2458
-            $this->_req_action,
2459
-            $this
2460
-        );
2461
-    }
2462
-
2463
-
2464
-    /**
2465
-     * @throws EE_Error
2466
-     */
2467
-    private function _publish_post_box()
2468
-    {
2469
-        $title = $this->getPublishBoxTitle();
2470
-        if (empty($this->_template_args['save_buttons'])) {
2471
-            $this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2472
-        } else {
2473
-            $this->addPublishPostMetaBoxHiddenFields(
2474
-                sanitize_key($title),
2475
-                ['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2476
-            );
2477
-        }
2478
-        $this->addMetaBox(
2479
-            "espresso_{$this->page_slug}_editor_overview",
2480
-            $title,
2481
-            [$this, 'editor_overview'],
2482
-            $this->_current_screen->id,
2483
-            'side',
2484
-            'high'
2485
-        );
2486
-    }
2487
-
2488
-
2489
-    public function editor_overview()
2490
-    {
2491
-        /**
2492
-         * @var string $publish_box_extra_content
2493
-         * @var string $publish_hidden_fields
2494
-         * @var string $publish_delete_link
2495
-         * @var string $save_buttons
2496
-         */
2497
-        // if we have extra content set let's add it in if not make sure its empty
2498
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2499
-        echo EEH_Template::display_template(
2500
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2501
-            $this->_template_args,
2502
-            true
2503
-        );
2504
-    }
2505
-
2506
-
2507
-    /** end of globally available metaboxes section **/
2508
-
2509
-
2510
-    /**
2511
-     * Sets the _template_args arguments used by the _publish_post_box shortcut
2512
-     * Note: currently there is no validation for this.  However, if you want the delete button, the
2513
-     * save, and save and close buttons to work properly, then you will want to include a
2514
-     * values for the name and id arguments.
2515
-     *
2516
-     * @param string|null $name                     key used for the action ID (i.e. event_id)
2517
-     * @param int|string  $id                       id attached to the item published
2518
-     * @param string|null $delete                   page route callback for the delete action
2519
-     * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2520
-     * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2521
-     *                                              or just the "Save" button
2522
-     * @throws EE_Error
2523
-     * @throws InvalidArgumentException
2524
-     * @throws InvalidDataTypeException
2525
-     * @throws InvalidInterfaceException
2526
-     * @todo  Add in validation for name/id arguments.
2527
-     */
2528
-    protected function _set_publish_post_box_vars(
2529
-        ?string $name = '',
2530
-        $id = 0,
2531
-        ?string $delete = '',
2532
-        ?string $save_close_redirect_URL = '',
2533
-        bool $both_btns = true
2534
-    ) {
2535
-        // if Save & Close, use a custom redirect URL or default to the main page?
2536
-        $save_close_redirect_URL = ! empty($save_close_redirect_URL)
2537
-            ? $save_close_redirect_URL
2538
-            : $this->_admin_base_url;
2539
-        // create the Save & Close and Save buttons
2540
-        $this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2541
-        // if we have extra content set let's add it in if not make sure its empty
2542
-        $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2543
-        if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2544
-            // make sure we have a default if just true is sent.
2545
-            $delete                                      = ! empty($delete) ? $delete : 'delete';
2546
-            $this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2547
-                $delete,
2548
-                $delete,
2549
-                [$name => $id],
2550
-                'submitdelete deletion button button--outline button--caution'
2551
-            );
2552
-        }
2553
-        if (! isset($this->_template_args['publish_delete_link'])) {
2554
-            $this->_template_args['publish_delete_link'] = '';
2555
-        }
2556
-        if (! empty($name) && ! empty($id)) {
2557
-            $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2558
-        }
2559
-        $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2560
-        // add hidden fields
2561
-        $this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2562
-        foreach ($hidden_fields as $hidden_field) {
2563
-            $this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2564
-        }
2565
-    }
2566
-
2567
-
2568
-    /**
2569
-     * @param string|null $name
2570
-     * @param int|string  $id
2571
-     * @param string|null $delete
2572
-     * @param string|null $save_close_redirect_URL
2573
-     * @param bool        $both_btns
2574
-     * @throws EE_Error
2575
-     */
2576
-    public function set_publish_post_box_vars(
2577
-        ?string $name = '',
2578
-        $id = 0,
2579
-        ?string $delete = '',
2580
-        ?string $save_close_redirect_URL = '',
2581
-        bool $both_btns = false
2582
-    ) {
2583
-        $this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2584
-    }
2585
-
2586
-
2587
-    protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2588
-    {
2589
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2590
-    }
2591
-
2592
-
2593
-    /**
2594
-     * displays an error message to ppl who have javascript disabled
2595
-     *
2596
-     * @return void
2597
-     */
2598
-    private function _display_no_javascript_warning()
2599
-    {
2600
-        ?>
2395
+	}
2396
+
2397
+
2398
+	private function _espresso_links_post_box()
2399
+	{
2400
+		// Hiding until we actually have content to put in here...
2401
+		// $this->addMetaBox('espresso_links_post_box', esc_html__('Helpful Plugin Links', 'event_espresso'), array( $this, 'espresso_links_post_box'), $this->_wp_page_slug, 'side');
2402
+	}
2403
+
2404
+
2405
+	public function espresso_links_post_box()
2406
+	{
2407
+		// Hiding until we actually have content to put in here...
2408
+		// EEH_Template::display_template(
2409
+		//     EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_links.template.php'
2410
+		// );
2411
+	}
2412
+
2413
+
2414
+	protected function _espresso_sponsors_post_box()
2415
+	{
2416
+		if (apply_filters('FHEE_show_sponsors_meta_box', true)) {
2417
+			$this->addMetaBox(
2418
+				'espresso_sponsors_post_box',
2419
+				esc_html__('Event Espresso Highlights', 'event_espresso'),
2420
+				[$this, 'espresso_sponsors_post_box'],
2421
+				$this->_wp_page_slug,
2422
+				'side'
2423
+			);
2424
+		}
2425
+	}
2426
+
2427
+
2428
+	public function espresso_sponsors_post_box()
2429
+	{
2430
+		EEH_Template::display_template(
2431
+			EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2432
+		);
2433
+	}
2434
+
2435
+
2436
+	/**
2437
+	 * if there is [ 'label' => [ 'publishbox' => 'some title' ]]
2438
+	 * present in the _page_config array, then we'll use that for the metabox label.
2439
+	 * Otherwise we'll just use publish
2440
+	 * (publishbox itself could be an array of labels indexed by routes)
2441
+	 *
2442
+	 * @return string
2443
+	 * @since   5.0.0.p
2444
+	 */
2445
+	protected function getPublishBoxTitle(): string
2446
+	{
2447
+		$publish_box_title = esc_html__('Publish', 'event_espresso');
2448
+		if (! empty($this->_labels['publishbox'])) {
2449
+			if (is_array($this->_labels['publishbox'])) {
2450
+				$publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2451
+			} else {
2452
+				$publish_box_title = $this->_labels['publishbox'];
2453
+			}
2454
+		}
2455
+		return apply_filters(
2456
+			'FHEE__EE_Admin_Page___publish_post_box__box_label',
2457
+			$publish_box_title,
2458
+			$this->_req_action,
2459
+			$this
2460
+		);
2461
+	}
2462
+
2463
+
2464
+	/**
2465
+	 * @throws EE_Error
2466
+	 */
2467
+	private function _publish_post_box()
2468
+	{
2469
+		$title = $this->getPublishBoxTitle();
2470
+		if (empty($this->_template_args['save_buttons'])) {
2471
+			$this->_set_publish_post_box_vars(sanitize_key($title), "espresso_{$this->page_slug}_editor_overview");
2472
+		} else {
2473
+			$this->addPublishPostMetaBoxHiddenFields(
2474
+				sanitize_key($title),
2475
+				['type' => 'hidden', 'value' => "espresso_{$this->page_slug}_editor_overview"]
2476
+			);
2477
+		}
2478
+		$this->addMetaBox(
2479
+			"espresso_{$this->page_slug}_editor_overview",
2480
+			$title,
2481
+			[$this, 'editor_overview'],
2482
+			$this->_current_screen->id,
2483
+			'side',
2484
+			'high'
2485
+		);
2486
+	}
2487
+
2488
+
2489
+	public function editor_overview()
2490
+	{
2491
+		/**
2492
+		 * @var string $publish_box_extra_content
2493
+		 * @var string $publish_hidden_fields
2494
+		 * @var string $publish_delete_link
2495
+		 * @var string $save_buttons
2496
+		 */
2497
+		// if we have extra content set let's add it in if not make sure its empty
2498
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2499
+		echo EEH_Template::display_template(
2500
+			EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2501
+			$this->_template_args,
2502
+			true
2503
+		);
2504
+	}
2505
+
2506
+
2507
+	/** end of globally available metaboxes section **/
2508
+
2509
+
2510
+	/**
2511
+	 * Sets the _template_args arguments used by the _publish_post_box shortcut
2512
+	 * Note: currently there is no validation for this.  However, if you want the delete button, the
2513
+	 * save, and save and close buttons to work properly, then you will want to include a
2514
+	 * values for the name and id arguments.
2515
+	 *
2516
+	 * @param string|null $name                     key used for the action ID (i.e. event_id)
2517
+	 * @param int|string  $id                       id attached to the item published
2518
+	 * @param string|null $delete                   page route callback for the delete action
2519
+	 * @param string|null $save_close_redirect_URL  custom URL to redirect to after Save & Close has been completed
2520
+	 * @param bool        $both_btns                whether to display BOTH the "Save & Close" and "Save" buttons
2521
+	 *                                              or just the "Save" button
2522
+	 * @throws EE_Error
2523
+	 * @throws InvalidArgumentException
2524
+	 * @throws InvalidDataTypeException
2525
+	 * @throws InvalidInterfaceException
2526
+	 * @todo  Add in validation for name/id arguments.
2527
+	 */
2528
+	protected function _set_publish_post_box_vars(
2529
+		?string $name = '',
2530
+		$id = 0,
2531
+		?string $delete = '',
2532
+		?string $save_close_redirect_URL = '',
2533
+		bool $both_btns = true
2534
+	) {
2535
+		// if Save & Close, use a custom redirect URL or default to the main page?
2536
+		$save_close_redirect_URL = ! empty($save_close_redirect_URL)
2537
+			? $save_close_redirect_URL
2538
+			: $this->_admin_base_url;
2539
+		// create the Save & Close and Save buttons
2540
+		$this->_set_save_buttons($both_btns, [], [], $save_close_redirect_URL);
2541
+		// if we have extra content set let's add it in if not make sure its empty
2542
+		$this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2543
+		if ($delete && ! empty($id) && empty($this->_template_args['publish_delete_link'])) {
2544
+			// make sure we have a default if just true is sent.
2545
+			$delete                                      = ! empty($delete) ? $delete : 'delete';
2546
+			$this->_template_args['publish_delete_link'] = $this->get_action_link_or_button(
2547
+				$delete,
2548
+				$delete,
2549
+				[$name => $id],
2550
+				'submitdelete deletion button button--outline button--caution'
2551
+			);
2552
+		}
2553
+		if (! isset($this->_template_args['publish_delete_link'])) {
2554
+			$this->_template_args['publish_delete_link'] = '';
2555
+		}
2556
+		if (! empty($name) && ! empty($id)) {
2557
+			$this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2558
+		}
2559
+		$hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
2560
+		// add hidden fields
2561
+		$this->_template_args['publish_hidden_fields'] = $this->_template_args['publish_hidden_fields'] ?? '';
2562
+		foreach ($hidden_fields as $hidden_field) {
2563
+			$this->_template_args['publish_hidden_fields'] .= $hidden_field['field'] ?? '';
2564
+		}
2565
+	}
2566
+
2567
+
2568
+	/**
2569
+	 * @param string|null $name
2570
+	 * @param int|string  $id
2571
+	 * @param string|null $delete
2572
+	 * @param string|null $save_close_redirect_URL
2573
+	 * @param bool        $both_btns
2574
+	 * @throws EE_Error
2575
+	 */
2576
+	public function set_publish_post_box_vars(
2577
+		?string $name = '',
2578
+		$id = 0,
2579
+		?string $delete = '',
2580
+		?string $save_close_redirect_URL = '',
2581
+		bool $both_btns = false
2582
+	) {
2583
+		$this->_set_publish_post_box_vars($name, $id, $delete, $save_close_redirect_URL, $both_btns);
2584
+	}
2585
+
2586
+
2587
+	protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2588
+	{
2589
+		$this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2590
+	}
2591
+
2592
+
2593
+	/**
2594
+	 * displays an error message to ppl who have javascript disabled
2595
+	 *
2596
+	 * @return void
2597
+	 */
2598
+	private function _display_no_javascript_warning()
2599
+	{
2600
+		?>
2601 2601
 <noscript>
2602 2602
 	<div id="no-js-message" class="error">
2603 2603
 		<p style="font-size:1.3em;">
2604 2604
 			<span style="color:red;"><?php esc_html_e('Warning!', 'event_espresso'); ?></span>
2605 2605
 			<?php esc_html_e(
2606
-                        '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.',
2607
-                        'event_espresso'
2608
-                    ); ?>
2606
+						'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.',
2607
+						'event_espresso'
2608
+					); ?>
2609 2609
 		</p>
2610 2610
 	</div>
2611 2611
 </noscript>
2612 2612
 <?php
2613
-    }
2614
-
2615
-
2616
-    /**
2617
-     * displays espresso success and/or error notices
2618
-     *
2619
-     * @return void
2620
-     */
2621
-    protected function _display_espresso_notices()
2622
-    {
2623
-        $notices = (array) $this->_get_transient(true);
2624
-        foreach ($notices as $notice) {
2625
-            echo $notice ? stripslashes($notice) : '';
2626
-        }
2627
-    }
2628
-
2629
-
2630
-    /**
2631
-     * spinny things pacify the masses
2632
-     *
2633
-     * @return void
2634
-     */
2635
-    protected function _add_admin_page_ajax_loading_img()
2636
-    {
2637
-        ?>
2613
+	}
2614
+
2615
+
2616
+	/**
2617
+	 * displays espresso success and/or error notices
2618
+	 *
2619
+	 * @return void
2620
+	 */
2621
+	protected function _display_espresso_notices()
2622
+	{
2623
+		$notices = (array) $this->_get_transient(true);
2624
+		foreach ($notices as $notice) {
2625
+			echo $notice ? stripslashes($notice) : '';
2626
+		}
2627
+	}
2628
+
2629
+
2630
+	/**
2631
+	 * spinny things pacify the masses
2632
+	 *
2633
+	 * @return void
2634
+	 */
2635
+	protected function _add_admin_page_ajax_loading_img()
2636
+	{
2637
+		?>
2638 2638
 <div id="espresso-ajax-loading" class="ajax-loading-grey">
2639 2639
 	<span class="ee-spinner ee-spin"></span><span class="hidden"><?php
2640
-                esc_html_e('loading...', 'event_espresso'); ?></span>
2640
+				esc_html_e('loading...', 'event_espresso'); ?></span>
2641 2641
 </div>
2642 2642
 <?php
2643
-    }
2643
+	}
2644 2644
 
2645 2645
 
2646
-    /**
2647
-     * add admin page overlay for modal boxes
2648
-     *
2649
-     * @return void
2650
-     */
2651
-    protected function _add_admin_page_overlay()
2652
-    {
2653
-        ?>
2646
+	/**
2647
+	 * add admin page overlay for modal boxes
2648
+	 *
2649
+	 * @return void
2650
+	 */
2651
+	protected function _add_admin_page_overlay()
2652
+	{
2653
+		?>
2654 2654
 <div id="espresso-admin-page-overlay-dv" class=""></div>
2655 2655
 <?php
2656
-    }
2657
-
2658
-
2659
-    /**
2660
-     * facade for $this->addMetaBox()
2661
-     *
2662
-     * @param string   $action        where the metabox gets displayed
2663
-     * @param string   $title         Title of Metabox (output in metabox header)
2664
-     * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2665
-     *                                instead of the one created in here.
2666
-     * @param array    $callback_args an array of args supplied for the metabox
2667
-     * @param string   $column        what metabox column
2668
-     * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2669
-     * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2670
-     *                                created but just set our own callback for wp's add_meta_box.
2671
-     * @throws DomainException
2672
-     */
2673
-    public function _add_admin_page_meta_box(
2674
-        string $action,
2675
-        string $title,
2676
-        callable $callback,
2677
-        array $callback_args,
2678
-        string $column = 'normal',
2679
-        string $priority = 'high',
2680
-        bool $create_func = true
2681
-    ) {
2682
-        // 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.
2683
-        if (empty($callback_args) && $create_func) {
2684
-            $callback_args = [
2685
-                'template_path' => $this->_template_path,
2686
-                'template_args' => $this->_template_args,
2687
-            ];
2688
-        }
2689
-        // 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)
2690
-        $call_back_func = $create_func
2691
-            ? static function ($post, $metabox) {
2692
-                do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2693
-                echo EEH_Template::display_template(
2694
-                    $metabox['args']['template_path'],
2695
-                    $metabox['args']['template_args'],
2696
-                    true
2697
-                );
2698
-            }
2699
-            : $callback;
2700
-        $this->addMetaBox(
2701
-            str_replace('_', '-', $action) . '-mbox',
2702
-            $title,
2703
-            $call_back_func,
2704
-            $this->_wp_page_slug,
2705
-            $column,
2706
-            $priority,
2707
-            $callback_args
2708
-        );
2709
-    }
2710
-
2711
-
2712
-    /**
2713
-     * generates HTML wrapper for and admin details page that contains metaboxes in columns
2714
-     *
2715
-     * @throws DomainException
2716
-     * @throws EE_Error
2717
-     * @throws InvalidArgumentException
2718
-     * @throws InvalidDataTypeException
2719
-     * @throws InvalidInterfaceException
2720
-     */
2721
-    public function display_admin_page_with_metabox_columns()
2722
-    {
2723
-        $this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2724
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2725
-            $this->_column_template_path,
2726
-            $this->_template_args,
2727
-            true
2728
-        );
2729
-        // the final wrapper
2730
-        $this->admin_page_wrapper();
2731
-    }
2732
-
2733
-
2734
-    /**
2735
-     * generates  HTML wrapper for an admin details page
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_admin_page_with_sidebar()
2745
-    {
2746
-        $this->_display_admin_page(true);
2747
-    }
2748
-
2749
-
2750
-    /**
2751
-     * generates  HTML wrapper for an admin details page (except no sidebar)
2752
-     *
2753
-     * @return void
2754
-     * @throws DomainException
2755
-     * @throws EE_Error
2756
-     * @throws InvalidArgumentException
2757
-     * @throws InvalidDataTypeException
2758
-     * @throws InvalidInterfaceException
2759
-     */
2760
-    public function display_admin_page_with_no_sidebar()
2761
-    {
2762
-        $this->_display_admin_page();
2763
-    }
2764
-
2765
-
2766
-    /**
2767
-     * generates HTML wrapper for an EE about admin page (no sidebar)
2768
-     *
2769
-     * @return void
2770
-     * @throws DomainException
2771
-     * @throws EE_Error
2772
-     * @throws InvalidArgumentException
2773
-     * @throws InvalidDataTypeException
2774
-     * @throws InvalidInterfaceException
2775
-     */
2776
-    public function display_about_admin_page()
2777
-    {
2778
-        $this->_display_admin_page(false, true);
2779
-    }
2780
-
2781
-
2782
-    /**
2783
-     * display_admin_page
2784
-     * contains the code for actually displaying an admin page
2785
-     *
2786
-     * @param bool $sidebar true with sidebar, false without
2787
-     * @param bool $about   use the about admin wrapper instead of the default.
2788
-     * @return void
2789
-     * @throws DomainException
2790
-     * @throws EE_Error
2791
-     * @throws InvalidArgumentException
2792
-     * @throws InvalidDataTypeException
2793
-     * @throws InvalidInterfaceException
2794
-     */
2795
-    private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2796
-    {
2797
-        // custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2798
-        do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2799
-
2800
-        // set current wp page slug - looks like: event-espresso_page_event_categories
2801
-        // keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2802
-        $post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2803
-
2804
-        $this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2805
-                                                  && $this->_req_action !== 'data_reset'
2806
-                                                  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2807
-                                                  && strpos($post_body_content, 'wp-list-table') === false;
2808
-
2809
-        $this->_template_args['current_page']                 = $this->_wp_page_slug;
2810
-        $this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2811
-            ? 'poststuff'
2812
-            : 'espresso-default-admin';
2813
-        $this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2814
-                                                                    'event-espresso_page_espresso_',
2815
-                                                                    '',
2816
-                                                                    $this->_wp_page_slug
2817
-                                                                ) . ' ' . $this->_req_action . '-route';
2818
-
2819
-        $template_path = $sidebar
2820
-            ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2821
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2822
-        if ($this->request->isAjax()) {
2823
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2824
-        }
2825
-        $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2826
-
2827
-        $this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2828
-        $this->_template_args['before_admin_page_content'] = $post_body_content;
2829
-        $this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2830
-        $this->_template_args['admin_page_content']        = EEH_Template::display_template(
2831
-            $template_path,
2832
-            $this->_template_args,
2833
-            true
2834
-        );
2835
-        // the final template wrapper
2836
-        $this->admin_page_wrapper($about);
2837
-    }
2838
-
2839
-
2840
-    /**
2841
-     * This is used to display caf preview pages.
2842
-     *
2843
-     * @param string $utm_campaign_source what is the key used for google analytics link
2844
-     * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2845
-     *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2846
-     * @return void
2847
-     * @throws DomainException
2848
-     * @throws EE_Error
2849
-     * @throws InvalidArgumentException
2850
-     * @throws InvalidDataTypeException
2851
-     * @throws InvalidInterfaceException
2852
-     * @since 4.3.2
2853
-     */
2854
-    public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2855
-    {
2856
-        // let's generate a default preview action button if there isn't one already present.
2857
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2858
-            'Upgrade to Event Espresso 4 Right Now',
2859
-            'event_espresso'
2860
-        );
2861
-        $buy_now_url                                   = add_query_arg(
2862
-            [
2863
-                'ee_ver'       => 'ee4',
2864
-                'utm_source'   => 'ee4_plugin_admin',
2865
-                'utm_medium'   => 'link',
2866
-                'utm_campaign' => $utm_campaign_source,
2867
-                'utm_content'  => 'buy_now_button',
2868
-            ],
2869
-            'https://eventespresso.com/pricing/'
2870
-        );
2871
-        $this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2872
-            ? $this->get_action_link_or_button(
2873
-                '',
2874
-                'buy_now',
2875
-                [],
2876
-                'button button--primary button--big',
2877
-                esc_url_raw($buy_now_url),
2878
-                true
2879
-            )
2880
-            : $this->_template_args['preview_action_button'];
2881
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2882
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2883
-            $this->_template_args,
2884
-            true
2885
-        );
2886
-        $this->_display_admin_page($display_sidebar);
2887
-    }
2888
-
2889
-
2890
-    /**
2891
-     * display_admin_list_table_page_with_sidebar
2892
-     * generates HTML wrapper for an admin_page with list_table
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_sidebar()
2902
-    {
2903
-        $this->_display_admin_list_table_page(true);
2904
-    }
2905
-
2906
-
2907
-    /**
2908
-     * display_admin_list_table_page_with_no_sidebar
2909
-     * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2910
-     *
2911
-     * @return void
2912
-     * @throws DomainException
2913
-     * @throws EE_Error
2914
-     * @throws InvalidArgumentException
2915
-     * @throws InvalidDataTypeException
2916
-     * @throws InvalidInterfaceException
2917
-     */
2918
-    public function display_admin_list_table_page_with_no_sidebar()
2919
-    {
2920
-        $this->_display_admin_list_table_page();
2921
-    }
2922
-
2923
-
2924
-    /**
2925
-     * generates html wrapper for an admin_list_table page
2926
-     *
2927
-     * @param bool $sidebar whether to display with sidebar or not.
2928
-     * @return void
2929
-     * @throws DomainException
2930
-     * @throws EE_Error
2931
-     * @throws InvalidArgumentException
2932
-     * @throws InvalidDataTypeException
2933
-     * @throws InvalidInterfaceException
2934
-     */
2935
-    private function _display_admin_list_table_page(bool $sidebar = false)
2936
-    {
2937
-        // setup search attributes
2938
-        $this->_set_search_attributes();
2939
-        $this->_template_args['current_page']     = $this->_wp_page_slug;
2940
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2941
-        $this->_template_args['table_url']        = $this->request->isAjax()
2942
-            ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2943
-            : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2944
-        $this->_template_args['list_table']       = $this->_list_table_object;
2945
-        $this->_template_args['current_route']    = $this->_req_action;
2946
-        $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2947
-        $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2948
-        if (! empty($ajax_sorting_callback)) {
2949
-            $sortable_list_table_form_fields = wp_nonce_field(
2950
-                $ajax_sorting_callback . '_nonce',
2951
-                $ajax_sorting_callback . '_nonce',
2952
-                false,
2953
-                false
2954
-            );
2955
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2956
-                                                . $this->page_slug
2957
-                                                . '" />';
2958
-            $sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2959
-                                                . $ajax_sorting_callback
2960
-                                                . '" />';
2961
-        } else {
2962
-            $sortable_list_table_form_fields = '';
2963
-        }
2964
-        $this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2965
-
2966
-        $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2967
-
2968
-        $nonce_ref          = $this->_req_action . '_nonce';
2969
-        $hidden_form_fields .= '
2656
+	}
2657
+
2658
+
2659
+	/**
2660
+	 * facade for $this->addMetaBox()
2661
+	 *
2662
+	 * @param string   $action        where the metabox gets displayed
2663
+	 * @param string   $title         Title of Metabox (output in metabox header)
2664
+	 * @param callable $callback      If not empty and $create_fun is set to false then we'll use a custom callback
2665
+	 *                                instead of the one created in here.
2666
+	 * @param array    $callback_args an array of args supplied for the metabox
2667
+	 * @param string   $column        what metabox column
2668
+	 * @param string   $priority      give this metabox a priority (using accepted priorities for wp meta boxes)
2669
+	 * @param bool     $create_func   default is true.  Basically we can say we don't WANT to have the runtime function
2670
+	 *                                created but just set our own callback for wp's add_meta_box.
2671
+	 * @throws DomainException
2672
+	 */
2673
+	public function _add_admin_page_meta_box(
2674
+		string $action,
2675
+		string $title,
2676
+		callable $callback,
2677
+		array $callback_args,
2678
+		string $column = 'normal',
2679
+		string $priority = 'high',
2680
+		bool $create_func = true
2681
+	) {
2682
+		// 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.
2683
+		if (empty($callback_args) && $create_func) {
2684
+			$callback_args = [
2685
+				'template_path' => $this->_template_path,
2686
+				'template_args' => $this->_template_args,
2687
+			];
2688
+		}
2689
+		// 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)
2690
+		$call_back_func = $create_func
2691
+			? static function ($post, $metabox) {
2692
+				do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2693
+				echo EEH_Template::display_template(
2694
+					$metabox['args']['template_path'],
2695
+					$metabox['args']['template_args'],
2696
+					true
2697
+				);
2698
+			}
2699
+			: $callback;
2700
+		$this->addMetaBox(
2701
+			str_replace('_', '-', $action) . '-mbox',
2702
+			$title,
2703
+			$call_back_func,
2704
+			$this->_wp_page_slug,
2705
+			$column,
2706
+			$priority,
2707
+			$callback_args
2708
+		);
2709
+	}
2710
+
2711
+
2712
+	/**
2713
+	 * generates HTML wrapper for and admin details page that contains metaboxes in columns
2714
+	 *
2715
+	 * @throws DomainException
2716
+	 * @throws EE_Error
2717
+	 * @throws InvalidArgumentException
2718
+	 * @throws InvalidDataTypeException
2719
+	 * @throws InvalidInterfaceException
2720
+	 */
2721
+	public function display_admin_page_with_metabox_columns()
2722
+	{
2723
+		$this->_template_args['post_body_content']  = $this->_template_args['admin_page_content'];
2724
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2725
+			$this->_column_template_path,
2726
+			$this->_template_args,
2727
+			true
2728
+		);
2729
+		// the final wrapper
2730
+		$this->admin_page_wrapper();
2731
+	}
2732
+
2733
+
2734
+	/**
2735
+	 * generates  HTML wrapper for an admin details page
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_admin_page_with_sidebar()
2745
+	{
2746
+		$this->_display_admin_page(true);
2747
+	}
2748
+
2749
+
2750
+	/**
2751
+	 * generates  HTML wrapper for an admin details page (except no sidebar)
2752
+	 *
2753
+	 * @return void
2754
+	 * @throws DomainException
2755
+	 * @throws EE_Error
2756
+	 * @throws InvalidArgumentException
2757
+	 * @throws InvalidDataTypeException
2758
+	 * @throws InvalidInterfaceException
2759
+	 */
2760
+	public function display_admin_page_with_no_sidebar()
2761
+	{
2762
+		$this->_display_admin_page();
2763
+	}
2764
+
2765
+
2766
+	/**
2767
+	 * generates HTML wrapper for an EE about admin page (no sidebar)
2768
+	 *
2769
+	 * @return void
2770
+	 * @throws DomainException
2771
+	 * @throws EE_Error
2772
+	 * @throws InvalidArgumentException
2773
+	 * @throws InvalidDataTypeException
2774
+	 * @throws InvalidInterfaceException
2775
+	 */
2776
+	public function display_about_admin_page()
2777
+	{
2778
+		$this->_display_admin_page(false, true);
2779
+	}
2780
+
2781
+
2782
+	/**
2783
+	 * display_admin_page
2784
+	 * contains the code for actually displaying an admin page
2785
+	 *
2786
+	 * @param bool $sidebar true with sidebar, false without
2787
+	 * @param bool $about   use the about admin wrapper instead of the default.
2788
+	 * @return void
2789
+	 * @throws DomainException
2790
+	 * @throws EE_Error
2791
+	 * @throws InvalidArgumentException
2792
+	 * @throws InvalidDataTypeException
2793
+	 * @throws InvalidInterfaceException
2794
+	 */
2795
+	private function _display_admin_page(bool $sidebar = false, bool $about = false): void
2796
+	{
2797
+		// custom remove metaboxes hook to add or remove any metaboxes to/from Admin pages.
2798
+		do_action('AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes');
2799
+
2800
+		// set current wp page slug - looks like: event-espresso_page_event_categories
2801
+		// keep in mind "event-espresso" COULD be something else if the top level menu label has been translated.
2802
+		$post_body_content = $this->_template_args['before_admin_page_content'] ?? '';
2803
+
2804
+		$this->_template_args['add_page_frame'] = $this->_req_action !== 'system_status'
2805
+												  && $this->_req_action !== 'data_reset'
2806
+												  && $this->_wp_page_slug !== 'event-espresso_page_espresso_packages'
2807
+												  && strpos($post_body_content, 'wp-list-table') === false;
2808
+
2809
+		$this->_template_args['current_page']                 = $this->_wp_page_slug;
2810
+		$this->_template_args['admin_page_wrapper_div_id']    = $this->_cpt_route
2811
+			? 'poststuff'
2812
+			: 'espresso-default-admin';
2813
+		$this->_template_args['admin_page_wrapper_div_class'] = str_replace(
2814
+																	'event-espresso_page_espresso_',
2815
+																	'',
2816
+																	$this->_wp_page_slug
2817
+																) . ' ' . $this->_req_action . '-route';
2818
+
2819
+		$template_path = $sidebar
2820
+			? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2821
+			: EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2822
+		if ($this->request->isAjax()) {
2823
+			$template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2824
+		}
2825
+		$template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2826
+
2827
+		$this->_template_args['post_body_content']         = $this->_template_args['admin_page_content'] ?? '';
2828
+		$this->_template_args['before_admin_page_content'] = $post_body_content;
2829
+		$this->_template_args['after_admin_page_content']  = $this->_template_args['after_admin_page_content'] ?? '';
2830
+		$this->_template_args['admin_page_content']        = EEH_Template::display_template(
2831
+			$template_path,
2832
+			$this->_template_args,
2833
+			true
2834
+		);
2835
+		// the final template wrapper
2836
+		$this->admin_page_wrapper($about);
2837
+	}
2838
+
2839
+
2840
+	/**
2841
+	 * This is used to display caf preview pages.
2842
+	 *
2843
+	 * @param string $utm_campaign_source what is the key used for google analytics link
2844
+	 * @param bool   $display_sidebar     whether to use the sidebar template or the full template for the page.  TRUE
2845
+	 *                                    = SHOW sidebar, FALSE = no sidebar. Default no sidebar.
2846
+	 * @return void
2847
+	 * @throws DomainException
2848
+	 * @throws EE_Error
2849
+	 * @throws InvalidArgumentException
2850
+	 * @throws InvalidDataTypeException
2851
+	 * @throws InvalidInterfaceException
2852
+	 * @since 4.3.2
2853
+	 */
2854
+	public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2855
+	{
2856
+		// let's generate a default preview action button if there isn't one already present.
2857
+		$this->_labels['buttons']['buy_now']           = esc_html__(
2858
+			'Upgrade to Event Espresso 4 Right Now',
2859
+			'event_espresso'
2860
+		);
2861
+		$buy_now_url                                   = add_query_arg(
2862
+			[
2863
+				'ee_ver'       => 'ee4',
2864
+				'utm_source'   => 'ee4_plugin_admin',
2865
+				'utm_medium'   => 'link',
2866
+				'utm_campaign' => $utm_campaign_source,
2867
+				'utm_content'  => 'buy_now_button',
2868
+			],
2869
+			'https://eventespresso.com/pricing/'
2870
+		);
2871
+		$this->_template_args['preview_action_button'] = ! isset($this->_template_args['preview_action_button'])
2872
+			? $this->get_action_link_or_button(
2873
+				'',
2874
+				'buy_now',
2875
+				[],
2876
+				'button button--primary button--big',
2877
+				esc_url_raw($buy_now_url),
2878
+				true
2879
+			)
2880
+			: $this->_template_args['preview_action_button'];
2881
+		$this->_template_args['admin_page_content']    = EEH_Template::display_template(
2882
+			EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2883
+			$this->_template_args,
2884
+			true
2885
+		);
2886
+		$this->_display_admin_page($display_sidebar);
2887
+	}
2888
+
2889
+
2890
+	/**
2891
+	 * display_admin_list_table_page_with_sidebar
2892
+	 * generates HTML wrapper for an admin_page with list_table
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_sidebar()
2902
+	{
2903
+		$this->_display_admin_list_table_page(true);
2904
+	}
2905
+
2906
+
2907
+	/**
2908
+	 * display_admin_list_table_page_with_no_sidebar
2909
+	 * generates HTML wrapper for an admin_page with list_table (but with no sidebar)
2910
+	 *
2911
+	 * @return void
2912
+	 * @throws DomainException
2913
+	 * @throws EE_Error
2914
+	 * @throws InvalidArgumentException
2915
+	 * @throws InvalidDataTypeException
2916
+	 * @throws InvalidInterfaceException
2917
+	 */
2918
+	public function display_admin_list_table_page_with_no_sidebar()
2919
+	{
2920
+		$this->_display_admin_list_table_page();
2921
+	}
2922
+
2923
+
2924
+	/**
2925
+	 * generates html wrapper for an admin_list_table page
2926
+	 *
2927
+	 * @param bool $sidebar whether to display with sidebar or not.
2928
+	 * @return void
2929
+	 * @throws DomainException
2930
+	 * @throws EE_Error
2931
+	 * @throws InvalidArgumentException
2932
+	 * @throws InvalidDataTypeException
2933
+	 * @throws InvalidInterfaceException
2934
+	 */
2935
+	private function _display_admin_list_table_page(bool $sidebar = false)
2936
+	{
2937
+		// setup search attributes
2938
+		$this->_set_search_attributes();
2939
+		$this->_template_args['current_page']     = $this->_wp_page_slug;
2940
+		$template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2941
+		$this->_template_args['table_url']        = $this->request->isAjax()
2942
+			? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2943
+			: add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
2944
+		$this->_template_args['list_table']       = $this->_list_table_object;
2945
+		$this->_template_args['current_route']    = $this->_req_action;
2946
+		$this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2947
+		$ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2948
+		if (! empty($ajax_sorting_callback)) {
2949
+			$sortable_list_table_form_fields = wp_nonce_field(
2950
+				$ajax_sorting_callback . '_nonce',
2951
+				$ajax_sorting_callback . '_nonce',
2952
+				false,
2953
+				false
2954
+			);
2955
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_page" name="ajax_table_sort_page" value="'
2956
+												. $this->page_slug
2957
+												. '" />';
2958
+			$sortable_list_table_form_fields .= '<input type="hidden" id="ajax_table_sort_action" name="ajax_table_sort_action" value="'
2959
+												. $ajax_sorting_callback
2960
+												. '" />';
2961
+		} else {
2962
+			$sortable_list_table_form_fields = '';
2963
+		}
2964
+		$this->_template_args['sortable_list_table_form_fields'] = $sortable_list_table_form_fields;
2965
+
2966
+		$hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2967
+
2968
+		$nonce_ref          = $this->_req_action . '_nonce';
2969
+		$hidden_form_fields .= '
2970 2970
             <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2971 2971
 
2972
-        $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2973
-        // display message about search results?
2974
-        $search                                    = $this->request->getRequestParam('s');
2975
-        $this->_template_args['before_list_table'] .= ! empty($search)
2976
-            ? '<p class="ee-search-results">' . sprintf(
2977
-                esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2978
-                trim($search, '%')
2979
-            ) . '</p>'
2980
-            : '';
2981
-        // filter before_list_table template arg
2982
-        $this->_template_args['before_list_table'] = apply_filters(
2983
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2984
-            $this->_template_args['before_list_table'],
2985
-            $this->page_slug,
2986
-            $this->request->requestParams(),
2987
-            $this->_req_action
2988
-        );
2989
-        // convert to array and filter again
2990
-        // arrays are easier to inject new items in a specific location,
2991
-        // but would not be backwards compatible, so we have to add a new filter
2992
-        $this->_template_args['before_list_table'] = implode(
2993
-            " \n",
2994
-            (array) apply_filters(
2995
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2996
-                (array) $this->_template_args['before_list_table'],
2997
-                $this->page_slug,
2998
-                $this->request->requestParams(),
2999
-                $this->_req_action
3000
-            )
3001
-        );
3002
-        // filter after_list_table template arg
3003
-        $this->_template_args['after_list_table'] = apply_filters(
3004
-            'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3005
-            $this->_template_args['after_list_table'],
3006
-            $this->page_slug,
3007
-            $this->request->requestParams(),
3008
-            $this->_req_action
3009
-        );
3010
-        // convert to array and filter again
3011
-        // arrays are easier to inject new items in a specific location,
3012
-        // but would not be backwards compatible, so we have to add a new filter
3013
-        $this->_template_args['after_list_table']   = implode(
3014
-            " \n",
3015
-            (array) apply_filters(
3016
-                'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3017
-                (array) $this->_template_args['after_list_table'],
3018
-                $this->page_slug,
3019
-                $this->request->requestParams(),
3020
-                $this->_req_action
3021
-            )
3022
-        );
3023
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3024
-            $template_path,
3025
-            $this->_template_args,
3026
-            true
3027
-        );
3028
-        // the final template wrapper
3029
-        if ($sidebar) {
3030
-            $this->display_admin_page_with_sidebar();
3031
-        } else {
3032
-            $this->display_admin_page_with_no_sidebar();
3033
-        }
3034
-    }
3035
-
3036
-
3037
-    /**
3038
-     * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3039
-     * html string for the legend.
3040
-     * $items are expected in an array in the following format:
3041
-     * $legend_items = array(
3042
-     *        'item_id' => array(
3043
-     *            'icon' => 'http://url_to_icon_being_described.png',
3044
-     *            'desc' => esc_html__('localized description of item');
3045
-     *        )
3046
-     * );
3047
-     *
3048
-     * @param array $items see above for format of array
3049
-     * @return string html string of legend
3050
-     * @throws DomainException
3051
-     */
3052
-    protected function _display_legend(array $items): string
3053
-    {
3054
-        $this->_template_args['items'] = (array) apply_filters(
3055
-            'FHEE__EE_Admin_Page___display_legend__items',
3056
-            $items,
3057
-            $this
3058
-        );
3059
-        /** @var StatusChangeNotice $status_change_notice */
3060
-        $status_change_notice                         = $this->loader->getShared(
3061
-            'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3062
-        );
3063
-        $this->_template_args['status_change_notice'] = $status_change_notice->display(
3064
-            '__admin-legend',
3065
-            $this->page_slug
3066
-        );
3067
-        return EEH_Template::display_template(
3068
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3069
-            $this->_template_args,
3070
-            true
3071
-        );
3072
-    }
3073
-
3074
-
3075
-    /**
3076
-     * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3077
-     * The returned json object is created from an array in the following format:
3078
-     * array(
3079
-     *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3080
-     *  'success' => FALSE, //(default FALSE) - contains any special success message.
3081
-     *  'notices' => '', // - contains any EE_Error formatted notices
3082
-     *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3083
-     *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3084
-     *  We're also going to include the template args with every package (so js can pick out any specific template args
3085
-     *  that might be included in here)
3086
-     * )
3087
-     * The json object is populated by whatever is set in the $_template_args property.
3088
-     *
3089
-     * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3090
-     *                                 instead of displayed.
3091
-     * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3092
-     * @return void
3093
-     * @throws EE_Error
3094
-     * @throws InvalidArgumentException
3095
-     * @throws InvalidDataTypeException
3096
-     * @throws InvalidInterfaceException
3097
-     */
3098
-    protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3099
-    {
3100
-        // make sure any EE_Error notices have been handled.
3101
-        $this->_process_notices($notices_arguments, true, $sticky_notices);
3102
-        $data = $this->_template_args['data'] ?? [];
3103
-        unset($this->_template_args['data']);
3104
-        $json = [
3105
-            'error'     => $this->_template_args['error'] ?? false,
3106
-            'success'   => $this->_template_args['success'] ?? false,
3107
-            'errors'    => $this->_template_args['errors'] ?? false,
3108
-            'attention' => $this->_template_args['attention'] ?? false,
3109
-            'notices'   => EE_Error::get_notices(),
3110
-            'content'   => $this->_template_args['admin_page_content'] ?? '',
3111
-            'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3112
-            'isEEajax'  => true,
3113
-            // special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3114
-        ];
3115
-        // make sure there are no php errors or headers_sent.  Then we can set correct json header.
3116
-        if (null === error_get_last() || ! headers_sent()) {
3117
-            header('Content-Type: application/json; charset=UTF-8');
3118
-        }
3119
-        echo wp_json_encode($json);
3120
-        exit();
3121
-    }
3122
-
3123
-
3124
-    /**
3125
-     * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3126
-     *
3127
-     * @return void
3128
-     * @throws EE_Error
3129
-     * @throws InvalidArgumentException
3130
-     * @throws InvalidDataTypeException
3131
-     * @throws InvalidInterfaceException
3132
-     */
3133
-    public function return_json()
3134
-    {
3135
-        if ($this->request->isAjax()) {
3136
-            $this->_return_json();
3137
-        } else {
3138
-            throw new EE_Error(
3139
-                sprintf(
3140
-                    esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3141
-                    __FUNCTION__
3142
-                )
3143
-            );
3144
-        }
3145
-    }
3146
-
3147
-
3148
-    /**
3149
-     * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3150
-     * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3151
-     *
3152
-     * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3153
-     * @deprecated  5.0.8.p
3154
-     */
3155
-    public function set_hook_object(EE_Admin_Hooks $hook_obj)
3156
-    {
3157
-        $this->_hook_obj = $hook_obj;
3158
-    }
3159
-
3160
-
3161
-    /**
3162
-     *        generates  HTML wrapper with Tabbed nav for an admin page
3163
-     *
3164
-     * @param bool $about whether to use the special about page wrapper or default.
3165
-     * @return void
3166
-     * @throws DomainException
3167
-     * @throws EE_Error
3168
-     * @throws InvalidArgumentException
3169
-     * @throws InvalidDataTypeException
3170
-     * @throws InvalidInterfaceException
3171
-     */
3172
-    public function admin_page_wrapper(bool $about = false)
3173
-    {
3174
-        $this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3175
-        $this->_template_args['admin_page_title'] = $this->_admin_page_title;
3176
-
3177
-        $this->_template_args['before_admin_page_content'] = apply_filters(
3178
-            "FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3179
-            $this->_template_args['before_admin_page_content'] ?? ''
3180
-        );
3181
-
3182
-        $this->_template_args['after_admin_page_content'] = apply_filters(
3183
-            "FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3184
-            $this->_template_args['after_admin_page_content'] ?? ''
3185
-        );
3186
-        $this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3187
-
3188
-        if ($this->request->isAjax()) {
3189
-            $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3190
-            // $template_path,
3191
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3192
-                $this->_template_args,
3193
-                true
3194
-            );
3195
-            $this->_return_json();
3196
-        }
3197
-        // load settings page wrapper template
3198
-        $template_path = $about
3199
-            ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3200
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3201
-
3202
-        EEH_Template::display_template($template_path, $this->_template_args);
3203
-    }
3204
-
3205
-
3206
-    /**
3207
-     * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3208
-     *
3209
-     * @return string html
3210
-     * @throws EE_Error
3211
-     */
3212
-    protected function _get_main_nav_tabs(): string
3213
-    {
3214
-        // let's generate the html using the EEH_Tabbed_Content helper.
3215
-        // We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3216
-        // (rather than setting in the page_routes array)
3217
-        return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3218
-    }
3219
-
3220
-
3221
-    /**
3222
-     *        sort nav tabs
3223
-     *
3224
-     * @param array $a
3225
-     * @param array $b
3226
-     * @return int
3227
-     */
3228
-    private function _sort_nav_tabs(array $a, array $b): int
3229
-    {
3230
-        if ($a['order'] === $b['order']) {
3231
-            return 0;
3232
-        }
3233
-        return ($a['order'] < $b['order']) ? -1 : 1;
3234
-    }
3235
-
3236
-
3237
-    /**
3238
-     * generates HTML for the forms used on admin pages
3239
-     *
3240
-     * @param array  $input_vars - array of input field details
3241
-     * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3242
-     * @param bool   $id
3243
-     * @return array|string
3244
-     * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3245
-     * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3246
-     */
3247
-    protected function _generate_admin_form_fields(
3248
-        array $input_vars = [],
3249
-        string $generator = 'string',
3250
-        bool $id = false
3251
-    ) {
3252
-        return $generator === 'string'
3253
-            ? EEH_Form_Fields::get_form_fields($input_vars, $id)
3254
-            : EEH_Form_Fields::get_form_fields_array($input_vars);
3255
-    }
3256
-
3257
-
3258
-    /**
3259
-     * generates the "Save" and "Save & Close" buttons for edit forms
3260
-     *
3261
-     * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3262
-     *                                   Close" button.
3263
-     * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3264
-     *                                   'Save', [1] => 'save & close')
3265
-     * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3266
-     *                                   via the "name" value in the button).  We can also use this to just dump
3267
-     *                                   default actions by submitting some other value.
3268
-     * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3269
-     *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3270
-     *                                   close (normal form handling).
3271
-     */
3272
-    protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3273
-    {
3274
-        $referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3275
-        $button_text   = ! empty($text)
3276
-            ? $text
3277
-            : [
3278
-                esc_html__('Save', 'event_espresso'),
3279
-                esc_html__('Save and Close', 'event_espresso'),
3280
-            ];
3281
-        $default_names = ['save', 'save_and_close'];
3282
-        $buttons       = '';
3283
-        foreach ($button_text as $key => $button) {
3284
-            $ref     = $default_names[ $key ];
3285
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3286
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3287
-                        . 'value="' . $button . '" name="' . $name . '" '
3288
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3289
-            if (! $both) {
3290
-                break;
3291
-            }
3292
-        }
3293
-        // add in a hidden index for the current page (so save and close redirects properly)
3294
-        $buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3295
-                    . $referrer_url
3296
-                    . '" />';
3297
-
3298
-        $this->_template_args['save_buttons'] = $buttons;
3299
-    }
3300
-
3301
-
3302
-    /**
3303
-     * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3304
-     *
3305
-     * @param string $route
3306
-     * @param array  $additional_hidden_fields
3307
-     * @see   $this->_set_add_edit_form_tags() for details on params
3308
-     * @since 4.6.0
3309
-     */
3310
-    public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3311
-    {
3312
-        $this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3313
-    }
3314
-
3315
-
3316
-    /**
3317
-     * set form open and close tags on add/edit pages.
3318
-     *
3319
-     * @param string $route                    the route you want the form to direct to
3320
-     * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3321
-     * @return void
3322
-     */
3323
-    protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3324
-    {
3325
-        if (empty($route)) {
3326
-            $user_msg = esc_html__(
3327
-                'An error occurred. No action was set for this page\'s form.',
3328
-                'event_espresso'
3329
-            );
3330
-            $dev_msg  = $user_msg . "\n"
3331
-                        . sprintf(
3332
-                            esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3333
-                            __FUNCTION__,
3334
-                            __CLASS__
3335
-                        );
3336
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3337
-        }
3338
-        // open form
3339
-        $action                                            = $this->_admin_base_url;
3340
-        $this->_template_args['before_admin_page_content'] = "
2972
+		$this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2973
+		// display message about search results?
2974
+		$search                                    = $this->request->getRequestParam('s');
2975
+		$this->_template_args['before_list_table'] .= ! empty($search)
2976
+			? '<p class="ee-search-results">' . sprintf(
2977
+				esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2978
+				trim($search, '%')
2979
+			) . '</p>'
2980
+			: '';
2981
+		// filter before_list_table template arg
2982
+		$this->_template_args['before_list_table'] = apply_filters(
2983
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg',
2984
+			$this->_template_args['before_list_table'],
2985
+			$this->page_slug,
2986
+			$this->request->requestParams(),
2987
+			$this->_req_action
2988
+		);
2989
+		// convert to array and filter again
2990
+		// arrays are easier to inject new items in a specific location,
2991
+		// but would not be backwards compatible, so we have to add a new filter
2992
+		$this->_template_args['before_list_table'] = implode(
2993
+			" \n",
2994
+			(array) apply_filters(
2995
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_args_array',
2996
+				(array) $this->_template_args['before_list_table'],
2997
+				$this->page_slug,
2998
+				$this->request->requestParams(),
2999
+				$this->_req_action
3000
+			)
3001
+		);
3002
+		// filter after_list_table template arg
3003
+		$this->_template_args['after_list_table'] = apply_filters(
3004
+			'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_arg',
3005
+			$this->_template_args['after_list_table'],
3006
+			$this->page_slug,
3007
+			$this->request->requestParams(),
3008
+			$this->_req_action
3009
+		);
3010
+		// convert to array and filter again
3011
+		// arrays are easier to inject new items in a specific location,
3012
+		// but would not be backwards compatible, so we have to add a new filter
3013
+		$this->_template_args['after_list_table']   = implode(
3014
+			" \n",
3015
+			(array) apply_filters(
3016
+				'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
3017
+				(array) $this->_template_args['after_list_table'],
3018
+				$this->page_slug,
3019
+				$this->request->requestParams(),
3020
+				$this->_req_action
3021
+			)
3022
+		);
3023
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3024
+			$template_path,
3025
+			$this->_template_args,
3026
+			true
3027
+		);
3028
+		// the final template wrapper
3029
+		if ($sidebar) {
3030
+			$this->display_admin_page_with_sidebar();
3031
+		} else {
3032
+			$this->display_admin_page_with_no_sidebar();
3033
+		}
3034
+	}
3035
+
3036
+
3037
+	/**
3038
+	 * This just prepares a legend using the given items and the admin_details_legend.template.php file and returns the
3039
+	 * html string for the legend.
3040
+	 * $items are expected in an array in the following format:
3041
+	 * $legend_items = array(
3042
+	 *        'item_id' => array(
3043
+	 *            'icon' => 'http://url_to_icon_being_described.png',
3044
+	 *            'desc' => esc_html__('localized description of item');
3045
+	 *        )
3046
+	 * );
3047
+	 *
3048
+	 * @param array $items see above for format of array
3049
+	 * @return string html string of legend
3050
+	 * @throws DomainException
3051
+	 */
3052
+	protected function _display_legend(array $items): string
3053
+	{
3054
+		$this->_template_args['items'] = (array) apply_filters(
3055
+			'FHEE__EE_Admin_Page___display_legend__items',
3056
+			$items,
3057
+			$this
3058
+		);
3059
+		/** @var StatusChangeNotice $status_change_notice */
3060
+		$status_change_notice                         = $this->loader->getShared(
3061
+			'EventEspresso\core\domain\services\admin\notices\status_change\StatusChangeNotice'
3062
+		);
3063
+		$this->_template_args['status_change_notice'] = $status_change_notice->display(
3064
+			'__admin-legend',
3065
+			$this->page_slug
3066
+		);
3067
+		return EEH_Template::display_template(
3068
+			EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3069
+			$this->_template_args,
3070
+			true
3071
+		);
3072
+	}
3073
+
3074
+
3075
+	/**
3076
+	 * This is used whenever we're DOING_AJAX to return a formatted json array that our calling javascript can expect
3077
+	 * The returned json object is created from an array in the following format:
3078
+	 * array(
3079
+	 *  'error' => FALSE, //(default FALSE), contains any errors and/or exceptions (exceptions return json early),
3080
+	 *  'success' => FALSE, //(default FALSE) - contains any special success message.
3081
+	 *  'notices' => '', // - contains any EE_Error formatted notices
3082
+	 *  'content' => 'string can be html', //this is a string of formatted content (can be html)
3083
+	 *  'data' => array() //this can be any key/value pairs that a method returns for later json parsing by the js.
3084
+	 *  We're also going to include the template args with every package (so js can pick out any specific template args
3085
+	 *  that might be included in here)
3086
+	 * )
3087
+	 * The json object is populated by whatever is set in the $_template_args property.
3088
+	 *
3089
+	 * @param bool  $sticky_notices    Used to indicate whether you want to ensure notices are added to a transient
3090
+	 *                                 instead of displayed.
3091
+	 * @param array $notices_arguments Use this to pass any additional args on to the _process_notices.
3092
+	 * @return void
3093
+	 * @throws EE_Error
3094
+	 * @throws InvalidArgumentException
3095
+	 * @throws InvalidDataTypeException
3096
+	 * @throws InvalidInterfaceException
3097
+	 */
3098
+	protected function _return_json(bool $sticky_notices = false, array $notices_arguments = [])
3099
+	{
3100
+		// make sure any EE_Error notices have been handled.
3101
+		$this->_process_notices($notices_arguments, true, $sticky_notices);
3102
+		$data = $this->_template_args['data'] ?? [];
3103
+		unset($this->_template_args['data']);
3104
+		$json = [
3105
+			'error'     => $this->_template_args['error'] ?? false,
3106
+			'success'   => $this->_template_args['success'] ?? false,
3107
+			'errors'    => $this->_template_args['errors'] ?? false,
3108
+			'attention' => $this->_template_args['attention'] ?? false,
3109
+			'notices'   => EE_Error::get_notices(),
3110
+			'content'   => $this->_template_args['admin_page_content'] ?? '',
3111
+			'data'      => array_merge($data, ['template_args' => $this->_template_args]),
3112
+			'isEEajax'  => true,
3113
+			// special flag so any ajax.Success methods in js can identify this return package as a EEajax package.
3114
+		];
3115
+		// make sure there are no php errors or headers_sent.  Then we can set correct json header.
3116
+		if (null === error_get_last() || ! headers_sent()) {
3117
+			header('Content-Type: application/json; charset=UTF-8');
3118
+		}
3119
+		echo wp_json_encode($json);
3120
+		exit();
3121
+	}
3122
+
3123
+
3124
+	/**
3125
+	 * Simply a wrapper for the protected method so we can call this outside the class (ONLY when doing ajax)
3126
+	 *
3127
+	 * @return void
3128
+	 * @throws EE_Error
3129
+	 * @throws InvalidArgumentException
3130
+	 * @throws InvalidDataTypeException
3131
+	 * @throws InvalidInterfaceException
3132
+	 */
3133
+	public function return_json()
3134
+	{
3135
+		if ($this->request->isAjax()) {
3136
+			$this->_return_json();
3137
+		} else {
3138
+			throw new EE_Error(
3139
+				sprintf(
3140
+					esc_html__('The public %s method can only be called when DOING_AJAX = TRUE', 'event_espresso'),
3141
+					__FUNCTION__
3142
+				)
3143
+			);
3144
+		}
3145
+	}
3146
+
3147
+
3148
+	/**
3149
+	 * This provides a way for child hook classes to send along themselves by reference so methods/properties within
3150
+	 * them can be accessed by EE_Admin_child pages. This is assigned to the $_hook_obj property.
3151
+	 *
3152
+	 * @param EE_Admin_Hooks $hook_obj This will be the object for the EE_Admin_Hooks child
3153
+	 * @deprecated  5.0.8.p
3154
+	 */
3155
+	public function set_hook_object(EE_Admin_Hooks $hook_obj)
3156
+	{
3157
+		$this->_hook_obj = $hook_obj;
3158
+	}
3159
+
3160
+
3161
+	/**
3162
+	 *        generates  HTML wrapper with Tabbed nav for an admin page
3163
+	 *
3164
+	 * @param bool $about whether to use the special about page wrapper or default.
3165
+	 * @return void
3166
+	 * @throws DomainException
3167
+	 * @throws EE_Error
3168
+	 * @throws InvalidArgumentException
3169
+	 * @throws InvalidDataTypeException
3170
+	 * @throws InvalidInterfaceException
3171
+	 */
3172
+	public function admin_page_wrapper(bool $about = false)
3173
+	{
3174
+		$this->_template_args['nav_tabs']         = $this->_get_main_nav_tabs();
3175
+		$this->_template_args['admin_page_title'] = $this->_admin_page_title;
3176
+
3177
+		$this->_template_args['before_admin_page_content'] = apply_filters(
3178
+			"FHEE_before_admin_page_content$this->_current_page$this->_current_view",
3179
+			$this->_template_args['before_admin_page_content'] ?? ''
3180
+		);
3181
+
3182
+		$this->_template_args['after_admin_page_content'] = apply_filters(
3183
+			"FHEE_after_admin_page_content$this->_current_page$this->_current_view",
3184
+			$this->_template_args['after_admin_page_content'] ?? ''
3185
+		);
3186
+		$this->_template_args['after_admin_page_content'] .= $this->_set_help_popup_content();
3187
+
3188
+		if ($this->request->isAjax()) {
3189
+			$this->_template_args['admin_page_content'] = EEH_Template::display_template(
3190
+			// $template_path,
3191
+				EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3192
+				$this->_template_args,
3193
+				true
3194
+			);
3195
+			$this->_return_json();
3196
+		}
3197
+		// load settings page wrapper template
3198
+		$template_path = $about
3199
+			? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3200
+			: EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3201
+
3202
+		EEH_Template::display_template($template_path, $this->_template_args);
3203
+	}
3204
+
3205
+
3206
+	/**
3207
+	 * This returns the admin_nav tabs html using the configuration in the _nav_tabs property
3208
+	 *
3209
+	 * @return string html
3210
+	 * @throws EE_Error
3211
+	 */
3212
+	protected function _get_main_nav_tabs(): string
3213
+	{
3214
+		// let's generate the html using the EEH_Tabbed_Content helper.
3215
+		// We do this here so that it's possible for child classes to add in nav tabs dynamically at the last minute
3216
+		// (rather than setting in the page_routes array)
3217
+		return EEH_Tabbed_Content::display_admin_nav_tabs($this->_nav_tabs, $this->page_slug);
3218
+	}
3219
+
3220
+
3221
+	/**
3222
+	 *        sort nav tabs
3223
+	 *
3224
+	 * @param array $a
3225
+	 * @param array $b
3226
+	 * @return int
3227
+	 */
3228
+	private function _sort_nav_tabs(array $a, array $b): int
3229
+	{
3230
+		if ($a['order'] === $b['order']) {
3231
+			return 0;
3232
+		}
3233
+		return ($a['order'] < $b['order']) ? -1 : 1;
3234
+	}
3235
+
3236
+
3237
+	/**
3238
+	 * generates HTML for the forms used on admin pages
3239
+	 *
3240
+	 * @param array  $input_vars - array of input field details
3241
+	 * @param string $generator  indicates which generator to use: options are 'string' or 'array'
3242
+	 * @param bool   $id
3243
+	 * @return array|string
3244
+	 * @uses   EEH_Form_Fields::get_form_fields (/helper/EEH_Form_Fields.helper.php)
3245
+	 * @uses   EEH_Form_Fields::get_form_fields_array (/helper/EEH_Form_Fields.helper.php)
3246
+	 */
3247
+	protected function _generate_admin_form_fields(
3248
+		array $input_vars = [],
3249
+		string $generator = 'string',
3250
+		bool $id = false
3251
+	) {
3252
+		return $generator === 'string'
3253
+			? EEH_Form_Fields::get_form_fields($input_vars, $id)
3254
+			: EEH_Form_Fields::get_form_fields_array($input_vars);
3255
+	}
3256
+
3257
+
3258
+	/**
3259
+	 * generates the "Save" and "Save & Close" buttons for edit forms
3260
+	 *
3261
+	 * @param bool             $both     if true then both buttons will be generated.  If false then just the "Save &
3262
+	 *                                   Close" button.
3263
+	 * @param array            $text     if included, generator will use the given text for the buttons ( array([0] =>
3264
+	 *                                   'Save', [1] => 'save & close')
3265
+	 * @param array            $actions  if included allows us to set the actions that each button will carry out (i.e.
3266
+	 *                                   via the "name" value in the button).  We can also use this to just dump
3267
+	 *                                   default actions by submitting some other value.
3268
+	 * @param bool|string|null $referrer if false then we just do the default action on save and close.  Other wise it
3269
+	 *                                   will use the $referrer string. IF null, then we don't do ANYTHING on save and
3270
+	 *                                   close (normal form handling).
3271
+	 */
3272
+	protected function _set_save_buttons(bool $both = true, array $text = [], array $actions = [], $referrer = null)
3273
+	{
3274
+		$referrer_url  = ! empty($referrer) ? $referrer : $this->request->getServerParam('REQUEST_URI');
3275
+		$button_text   = ! empty($text)
3276
+			? $text
3277
+			: [
3278
+				esc_html__('Save', 'event_espresso'),
3279
+				esc_html__('Save and Close', 'event_espresso'),
3280
+			];
3281
+		$default_names = ['save', 'save_and_close'];
3282
+		$buttons       = '';
3283
+		foreach ($button_text as $key => $button) {
3284
+			$ref     = $default_names[ $key ];
3285
+			$name    = ! empty($actions) ? $actions[ $key ] : $ref;
3286
+			$buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3287
+						. 'value="' . $button . '" name="' . $name . '" '
3288
+						. 'id="' . $this->_current_view . '_' . $ref . '" />';
3289
+			if (! $both) {
3290
+				break;
3291
+			}
3292
+		}
3293
+		// add in a hidden index for the current page (so save and close redirects properly)
3294
+		$buttons .= '<input type="hidden" id="save_and_close_referrer" name="save_and_close_referrer" value="'
3295
+					. $referrer_url
3296
+					. '" />';
3297
+
3298
+		$this->_template_args['save_buttons'] = $buttons;
3299
+	}
3300
+
3301
+
3302
+	/**
3303
+	 * Wrapper for the protected function.  Allows plugins/addons to call this to set the form tags.
3304
+	 *
3305
+	 * @param string $route
3306
+	 * @param array  $additional_hidden_fields
3307
+	 * @see   $this->_set_add_edit_form_tags() for details on params
3308
+	 * @since 4.6.0
3309
+	 */
3310
+	public function set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3311
+	{
3312
+		$this->_set_add_edit_form_tags($route, $additional_hidden_fields);
3313
+	}
3314
+
3315
+
3316
+	/**
3317
+	 * set form open and close tags on add/edit pages.
3318
+	 *
3319
+	 * @param string $route                    the route you want the form to direct to
3320
+	 * @param array  $additional_hidden_fields any additional hidden fields required in the form header
3321
+	 * @return void
3322
+	 */
3323
+	protected function _set_add_edit_form_tags(string $route = '', array $additional_hidden_fields = [])
3324
+	{
3325
+		if (empty($route)) {
3326
+			$user_msg = esc_html__(
3327
+				'An error occurred. No action was set for this page\'s form.',
3328
+				'event_espresso'
3329
+			);
3330
+			$dev_msg  = $user_msg . "\n"
3331
+						. sprintf(
3332
+							esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3333
+							__FUNCTION__,
3334
+							__CLASS__
3335
+						);
3336
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3337
+		}
3338
+		// open form
3339
+		$action                                            = $this->_admin_base_url;
3340
+		$this->_template_args['before_admin_page_content'] = "
3341 3341
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3342 3342
             ";
3343
-        // add nonce
3344
-        $nonce                                             =
3345
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3346
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3347
-        // add REQUIRED form action
3348
-        $hidden_fields = [
3349
-            'action' => ['type' => 'hidden', 'value' => $route],
3350
-        ];
3351
-        // merge arrays
3352
-        $hidden_fields = is_array($additional_hidden_fields)
3353
-            ? array_merge($hidden_fields, $additional_hidden_fields)
3354
-            : $hidden_fields;
3355
-        // generate form fields
3356
-        $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3357
-        // add fields to form
3358
-        foreach ((array) $form_fields as $form_field) {
3359
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3360
-        }
3361
-        // close form
3362
-        $this->_template_args['after_admin_page_content'] = '</form>';
3363
-    }
3364
-
3365
-
3366
-    /**
3367
-     * Public Wrapper for _redirect_after_action() method since its
3368
-     * discovered it would be useful for external code to have access.
3369
-     *
3370
-     * @param bool|int $success
3371
-     * @param string   $what
3372
-     * @param string   $action_desc
3373
-     * @param array    $query_args
3374
-     * @param bool     $override_overwrite
3375
-     * @throws EE_Error
3376
-     * @see   EE_Admin_Page::_redirect_after_action() for params.
3377
-     * @since 4.5.0
3378
-     */
3379
-    public function redirect_after_action(
3380
-        $success = false,
3381
-        string $what = 'item',
3382
-        string $action_desc = 'processed',
3383
-        array $query_args = [],
3384
-        bool $override_overwrite = false
3385
-    ) {
3386
-        $this->_redirect_after_action(
3387
-            $success,
3388
-            $what,
3389
-            $action_desc,
3390
-            $query_args,
3391
-            $override_overwrite
3392
-        );
3393
-    }
3394
-
3395
-
3396
-    /**
3397
-     * Helper method for merging existing request data with the returned redirect url.
3398
-     * This is typically used for redirects after an action so that if the original view was a filtered view those
3399
-     * filters are still applied.
3400
-     *
3401
-     * @param array $new_route_data
3402
-     * @return array
3403
-     */
3404
-    protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3405
-    {
3406
-        foreach ($this->request->requestParams() as $ref => $value) {
3407
-            // unset nonces
3408
-            if (strpos($ref, 'nonce') !== false) {
3409
-                $this->request->unSetRequestParam($ref);
3410
-                continue;
3411
-            }
3412
-            // urlencode values.
3413
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3414
-            $this->request->setRequestParam($ref, $value);
3415
-        }
3416
-        return array_merge($this->request->requestParams(), $new_route_data);
3417
-    }
3418
-
3419
-
3420
-    /**
3421
-     * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3422
-     * @param string           $what               - what the action was performed on
3423
-     * @param string           $action_desc        - what was done ie: updated, deleted, etc
3424
-     * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3425
-     * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3426
-     *                                             this allows you to override this so that they show.
3427
-     * @return void
3428
-     * @throws EE_Error
3429
-     * @throws InvalidArgumentException
3430
-     * @throws InvalidDataTypeException
3431
-     * @throws InvalidInterfaceException
3432
-     */
3433
-    protected function _redirect_after_action(
3434
-        $success = 0,
3435
-        string $what = 'item',
3436
-        string $action_desc = 'processed',
3437
-        array $query_args = [],
3438
-        bool $override_overwrite = false
3439
-    ) {
3440
-        $notices = EE_Error::get_notices(false);
3441
-        // overwrite default success messages //BUT ONLY if overwrite not overridden
3442
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3443
-            EE_Error::overwrite_success();
3444
-        }
3445
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3446
-            // how many records affected ? more than one record ? or just one ?
3447
-            EE_Error::add_success(
3448
-                sprintf(
3449
-                    esc_html(
3450
-                        _n(
3451
-                            'The "%1$s" has been successfully %2$s.',
3452
-                            'The "%1$s" have been successfully %2$s.',
3453
-                            $success,
3454
-                            'event_espresso'
3455
-                        )
3456
-                    ),
3457
-                    $what,
3458
-                    $action_desc
3459
-                ),
3460
-                __FILE__,
3461
-                __FUNCTION__,
3462
-                __LINE__
3463
-            );
3464
-        }
3465
-        // check that $query_args isn't something crazy
3466
-        $query_args = is_array($query_args) ? $query_args : [];
3467
-        /**
3468
-         * Allow injecting actions before the query_args are modified for possible different
3469
-         * redirections on save and close actions
3470
-         *
3471
-         * @param array $query_args       The original query_args array coming into the
3472
-         *                                method.
3473
-         * @since 4.2.0
3474
-         */
3475
-        do_action(
3476
-            "AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3477
-            $query_args
3478
-        );
3479
-        // set redirect url.
3480
-        // Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3481
-        // otherwise we go with whatever is set as the _admin_base_url
3482
-        $redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3483
-        // calculate where we're going (if we have a "save and close" button pushed)
3484
-        if (
3485
-            $this->request->requestParamIsSet('save_and_close')
3486
-            && $this->request->requestParamIsSet('save_and_close_referrer')
3487
-        ) {
3488
-            // even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3489
-            $parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3490
-            // regenerate query args array from referrer URL
3491
-            parse_str($parsed_url['query'], $query_args);
3492
-            // correct page and action will be in the query args now
3493
-            $redirect_url = admin_url('admin.php');
3494
-        }
3495
-        // merge any default query_args set in _default_route_query_args property
3496
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3497
-            $args_to_merge = [];
3498
-            foreach ($this->_default_route_query_args as $query_param => $query_value) {
3499
-                // is there a wp_referer array in our _default_route_query_args property?
3500
-                if ($query_param === 'wp_referer') {
3501
-                    $query_value = (array) $query_value;
3502
-                    foreach ($query_value as $reference => $value) {
3503
-                        if (strpos($reference, 'nonce') !== false) {
3504
-                            continue;
3505
-                        }
3506
-                        // finally we will override any arguments in the referer with
3507
-                        // what might be set on the _default_route_query_args array.
3508
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3509
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3510
-                        } else {
3511
-                            $args_to_merge[ $reference ] = urlencode($value);
3512
-                        }
3513
-                    }
3514
-                    continue;
3515
-                }
3516
-                $args_to_merge[ $query_param ] = $query_value;
3517
-            }
3518
-            // now let's merge these arguments but override with what was specifically sent in to the
3519
-            // redirect.
3520
-            $query_args = array_merge($args_to_merge, $query_args);
3521
-        }
3522
-        $this->_process_notices($query_args);
3523
-        // generate redirect url
3524
-        // if redirecting to anything other than the main page, add a nonce
3525
-        if (isset($query_args['action'])) {
3526
-            // manually generate wp_nonce and merge that with the query vars
3527
-            // becuz the wp_nonce_url function wrecks havoc on some vars
3528
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3529
-        }
3530
-        // we're adding some hooks and filters in here for processing any things just before redirects
3531
-        // (example: an admin page has done an insert or update and we want to run something after that).
3532
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3533
-        $redirect_url = apply_filters(
3534
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3535
-            EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3536
-            $query_args
3537
-        );
3538
-        // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3539
-        if ($this->request->isAjax()) {
3540
-            $default_data                    = [
3541
-                'close'        => true,
3542
-                'redirect_url' => $redirect_url,
3543
-                'where'        => 'main',
3544
-                'what'         => 'append',
3545
-            ];
3546
-            $this->_template_args['success'] = $success;
3547
-            $this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3548
-                $default_data,
3549
-                $this->_template_args['data']
3550
-            ) : $default_data;
3551
-            $this->_return_json();
3552
-        }
3553
-        wp_safe_redirect($redirect_url);
3554
-        exit();
3555
-    }
3556
-
3557
-
3558
-    /**
3559
-     * process any notices before redirecting (or returning ajax request)
3560
-     * This method sets the $this->_template_args['notices'] attribute;
3561
-     *
3562
-     * @param array $query_args         any query args that need to be used for notice transient ('action')
3563
-     * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3564
-     *                                  page_routes haven't been defined yet.
3565
-     * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3566
-     *                                  still save a transient for the notice.
3567
-     * @return void
3568
-     * @throws EE_Error
3569
-     * @throws InvalidArgumentException
3570
-     * @throws InvalidDataTypeException
3571
-     * @throws InvalidInterfaceException
3572
-     */
3573
-    protected function _process_notices(
3574
-        array $query_args = [],
3575
-        bool $skip_route_verify = false,
3576
-        bool $sticky_notices = true
3577
-    ) {
3578
-        // first let's set individual error properties if doing_ajax and the properties aren't already set.
3579
-        if ($this->request->isAjax()) {
3580
-            $notices = EE_Error::get_notices(false);
3581
-            if (empty($this->_template_args['success'])) {
3582
-                $this->_template_args['success'] = $notices['success'] ?? false;
3583
-            }
3584
-            if (empty($this->_template_args['errors'])) {
3585
-                $this->_template_args['errors'] = $notices['errors'] ?? false;
3586
-            }
3587
-            if (empty($this->_template_args['attention'])) {
3588
-                $this->_template_args['attention'] = $notices['attention'] ?? false;
3589
-            }
3590
-        }
3591
-        $this->_template_args['notices'] = EE_Error::get_notices();
3592
-        // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3593
-        if (! $this->request->isAjax() || $sticky_notices) {
3594
-            $route = $query_args['action'] ?? 'default';
3595
-            $this->_add_transient(
3596
-                $route,
3597
-                (array) $this->_template_args['notices'],
3598
-                true,
3599
-                $skip_route_verify
3600
-            );
3601
-        }
3602
-    }
3603
-
3604
-
3605
-    /**
3606
-     * get_action_link_or_button
3607
-     * returns the button html for adding, editing, or deleting an item (depending on given type)
3608
-     *
3609
-     * @param string $action        use this to indicate which action the url is generated with.
3610
-     * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3611
-     *                              property.
3612
-     * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3613
-     * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3614
-     * @param string $base_url      If this is not provided
3615
-     *                              the _admin_base_url will be used as the default for the button base_url.
3616
-     *                              Otherwise this value will be used.
3617
-     * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3618
-     * @return string
3619
-     * @throws InvalidArgumentException
3620
-     * @throws InvalidInterfaceException
3621
-     * @throws InvalidDataTypeException
3622
-     * @throws EE_Error
3623
-     */
3624
-    public function get_action_link_or_button(
3625
-        string $action,
3626
-        string $type = 'add',
3627
-        array $extra_request = [],
3628
-        string $class = 'button button--primary',
3629
-        string $base_url = '',
3630
-        bool $exclude_nonce = false
3631
-    ): string {
3632
-        // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3633
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3634
-            throw new EE_Error(
3635
-                sprintf(
3636
-                    esc_html__(
3637
-                        'There is no page route for given action for the button.  This action was given: %s',
3638
-                        'event_espresso'
3639
-                    ),
3640
-                    $action
3641
-                )
3642
-            );
3643
-        }
3644
-        if (! isset($this->_labels['buttons'][ $type ])) {
3645
-            throw new EE_Error(
3646
-                sprintf(
3647
-                    esc_html__(
3648
-                        'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3649
-                        'event_espresso'
3650
-                    ),
3651
-                    $type
3652
-                )
3653
-            );
3654
-        }
3655
-        // finally check user access for this button.
3656
-        $has_access = $this->check_user_access($action, true);
3657
-        if (! $has_access) {
3658
-            return '';
3659
-        }
3660
-        $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3661
-        $query_args = [
3662
-            'action' => $action,
3663
-        ];
3664
-        // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3665
-        if (! empty($extra_request)) {
3666
-            $query_args = array_merge($extra_request, $query_args);
3667
-        }
3668
-        $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3669
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3670
-    }
3671
-
3672
-
3673
-    /**
3674
-     * _per_page_screen_option
3675
-     * Utility function for adding in a per_page_option in the screen_options_dropdown.
3676
-     *
3677
-     * @return void
3678
-     * @throws InvalidArgumentException
3679
-     * @throws InvalidInterfaceException
3680
-     * @throws InvalidDataTypeException
3681
-     */
3682
-    protected function _per_page_screen_option()
3683
-    {
3684
-        $option = 'per_page';
3685
-        $args   = [
3686
-            'label'   => apply_filters(
3687
-                'FHEE__EE_Admin_Page___per_page_screen_options___label',
3688
-                $this->_admin_page_title,
3689
-                $this
3690
-            ),
3691
-            'default' => (int) apply_filters(
3692
-                'FHEE__EE_Admin_Page___per_page_screen_options__default',
3693
-                20
3694
-            ),
3695
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3696
-        ];
3697
-        // ONLY add the screen option if the user has access to it.
3698
-        if ($this->check_user_access($this->_current_view, true)) {
3699
-            add_screen_option($option, $args);
3700
-        }
3701
-    }
3702
-
3703
-
3704
-    /**
3705
-     * set_per_page_screen_option
3706
-     * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3707
-     * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3708
-     * admin_menu.
3709
-     *
3710
-     * @return void
3711
-     */
3712
-    private function _set_per_page_screen_options()
3713
-    {
3714
-        if ($this->request->requestParamIsSet('wp_screen_options')) {
3715
-            check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3716
-            if (! $user = wp_get_current_user()) {
3717
-                return;
3718
-            }
3719
-            $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3720
-            if (! $option) {
3721
-                return;
3722
-            }
3723
-            $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3724
-            $map_option = $option;
3725
-            $option     = str_replace('-', '_', $option);
3726
-            switch ($map_option) {
3727
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3728
-                    $max_value = apply_filters(
3729
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3730
-                        999,
3731
-                        $this->_current_page,
3732
-                        $this->_current_view
3733
-                    );
3734
-                    if ($value < 1) {
3735
-                        return;
3736
-                    }
3737
-                    $value = min($value, $max_value);
3738
-                    break;
3739
-                default:
3740
-                    $value = apply_filters(
3741
-                        'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3742
-                        false,
3743
-                        $option,
3744
-                        $value
3745
-                    );
3746
-                    if (false === $value) {
3747
-                        return;
3748
-                    }
3749
-                    break;
3750
-            }
3751
-            update_user_meta($user->ID, $option, $value);
3752
-            wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3753
-            exit;
3754
-        }
3755
-    }
3756
-
3757
-
3758
-    /**
3759
-     * This just allows for setting the $_template_args property if it needs to be set outside the object
3760
-     *
3761
-     * @param array $data array that will be assigned to template args.
3762
-     */
3763
-    public function set_template_args(array $data)
3764
-    {
3765
-        $this->_template_args = array_merge($this->_template_args, $data);
3766
-    }
3767
-
3768
-
3769
-    /**
3770
-     * This makes available the WP transient system for temporarily moving data between routes
3771
-     *
3772
-     * @param string $route             the route that should receive the transient
3773
-     * @param array  $data              the data that gets sent
3774
-     * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3775
-     *                                  normal route transient.
3776
-     * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3777
-     *                                  when we are adding a transient before page_routes have been defined.
3778
-     * @return void
3779
-     * @throws EE_Error
3780
-     */
3781
-    protected function _add_transient(
3782
-        string $route,
3783
-        array $data,
3784
-        bool $notices = false,
3785
-        bool $skip_route_verify = false
3786
-    ) {
3787
-        $user_id = get_current_user_id();
3788
-        if (! $skip_route_verify) {
3789
-            $this->_verify_route($route);
3790
-        }
3791
-        // now let's set the string for what kind of transient we're setting
3792
-        $transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3793
-        $data      = $notices ? ['notices' => $data] : $data;
3794
-        // is there already a transient for this route?  If there is then let's ADD to that transient
3795
-        $existing = is_multisite() && is_network_admin()
3796
-            ? get_site_transient($transient)
3797
-            : get_transient($transient);
3798
-        if ($existing) {
3799
-            $data = array_merge($data, (array) $existing);
3800
-        }
3801
-        if (is_multisite() && is_network_admin()) {
3802
-            set_site_transient($transient, $data, 8);
3803
-        } else {
3804
-            set_transient($transient, $data, 8);
3805
-        }
3806
-    }
3807
-
3808
-
3809
-    /**
3810
-     * this retrieves the temporary transient that has been set for moving data between routes.
3811
-     *
3812
-     * @param bool   $notices true we get notices transient. False we just return normal route transient
3813
-     * @param string $route
3814
-     * @return mixed data
3815
-     */
3816
-    protected function _get_transient(bool $notices = false, string $route = '')
3817
-    {
3818
-        $user_id   = get_current_user_id();
3819
-        $route     = ! $route ? $this->_req_action : $route;
3820
-        $transient = $notices
3821
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3822
-            : 'rte_tx_' . $route . '_' . $user_id;
3823
-        $data      = is_multisite() && is_network_admin()
3824
-            ? get_site_transient($transient)
3825
-            : get_transient($transient);
3826
-        // delete transient after retrieval (just in case it hasn't expired);
3827
-        if (is_multisite() && is_network_admin()) {
3828
-            delete_site_transient($transient);
3829
-        } else {
3830
-            delete_transient($transient);
3831
-        }
3832
-        return $notices && isset($data['notices']) ? $data['notices'] : $data;
3833
-    }
3834
-
3835
-
3836
-    /**
3837
-     * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3838
-     * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3839
-     * default route callback on the EE_Admin page you want it run.)
3840
-     *
3841
-     * @return void
3842
-     */
3843
-    protected function _transient_garbage_collection()
3844
-    {
3845
-        global $wpdb;
3846
-        // retrieve all existing transients
3847
-        $query =
3848
-            "SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3849
-        if ($results = $wpdb->get_results($query)) {
3850
-            foreach ($results as $result) {
3851
-                $transient = str_replace('_transient_', '', $result->option_name);
3852
-                get_transient($transient);
3853
-                if (is_multisite() && is_network_admin()) {
3854
-                    get_site_transient($transient);
3855
-                }
3856
-            }
3857
-        }
3858
-    }
3859
-
3860
-
3861
-    /**
3862
-     * get_view
3863
-     *
3864
-     * @return string content of _view property
3865
-     */
3866
-    public function get_view(): string
3867
-    {
3868
-        return $this->_view;
3869
-    }
3870
-
3871
-
3872
-    /**
3873
-     * getter for the protected $_views property
3874
-     *
3875
-     * @return array
3876
-     */
3877
-    public function get_views(): array
3878
-    {
3879
-        return $this->_views;
3880
-    }
3881
-
3882
-
3883
-    /**
3884
-     * get_current_page
3885
-     *
3886
-     * @return string _current_page property value
3887
-     */
3888
-    public function get_current_page(): string
3889
-    {
3890
-        return $this->_current_page;
3891
-    }
3892
-
3893
-
3894
-    /**
3895
-     * get_current_view
3896
-     *
3897
-     * @return string _current_view property value
3898
-     */
3899
-    public function get_current_view(): string
3900
-    {
3901
-        return $this->_current_view;
3902
-    }
3903
-
3904
-
3905
-    /**
3906
-     * get_current_screen
3907
-     *
3908
-     * @return object The current WP_Screen object
3909
-     */
3910
-    public function get_current_screen()
3911
-    {
3912
-        return $this->_current_screen;
3913
-    }
3914
-
3915
-
3916
-    /**
3917
-     * get_current_page_view_url
3918
-     *
3919
-     * @return string This returns the url for the current_page_view.
3920
-     */
3921
-    public function get_current_page_view_url(): string
3922
-    {
3923
-        return $this->_current_page_view_url;
3924
-    }
3925
-
3926
-
3927
-    /**
3928
-     * just returns the Request
3929
-     *
3930
-     * @return RequestInterface
3931
-     */
3932
-    public function get_request(): ?RequestInterface
3933
-    {
3934
-        return $this->request;
3935
-    }
3936
-
3937
-
3938
-    /**
3939
-     * just returns the _req_data property
3940
-     *
3941
-     * @return array
3942
-     */
3943
-    public function get_request_data(): array
3944
-    {
3945
-        return $this->request->requestParams();
3946
-    }
3947
-
3948
-
3949
-    /**
3950
-     * returns the _req_data protected property
3951
-     *
3952
-     * @return string
3953
-     */
3954
-    public function get_req_action(): string
3955
-    {
3956
-        return $this->_req_action;
3957
-    }
3958
-
3959
-
3960
-    /**
3961
-     * @return bool  value of $_is_caf property
3962
-     */
3963
-    public function is_caf(): bool
3964
-    {
3965
-        return $this->_is_caf;
3966
-    }
3967
-
3968
-
3969
-    /**
3970
-     * @return array
3971
-     */
3972
-    public function default_espresso_metaboxes(): array
3973
-    {
3974
-        return $this->_default_espresso_metaboxes;
3975
-    }
3976
-
3977
-
3978
-    /**
3979
-     * @return string
3980
-     */
3981
-    public function admin_base_url(): string
3982
-    {
3983
-        return $this->_admin_base_url;
3984
-    }
3985
-
3986
-
3987
-    /**
3988
-     * @return string
3989
-     */
3990
-    public function wp_page_slug(): string
3991
-    {
3992
-        return $this->_wp_page_slug;
3993
-    }
3994
-
3995
-
3996
-    /**
3997
-     * updates  espresso configuration settings
3998
-     *
3999
-     * @param string                   $tab
4000
-     * @param EE_Config_Base|EE_Config $config
4001
-     * @param string                   $file file where error occurred
4002
-     * @param string                   $func function  where error occurred
4003
-     * @param string                   $line line no where error occurred
4004
-     * @return bool
4005
-     */
4006
-    protected function _update_espresso_configuration(
4007
-        string $tab,
4008
-        $config,
4009
-        string $file = '',
4010
-        string $func = '',
4011
-        string $line = ''
4012
-    ): bool {
4013
-        // remove any options that are NOT going to be saved with the config settings.
4014
-        if (isset($config->core->ee_ueip_optin)) {
4015
-            // TODO: remove the following two lines and make sure values are migrated from 3.1
4016
-            update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4017
-            update_option('ee_ueip_has_notified', true);
4018
-        }
4019
-        // and save it (note we're also doing the network save here)
4020
-        $net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4021
-        $config_saved = EE_Config::instance()->update_espresso_config(false, false);
4022
-        if ($config_saved && $net_saved) {
4023
-            EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4024
-            return true;
4025
-        }
4026
-        EE_Error::add_error(
4027
-            sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4028
-            $file,
4029
-            $func,
4030
-            $line
4031
-        );
4032
-        return false;
4033
-    }
4034
-
4035
-
4036
-    /**
4037
-     * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4038
-     *
4039
-     * @return array
4040
-     */
4041
-    public function get_yes_no_values(): array
4042
-    {
4043
-        return $this->_yes_no_values;
4044
-    }
4045
-
4046
-
4047
-    /**
4048
-     * @return string
4049
-     * @throws ReflectionException
4050
-     * @since 5.0.0.p
4051
-     */
4052
-    protected function _get_dir(): string
4053
-    {
4054
-        $reflector = new ReflectionClass($this->class_name);
4055
-        return dirname($reflector->getFileName());
4056
-    }
4057
-
4058
-
4059
-    /**
4060
-     * A helper for getting a "next link".
4061
-     *
4062
-     * @param string $url   The url to link to
4063
-     * @param string $class The class to use.
4064
-     * @return string
4065
-     */
4066
-    protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4067
-    {
4068
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4069
-    }
4070
-
4071
-
4072
-    /**
4073
-     * A helper for getting a "previous link".
4074
-     *
4075
-     * @param string $url   The url to link to
4076
-     * @param string $class The class to use.
4077
-     * @return string
4078
-     */
4079
-    protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4080
-    {
4081
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4082
-    }
4083
-
4084
-
4085
-
4086
-
4087
-
4088
-
4089
-
4090
-    // below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4091
-
4092
-
4093
-    /**
4094
-     * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4095
-     * 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
4096
-     * _req_data array.
4097
-     *
4098
-     * @return bool success/fail
4099
-     * @throws EE_Error
4100
-     * @throws InvalidArgumentException
4101
-     * @throws ReflectionException
4102
-     * @throws InvalidDataTypeException
4103
-     * @throws InvalidInterfaceException
4104
-     */
4105
-    protected function _process_resend_registration(): bool
4106
-    {
4107
-        $this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4108
-        do_action(
4109
-            'AHEE__EE_Admin_Page___process_resend_registration',
4110
-            $this->_template_args['success'],
4111
-            $this->request->requestParams()
4112
-        );
4113
-        return $this->_template_args['success'];
4114
-    }
4115
-
4116
-
4117
-    /**
4118
-     * This automatically processes any payment message notifications when manual payment has been applied.
4119
-     *
4120
-     * @param EE_Payment $payment
4121
-     * @return bool success/fail
4122
-     */
4123
-    protected function _process_payment_notification(EE_Payment $payment): bool
4124
-    {
4125
-        add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4126
-        do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4127
-        $this->_template_args['success'] = apply_filters(
4128
-            'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4129
-            false,
4130
-            $payment
4131
-        );
4132
-        return $this->_template_args['success'];
4133
-    }
4134
-
4135
-
4136
-    /**
4137
-     * @param EEM_Base      $entity_model
4138
-     * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4139
-     * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4140
-     * @param string        $delete_column  name of the field that denotes whether entity is trashed
4141
-     * @param callable|null $callback       called after entity is trashed, restored, or deleted
4142
-     * @return int|float
4143
-     * @throws EE_Error
4144
-     */
4145
-    protected function trashRestoreDeleteEntities(
4146
-        EEM_Base $entity_model,
4147
-        string $entity_PK_name,
4148
-        string $action = EE_Admin_List_Table::ACTION_DELETE,
4149
-        string $delete_column = '',
4150
-        ?callable $callback = null
4151
-    ) {
4152
-        $entity_PK      = $entity_model->get_primary_key_field();
4153
-        $entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4154
-        $entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4155
-        // grab ID if deleting a single entity
4156
-        if ($this->request->requestParamIsSet($entity_PK_name)) {
4157
-            $ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4158
-            return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4159
-        }
4160
-        // or grab checkbox array if bulk deleting
4161
-        $checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4162
-        if (empty($checkboxes)) {
4163
-            return 0;
4164
-        }
4165
-        $success = 0;
4166
-        $IDs     = array_keys($checkboxes);
4167
-        // cycle thru bulk action checkboxes
4168
-        foreach ($IDs as $ID) {
4169
-            // increment $success
4170
-            if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4171
-                $success++;
4172
-            }
4173
-        }
4174
-        $count = (int) count($checkboxes);
4175
-        // if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4176
-        // otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4177
-        return $success === $count ? $count : $success / $count;
4178
-    }
4179
-
4180
-
4181
-    /**
4182
-     * @param EE_Primary_Key_Field_Base $entity_PK
4183
-     * @return string
4184
-     * @throws EE_Error
4185
-     * @since   4.10.30.p
4186
-     */
4187
-    private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4188
-    {
4189
-        $entity_PK_type = $entity_PK->getSchemaType();
4190
-        switch ($entity_PK_type) {
4191
-            case 'boolean':
4192
-                return DataType::BOOL;
4193
-            case 'integer':
4194
-                return DataType::INT;
4195
-            case 'number':
4196
-                return DataType::FLOAT;
4197
-            case 'string':
4198
-                return DataType::STRING;
4199
-        }
4200
-        throw new RuntimeException(
4201
-            sprintf(
4202
-                esc_html__(
4203
-                    '"%1$s" is an invalid schema type for the %2$s primary key.',
4204
-                    'event_espresso'
4205
-                ),
4206
-                $entity_PK_type,
4207
-                $entity_PK->get_name()
4208
-            )
4209
-        );
4210
-    }
4211
-
4212
-
4213
-    /**
4214
-     * @param EEM_Base      $entity_model
4215
-     * @param int|string    $entity_ID
4216
-     * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4217
-     * @param string        $delete_column name of the field that denotes whether entity is trashed
4218
-     * @param callable|null $callback      called after entity is trashed, restored, or deleted
4219
-     * @return bool
4220
-     */
4221
-    protected function trashRestoreDeleteEntity(
4222
-        EEM_Base $entity_model,
4223
-        $entity_ID,
4224
-        string $action,
4225
-        string $delete_column,
4226
-        ?callable $callback = null
4227
-    ): bool {
4228
-        $entity_ID = absint($entity_ID);
4229
-        if (! $entity_ID) {
4230
-            $this->trashRestoreDeleteError($action, $entity_model);
4231
-        }
4232
-        $result = 0;
4233
-        try {
4234
-            $entity = $entity_model->get_one_by_ID($entity_ID);
4235
-            if (! $entity instanceof EE_Base_Class) {
4236
-                throw new DomainException(
4237
-                    sprintf(
4238
-                        esc_html__(
4239
-                            'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4240
-                            'event_espresso'
4241
-                        ),
4242
-                        str_replace('EEM_', '', $entity_model->get_this_model_name()),
4243
-                        $entity_ID
4244
-                    )
4245
-                );
4246
-            }
4247
-            switch ($action) {
4248
-                case EE_Admin_List_Table::ACTION_DELETE:
4249
-                    $result = (bool) $entity->delete_permanently();
4250
-                    break;
4251
-                case EE_Admin_List_Table::ACTION_RESTORE:
4252
-                    $result = $entity->delete_or_restore(false);
4253
-                    break;
4254
-                case EE_Admin_List_Table::ACTION_TRASH:
4255
-                    $result = $entity->delete_or_restore();
4256
-                    break;
4257
-            }
4258
-        } catch (Exception $exception) {
4259
-            $this->trashRestoreDeleteError($action, $entity_model, $exception);
4260
-        }
4261
-        if (is_callable($callback)) {
4262
-            call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4263
-        }
4264
-        return $result;
4265
-    }
4266
-
4267
-
4268
-    /**
4269
-     * @param EEM_Base $entity_model
4270
-     * @param string   $delete_column
4271
-     * @since 4.10.30.p
4272
-     */
4273
-    private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4274
-    {
4275
-        if (empty($delete_column)) {
4276
-            throw new DomainException(
4277
-                sprintf(
4278
-                    esc_html__(
4279
-                        'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4280
-                        'event_espresso'
4281
-                    ),
4282
-                    $entity_model->get_this_model_name()
4283
-                )
4284
-            );
4285
-        }
4286
-        if (! $entity_model->has_field($delete_column)) {
4287
-            throw new DomainException(
4288
-                sprintf(
4289
-                    esc_html__(
4290
-                        'The %1$s field does not exist on the %2$s model.',
4291
-                        'event_espresso'
4292
-                    ),
4293
-                    $delete_column,
4294
-                    $entity_model->get_this_model_name()
4295
-                )
4296
-            );
4297
-        }
4298
-    }
4299
-
4300
-
4301
-    /**
4302
-     * @param EEM_Base       $entity_model
4303
-     * @param Exception|null $exception
4304
-     * @param string         $action
4305
-     * @since 4.10.30.p
4306
-     */
4307
-    private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4308
-    {
4309
-        if ($exception instanceof Exception) {
4310
-            throw new RuntimeException(
4311
-                sprintf(
4312
-                    esc_html__(
4313
-                        'Could not %1$s the %2$s because the following error occurred: %3$s',
4314
-                        'event_espresso'
4315
-                    ),
4316
-                    $action,
4317
-                    $entity_model->get_this_model_name(),
4318
-                    $exception->getMessage()
4319
-                )
4320
-            );
4321
-        }
4322
-        throw new RuntimeException(
4323
-            sprintf(
4324
-                esc_html__(
4325
-                    'Could not %1$s the %2$s because an invalid ID was received.',
4326
-                    'event_espresso'
4327
-                ),
4328
-                $action,
4329
-                $entity_model->get_this_model_name()
4330
-            )
4331
-        );
4332
-    }
3343
+		// add nonce
3344
+		$nonce                                             =
3345
+			wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3346
+		$this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3347
+		// add REQUIRED form action
3348
+		$hidden_fields = [
3349
+			'action' => ['type' => 'hidden', 'value' => $route],
3350
+		];
3351
+		// merge arrays
3352
+		$hidden_fields = is_array($additional_hidden_fields)
3353
+			? array_merge($hidden_fields, $additional_hidden_fields)
3354
+			: $hidden_fields;
3355
+		// generate form fields
3356
+		$form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3357
+		// add fields to form
3358
+		foreach ((array) $form_fields as $form_field) {
3359
+			$this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3360
+		}
3361
+		// close form
3362
+		$this->_template_args['after_admin_page_content'] = '</form>';
3363
+	}
3364
+
3365
+
3366
+	/**
3367
+	 * Public Wrapper for _redirect_after_action() method since its
3368
+	 * discovered it would be useful for external code to have access.
3369
+	 *
3370
+	 * @param bool|int $success
3371
+	 * @param string   $what
3372
+	 * @param string   $action_desc
3373
+	 * @param array    $query_args
3374
+	 * @param bool     $override_overwrite
3375
+	 * @throws EE_Error
3376
+	 * @see   EE_Admin_Page::_redirect_after_action() for params.
3377
+	 * @since 4.5.0
3378
+	 */
3379
+	public function redirect_after_action(
3380
+		$success = false,
3381
+		string $what = 'item',
3382
+		string $action_desc = 'processed',
3383
+		array $query_args = [],
3384
+		bool $override_overwrite = false
3385
+	) {
3386
+		$this->_redirect_after_action(
3387
+			$success,
3388
+			$what,
3389
+			$action_desc,
3390
+			$query_args,
3391
+			$override_overwrite
3392
+		);
3393
+	}
3394
+
3395
+
3396
+	/**
3397
+	 * Helper method for merging existing request data with the returned redirect url.
3398
+	 * This is typically used for redirects after an action so that if the original view was a filtered view those
3399
+	 * filters are still applied.
3400
+	 *
3401
+	 * @param array $new_route_data
3402
+	 * @return array
3403
+	 */
3404
+	protected function mergeExistingRequestParamsWithRedirectArgs(array $new_route_data): array
3405
+	{
3406
+		foreach ($this->request->requestParams() as $ref => $value) {
3407
+			// unset nonces
3408
+			if (strpos($ref, 'nonce') !== false) {
3409
+				$this->request->unSetRequestParam($ref);
3410
+				continue;
3411
+			}
3412
+			// urlencode values.
3413
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
3414
+			$this->request->setRequestParam($ref, $value);
3415
+		}
3416
+		return array_merge($this->request->requestParams(), $new_route_data);
3417
+	}
3418
+
3419
+
3420
+	/**
3421
+	 * @param int|float|string $success            - whether success was for two or more records, or just one, or none
3422
+	 * @param string           $what               - what the action was performed on
3423
+	 * @param string           $action_desc        - what was done ie: updated, deleted, etc
3424
+	 * @param array            $query_args         - an array of query_args to be added to the URL to redirect to
3425
+	 * @param BOOL             $override_overwrite - by default all EE_Error::success messages are overwritten,
3426
+	 *                                             this allows you to override this so that they show.
3427
+	 * @return void
3428
+	 * @throws EE_Error
3429
+	 * @throws InvalidArgumentException
3430
+	 * @throws InvalidDataTypeException
3431
+	 * @throws InvalidInterfaceException
3432
+	 */
3433
+	protected function _redirect_after_action(
3434
+		$success = 0,
3435
+		string $what = 'item',
3436
+		string $action_desc = 'processed',
3437
+		array $query_args = [],
3438
+		bool $override_overwrite = false
3439
+	) {
3440
+		$notices = EE_Error::get_notices(false);
3441
+		// overwrite default success messages //BUT ONLY if overwrite not overridden
3442
+		if (! $override_overwrite || ! empty($notices['errors'])) {
3443
+			EE_Error::overwrite_success();
3444
+		}
3445
+		if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3446
+			// how many records affected ? more than one record ? or just one ?
3447
+			EE_Error::add_success(
3448
+				sprintf(
3449
+					esc_html(
3450
+						_n(
3451
+							'The "%1$s" has been successfully %2$s.',
3452
+							'The "%1$s" have been successfully %2$s.',
3453
+							$success,
3454
+							'event_espresso'
3455
+						)
3456
+					),
3457
+					$what,
3458
+					$action_desc
3459
+				),
3460
+				__FILE__,
3461
+				__FUNCTION__,
3462
+				__LINE__
3463
+			);
3464
+		}
3465
+		// check that $query_args isn't something crazy
3466
+		$query_args = is_array($query_args) ? $query_args : [];
3467
+		/**
3468
+		 * Allow injecting actions before the query_args are modified for possible different
3469
+		 * redirections on save and close actions
3470
+		 *
3471
+		 * @param array $query_args       The original query_args array coming into the
3472
+		 *                                method.
3473
+		 * @since 4.2.0
3474
+		 */
3475
+		do_action(
3476
+			"AHEE__{$this->class_name}___redirect_after_action__before_redirect_modification_$this->_req_action",
3477
+			$query_args
3478
+		);
3479
+		// set redirect url.
3480
+		// Note if there is a "page" index in the $query_args then we go with vanilla admin.php route,
3481
+		// otherwise we go with whatever is set as the _admin_base_url
3482
+		$redirect_url = isset($query_args['page']) ? admin_url('admin.php') : $this->_admin_base_url;
3483
+		// calculate where we're going (if we have a "save and close" button pushed)
3484
+		if (
3485
+			$this->request->requestParamIsSet('save_and_close')
3486
+			&& $this->request->requestParamIsSet('save_and_close_referrer')
3487
+		) {
3488
+			// even though we have the save_and_close referrer, we need to parse the url for the action in order to generate a nonce
3489
+			$parsed_url = parse_url($this->request->getRequestParam('save_and_close_referrer', '', DataType::URL));
3490
+			// regenerate query args array from referrer URL
3491
+			parse_str($parsed_url['query'], $query_args);
3492
+			// correct page and action will be in the query args now
3493
+			$redirect_url = admin_url('admin.php');
3494
+		}
3495
+		// merge any default query_args set in _default_route_query_args property
3496
+		if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3497
+			$args_to_merge = [];
3498
+			foreach ($this->_default_route_query_args as $query_param => $query_value) {
3499
+				// is there a wp_referer array in our _default_route_query_args property?
3500
+				if ($query_param === 'wp_referer') {
3501
+					$query_value = (array) $query_value;
3502
+					foreach ($query_value as $reference => $value) {
3503
+						if (strpos($reference, 'nonce') !== false) {
3504
+							continue;
3505
+						}
3506
+						// finally we will override any arguments in the referer with
3507
+						// what might be set on the _default_route_query_args array.
3508
+						if (isset($this->_default_route_query_args[ $reference ])) {
3509
+							$args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3510
+						} else {
3511
+							$args_to_merge[ $reference ] = urlencode($value);
3512
+						}
3513
+					}
3514
+					continue;
3515
+				}
3516
+				$args_to_merge[ $query_param ] = $query_value;
3517
+			}
3518
+			// now let's merge these arguments but override with what was specifically sent in to the
3519
+			// redirect.
3520
+			$query_args = array_merge($args_to_merge, $query_args);
3521
+		}
3522
+		$this->_process_notices($query_args);
3523
+		// generate redirect url
3524
+		// if redirecting to anything other than the main page, add a nonce
3525
+		if (isset($query_args['action'])) {
3526
+			// manually generate wp_nonce and merge that with the query vars
3527
+			// becuz the wp_nonce_url function wrecks havoc on some vars
3528
+			$query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3529
+		}
3530
+		// we're adding some hooks and filters in here for processing any things just before redirects
3531
+		// (example: an admin page has done an insert or update and we want to run something after that).
3532
+		do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3533
+		$redirect_url = apply_filters(
3534
+			'FHEE_redirect_' . $this->class_name . $this->_req_action,
3535
+			EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3536
+			$query_args
3537
+		);
3538
+		// check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3539
+		if ($this->request->isAjax()) {
3540
+			$default_data                    = [
3541
+				'close'        => true,
3542
+				'redirect_url' => $redirect_url,
3543
+				'where'        => 'main',
3544
+				'what'         => 'append',
3545
+			];
3546
+			$this->_template_args['success'] = $success;
3547
+			$this->_template_args['data']    = ! empty($this->_template_args['data']) ? array_merge(
3548
+				$default_data,
3549
+				$this->_template_args['data']
3550
+			) : $default_data;
3551
+			$this->_return_json();
3552
+		}
3553
+		wp_safe_redirect($redirect_url);
3554
+		exit();
3555
+	}
3556
+
3557
+
3558
+	/**
3559
+	 * process any notices before redirecting (or returning ajax request)
3560
+	 * This method sets the $this->_template_args['notices'] attribute;
3561
+	 *
3562
+	 * @param array $query_args         any query args that need to be used for notice transient ('action')
3563
+	 * @param bool  $skip_route_verify  This is typically used when we are processing notices REALLY early and
3564
+	 *                                  page_routes haven't been defined yet.
3565
+	 * @param bool  $sticky_notices     This is used to flag that regardless of whether this is doing_ajax or not, we
3566
+	 *                                  still save a transient for the notice.
3567
+	 * @return void
3568
+	 * @throws EE_Error
3569
+	 * @throws InvalidArgumentException
3570
+	 * @throws InvalidDataTypeException
3571
+	 * @throws InvalidInterfaceException
3572
+	 */
3573
+	protected function _process_notices(
3574
+		array $query_args = [],
3575
+		bool $skip_route_verify = false,
3576
+		bool $sticky_notices = true
3577
+	) {
3578
+		// first let's set individual error properties if doing_ajax and the properties aren't already set.
3579
+		if ($this->request->isAjax()) {
3580
+			$notices = EE_Error::get_notices(false);
3581
+			if (empty($this->_template_args['success'])) {
3582
+				$this->_template_args['success'] = $notices['success'] ?? false;
3583
+			}
3584
+			if (empty($this->_template_args['errors'])) {
3585
+				$this->_template_args['errors'] = $notices['errors'] ?? false;
3586
+			}
3587
+			if (empty($this->_template_args['attention'])) {
3588
+				$this->_template_args['attention'] = $notices['attention'] ?? false;
3589
+			}
3590
+		}
3591
+		$this->_template_args['notices'] = EE_Error::get_notices();
3592
+		// IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3593
+		if (! $this->request->isAjax() || $sticky_notices) {
3594
+			$route = $query_args['action'] ?? 'default';
3595
+			$this->_add_transient(
3596
+				$route,
3597
+				(array) $this->_template_args['notices'],
3598
+				true,
3599
+				$skip_route_verify
3600
+			);
3601
+		}
3602
+	}
3603
+
3604
+
3605
+	/**
3606
+	 * get_action_link_or_button
3607
+	 * returns the button html for adding, editing, or deleting an item (depending on given type)
3608
+	 *
3609
+	 * @param string $action        use this to indicate which action the url is generated with.
3610
+	 * @param string $type          accepted strings must be defined in the $_labels['button'] array(as the key)
3611
+	 *                              property.
3612
+	 * @param array  $extra_request if the button requires extra params you can include them in $key=>$value pairs.
3613
+	 * @param string $class         Use this to give the class for the button. Defaults to 'button--primary'
3614
+	 * @param string $base_url      If this is not provided
3615
+	 *                              the _admin_base_url will be used as the default for the button base_url.
3616
+	 *                              Otherwise this value will be used.
3617
+	 * @param bool   $exclude_nonce If true then no nonce will be in the generated button link.
3618
+	 * @return string
3619
+	 * @throws InvalidArgumentException
3620
+	 * @throws InvalidInterfaceException
3621
+	 * @throws InvalidDataTypeException
3622
+	 * @throws EE_Error
3623
+	 */
3624
+	public function get_action_link_or_button(
3625
+		string $action,
3626
+		string $type = 'add',
3627
+		array $extra_request = [],
3628
+		string $class = 'button button--primary',
3629
+		string $base_url = '',
3630
+		bool $exclude_nonce = false
3631
+	): string {
3632
+		// first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3633
+		if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3634
+			throw new EE_Error(
3635
+				sprintf(
3636
+					esc_html__(
3637
+						'There is no page route for given action for the button.  This action was given: %s',
3638
+						'event_espresso'
3639
+					),
3640
+					$action
3641
+				)
3642
+			);
3643
+		}
3644
+		if (! isset($this->_labels['buttons'][ $type ])) {
3645
+			throw new EE_Error(
3646
+				sprintf(
3647
+					esc_html__(
3648
+						'There is no label for the given button type (%s). Labels are set in the <code>_page_config</code> property.',
3649
+						'event_espresso'
3650
+					),
3651
+					$type
3652
+				)
3653
+			);
3654
+		}
3655
+		// finally check user access for this button.
3656
+		$has_access = $this->check_user_access($action, true);
3657
+		if (! $has_access) {
3658
+			return '';
3659
+		}
3660
+		$_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
3661
+		$query_args = [
3662
+			'action' => $action,
3663
+		];
3664
+		// merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3665
+		if (! empty($extra_request)) {
3666
+			$query_args = array_merge($extra_request, $query_args);
3667
+		}
3668
+		$url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3669
+		return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3670
+	}
3671
+
3672
+
3673
+	/**
3674
+	 * _per_page_screen_option
3675
+	 * Utility function for adding in a per_page_option in the screen_options_dropdown.
3676
+	 *
3677
+	 * @return void
3678
+	 * @throws InvalidArgumentException
3679
+	 * @throws InvalidInterfaceException
3680
+	 * @throws InvalidDataTypeException
3681
+	 */
3682
+	protected function _per_page_screen_option()
3683
+	{
3684
+		$option = 'per_page';
3685
+		$args   = [
3686
+			'label'   => apply_filters(
3687
+				'FHEE__EE_Admin_Page___per_page_screen_options___label',
3688
+				$this->_admin_page_title,
3689
+				$this
3690
+			),
3691
+			'default' => (int) apply_filters(
3692
+				'FHEE__EE_Admin_Page___per_page_screen_options__default',
3693
+				20
3694
+			),
3695
+			'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3696
+		];
3697
+		// ONLY add the screen option if the user has access to it.
3698
+		if ($this->check_user_access($this->_current_view, true)) {
3699
+			add_screen_option($option, $args);
3700
+		}
3701
+	}
3702
+
3703
+
3704
+	/**
3705
+	 * set_per_page_screen_option
3706
+	 * All this does is make sure that WordPress saves any per_page screen options (if set) for the current page.
3707
+	 * we have to do this rather than running inside the 'set-screen-options' hook because it runs earlier than
3708
+	 * admin_menu.
3709
+	 *
3710
+	 * @return void
3711
+	 */
3712
+	private function _set_per_page_screen_options()
3713
+	{
3714
+		if ($this->request->requestParamIsSet('wp_screen_options')) {
3715
+			check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3716
+			if (! $user = wp_get_current_user()) {
3717
+				return;
3718
+			}
3719
+			$option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3720
+			if (! $option) {
3721
+				return;
3722
+			}
3723
+			$value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3724
+			$map_option = $option;
3725
+			$option     = str_replace('-', '_', $option);
3726
+			switch ($map_option) {
3727
+				case $this->_current_page . '_' . $this->_current_view . '_per_page':
3728
+					$max_value = apply_filters(
3729
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3730
+						999,
3731
+						$this->_current_page,
3732
+						$this->_current_view
3733
+					);
3734
+					if ($value < 1) {
3735
+						return;
3736
+					}
3737
+					$value = min($value, $max_value);
3738
+					break;
3739
+				default:
3740
+					$value = apply_filters(
3741
+						'FHEE__EE_Admin_Page___set_per_page_screen_options__value',
3742
+						false,
3743
+						$option,
3744
+						$value
3745
+					);
3746
+					if (false === $value) {
3747
+						return;
3748
+					}
3749
+					break;
3750
+			}
3751
+			update_user_meta($user->ID, $option, $value);
3752
+			wp_safe_redirect(remove_query_arg(['pagenum', 'apage', 'paged'], wp_get_referer()));
3753
+			exit;
3754
+		}
3755
+	}
3756
+
3757
+
3758
+	/**
3759
+	 * This just allows for setting the $_template_args property if it needs to be set outside the object
3760
+	 *
3761
+	 * @param array $data array that will be assigned to template args.
3762
+	 */
3763
+	public function set_template_args(array $data)
3764
+	{
3765
+		$this->_template_args = array_merge($this->_template_args, $data);
3766
+	}
3767
+
3768
+
3769
+	/**
3770
+	 * This makes available the WP transient system for temporarily moving data between routes
3771
+	 *
3772
+	 * @param string $route             the route that should receive the transient
3773
+	 * @param array  $data              the data that gets sent
3774
+	 * @param bool   $notices           If this is for notices then we use this to indicate so, otherwise its just a
3775
+	 *                                  normal route transient.
3776
+	 * @param bool   $skip_route_verify Used to indicate we want to skip route verification.  This is usually ONLY used
3777
+	 *                                  when we are adding a transient before page_routes have been defined.
3778
+	 * @return void
3779
+	 * @throws EE_Error
3780
+	 */
3781
+	protected function _add_transient(
3782
+		string $route,
3783
+		array $data,
3784
+		bool $notices = false,
3785
+		bool $skip_route_verify = false
3786
+	) {
3787
+		$user_id = get_current_user_id();
3788
+		if (! $skip_route_verify) {
3789
+			$this->_verify_route($route);
3790
+		}
3791
+		// now let's set the string for what kind of transient we're setting
3792
+		$transient = $notices ? "ee_rte_n_tx_{$route}_$user_id" : "rte_tx_{$route}_$user_id";
3793
+		$data      = $notices ? ['notices' => $data] : $data;
3794
+		// is there already a transient for this route?  If there is then let's ADD to that transient
3795
+		$existing = is_multisite() && is_network_admin()
3796
+			? get_site_transient($transient)
3797
+			: get_transient($transient);
3798
+		if ($existing) {
3799
+			$data = array_merge($data, (array) $existing);
3800
+		}
3801
+		if (is_multisite() && is_network_admin()) {
3802
+			set_site_transient($transient, $data, 8);
3803
+		} else {
3804
+			set_transient($transient, $data, 8);
3805
+		}
3806
+	}
3807
+
3808
+
3809
+	/**
3810
+	 * this retrieves the temporary transient that has been set for moving data between routes.
3811
+	 *
3812
+	 * @param bool   $notices true we get notices transient. False we just return normal route transient
3813
+	 * @param string $route
3814
+	 * @return mixed data
3815
+	 */
3816
+	protected function _get_transient(bool $notices = false, string $route = '')
3817
+	{
3818
+		$user_id   = get_current_user_id();
3819
+		$route     = ! $route ? $this->_req_action : $route;
3820
+		$transient = $notices
3821
+			? 'ee_rte_n_tx_' . $route . '_' . $user_id
3822
+			: 'rte_tx_' . $route . '_' . $user_id;
3823
+		$data      = is_multisite() && is_network_admin()
3824
+			? get_site_transient($transient)
3825
+			: get_transient($transient);
3826
+		// delete transient after retrieval (just in case it hasn't expired);
3827
+		if (is_multisite() && is_network_admin()) {
3828
+			delete_site_transient($transient);
3829
+		} else {
3830
+			delete_transient($transient);
3831
+		}
3832
+		return $notices && isset($data['notices']) ? $data['notices'] : $data;
3833
+	}
3834
+
3835
+
3836
+	/**
3837
+	 * The purpose of this method is just to run garbage collection on any EE transients that might have expired but
3838
+	 * would not be called later. This will be assigned to run on a specific EE Admin page. (place the method in the
3839
+	 * default route callback on the EE_Admin page you want it run.)
3840
+	 *
3841
+	 * @return void
3842
+	 */
3843
+	protected function _transient_garbage_collection()
3844
+	{
3845
+		global $wpdb;
3846
+		// retrieve all existing transients
3847
+		$query =
3848
+			"SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%rte_tx_%' OR option_name LIKE '%rte_n_tx_%'";
3849
+		if ($results = $wpdb->get_results($query)) {
3850
+			foreach ($results as $result) {
3851
+				$transient = str_replace('_transient_', '', $result->option_name);
3852
+				get_transient($transient);
3853
+				if (is_multisite() && is_network_admin()) {
3854
+					get_site_transient($transient);
3855
+				}
3856
+			}
3857
+		}
3858
+	}
3859
+
3860
+
3861
+	/**
3862
+	 * get_view
3863
+	 *
3864
+	 * @return string content of _view property
3865
+	 */
3866
+	public function get_view(): string
3867
+	{
3868
+		return $this->_view;
3869
+	}
3870
+
3871
+
3872
+	/**
3873
+	 * getter for the protected $_views property
3874
+	 *
3875
+	 * @return array
3876
+	 */
3877
+	public function get_views(): array
3878
+	{
3879
+		return $this->_views;
3880
+	}
3881
+
3882
+
3883
+	/**
3884
+	 * get_current_page
3885
+	 *
3886
+	 * @return string _current_page property value
3887
+	 */
3888
+	public function get_current_page(): string
3889
+	{
3890
+		return $this->_current_page;
3891
+	}
3892
+
3893
+
3894
+	/**
3895
+	 * get_current_view
3896
+	 *
3897
+	 * @return string _current_view property value
3898
+	 */
3899
+	public function get_current_view(): string
3900
+	{
3901
+		return $this->_current_view;
3902
+	}
3903
+
3904
+
3905
+	/**
3906
+	 * get_current_screen
3907
+	 *
3908
+	 * @return object The current WP_Screen object
3909
+	 */
3910
+	public function get_current_screen()
3911
+	{
3912
+		return $this->_current_screen;
3913
+	}
3914
+
3915
+
3916
+	/**
3917
+	 * get_current_page_view_url
3918
+	 *
3919
+	 * @return string This returns the url for the current_page_view.
3920
+	 */
3921
+	public function get_current_page_view_url(): string
3922
+	{
3923
+		return $this->_current_page_view_url;
3924
+	}
3925
+
3926
+
3927
+	/**
3928
+	 * just returns the Request
3929
+	 *
3930
+	 * @return RequestInterface
3931
+	 */
3932
+	public function get_request(): ?RequestInterface
3933
+	{
3934
+		return $this->request;
3935
+	}
3936
+
3937
+
3938
+	/**
3939
+	 * just returns the _req_data property
3940
+	 *
3941
+	 * @return array
3942
+	 */
3943
+	public function get_request_data(): array
3944
+	{
3945
+		return $this->request->requestParams();
3946
+	}
3947
+
3948
+
3949
+	/**
3950
+	 * returns the _req_data protected property
3951
+	 *
3952
+	 * @return string
3953
+	 */
3954
+	public function get_req_action(): string
3955
+	{
3956
+		return $this->_req_action;
3957
+	}
3958
+
3959
+
3960
+	/**
3961
+	 * @return bool  value of $_is_caf property
3962
+	 */
3963
+	public function is_caf(): bool
3964
+	{
3965
+		return $this->_is_caf;
3966
+	}
3967
+
3968
+
3969
+	/**
3970
+	 * @return array
3971
+	 */
3972
+	public function default_espresso_metaboxes(): array
3973
+	{
3974
+		return $this->_default_espresso_metaboxes;
3975
+	}
3976
+
3977
+
3978
+	/**
3979
+	 * @return string
3980
+	 */
3981
+	public function admin_base_url(): string
3982
+	{
3983
+		return $this->_admin_base_url;
3984
+	}
3985
+
3986
+
3987
+	/**
3988
+	 * @return string
3989
+	 */
3990
+	public function wp_page_slug(): string
3991
+	{
3992
+		return $this->_wp_page_slug;
3993
+	}
3994
+
3995
+
3996
+	/**
3997
+	 * updates  espresso configuration settings
3998
+	 *
3999
+	 * @param string                   $tab
4000
+	 * @param EE_Config_Base|EE_Config $config
4001
+	 * @param string                   $file file where error occurred
4002
+	 * @param string                   $func function  where error occurred
4003
+	 * @param string                   $line line no where error occurred
4004
+	 * @return bool
4005
+	 */
4006
+	protected function _update_espresso_configuration(
4007
+		string $tab,
4008
+		$config,
4009
+		string $file = '',
4010
+		string $func = '',
4011
+		string $line = ''
4012
+	): bool {
4013
+		// remove any options that are NOT going to be saved with the config settings.
4014
+		if (isset($config->core->ee_ueip_optin)) {
4015
+			// TODO: remove the following two lines and make sure values are migrated from 3.1
4016
+			update_option('ee_ueip_optin', $config->core->ee_ueip_optin);
4017
+			update_option('ee_ueip_has_notified', true);
4018
+		}
4019
+		// and save it (note we're also doing the network save here)
4020
+		$net_saved    = ! is_main_site() || EE_Network_Config::instance()->update_config(false, false);
4021
+		$config_saved = EE_Config::instance()->update_espresso_config(false, false);
4022
+		if ($config_saved && $net_saved) {
4023
+			EE_Error::add_success(sprintf(esc_html__('"%s" have been successfully updated.', 'event_espresso'), $tab));
4024
+			return true;
4025
+		}
4026
+		EE_Error::add_error(
4027
+			sprintf(esc_html__('The "%s" were not updated.', 'event_espresso'), $tab),
4028
+			$file,
4029
+			$func,
4030
+			$line
4031
+		);
4032
+		return false;
4033
+	}
4034
+
4035
+
4036
+	/**
4037
+	 * Returns an array to be used for EE_FOrm_Fields.helper.php's select_input as the $values argument.
4038
+	 *
4039
+	 * @return array
4040
+	 */
4041
+	public function get_yes_no_values(): array
4042
+	{
4043
+		return $this->_yes_no_values;
4044
+	}
4045
+
4046
+
4047
+	/**
4048
+	 * @return string
4049
+	 * @throws ReflectionException
4050
+	 * @since 5.0.0.p
4051
+	 */
4052
+	protected function _get_dir(): string
4053
+	{
4054
+		$reflector = new ReflectionClass($this->class_name);
4055
+		return dirname($reflector->getFileName());
4056
+	}
4057
+
4058
+
4059
+	/**
4060
+	 * A helper for getting a "next link".
4061
+	 *
4062
+	 * @param string $url   The url to link to
4063
+	 * @param string $class The class to use.
4064
+	 * @return string
4065
+	 */
4066
+	protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4067
+	{
4068
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4069
+	}
4070
+
4071
+
4072
+	/**
4073
+	 * A helper for getting a "previous link".
4074
+	 *
4075
+	 * @param string $url   The url to link to
4076
+	 * @param string $class The class to use.
4077
+	 * @return string
4078
+	 */
4079
+	protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4080
+	{
4081
+		return '<a class="' . $class . '" href="' . $url . '"></a>';
4082
+	}
4083
+
4084
+
4085
+
4086
+
4087
+
4088
+
4089
+
4090
+	// below are some messages related methods that should be available across the EE_Admin system.  Note, these methods are NOT page specific
4091
+
4092
+
4093
+	/**
4094
+	 * This processes an request to resend a registration and assumes we have a _REG_ID for doing so. So if the caller
4095
+	 * 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
4096
+	 * _req_data array.
4097
+	 *
4098
+	 * @return bool success/fail
4099
+	 * @throws EE_Error
4100
+	 * @throws InvalidArgumentException
4101
+	 * @throws ReflectionException
4102
+	 * @throws InvalidDataTypeException
4103
+	 * @throws InvalidInterfaceException
4104
+	 */
4105
+	protected function _process_resend_registration(): bool
4106
+	{
4107
+		$this->_template_args['success'] = EED_Messages::process_resend($this->request->requestParams());
4108
+		do_action(
4109
+			'AHEE__EE_Admin_Page___process_resend_registration',
4110
+			$this->_template_args['success'],
4111
+			$this->request->requestParams()
4112
+		);
4113
+		return $this->_template_args['success'];
4114
+	}
4115
+
4116
+
4117
+	/**
4118
+	 * This automatically processes any payment message notifications when manual payment has been applied.
4119
+	 *
4120
+	 * @param EE_Payment $payment
4121
+	 * @return bool success/fail
4122
+	 */
4123
+	protected function _process_payment_notification(EE_Payment $payment): bool
4124
+	{
4125
+		add_filter('FHEE__EE_Payment_Processor__process_registration_payments__display_notifications', '__return_true');
4126
+		do_action('AHEE__EE_Admin_Page___process_admin_payment_notification', $payment);
4127
+		$this->_template_args['success'] = apply_filters(
4128
+			'FHEE__EE_Admin_Page___process_admin_payment_notification__success',
4129
+			false,
4130
+			$payment
4131
+		);
4132
+		return $this->_template_args['success'];
4133
+	}
4134
+
4135
+
4136
+	/**
4137
+	 * @param EEM_Base      $entity_model
4138
+	 * @param string        $entity_PK_name name of the primary key field used as a request param, ie: id, ID, etc
4139
+	 * @param string        $action         one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4140
+	 * @param string        $delete_column  name of the field that denotes whether entity is trashed
4141
+	 * @param callable|null $callback       called after entity is trashed, restored, or deleted
4142
+	 * @return int|float
4143
+	 * @throws EE_Error
4144
+	 */
4145
+	protected function trashRestoreDeleteEntities(
4146
+		EEM_Base $entity_model,
4147
+		string $entity_PK_name,
4148
+		string $action = EE_Admin_List_Table::ACTION_DELETE,
4149
+		string $delete_column = '',
4150
+		?callable $callback = null
4151
+	) {
4152
+		$entity_PK      = $entity_model->get_primary_key_field();
4153
+		$entity_PK_name = $entity_PK_name ?: $entity_PK->get_name();
4154
+		$entity_PK_type = $this->resolveEntityFieldDataType($entity_PK);
4155
+		// grab ID if deleting a single entity
4156
+		if ($this->request->requestParamIsSet($entity_PK_name)) {
4157
+			$ID = $this->request->getRequestParam($entity_PK_name, 0, $entity_PK_type);
4158
+			return $this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback) ? 1 : 0;
4159
+		}
4160
+		// or grab checkbox array if bulk deleting
4161
+		$checkboxes = $this->request->getRequestParam('checkbox', [], $entity_PK_type, true);
4162
+		if (empty($checkboxes)) {
4163
+			return 0;
4164
+		}
4165
+		$success = 0;
4166
+		$IDs     = array_keys($checkboxes);
4167
+		// cycle thru bulk action checkboxes
4168
+		foreach ($IDs as $ID) {
4169
+			// increment $success
4170
+			if ($this->trashRestoreDeleteEntity($entity_model, $ID, $action, $delete_column, $callback)) {
4171
+				$success++;
4172
+			}
4173
+		}
4174
+		$count = (int) count($checkboxes);
4175
+		// if multiple entities were deleted successfully, then $deleted will be full count of deletions,
4176
+		// otherwise it will be a fraction of ( actual deletions / total entities to be deleted )
4177
+		return $success === $count ? $count : $success / $count;
4178
+	}
4179
+
4180
+
4181
+	/**
4182
+	 * @param EE_Primary_Key_Field_Base $entity_PK
4183
+	 * @return string
4184
+	 * @throws EE_Error
4185
+	 * @since   4.10.30.p
4186
+	 */
4187
+	private function resolveEntityFieldDataType(EE_Primary_Key_Field_Base $entity_PK): string
4188
+	{
4189
+		$entity_PK_type = $entity_PK->getSchemaType();
4190
+		switch ($entity_PK_type) {
4191
+			case 'boolean':
4192
+				return DataType::BOOL;
4193
+			case 'integer':
4194
+				return DataType::INT;
4195
+			case 'number':
4196
+				return DataType::FLOAT;
4197
+			case 'string':
4198
+				return DataType::STRING;
4199
+		}
4200
+		throw new RuntimeException(
4201
+			sprintf(
4202
+				esc_html__(
4203
+					'"%1$s" is an invalid schema type for the %2$s primary key.',
4204
+					'event_espresso'
4205
+				),
4206
+				$entity_PK_type,
4207
+				$entity_PK->get_name()
4208
+			)
4209
+		);
4210
+	}
4211
+
4212
+
4213
+	/**
4214
+	 * @param EEM_Base      $entity_model
4215
+	 * @param int|string    $entity_ID
4216
+	 * @param string        $action        one of the EE_Admin_List_Table::ACTION_* constants: delete, restore, trash
4217
+	 * @param string        $delete_column name of the field that denotes whether entity is trashed
4218
+	 * @param callable|null $callback      called after entity is trashed, restored, or deleted
4219
+	 * @return bool
4220
+	 */
4221
+	protected function trashRestoreDeleteEntity(
4222
+		EEM_Base $entity_model,
4223
+		$entity_ID,
4224
+		string $action,
4225
+		string $delete_column,
4226
+		?callable $callback = null
4227
+	): bool {
4228
+		$entity_ID = absint($entity_ID);
4229
+		if (! $entity_ID) {
4230
+			$this->trashRestoreDeleteError($action, $entity_model);
4231
+		}
4232
+		$result = 0;
4233
+		try {
4234
+			$entity = $entity_model->get_one_by_ID($entity_ID);
4235
+			if (! $entity instanceof EE_Base_Class) {
4236
+				throw new DomainException(
4237
+					sprintf(
4238
+						esc_html__(
4239
+							'Missing or invalid %1$s entity with ID of "%2$s" returned from db.',
4240
+							'event_espresso'
4241
+						),
4242
+						str_replace('EEM_', '', $entity_model->get_this_model_name()),
4243
+						$entity_ID
4244
+					)
4245
+				);
4246
+			}
4247
+			switch ($action) {
4248
+				case EE_Admin_List_Table::ACTION_DELETE:
4249
+					$result = (bool) $entity->delete_permanently();
4250
+					break;
4251
+				case EE_Admin_List_Table::ACTION_RESTORE:
4252
+					$result = $entity->delete_or_restore(false);
4253
+					break;
4254
+				case EE_Admin_List_Table::ACTION_TRASH:
4255
+					$result = $entity->delete_or_restore();
4256
+					break;
4257
+			}
4258
+		} catch (Exception $exception) {
4259
+			$this->trashRestoreDeleteError($action, $entity_model, $exception);
4260
+		}
4261
+		if (is_callable($callback)) {
4262
+			call_user_func_array($callback, [$entity_model, $entity_ID, $action, $result, $delete_column]);
4263
+		}
4264
+		return $result;
4265
+	}
4266
+
4267
+
4268
+	/**
4269
+	 * @param EEM_Base $entity_model
4270
+	 * @param string   $delete_column
4271
+	 * @since 4.10.30.p
4272
+	 */
4273
+	private function validateDeleteColumn(EEM_Base $entity_model, string $delete_column)
4274
+	{
4275
+		if (empty($delete_column)) {
4276
+			throw new DomainException(
4277
+				sprintf(
4278
+					esc_html__(
4279
+						'You need to specify the name of the "delete column" on the %2$s model, in order to trash or restore an entity.',
4280
+						'event_espresso'
4281
+					),
4282
+					$entity_model->get_this_model_name()
4283
+				)
4284
+			);
4285
+		}
4286
+		if (! $entity_model->has_field($delete_column)) {
4287
+			throw new DomainException(
4288
+				sprintf(
4289
+					esc_html__(
4290
+						'The %1$s field does not exist on the %2$s model.',
4291
+						'event_espresso'
4292
+					),
4293
+					$delete_column,
4294
+					$entity_model->get_this_model_name()
4295
+				)
4296
+			);
4297
+		}
4298
+	}
4299
+
4300
+
4301
+	/**
4302
+	 * @param EEM_Base       $entity_model
4303
+	 * @param Exception|null $exception
4304
+	 * @param string         $action
4305
+	 * @since 4.10.30.p
4306
+	 */
4307
+	private function trashRestoreDeleteError(string $action, EEM_Base $entity_model, Exception $exception = null)
4308
+	{
4309
+		if ($exception instanceof Exception) {
4310
+			throw new RuntimeException(
4311
+				sprintf(
4312
+					esc_html__(
4313
+						'Could not %1$s the %2$s because the following error occurred: %3$s',
4314
+						'event_espresso'
4315
+					),
4316
+					$action,
4317
+					$entity_model->get_this_model_name(),
4318
+					$exception->getMessage()
4319
+				)
4320
+			);
4321
+		}
4322
+		throw new RuntimeException(
4323
+			sprintf(
4324
+				esc_html__(
4325
+					'Could not %1$s the %2$s because an invalid ID was received.',
4326
+					'event_espresso'
4327
+				),
4328
+				$action,
4329
+				$entity_model->get_this_model_name()
4330
+			)
4331
+		);
4332
+	}
4333 4333
 }
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)) {
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.',
@@ -1150,7 +1150,7 @@  discard block
 block discarded – undo
1150 1150
             } catch (Throwable $throwable) {
1151 1151
                 $nice_args = [];
1152 1152
                 foreach ($args as $key => $arg) {
1153
-                    $nice_args[ $key ] = is_object($arg) ? get_class($arg) : $key;
1153
+                    $nice_args[$key] = is_object($arg) ? get_class($arg) : $key;
1154 1154
                 }
1155 1155
                 new ExceptionStackTraceDisplay(
1156 1156
                     new RuntimeException(
@@ -1254,7 +1254,7 @@  discard block
 block discarded – undo
1254 1254
                 if (strpos($key, 'nonce') !== false) {
1255 1255
                     continue;
1256 1256
                 }
1257
-                $args[ 'wp_referer[' . $key . ']' ] = is_string($value) ? htmlspecialchars($value) : $value;
1257
+                $args['wp_referer['.$key.']'] = is_string($value) ? htmlspecialchars($value) : $value;
1258 1258
             }
1259 1259
         }
1260 1260
         return EEH_URL::add_query_args_and_nonce($args, $url, $exclude_nonce, $context);
@@ -1294,12 +1294,12 @@  discard block
 block discarded – undo
1294 1294
      */
1295 1295
     protected function _add_help_tabs()
1296 1296
     {
1297
-        if (isset($this->_page_config[ $this->_req_action ])) {
1298
-            $config = $this->_page_config[ $this->_req_action ];
1297
+        if (isset($this->_page_config[$this->_req_action])) {
1298
+            $config = $this->_page_config[$this->_req_action];
1299 1299
             // let's see if there is a help_sidebar set for the current route and we'll set that up for usage as well.
1300 1300
             if (is_array($config) && isset($config['help_sidebar'])) {
1301 1301
                 // check that the callback given is valid
1302
-                if (! method_exists($this, $config['help_sidebar'])) {
1302
+                if ( ! method_exists($this, $config['help_sidebar'])) {
1303 1303
                     throw new EE_Error(
1304 1304
                         sprintf(
1305 1305
                             esc_html__(
@@ -1312,18 +1312,18 @@  discard block
 block discarded – undo
1312 1312
                     );
1313 1313
                 }
1314 1314
                 $content = apply_filters(
1315
-                    'FHEE__' . $this->class_name . '__add_help_tabs__help_sidebar',
1315
+                    'FHEE__'.$this->class_name.'__add_help_tabs__help_sidebar',
1316 1316
                     $this->{$config['help_sidebar']}()
1317 1317
                 );
1318 1318
                 $this->_current_screen->set_help_sidebar($content);
1319 1319
             }
1320
-            if (! isset($config['help_tabs'])) {
1320
+            if ( ! isset($config['help_tabs'])) {
1321 1321
                 return;
1322 1322
             } //no help tabs for this route
1323 1323
             foreach ((array) $config['help_tabs'] as $tab_id => $cfg) {
1324 1324
                 // we're here so there ARE help tabs!
1325 1325
                 // make sure we've got what we need
1326
-                if (! isset($cfg['title'])) {
1326
+                if ( ! isset($cfg['title'])) {
1327 1327
                     throw new EE_Error(
1328 1328
                         esc_html__(
1329 1329
                             'The _page_config array is not set up properly for help tabs.  It is missing a title',
@@ -1331,7 +1331,7 @@  discard block
 block discarded – undo
1331 1331
                         )
1332 1332
                     );
1333 1333
                 }
1334
-                if (! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1334
+                if ( ! isset($cfg['filename']) && ! isset($cfg['callback']) && ! isset($cfg['content'])) {
1335 1335
                     throw new EE_Error(
1336 1336
                         esc_html__(
1337 1337
                             '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',
@@ -1340,11 +1340,11 @@  discard block
 block discarded – undo
1340 1340
                     );
1341 1341
                 }
1342 1342
                 // first priority goes to content.
1343
-                if (! empty($cfg['content'])) {
1343
+                if ( ! empty($cfg['content'])) {
1344 1344
                     $content = $cfg['content'];
1345 1345
                     // second priority goes to filename
1346
-                } elseif (! empty($cfg['filename'])) {
1347
-                    $file_path = $this->_get_dir() . '/help_tabs/' . $cfg['filename'] . '.help_tab.php';
1346
+                } elseif ( ! empty($cfg['filename'])) {
1347
+                    $file_path = $this->_get_dir().'/help_tabs/'.$cfg['filename'].'.help_tab.php';
1348 1348
                     // 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)
1349 1349
                     $file_path = ! is_readable($file_path) ? EE_ADMIN_PAGES
1350 1350
                                                              . basename($this->_get_dir())
@@ -1352,7 +1352,7 @@  discard block
 block discarded – undo
1352 1352
                                                              . $cfg['filename']
1353 1353
                                                              . '.help_tab.php' : $file_path;
1354 1354
                     // if file is STILL not readable then let's do a EE_Error so its more graceful than a fatal error.
1355
-                    if (! isset($cfg['callback']) && ! is_readable($file_path)) {
1355
+                    if ( ! isset($cfg['callback']) && ! is_readable($file_path)) {
1356 1356
                         EE_Error::add_error(
1357 1357
                             sprintf(
1358 1358
                                 esc_html__(
@@ -1400,7 +1400,7 @@  discard block
 block discarded – undo
1400 1400
                     return;
1401 1401
                 }
1402 1402
                 // setup config array for help tab method
1403
-                $id  = $this->page_slug . '-' . $this->_req_action . '-' . $tab_id;
1403
+                $id  = $this->page_slug.'-'.$this->_req_action.'-'.$tab_id;
1404 1404
                 $_ht = [
1405 1405
                     'id'       => $id,
1406 1406
                     'title'    => $cfg['title'],
@@ -1426,8 +1426,8 @@  discard block
 block discarded – undo
1426 1426
             $qtips = (array) $this->_route_config['qtips'];
1427 1427
             // load qtip loader
1428 1428
             $path = [
1429
-                $this->_get_dir() . '/qtips/',
1430
-                EE_ADMIN_PAGES . basename($this->_get_dir()) . '/qtips/',
1429
+                $this->_get_dir().'/qtips/',
1430
+                EE_ADMIN_PAGES.basename($this->_get_dir()).'/qtips/',
1431 1431
             ];
1432 1432
             EEH_Qtip_Loader::instance()->register($qtips, $path);
1433 1433
         }
@@ -1449,7 +1449,7 @@  discard block
 block discarded – undo
1449 1449
         $i        = 0;
1450 1450
         $only_tab = count($this->_page_config) < 2;
1451 1451
         foreach ($this->_page_config as $slug => $config) {
1452
-            if (! is_array($config) || empty($config['nav'])) {
1452
+            if ( ! is_array($config) || empty($config['nav'])) {
1453 1453
                 continue;
1454 1454
             }
1455 1455
             // no nav tab for this config
@@ -1458,7 +1458,7 @@  discard block
 block discarded – undo
1458 1458
                 // nav tab is only to appear when route requested.
1459 1459
                 continue;
1460 1460
             }
1461
-            if (! $this->check_user_access($slug, true)) {
1461
+            if ( ! $this->check_user_access($slug, true)) {
1462 1462
                 // no nav tab because current user does not have access.
1463 1463
                 continue;
1464 1464
             }
@@ -1466,20 +1466,20 @@  discard block
 block discarded – undo
1466 1466
             $css_class .= $only_tab ? ' ee-only-tab' : '';
1467 1467
             $css_class .= " ee-nav-tab__$slug";
1468 1468
 
1469
-            $this->_nav_tabs[ $slug ] = [
1469
+            $this->_nav_tabs[$slug] = [
1470 1470
                 'url'       => $config['nav']['url'] ?? EE_Admin_Page::add_query_args_and_nonce(
1471 1471
                         ['action' => $slug],
1472 1472
                         $this->_admin_base_url
1473 1473
                     ),
1474 1474
                 'link_text' => $this->navTabLabel($config['nav'], $slug),
1475
-                'css_class' => $this->_req_action === $slug ? $css_class . ' nav-tab-active' : $css_class,
1475
+                'css_class' => $this->_req_action === $slug ? $css_class.' nav-tab-active' : $css_class,
1476 1476
                 'order'     => $config['nav']['order'] ?? $i,
1477 1477
             ];
1478 1478
             $i++;
1479 1479
         }
1480 1480
         // if $this->_nav_tabs is empty then lets set the default
1481 1481
         if (empty($this->_nav_tabs)) {
1482
-            $this->_nav_tabs[ $this->_default_nav_tab_name ] = [
1482
+            $this->_nav_tabs[$this->_default_nav_tab_name] = [
1483 1483
                 'url'       => $this->_admin_base_url,
1484 1484
                 'link_text' => ucwords(str_replace('_', ' ', $this->_default_nav_tab_name)),
1485 1485
                 'css_class' => 'nav-tab-active',
@@ -1495,11 +1495,11 @@  discard block
 block discarded – undo
1495 1495
     {
1496 1496
         $label = $nav_tab['label'] ?? ucwords(str_replace('_', ' ', $slug));
1497 1497
         $icon  = $nav_tab['icon'] ?? null;
1498
-        $icon  = $icon ? '<span class="dashicons ' . $icon . '"></span>' : '';
1498
+        $icon  = $icon ? '<span class="dashicons '.$icon.'"></span>' : '';
1499 1499
         return '
1500 1500
             <span class="ee-admin-screen-tab__label">
1501
-                ' . $icon . '
1502
-                <span class="ee-nav-label__text">' . $label . '</span>
1501
+                ' . $icon.'
1502
+                <span class="ee-nav-label__text">' . $label.'</span>
1503 1503
             </span>';
1504 1504
     }
1505 1505
 
@@ -1517,10 +1517,10 @@  discard block
 block discarded – undo
1517 1517
             foreach ($this->_route_config['labels'] as $label => $text) {
1518 1518
                 if (is_array($text)) {
1519 1519
                     foreach ($text as $sublabel => $subtext) {
1520
-                        $this->_labels[ $label ][ $sublabel ] = $subtext;
1520
+                        $this->_labels[$label][$sublabel] = $subtext;
1521 1521
                     }
1522 1522
                 } else {
1523
-                    $this->_labels[ $label ] = $text;
1523
+                    $this->_labels[$label] = $text;
1524 1524
                 }
1525 1525
             }
1526 1526
         }
@@ -1546,10 +1546,10 @@  discard block
 block discarded – undo
1546 1546
             : $this->_req_action;
1547 1547
         $route_to_check = ! empty($route_to_check) ? $route_to_check : $req_action;
1548 1548
         $capability     = ! empty($route_to_check)
1549
-                          && isset($this->_page_routes[ $route_to_check ])
1550
-                          && is_array($this->_page_routes[ $route_to_check ])
1551
-                          && ! empty($this->_page_routes[ $route_to_check ]['capability'])
1552
-            ? $this->_page_routes[ $route_to_check ]['capability']
1549
+                          && isset($this->_page_routes[$route_to_check])
1550
+                          && is_array($this->_page_routes[$route_to_check])
1551
+                          && ! empty($this->_page_routes[$route_to_check]['capability'])
1552
+            ? $this->_page_routes[$route_to_check]['capability']
1553 1553
             : null;
1554 1554
 
1555 1555
         if (empty($capability) && empty($route_to_check)) {
@@ -1599,14 +1599,14 @@  discard block
 block discarded – undo
1599 1599
         string $priority = 'default',
1600 1600
         ?array $callback_args = null
1601 1601
     ) {
1602
-        if (! (is_callable($callback) || ! function_exists($callback))) {
1602
+        if ( ! (is_callable($callback) || ! function_exists($callback))) {
1603 1603
             return;
1604 1604
         }
1605 1605
 
1606 1606
         add_meta_box($box_id, $title, $callback, $screen, $context, $priority, $callback_args);
1607 1607
         add_filter(
1608 1608
             "postbox_classes_{$this->_wp_page_slug}_$box_id",
1609
-            function ($classes) {
1609
+            function($classes) {
1610 1610
                 $classes[] = 'ee-admin-container';
1611 1611
                 return $classes;
1612 1612
             }
@@ -1700,7 +1700,7 @@  discard block
 block discarded – undo
1700 1700
         ';
1701 1701
 
1702 1702
         // current set timezone for timezone js
1703
-        echo '<span id="current_timezone" class="hidden">' . esc_html(EEH_DTT_Helper::get_timezone()) . '</span>';
1703
+        echo '<span id="current_timezone" class="hidden">'.esc_html(EEH_DTT_Helper::get_timezone()).'</span>';
1704 1704
     }
1705 1705
 
1706 1706
 
@@ -1734,7 +1734,7 @@  discard block
 block discarded – undo
1734 1734
         // loop through the array and setup content
1735 1735
         foreach ($help_array as $trigger => $help) {
1736 1736
             // make sure the array is setup properly
1737
-            if (! isset($help['title'], $help['content'])) {
1737
+            if ( ! isset($help['title'], $help['content'])) {
1738 1738
                 throw new EE_Error(
1739 1739
                     esc_html__(
1740 1740
                         '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',
@@ -1748,8 +1748,8 @@  discard block
 block discarded – undo
1748 1748
                 'help_popup_title'   => $help['title'],
1749 1749
                 'help_popup_content' => $help['content'],
1750 1750
             ];
1751
-            $content       .= EEH_Template::display_template(
1752
-                EE_ADMIN_TEMPLATE . 'admin_help_popup.template.php',
1751
+            $content .= EEH_Template::display_template(
1752
+                EE_ADMIN_TEMPLATE.'admin_help_popup.template.php',
1753 1753
                 $template_args,
1754 1754
                 true
1755 1755
             );
@@ -1771,15 +1771,15 @@  discard block
 block discarded – undo
1771 1771
     private function _get_help_content(): array
1772 1772
     {
1773 1773
         // what is the method we're looking for?
1774
-        $method_name = '_help_popup_content_' . $this->_req_action;
1774
+        $method_name = '_help_popup_content_'.$this->_req_action;
1775 1775
         // if method doesn't exist let's get out.
1776
-        if (! method_exists($this, $method_name)) {
1776
+        if ( ! method_exists($this, $method_name)) {
1777 1777
             return [];
1778 1778
         }
1779 1779
         // k we're good to go let's retrieve the help array
1780 1780
         $help_array = $this->{$method_name}();
1781 1781
         // make sure we've got an array!
1782
-        if (! is_array($help_array)) {
1782
+        if ( ! is_array($help_array)) {
1783 1783
             throw new EE_Error(
1784 1784
                 esc_html__(
1785 1785
                     'Something went wrong with help popup content generation. Expecting an array and well, this ain\'t no array bub.',
@@ -1811,15 +1811,15 @@  discard block
 block discarded – undo
1811 1811
         // 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
1812 1812
         $help_array   = $this->_get_help_content();
1813 1813
         $help_content = '';
1814
-        if (empty($help_array) || ! isset($help_array[ $trigger_id ])) {
1815
-            $help_array[ $trigger_id ] = [
1814
+        if (empty($help_array) || ! isset($help_array[$trigger_id])) {
1815
+            $help_array[$trigger_id] = [
1816 1816
                 'title'   => esc_html__('Missing Content', 'event_espresso'),
1817 1817
                 'content' => esc_html__(
1818 1818
                     '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.)',
1819 1819
                     'event_espresso'
1820 1820
                 ),
1821 1821
             ];
1822
-            $help_content              = $this->_set_help_popup_content($help_array);
1822
+            $help_content = $this->_set_help_popup_content($help_array);
1823 1823
         }
1824 1824
         $height   = esc_attr($dimensions[0]) ?? 400;
1825 1825
         $width    = esc_attr($dimensions[1]) ?? 640;
@@ -1907,7 +1907,7 @@  discard block
 block discarded – undo
1907 1907
 
1908 1908
         add_filter(
1909 1909
             'admin_body_class',
1910
-            function ($classes) {
1910
+            function($classes) {
1911 1911
                 if (strpos($classes, 'espresso-admin') === false) {
1912 1912
                     $classes .= ' espresso-admin';
1913 1913
                 }
@@ -1998,12 +1998,12 @@  discard block
 block discarded – undo
1998 1998
     protected function _set_list_table()
1999 1999
     {
2000 2000
         // first is this a list_table view?
2001
-        if (! isset($this->_route_config['list_table'])) {
2001
+        if ( ! isset($this->_route_config['list_table'])) {
2002 2002
             return;
2003 2003
         } //not a list_table view so get out.
2004 2004
         // list table functions are per view specific (because some admin pages might have more than one list table!)
2005
-        $list_table_view = '_set_list_table_views_' . $this->_req_action;
2006
-        if (! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2005
+        $list_table_view = '_set_list_table_views_'.$this->_req_action;
2006
+        if ( ! method_exists($this, $list_table_view) || $this->{$list_table_view}() === false) {
2007 2007
             // user error msg
2008 2008
             $error_msg = esc_html__(
2009 2009
                 'An error occurred. The requested list table views could not be found.',
@@ -2023,10 +2023,10 @@  discard block
 block discarded – undo
2023 2023
         }
2024 2024
         // let's provide the ability to filter the views per PAGE AND ROUTE, per PAGE, and globally
2025 2025
         $this->_views = apply_filters(
2026
-            'FHEE_list_table_views_' . $this->page_slug . '_' . $this->_req_action,
2026
+            'FHEE_list_table_views_'.$this->page_slug.'_'.$this->_req_action,
2027 2027
             $this->_views
2028 2028
         );
2029
-        $this->_views = apply_filters('FHEE_list_table_views_' . $this->page_slug, $this->_views);
2029
+        $this->_views = apply_filters('FHEE_list_table_views_'.$this->page_slug, $this->_views);
2030 2030
         $this->_views = apply_filters('FHEE_list_table_views', $this->_views);
2031 2031
         $this->_set_list_table_view();
2032 2032
         $this->_set_list_table_object();
@@ -2061,7 +2061,7 @@  discard block
 block discarded – undo
2061 2061
     protected function _set_list_table_object()
2062 2062
     {
2063 2063
         if (isset($this->_route_config['list_table'])) {
2064
-            if (! class_exists($this->_route_config['list_table'])) {
2064
+            if ( ! class_exists($this->_route_config['list_table'])) {
2065 2065
                 throw new EE_Error(
2066 2066
                     sprintf(
2067 2067
                         esc_html__(
@@ -2102,17 +2102,17 @@  discard block
 block discarded – undo
2102 2102
         foreach ($this->_views as $key => $view) {
2103 2103
             $query_args = [];
2104 2104
             // check for current view
2105
-            $this->_views[ $key ]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2105
+            $this->_views[$key]['class']               = $this->_view === $view['slug'] ? 'current' : '';
2106 2106
             $query_args['action']                        = $this->_req_action;
2107
-            $query_args[ $this->_req_action . '_nonce' ] = wp_create_nonce($query_args['action'] . '_nonce');
2107
+            $query_args[$this->_req_action.'_nonce'] = wp_create_nonce($query_args['action'].'_nonce');
2108 2108
             $query_args['status']                        = $view['slug'];
2109 2109
             // merge any other arguments sent in.
2110
-            if (isset($extra_query_args[ $view['slug'] ])) {
2111
-                foreach ($extra_query_args[ $view['slug'] ] as $extra_query_arg) {
2110
+            if (isset($extra_query_args[$view['slug']])) {
2111
+                foreach ($extra_query_args[$view['slug']] as $extra_query_arg) {
2112 2112
                     $query_args[] = $extra_query_arg;
2113 2113
                 }
2114 2114
             }
2115
-            $this->_views[ $key ]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2115
+            $this->_views[$key]['url'] = EE_Admin_Page::add_query_args_and_nonce($query_args, $this->_admin_base_url);
2116 2116
         }
2117 2117
         return $this->_views;
2118 2118
     }
@@ -2142,14 +2142,14 @@  discard block
 block discarded – undo
2142 2142
 					<select id="entries-per-page-slct" name="entries-per-page-slct">';
2143 2143
         foreach ($values as $value) {
2144 2144
             if ($value < $max_entries) {
2145
-                $selected                  = $value === $per_page ? ' selected="' . $per_page . '"' : '';
2145
+                $selected = $value === $per_page ? ' selected="'.$per_page.'"' : '';
2146 2146
                 $entries_per_page_dropdown .= '
2147
-						<option value="' . $value . '"' . $selected . '>' . $value . '&nbsp;&nbsp;</option>';
2147
+						<option value="' . $value.'"'.$selected.'>'.$value.'&nbsp;&nbsp;</option>';
2148 2148
             }
2149 2149
         }
2150
-        $selected                  = $max_entries === $per_page ? ' selected="' . $per_page . '"' : '';
2150
+        $selected = $max_entries === $per_page ? ' selected="'.$per_page.'"' : '';
2151 2151
         $entries_per_page_dropdown .= '
2152
-						<option value="' . $max_entries . '"' . $selected . '>All&nbsp;&nbsp;</option>';
2152
+						<option value="' . $max_entries.'"'.$selected.'>All&nbsp;&nbsp;</option>';
2153 2153
         $entries_per_page_dropdown .= '
2154 2154
 					</select>
2155 2155
 					entries
@@ -2173,7 +2173,7 @@  discard block
 block discarded – undo
2173 2173
             empty($this->_search_btn_label) ? $this->page_label
2174 2174
                 : $this->_search_btn_label
2175 2175
         );
2176
-        $this->_template_args['search']['callback']  = 'search_' . $this->page_slug;
2176
+        $this->_template_args['search']['callback'] = 'search_'.$this->page_slug;
2177 2177
     }
2178 2178
 
2179 2179
 
@@ -2234,7 +2234,7 @@  discard block
 block discarded – undo
2234 2234
                                   );
2235 2235
                     throw new EE_Error($error_msg);
2236 2236
                 }
2237
-                unset($this->_route_config['metaboxes'][ $key ]);
2237
+                unset($this->_route_config['metaboxes'][$key]);
2238 2238
             }
2239 2239
         }
2240 2240
     }
@@ -2267,7 +2267,7 @@  discard block
 block discarded – undo
2267 2267
             $total_columns                                       = ! empty($screen_columns)
2268 2268
                 ? $screen_columns
2269 2269
                 : $this->_route_config['columns'][1];
2270
-            $this->_template_args['current_screen_widget_class'] = 'columns-' . $total_columns;
2270
+            $this->_template_args['current_screen_widget_class'] = 'columns-'.$total_columns;
2271 2271
             $this->_template_args['current_page']                = $this->_wp_page_slug;
2272 2272
             $this->_template_args['screen']                      = $this->_current_screen;
2273 2273
             $this->_column_template_path                         = EE_ADMIN_TEMPLATE
@@ -2313,7 +2313,7 @@  discard block
 block discarded – undo
2313 2313
      */
2314 2314
     protected function _espresso_ratings_request()
2315 2315
     {
2316
-        if (! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2316
+        if ( ! apply_filters('FHEE_show_ratings_request_meta_box', true)) {
2317 2317
             return;
2318 2318
         }
2319 2319
         $ratings_box_title = apply_filters(
@@ -2340,28 +2340,28 @@  discard block
 block discarded – undo
2340 2340
      */
2341 2341
     public function espresso_ratings_request()
2342 2342
     {
2343
-        EEH_Template::display_template(EE_ADMIN_TEMPLATE . 'espresso_ratings_request_content.template.php');
2343
+        EEH_Template::display_template(EE_ADMIN_TEMPLATE.'espresso_ratings_request_content.template.php');
2344 2344
     }
2345 2345
 
2346 2346
 
2347 2347
     public static function cached_rss_display(string $rss_id, string $url): bool
2348 2348
     {
2349
-        $loading   = '<p class="widget-loading hide-if-no-js">'
2349
+        $loading = '<p class="widget-loading hide-if-no-js">'
2350 2350
                      . esc_html__('Loading&#8230;', 'event_espresso')
2351 2351
                      . '</p><p class="hide-if-js">'
2352 2352
                      . esc_html__('This widget requires JavaScript.', 'event_espresso')
2353 2353
                      . '</p>';
2354
-        $pre       = '<div class="espresso-rss-display">' . "\n\t";
2355
-        $pre       .= '<span id="' . esc_attr($rss_id) . '_url" class="hidden">' . esc_url_raw($url) . '</span>';
2356
-        $post      = '</div>' . "\n";
2357
-        $cache_key = 'ee_rss_' . md5($rss_id);
2354
+        $pre       = '<div class="espresso-rss-display">'."\n\t";
2355
+        $pre .= '<span id="'.esc_attr($rss_id).'_url" class="hidden">'.esc_url_raw($url).'</span>';
2356
+        $post      = '</div>'."\n";
2357
+        $cache_key = 'ee_rss_'.md5($rss_id);
2358 2358
         $output    = get_transient($cache_key);
2359 2359
         if ($output !== false) {
2360
-            echo wp_kses($pre . $output . $post, AllowedTags::getWithFormTags());
2360
+            echo wp_kses($pre.$output.$post, AllowedTags::getWithFormTags());
2361 2361
             return true;
2362 2362
         }
2363
-        if (! (defined('DOING_AJAX') && DOING_AJAX)) {
2364
-            echo wp_kses($pre . $loading . $post, AllowedTags::getWithFormTags());
2363
+        if ( ! (defined('DOING_AJAX') && DOING_AJAX)) {
2364
+            echo wp_kses($pre.$loading.$post, AllowedTags::getWithFormTags());
2365 2365
             return false;
2366 2366
         }
2367 2367
         ob_start();
@@ -2428,7 +2428,7 @@  discard block
 block discarded – undo
2428 2428
     public function espresso_sponsors_post_box()
2429 2429
     {
2430 2430
         EEH_Template::display_template(
2431
-            EE_ADMIN_TEMPLATE . 'admin_general_metabox_contents_espresso_sponsors.template.php'
2431
+            EE_ADMIN_TEMPLATE.'admin_general_metabox_contents_espresso_sponsors.template.php'
2432 2432
         );
2433 2433
     }
2434 2434
 
@@ -2445,9 +2445,9 @@  discard block
 block discarded – undo
2445 2445
     protected function getPublishBoxTitle(): string
2446 2446
     {
2447 2447
         $publish_box_title = esc_html__('Publish', 'event_espresso');
2448
-        if (! empty($this->_labels['publishbox'])) {
2448
+        if ( ! empty($this->_labels['publishbox'])) {
2449 2449
             if (is_array($this->_labels['publishbox'])) {
2450
-                $publish_box_title = $this->_labels['publishbox'][ $this->_req_action ] ?? $publish_box_title;
2450
+                $publish_box_title = $this->_labels['publishbox'][$this->_req_action] ?? $publish_box_title;
2451 2451
             } else {
2452 2452
                 $publish_box_title = $this->_labels['publishbox'];
2453 2453
             }
@@ -2497,7 +2497,7 @@  discard block
 block discarded – undo
2497 2497
         // if we have extra content set let's add it in if not make sure its empty
2498 2498
         $this->_template_args['publish_box_extra_content'] = $this->_template_args['publish_box_extra_content'] ?? '';
2499 2499
         echo EEH_Template::display_template(
2500
-            EE_ADMIN_TEMPLATE . 'admin_details_publish_metabox.template.php',
2500
+            EE_ADMIN_TEMPLATE.'admin_details_publish_metabox.template.php',
2501 2501
             $this->_template_args,
2502 2502
             true
2503 2503
         );
@@ -2550,10 +2550,10 @@  discard block
 block discarded – undo
2550 2550
                 'submitdelete deletion button button--outline button--caution'
2551 2551
             );
2552 2552
         }
2553
-        if (! isset($this->_template_args['publish_delete_link'])) {
2553
+        if ( ! isset($this->_template_args['publish_delete_link'])) {
2554 2554
             $this->_template_args['publish_delete_link'] = '';
2555 2555
         }
2556
-        if (! empty($name) && ! empty($id)) {
2556
+        if ( ! empty($name) && ! empty($id)) {
2557 2557
             $this->addPublishPostMetaBoxHiddenFields($name, ['type' => 'hidden', 'value' => $id]);
2558 2558
         }
2559 2559
         $hidden_fields = $this->_generate_admin_form_fields($this->publish_post_meta_box_hidden_fields, 'array');
@@ -2586,7 +2586,7 @@  discard block
 block discarded – undo
2586 2586
 
2587 2587
     protected function addPublishPostMetaBoxHiddenFields(string $field_name, array $field_attributes)
2588 2588
     {
2589
-        $this->publish_post_meta_box_hidden_fields[ $field_name ] = $field_attributes;
2589
+        $this->publish_post_meta_box_hidden_fields[$field_name] = $field_attributes;
2590 2590
     }
2591 2591
 
2592 2592
 
@@ -2688,7 +2688,7 @@  discard block
 block discarded – undo
2688 2688
         }
2689 2689
         // 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)
2690 2690
         $call_back_func = $create_func
2691
-            ? static function ($post, $metabox) {
2691
+            ? static function($post, $metabox) {
2692 2692
                 do_action('AHEE_log', __FILE__, __FUNCTION__, '');
2693 2693
                 echo EEH_Template::display_template(
2694 2694
                     $metabox['args']['template_path'],
@@ -2698,7 +2698,7 @@  discard block
 block discarded – undo
2698 2698
             }
2699 2699
             : $callback;
2700 2700
         $this->addMetaBox(
2701
-            str_replace('_', '-', $action) . '-mbox',
2701
+            str_replace('_', '-', $action).'-mbox',
2702 2702
             $title,
2703 2703
             $call_back_func,
2704 2704
             $this->_wp_page_slug,
@@ -2814,13 +2814,13 @@  discard block
 block discarded – undo
2814 2814
                                                                     'event-espresso_page_espresso_',
2815 2815
                                                                     '',
2816 2816
                                                                     $this->_wp_page_slug
2817
-                                                                ) . ' ' . $this->_req_action . '-route';
2817
+                                                                ).' '.$this->_req_action.'-route';
2818 2818
 
2819 2819
         $template_path = $sidebar
2820 2820
             ? EE_ADMIN_TEMPLATE . 'admin_details_wrapper.template.php'
2821
-            : EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar.template.php';
2821
+            : EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar.template.php';
2822 2822
         if ($this->request->isAjax()) {
2823
-            $template_path = EE_ADMIN_TEMPLATE . 'admin_details_wrapper_no_sidebar_ajax.template.php';
2823
+            $template_path = EE_ADMIN_TEMPLATE.'admin_details_wrapper_no_sidebar_ajax.template.php';
2824 2824
         }
2825 2825
         $template_path = ! empty($this->_column_template_path) ? $this->_column_template_path : $template_path;
2826 2826
 
@@ -2854,11 +2854,11 @@  discard block
 block discarded – undo
2854 2854
     public function display_admin_caf_preview_page(string $utm_campaign_source = '', bool $display_sidebar = true)
2855 2855
     {
2856 2856
         // let's generate a default preview action button if there isn't one already present.
2857
-        $this->_labels['buttons']['buy_now']           = esc_html__(
2857
+        $this->_labels['buttons']['buy_now'] = esc_html__(
2858 2858
             'Upgrade to Event Espresso 4 Right Now',
2859 2859
             'event_espresso'
2860 2860
         );
2861
-        $buy_now_url                                   = add_query_arg(
2861
+        $buy_now_url = add_query_arg(
2862 2862
             [
2863 2863
                 'ee_ver'       => 'ee4',
2864 2864
                 'utm_source'   => 'ee4_plugin_admin',
@@ -2878,8 +2878,8 @@  discard block
 block discarded – undo
2878 2878
                 true
2879 2879
             )
2880 2880
             : $this->_template_args['preview_action_button'];
2881
-        $this->_template_args['admin_page_content']    = EEH_Template::display_template(
2882
-            EE_ADMIN_TEMPLATE . 'admin_caf_full_page_preview.template.php',
2881
+        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2882
+            EE_ADMIN_TEMPLATE.'admin_caf_full_page_preview.template.php',
2883 2883
             $this->_template_args,
2884 2884
             true
2885 2885
         );
@@ -2937,7 +2937,7 @@  discard block
 block discarded – undo
2937 2937
         // setup search attributes
2938 2938
         $this->_set_search_attributes();
2939 2939
         $this->_template_args['current_page']     = $this->_wp_page_slug;
2940
-        $template_path                            = EE_ADMIN_TEMPLATE . 'admin_list_wrapper.template.php';
2940
+        $template_path                            = EE_ADMIN_TEMPLATE.'admin_list_wrapper.template.php';
2941 2941
         $this->_template_args['table_url']        = $this->request->isAjax()
2942 2942
             ? add_query_arg(['noheader' => 'true', 'route' => $this->_req_action], $this->_admin_base_url)
2943 2943
             : add_query_arg(['route' => $this->_req_action], $this->_admin_base_url);
@@ -2945,10 +2945,10 @@  discard block
 block discarded – undo
2945 2945
         $this->_template_args['current_route']    = $this->_req_action;
2946 2946
         $this->_template_args['list_table_class'] = get_class($this->_list_table_object);
2947 2947
         $ajax_sorting_callback                    = $this->_list_table_object->get_ajax_sorting_callback();
2948
-        if (! empty($ajax_sorting_callback)) {
2948
+        if ( ! empty($ajax_sorting_callback)) {
2949 2949
             $sortable_list_table_form_fields = wp_nonce_field(
2950
-                $ajax_sorting_callback . '_nonce',
2951
-                $ajax_sorting_callback . '_nonce',
2950
+                $ajax_sorting_callback.'_nonce',
2951
+                $ajax_sorting_callback.'_nonce',
2952 2952
                 false,
2953 2953
                 false
2954 2954
             );
@@ -2965,18 +2965,18 @@  discard block
 block discarded – undo
2965 2965
 
2966 2966
         $hidden_form_fields = $this->_template_args['list_table_hidden_fields'] ?? '';
2967 2967
 
2968
-        $nonce_ref          = $this->_req_action . '_nonce';
2968
+        $nonce_ref          = $this->_req_action.'_nonce';
2969 2969
         $hidden_form_fields .= '
2970
-            <input type="hidden" name="' . $nonce_ref . '" value="' . wp_create_nonce($nonce_ref) . '">';
2970
+            <input type="hidden" name="' . $nonce_ref.'" value="'.wp_create_nonce($nonce_ref).'">';
2971 2971
 
2972 2972
         $this->_template_args['list_table_hidden_fields'] = $hidden_form_fields;
2973 2973
         // display message about search results?
2974
-        $search                                    = $this->request->getRequestParam('s');
2974
+        $search = $this->request->getRequestParam('s');
2975 2975
         $this->_template_args['before_list_table'] .= ! empty($search)
2976
-            ? '<p class="ee-search-results">' . sprintf(
2976
+            ? '<p class="ee-search-results">'.sprintf(
2977 2977
                 esc_html__('Displaying search results for the search string: %1$s', 'event_espresso'),
2978 2978
                 trim($search, '%')
2979
-            ) . '</p>'
2979
+            ).'</p>'
2980 2980
             : '';
2981 2981
         // filter before_list_table template arg
2982 2982
         $this->_template_args['before_list_table'] = apply_filters(
@@ -3010,7 +3010,7 @@  discard block
 block discarded – undo
3010 3010
         // convert to array and filter again
3011 3011
         // arrays are easier to inject new items in a specific location,
3012 3012
         // but would not be backwards compatible, so we have to add a new filter
3013
-        $this->_template_args['after_list_table']   = implode(
3013
+        $this->_template_args['after_list_table'] = implode(
3014 3014
             " \n",
3015 3015
             (array) apply_filters(
3016 3016
                 'FHEE__EE_Admin_Page___display_admin_list_table_page__after_list_table__template_args_array',
@@ -3065,7 +3065,7 @@  discard block
 block discarded – undo
3065 3065
             $this->page_slug
3066 3066
         );
3067 3067
         return EEH_Template::display_template(
3068
-            EE_ADMIN_TEMPLATE . 'admin_details_legend.template.php',
3068
+            EE_ADMIN_TEMPLATE.'admin_details_legend.template.php',
3069 3069
             $this->_template_args,
3070 3070
             true
3071 3071
         );
@@ -3188,7 +3188,7 @@  discard block
 block discarded – undo
3188 3188
         if ($this->request->isAjax()) {
3189 3189
             $this->_template_args['admin_page_content'] = EEH_Template::display_template(
3190 3190
             // $template_path,
3191
-                EE_ADMIN_TEMPLATE . 'admin_wrapper_ajax.template.php',
3191
+                EE_ADMIN_TEMPLATE.'admin_wrapper_ajax.template.php',
3192 3192
                 $this->_template_args,
3193 3193
                 true
3194 3194
             );
@@ -3197,7 +3197,7 @@  discard block
 block discarded – undo
3197 3197
         // load settings page wrapper template
3198 3198
         $template_path = $about
3199 3199
             ? EE_ADMIN_TEMPLATE . 'about_admin_wrapper.template.php'
3200
-            : EE_ADMIN_TEMPLATE . 'admin_wrapper.template.php';
3200
+            : EE_ADMIN_TEMPLATE.'admin_wrapper.template.php';
3201 3201
 
3202 3202
         EEH_Template::display_template($template_path, $this->_template_args);
3203 3203
     }
@@ -3281,12 +3281,12 @@  discard block
 block discarded – undo
3281 3281
         $default_names = ['save', 'save_and_close'];
3282 3282
         $buttons       = '';
3283 3283
         foreach ($button_text as $key => $button) {
3284
-            $ref     = $default_names[ $key ];
3285
-            $name    = ! empty($actions) ? $actions[ $key ] : $ref;
3286
-            $buttons .= '<input type="submit" class="button button--primary ' . $ref . '" '
3287
-                        . 'value="' . $button . '" name="' . $name . '" '
3288
-                        . 'id="' . $this->_current_view . '_' . $ref . '" />';
3289
-            if (! $both) {
3284
+            $ref     = $default_names[$key];
3285
+            $name    = ! empty($actions) ? $actions[$key] : $ref;
3286
+            $buttons .= '<input type="submit" class="button button--primary '.$ref.'" '
3287
+                        . 'value="'.$button.'" name="'.$name.'" '
3288
+                        . 'id="'.$this->_current_view.'_'.$ref.'" />';
3289
+            if ( ! $both) {
3290 3290
                 break;
3291 3291
             }
3292 3292
         }
@@ -3327,13 +3327,13 @@  discard block
 block discarded – undo
3327 3327
                 'An error occurred. No action was set for this page\'s form.',
3328 3328
                 'event_espresso'
3329 3329
             );
3330
-            $dev_msg  = $user_msg . "\n"
3330
+            $dev_msg = $user_msg."\n"
3331 3331
                         . sprintf(
3332 3332
                             esc_html__('The $route argument is required for the %s->%s method.', 'event_espresso'),
3333 3333
                             __FUNCTION__,
3334 3334
                             __CLASS__
3335 3335
                         );
3336
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
3336
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
3337 3337
         }
3338 3338
         // open form
3339 3339
         $action                                            = $this->_admin_base_url;
@@ -3341,9 +3341,9 @@  discard block
 block discarded – undo
3341 3341
             <form name='form' method='post' action='$action' id='{$route}_event_form' class='ee-admin-page-form' >
3342 3342
             ";
3343 3343
         // add nonce
3344
-        $nonce                                             =
3345
-            wp_nonce_field($route . '_nonce', $route . '_nonce', false, false);
3346
-        $this->_template_args['before_admin_page_content'] .= "\n\t" . $nonce;
3344
+        $nonce =
3345
+            wp_nonce_field($route.'_nonce', $route.'_nonce', false, false);
3346
+        $this->_template_args['before_admin_page_content'] .= "\n\t".$nonce;
3347 3347
         // add REQUIRED form action
3348 3348
         $hidden_fields = [
3349 3349
             'action' => ['type' => 'hidden', 'value' => $route],
@@ -3356,7 +3356,7 @@  discard block
 block discarded – undo
3356 3356
         $form_fields = $this->_generate_admin_form_fields($hidden_fields, 'array');
3357 3357
         // add fields to form
3358 3358
         foreach ((array) $form_fields as $form_field) {
3359
-            $this->_template_args['before_admin_page_content'] .= "\n\t" . $form_field['field'];
3359
+            $this->_template_args['before_admin_page_content'] .= "\n\t".$form_field['field'];
3360 3360
         }
3361 3361
         // close form
3362 3362
         $this->_template_args['after_admin_page_content'] = '</form>';
@@ -3439,10 +3439,10 @@  discard block
 block discarded – undo
3439 3439
     ) {
3440 3440
         $notices = EE_Error::get_notices(false);
3441 3441
         // overwrite default success messages //BUT ONLY if overwrite not overridden
3442
-        if (! $override_overwrite || ! empty($notices['errors'])) {
3442
+        if ( ! $override_overwrite || ! empty($notices['errors'])) {
3443 3443
             EE_Error::overwrite_success();
3444 3444
         }
3445
-        if (! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3445
+        if ( ! $override_overwrite && ! empty($what) && ! empty($action_desc) && empty($notices['errors'])) {
3446 3446
             // how many records affected ? more than one record ? or just one ?
3447 3447
             EE_Error::add_success(
3448 3448
                 sprintf(
@@ -3493,7 +3493,7 @@  discard block
 block discarded – undo
3493 3493
             $redirect_url = admin_url('admin.php');
3494 3494
         }
3495 3495
         // merge any default query_args set in _default_route_query_args property
3496
-        if (! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3496
+        if ( ! empty($this->_default_route_query_args) && ! $this->_is_UI_request) {
3497 3497
             $args_to_merge = [];
3498 3498
             foreach ($this->_default_route_query_args as $query_param => $query_value) {
3499 3499
                 // is there a wp_referer array in our _default_route_query_args property?
@@ -3505,15 +3505,15 @@  discard block
 block discarded – undo
3505 3505
                         }
3506 3506
                         // finally we will override any arguments in the referer with
3507 3507
                         // what might be set on the _default_route_query_args array.
3508
-                        if (isset($this->_default_route_query_args[ $reference ])) {
3509
-                            $args_to_merge[ $reference ] = urlencode($this->_default_route_query_args[ $reference ]);
3508
+                        if (isset($this->_default_route_query_args[$reference])) {
3509
+                            $args_to_merge[$reference] = urlencode($this->_default_route_query_args[$reference]);
3510 3510
                         } else {
3511
-                            $args_to_merge[ $reference ] = urlencode($value);
3511
+                            $args_to_merge[$reference] = urlencode($value);
3512 3512
                         }
3513 3513
                     }
3514 3514
                     continue;
3515 3515
                 }
3516
-                $args_to_merge[ $query_param ] = $query_value;
3516
+                $args_to_merge[$query_param] = $query_value;
3517 3517
             }
3518 3518
             // now let's merge these arguments but override with what was specifically sent in to the
3519 3519
             // redirect.
@@ -3525,19 +3525,19 @@  discard block
 block discarded – undo
3525 3525
         if (isset($query_args['action'])) {
3526 3526
             // manually generate wp_nonce and merge that with the query vars
3527 3527
             // becuz the wp_nonce_url function wrecks havoc on some vars
3528
-            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'] . '_nonce');
3528
+            $query_args['_wpnonce'] = wp_create_nonce($query_args['action'].'_nonce');
3529 3529
         }
3530 3530
         // we're adding some hooks and filters in here for processing any things just before redirects
3531 3531
         // (example: an admin page has done an insert or update and we want to run something after that).
3532
-        do_action('AHEE_redirect_' . $this->class_name . $this->_req_action, $query_args);
3532
+        do_action('AHEE_redirect_'.$this->class_name.$this->_req_action, $query_args);
3533 3533
         $redirect_url = apply_filters(
3534
-            'FHEE_redirect_' . $this->class_name . $this->_req_action,
3534
+            'FHEE_redirect_'.$this->class_name.$this->_req_action,
3535 3535
             EE_Admin_Page::add_query_args_and_nonce($query_args, $redirect_url),
3536 3536
             $query_args
3537 3537
         );
3538 3538
         // check if we're doing ajax.  If we are then lets just return the results and js can handle how it wants.
3539 3539
         if ($this->request->isAjax()) {
3540
-            $default_data                    = [
3540
+            $default_data = [
3541 3541
                 'close'        => true,
3542 3542
                 'redirect_url' => $redirect_url,
3543 3543
                 'where'        => 'main',
@@ -3590,7 +3590,7 @@  discard block
 block discarded – undo
3590 3590
         }
3591 3591
         $this->_template_args['notices'] = EE_Error::get_notices();
3592 3592
         // IF this isn't ajax we need to create a transient for the notices using the route (however, overridden if $sticky_notices == true)
3593
-        if (! $this->request->isAjax() || $sticky_notices) {
3593
+        if ( ! $this->request->isAjax() || $sticky_notices) {
3594 3594
             $route = $query_args['action'] ?? 'default';
3595 3595
             $this->_add_transient(
3596 3596
                 $route,
@@ -3630,7 +3630,7 @@  discard block
 block discarded – undo
3630 3630
         bool $exclude_nonce = false
3631 3631
     ): string {
3632 3632
         // first let's validate the action (if $base_url is FALSE otherwise validation will happen further along)
3633
-        if (empty($base_url) && ! isset($this->_page_routes[ $action ])) {
3633
+        if (empty($base_url) && ! isset($this->_page_routes[$action])) {
3634 3634
             throw new EE_Error(
3635 3635
                 sprintf(
3636 3636
                     esc_html__(
@@ -3641,7 +3641,7 @@  discard block
 block discarded – undo
3641 3641
                 )
3642 3642
             );
3643 3643
         }
3644
-        if (! isset($this->_labels['buttons'][ $type ])) {
3644
+        if ( ! isset($this->_labels['buttons'][$type])) {
3645 3645
             throw new EE_Error(
3646 3646
                 sprintf(
3647 3647
                     esc_html__(
@@ -3654,7 +3654,7 @@  discard block
 block discarded – undo
3654 3654
         }
3655 3655
         // finally check user access for this button.
3656 3656
         $has_access = $this->check_user_access($action, true);
3657
-        if (! $has_access) {
3657
+        if ( ! $has_access) {
3658 3658
             return '';
3659 3659
         }
3660 3660
         $_base_url  = ! $base_url ? $this->_admin_base_url : $base_url;
@@ -3662,11 +3662,11 @@  discard block
 block discarded – undo
3662 3662
             'action' => $action,
3663 3663
         ];
3664 3664
         // merge extra_request args but make sure our original action takes precedence and doesn't get overwritten.
3665
-        if (! empty($extra_request)) {
3665
+        if ( ! empty($extra_request)) {
3666 3666
             $query_args = array_merge($extra_request, $query_args);
3667 3667
         }
3668 3668
         $url = EE_Admin_Page::add_query_args_and_nonce($query_args, $_base_url, false, $exclude_nonce);
3669
-        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][ $type ], $class);
3669
+        return EEH_Template::get_button_or_link($url, $this->_labels['buttons'][$type], $class);
3670 3670
     }
3671 3671
 
3672 3672
 
@@ -3692,7 +3692,7 @@  discard block
 block discarded – undo
3692 3692
                 'FHEE__EE_Admin_Page___per_page_screen_options__default',
3693 3693
                 20
3694 3694
             ),
3695
-            'option'  => $this->_current_page . '_' . $this->_current_view . '_per_page',
3695
+            'option'  => $this->_current_page.'_'.$this->_current_view.'_per_page',
3696 3696
         ];
3697 3697
         // ONLY add the screen option if the user has access to it.
3698 3698
         if ($this->check_user_access($this->_current_view, true)) {
@@ -3713,18 +3713,18 @@  discard block
 block discarded – undo
3713 3713
     {
3714 3714
         if ($this->request->requestParamIsSet('wp_screen_options')) {
3715 3715
             check_admin_referer('screen-options-nonce', 'screenoptionnonce');
3716
-            if (! $user = wp_get_current_user()) {
3716
+            if ( ! $user = wp_get_current_user()) {
3717 3717
                 return;
3718 3718
             }
3719 3719
             $option = $this->request->getRequestParam('wp_screen_options[option]', '', DataType::KEY);
3720
-            if (! $option) {
3720
+            if ( ! $option) {
3721 3721
                 return;
3722 3722
             }
3723 3723
             $value      = $this->request->getRequestParam('wp_screen_options[value]', 0, DataType::INT);
3724 3724
             $map_option = $option;
3725 3725
             $option     = str_replace('-', '_', $option);
3726 3726
             switch ($map_option) {
3727
-                case $this->_current_page . '_' . $this->_current_view . '_per_page':
3727
+                case $this->_current_page.'_'.$this->_current_view.'_per_page':
3728 3728
                     $max_value = apply_filters(
3729 3729
                         'FHEE__EE_Admin_Page___set_per_page_screen_options__max_value',
3730 3730
                         999,
@@ -3785,7 +3785,7 @@  discard block
 block discarded – undo
3785 3785
         bool $skip_route_verify = false
3786 3786
     ) {
3787 3787
         $user_id = get_current_user_id();
3788
-        if (! $skip_route_verify) {
3788
+        if ( ! $skip_route_verify) {
3789 3789
             $this->_verify_route($route);
3790 3790
         }
3791 3791
         // now let's set the string for what kind of transient we're setting
@@ -3818,8 +3818,8 @@  discard block
 block discarded – undo
3818 3818
         $user_id   = get_current_user_id();
3819 3819
         $route     = ! $route ? $this->_req_action : $route;
3820 3820
         $transient = $notices
3821
-            ? 'ee_rte_n_tx_' . $route . '_' . $user_id
3822
-            : 'rte_tx_' . $route . '_' . $user_id;
3821
+            ? 'ee_rte_n_tx_'.$route.'_'.$user_id
3822
+            : 'rte_tx_'.$route.'_'.$user_id;
3823 3823
         $data      = is_multisite() && is_network_admin()
3824 3824
             ? get_site_transient($transient)
3825 3825
             : get_transient($transient);
@@ -4065,7 +4065,7 @@  discard block
 block discarded – undo
4065 4065
      */
4066 4066
     protected function _next_link(string $url, string $class = 'dashicons dashicons-arrow-right'): string
4067 4067
     {
4068
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4068
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4069 4069
     }
4070 4070
 
4071 4071
 
@@ -4078,7 +4078,7 @@  discard block
 block discarded – undo
4078 4078
      */
4079 4079
     protected function _previous_link(string $url, string $class = 'dashicons dashicons-arrow-left'): string
4080 4080
     {
4081
-        return '<a class="' . $class . '" href="' . $url . '"></a>';
4081
+        return '<a class="'.$class.'" href="'.$url.'"></a>';
4082 4082
     }
4083 4083
 
4084 4084
 
@@ -4226,13 +4226,13 @@  discard block
 block discarded – undo
4226 4226
         ?callable $callback = null
4227 4227
     ): bool {
4228 4228
         $entity_ID = absint($entity_ID);
4229
-        if (! $entity_ID) {
4229
+        if ( ! $entity_ID) {
4230 4230
             $this->trashRestoreDeleteError($action, $entity_model);
4231 4231
         }
4232 4232
         $result = 0;
4233 4233
         try {
4234 4234
             $entity = $entity_model->get_one_by_ID($entity_ID);
4235
-            if (! $entity instanceof EE_Base_Class) {
4235
+            if ( ! $entity instanceof EE_Base_Class) {
4236 4236
                 throw new DomainException(
4237 4237
                     sprintf(
4238 4238
                         esc_html__(
@@ -4283,7 +4283,7 @@  discard block
 block discarded – undo
4283 4283
                 )
4284 4284
             );
4285 4285
         }
4286
-        if (! $entity_model->has_field($delete_column)) {
4286
+        if ( ! $entity_model->has_field($delete_column)) {
4287 4287
             throw new DomainException(
4288 4288
                 sprintf(
4289 4289
                     esc_html__(
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT_Init.core.php 1 patch
Indentation   +37 added lines, -37 removed lines patch added patch discarded remove patch
@@ -12,45 +12,45 @@
 block discarded – undo
12 12
  */
13 13
 abstract class EE_Admin_Page_CPT_Init extends EE_Admin_Page_Init
14 14
 {
15
-    public function do_initial_loads()
16
-    {
17
-        // we want to use the corresponding admin page object (but not route it!).
18
-        // To do this we just set _routing to false.
19
-        // That way this page object is being loaded on all pages to make sure we hook into admin properly.
20
-        // But note... we are ONLY doing this if the given page is NOT pages we WANT to load ;)
21
-        // This is important because we have hooks that help redirect custom post type saves
22
-        $page           = $this->request->getRequestParam('page');
23
-        $page           = $this->request->getRequestParam('current_page', $page);
24
-        $this->_routing = $page === $this->_menu_map->menuSlug();
25
-        $this->_initialize_admin_page();
26
-        if ($this->_routing) {
27
-            // added for 4.1 to completely disable autosave for our pages.
28
-            // This can be removed once we fully enable autosave functionality
29
-            remove_filter('wp_print_scripts', 'wp_just_in_time_script_localization');
30
-            add_filter('wp_print_scripts', [$this, 'wp_just_in_time_script_localization'], 100);
31
-            // end removal of autosave functionality.
32
-        }
33
-    }
15
+	public function do_initial_loads()
16
+	{
17
+		// we want to use the corresponding admin page object (but not route it!).
18
+		// To do this we just set _routing to false.
19
+		// That way this page object is being loaded on all pages to make sure we hook into admin properly.
20
+		// But note... we are ONLY doing this if the given page is NOT pages we WANT to load ;)
21
+		// This is important because we have hooks that help redirect custom post type saves
22
+		$page           = $this->request->getRequestParam('page');
23
+		$page           = $this->request->getRequestParam('current_page', $page);
24
+		$this->_routing = $page === $this->_menu_map->menuSlug();
25
+		$this->_initialize_admin_page();
26
+		if ($this->_routing) {
27
+			// added for 4.1 to completely disable autosave for our pages.
28
+			// This can be removed once we fully enable autosave functionality
29
+			remove_filter('wp_print_scripts', 'wp_just_in_time_script_localization');
30
+			add_filter('wp_print_scripts', [$this, 'wp_just_in_time_script_localization'], 100);
31
+			// end removal of autosave functionality.
32
+		}
33
+	}
34 34
 
35 35
 
36
-    public function wp_just_in_time_script_localization()
37
-    {
38
-        wp_localize_script(
39
-            'autosave',
40
-            'autosaveL10n',
41
-            [
42
-                'autosaveInterval' => 172800,
43
-                'savingText'       => wp_strip_all_tags(__('Saving Draft&#8230;', 'event_espresso')),
44
-                'saveAlert'        => wp_strip_all_tags(
45
-                    __('The changes you made will be lost if you navigate away from this page.', 'event_espresso')
46
-                ),
47
-            ]
48
-        );
49
-    }
36
+	public function wp_just_in_time_script_localization()
37
+	{
38
+		wp_localize_script(
39
+			'autosave',
40
+			'autosaveL10n',
41
+			[
42
+				'autosaveInterval' => 172800,
43
+				'savingText'       => wp_strip_all_tags(__('Saving Draft&#8230;', 'event_espresso')),
44
+				'saveAlert'        => wp_strip_all_tags(
45
+					__('The changes you made will be lost if you navigate away from this page.', 'event_espresso')
46
+				),
47
+			]
48
+		);
49
+	}
50 50
 
51 51
 
52
-    public function adjust_post_lock_window($interval)
53
-    {
54
-        return 172800;
55
-    }
52
+	public function adjust_post_lock_window($interval)
53
+	{
54
+		return 172800;
55
+	}
56 56
 }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_Init.core.php 2 patches
Indentation   +489 added lines, -489 removed lines patch added patch discarded remove patch
@@ -18,494 +18,494 @@
 block discarded – undo
18 18
  */
19 19
 abstract class EE_Admin_Page_Init extends EE_Base
20 20
 {
21
-    /**
22
-     * This holds the menu map object for this admin page.
23
-     */
24
-    protected ?AdminMenuItem    $_menu_map           = null;
25
-
26
-    protected ?EE_Admin_Page    $_loaded_page_object = null;
21
+	/**
22
+	 * This holds the menu map object for this admin page.
23
+	 */
24
+	protected ?AdminMenuItem    $_menu_map           = null;
25
+
26
+	protected ?EE_Admin_Page    $_loaded_page_object = null;
27 27
 
28
-    protected ?LoaderInterface  $loader              = null;
29
-
30
-    protected ?RequestInterface $request             = null;
31
-
32
-    private bool                $_load_page          = false;
33
-
34
-    protected bool              $_routing            = false;
35
-
36
-    /**
37
-     * Menu map has a capability.  However, this allows admin pages to have separate capability requirements for menus
38
-     * and accessing pages.  If capability is NOT set, then it defaults to the menu_map capability.
39
-     *
40
-     * @var string
41
-     */
42
-    public string $capability = '';
43
-
44
-    /**
45
-     * identity properties (set in _set_defaults and _set_init_properties)
46
-     */
47
-    public string    $label         = '';
48
-
49
-    protected string $_file_name    = '';
50
-
51
-    protected string $_folder_name  = '';
52
-
53
-    protected string $_folder_path  = '';
54
-
55
-    protected string $_wp_page_slug = '';
56
-
57
-    public string    $hook_file     = '';
58
-
59
-    public string    $menu_slug     = '';
60
-
61
-    /**
62
-     * @deprecated
63
-     */
64
-    public string   $menu_label    = '';
65
-
66
-    protected array $_files_hooked = [];
67
-
68
-    protected array $_hook_paths   = [];
69
-
70
-
71
-    /**
72
-     * @throws InvalidArgumentException
73
-     * @throws InvalidDataTypeException
74
-     * @throws InvalidInterfaceException
75
-     */
76
-    public function __construct(RequestInterface $request = null)
77
-    {
78
-        $this->loader  = LoaderFactory::getLoader();
79
-        $this->request = $request instanceof RequestInterface
80
-            ? $request
81
-            : $this->loader->getShared(RequestInterface::class);
82
-        // set global defaults
83
-        $this->_set_defaults();
84
-        // set properties that are always available with objects.
85
-        $this->_set_init_properties();
86
-        // global styles/scripts across all wp admin pages
87
-        add_action('admin_enqueue_scripts', [$this, 'load_wp_global_scripts_styles'], 5);
88
-        // load initial stuff.
89
-        $this->_set_file_and_folder_name();
90
-    }
91
-
92
-
93
-    /**
94
-     * _set_init_properties
95
-     * Child classes use to set the following properties:
96
-     * $label
97
-     *
98
-     * @abstract
99
-     * @return void
100
-     */
101
-    abstract protected function _set_init_properties();
102
-
103
-
104
-    /**
105
-     * @return AdminMenuItem|null
106
-     * @since       4.4.0
107
-     * @deprecated  5.0.0.p
108
-     */
109
-    public function get_menu_map()
110
-    {
111
-        return $this->adminMenu();
112
-    }
113
-
114
-
115
-    /**
116
-     * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of
117
-     * EE_Admin_Page_Menu_Map.  Their menu can either be EE_Admin_Page_Main_Menu or AdminMenuSubItem.
118
-     *
119
-     * @since       4.4.0
120
-     * @deprecated  5.0.0.p
121
-     */
122
-    protected function _set_menu_map()
123
-    {
124
-    }
125
-
126
-
127
-    /**
128
-     * @since   5.0.0.p
129
-     */
130
-    public function setupLegacyAdminMenuItem()
131
-    {
132
-        // will be overridden by child classes not using new system
133
-        $this->_set_menu_map();
134
-    }
135
-
136
-
137
-    /**
138
-     * Child classes should return an array of properties used to construct the AdminMenuItem
139
-     *
140
-     * @return array
141
-     * @since 5.0.0.p
142
-     */
143
-    public function getMenuProperties(): array
144
-    {
145
-        return [];
146
-    }
147
-
148
-
149
-    /**
150
-     * @param AdminMenuItem $menu
151
-     * @return void
152
-     * @since 5.0.0.p
153
-     */
154
-    public function setAdminMenu(AdminMenuItem $menu): void
155
-    {
156
-        $this->_menu_map = $menu;
157
-    }
158
-
159
-
160
-    /**
161
-     * returns the menu map for this admin page
162
-     *
163
-     * @return AdminMenuItem|null
164
-     * @since 5.0.0.p
165
-     */
166
-    public function adminMenu(): ?AdminMenuItem
167
-    {
168
-        return $this->_menu_map;
169
-    }
170
-
171
-
172
-    /**
173
-     * @param string $wp_page_slug
174
-     * @since 5.0.0.p
175
-     */
176
-    public function setWpPageSlug(string $wp_page_slug): void
177
-    {
178
-        $this->_wp_page_slug = $wp_page_slug;
179
-    }
180
-
181
-
182
-    /**
183
-     * This loads scripts and styles for the EE_Admin system
184
-     * that must be available on ALL WP admin pages (i.e. EE_menu items)
185
-     *
186
-     * @return void
187
-     */
188
-    public function load_wp_global_scripts_styles()
189
-    {
190
-        wp_register_style(
191
-            'espresso_admin_base',
192
-            EE_ADMIN_URL . 'assets/ee-admin-base.css',
193
-            ['dashicons'],
194
-            EVENT_ESPRESSO_VERSION
195
-        );
196
-        wp_register_style(
197
-            'espresso_menu',
198
-            EE_ADMIN_URL . 'assets/ee-admin-menu.css',
199
-            ['espresso_admin_base'],
200
-            EVENT_ESPRESSO_VERSION
201
-        );
202
-        wp_enqueue_style('espresso_admin_base');
203
-        wp_enqueue_style('espresso_menu');
204
-    }
205
-
206
-
207
-    /**
208
-     * this sets default properties (might be overridden in _set_init_properties);
209
-     *
210
-     * @return  void
211
-     */
212
-    private function _set_defaults()
213
-    {
214
-        $this->_file_name    = '';
215
-        $this->_folder_name  = '';
216
-        $this->_wp_page_slug = '';
217
-        $this->capability    = '';
218
-        $this->_routing      = true;
219
-        $this->_load_page    = false;
220
-        $this->_files_hooked = [];
221
-        $this->_hook_paths   = [];
222
-    }
223
-
224
-
225
-    public function setCapability($capability, $menu_slug)
226
-    {
227
-        $this->capability = apply_filters('FHEE_' . $menu_slug . '_capability', $capability);
228
-    }
229
-
230
-
231
-    /**
232
-     * @deprecated 5.0.0.p
233
-     */
234
-    protected function _set_capability()
235
-    {
236
-        if ($this->_menu_map instanceof AdminMenuItem) {
237
-            $this->setCapability($this->_menu_map->capability(), $this->_menu_map->menuSlug());
238
-        }
239
-    }
240
-
241
-
242
-    /**
243
-     * initialize_admin_page
244
-     * This method is what executes the loading of the specific page class for the given dir_name as called by the
245
-     * EE_Admin_Init class.
246
-     *
247
-     * @return void
248
-     * @throws EE_Error
249
-     * @throws ReflectionException
250
-     */
251
-    public function initialize_admin_page()
252
-    {
253
-        // let's check user access first
254
-        $this->_check_user_access();
255
-        if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
256
-            return;
257
-        }
258
-        $this->_loaded_page_object->route_admin_request();
259
-    }
260
-
261
-
262
-    /**
263
-     * @param string $wp_page_slug
264
-     * @throws EE_Error
265
-     */
266
-    public function set_page_dependencies(string $wp_page_slug)
267
-    {
268
-        if (! $this->_load_page) {
269
-            return;
270
-        }
271
-        if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
272
-            $msg[] = esc_html__(
273
-                'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
274
-                'event_espresso'
275
-            );
276
-            $msg[] = $msg[0] . "\r\n"
277
-                     . sprintf(
278
-                         esc_html__(
279
-                             'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
280
-                             'event_espresso'
281
-                         ),
282
-                         $this->_file_name,
283
-                         $this->_file_name,
284
-                         $this->_folder_path . $this->_file_name,
285
-                         $this->_menu_map->menuSlug()
286
-                     );
287
-            throw new EE_Error(implode('||', $msg));
288
-        }
289
-        $this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
290
-        $page_hook = "load-$wp_page_slug";
291
-        // hook into page load hook so all page specific stuff gets loaded.
292
-        if (! empty($wp_page_slug)) {
293
-            add_action($page_hook, [$this->_loaded_page_object, 'load_page_dependencies']);
294
-        }
295
-    }
296
-
297
-
298
-    /**
299
-     * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run
300
-     * before the load-page... hook. Note, the page loads are happening around the wp_init hook.
301
-     *
302
-     * @return void
303
-     * @throws InvalidArgumentException
304
-     * @throws InvalidDataTypeException
305
-     * @throws InvalidInterfaceException
306
-     * @throws EE_Error
307
-     * @throws ReflectionException
308
-     */
309
-    public function do_initial_loads()
310
-    {
311
-        // no loading or initializing if menu map is setup incorrectly.
312
-        if (! $this->_menu_map instanceof AdminMenuItem) {
313
-            return;
314
-        }
315
-        $this->_initialize_admin_page();
316
-    }
317
-
318
-
319
-    /**
320
-     * all we're doing here is setting the $_file_name property for later use.
321
-     *
322
-     * @return void
323
-     */
324
-    private function _set_file_and_folder_name()
325
-    {
326
-        $bt = debug_backtrace();
327
-        // for more reliable determination of folder name
328
-        // we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this).  Why?  Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins)
329
-        $class = get_class($this);
330
-        foreach ($bt as $index => $values) {
331
-            if (isset($values['class']) && $values['class'] == $class) {
332
-                $file_index         = $index - 1;
333
-                $this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
334
-                if (! empty($this->_folder_name)) {
335
-                    break;
336
-                }
337
-            }
338
-        }
339
-        $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
340
-        $this->_file_name   = preg_replace('/^ee/', 'EE', $this->_folder_name);
341
-        $this->_file_name   = ucwords(str_replace('_', ' ', $this->_file_name));
342
-        $this->_file_name   = str_replace(' ', '_', $this->_file_name);
343
-    }
344
-
345
-
346
-    /**
347
-     * This automatically checks if we have a hook class in the loaded child directory.  If we DO then we will register
348
-     * it with the appropriate pages.  That way all we have to do is make sure the file is named correctly and
349
-     * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do:
350
-     * events_Messages_Hooks.class.php
351
-     *
352
-     * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks
353
-     *                     files/classes
354
-     * @return array
355
-     */
356
-    public function register_hooks(bool $extend = false): array
357
-    {
358
-        // get a list of files in the directory that have the "Hook" in their name an
359
-        // if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property.  Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf.
360
-        if ($extend) {
361
-            $hook_files_glob_path = apply_filters(
362
-                'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend',
363
-                EE_CORE_CAF_ADMIN_EXTEND
364
-                . $this->_folder_name
365
-                . '/*'
366
-                . $this->_file_name
367
-                . '_Hooks_Extend.class.php'
368
-            );
369
-            $this->_hook_paths    = $this->_register_hook_files($hook_files_glob_path, $extend);
370
-        }
371
-        // loop through decaf folders
372
-        $hook_files_glob_path = apply_filters(
373
-            'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
374
-            $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
375
-        );
376
-        $this->_hook_paths    = array_merge(
377
-            $this->_register_hook_files($hook_files_glob_path),
378
-            $this->_hook_paths
379
-        );  // making sure any extended hook paths are later in the array than the core hook paths!
380
-        return $this->_hook_paths;
381
-    }
382
-
383
-
384
-    protected function _register_hook_files($hook_files_glob_path, $extend = false): array
385
-    {
386
-        $hook_paths = glob($hook_files_glob_path);
387
-        if (empty($hook_paths)) {
388
-            return [];
389
-        }
390
-        foreach ($hook_paths as $file) {
391
-            // lets get the linked admin.
392
-            $hook_file = $extend
393
-                ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
394
-                : str_replace($this->_folder_path, '', $file);
395
-            $replace   = $extend
396
-                ? '_' . $this->_file_name . '_Hooks_Extend.class.php'
397
-                : '_' . $this->_file_name . '_Hooks.class.php';
398
-            $rel_admin = str_replace($replace, '', $hook_file);
399
-            $rel_admin = strtolower($rel_admin);
400
-            // make sure we haven't already got a hook setup for this page path
401
-            if (in_array($rel_admin, $this->_files_hooked)) {
402
-                continue;
403
-            }
404
-            require_once $file;
405
-            $this->hook_file = $hook_file;
406
-            $rel_admin_hook  = 'FHEE_do_other_page_hooks_' . $rel_admin;
407
-            add_filter($rel_admin_hook, [$this, 'load_admin_hook']);
408
-            $this->_files_hooked[] = $rel_admin;
409
-        }
410
-        return $hook_paths;
411
-    }
412
-
413
-
414
-    public function load_admin_hook($registered_pages)
415
-    {
416
-        return array_merge((array) $this->hook_file, $registered_pages);
417
-    }
418
-
419
-
420
-    /**
421
-     * _initialize_admin_page
422
-     *
423
-     * @throws EE_Error
424
-     * @throws ReflectionException
425
-     * @see  initialize_admin_page() for info
426
-     */
427
-    protected function _initialize_admin_page()
428
-    {
429
-        // JUST CHECK WE'RE ON RIGHT PAGE.
430
-        $page      = $this->request->getRequestParam('page');
431
-        $page      = $this->request->getRequestParam('current_page', $page);
432
-        $menu_slug = $this->_menu_map->menuSlug();
433
-
434
-        // leaving the following in for the time being
435
-        // because not sure if preventing multiple admin page loading will result in bad things happening
436
-        $darren_logic                       = false;  // true    false
437
-        $not_the_droids_you_are_looking_for = $darren_logic
438
-            ? $this->_routing && ($page === '' || $page !== $menu_slug)
439
-            : $page === '' || $page !== $menu_slug;
440
-        if ($not_the_droids_you_are_looking_for) {
441
-            // not on the right page so let's get out.
442
-            return;
443
-        }
444
-        $this->_load_page = true;
445
-
446
-        // we don't need to do a page_request check here because it's only called via WP menu system.
447
-        $admin_page  = $this->_file_name . '_Admin_Page';
448
-        $hook_suffix = "{$menu_slug}_$admin_page";
449
-        $admin_page  = apply_filters(
450
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__$hook_suffix",
451
-            $admin_page
452
-        );
453
-        if (empty($admin_page)) {
454
-            return;
455
-        }
456
-        // define requested admin page class name then load the file and instantiate
457
-        $path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path . $admin_page . '.core.php');
458
-        // so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be:
459
-        // FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
460
-        $path_to_file = apply_filters(
461
-            "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__$hook_suffix",
462
-            $path_to_file
463
-        );
464
-        if (! is_readable($path_to_file)) {
465
-            return;
466
-        }
467
-        // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
468
-        do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
469
-        do_action("AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_$menu_slug");
470
-        require_once($path_to_file);
471
-        $this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]);
472
-        $this->_loaded_page_object->initializePage();
473
-
474
-        do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
475
-        do_action("AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_$menu_slug");
476
-    }
477
-
478
-
479
-    public function get_admin_page_name(): string
480
-    {
481
-        return $this->_file_name . '_Admin_Page';
482
-    }
483
-
484
-
485
-    /**
486
-     * @return EE_Admin_Page|null
487
-     */
488
-    public function loaded_page_object(): ?EE_Admin_Page
489
-    {
490
-        return $this->_loaded_page_object;
491
-    }
492
-
493
-
494
-    /**
495
-     * _check_user_access
496
-     * verifies user access for this admin page.  If no user access is available then let's gracefully exit with a
497
-     * WordPress die message.
498
-     *
499
-     * @return void  wp_die if fail
500
-     */
501
-    private function _check_user_access()
502
-    {
503
-        if (! $this->_menu_map->currentUserHasAccess()) {
504
-            wp_die(
505
-                esc_html__('You don\'t have access to this page.', 'event_espresso'),
506
-                '',
507
-                ['back_link' => true]
508
-            );
509
-        }
510
-    }
28
+	protected ?LoaderInterface  $loader              = null;
29
+
30
+	protected ?RequestInterface $request             = null;
31
+
32
+	private bool                $_load_page          = false;
33
+
34
+	protected bool              $_routing            = false;
35
+
36
+	/**
37
+	 * Menu map has a capability.  However, this allows admin pages to have separate capability requirements for menus
38
+	 * and accessing pages.  If capability is NOT set, then it defaults to the menu_map capability.
39
+	 *
40
+	 * @var string
41
+	 */
42
+	public string $capability = '';
43
+
44
+	/**
45
+	 * identity properties (set in _set_defaults and _set_init_properties)
46
+	 */
47
+	public string    $label         = '';
48
+
49
+	protected string $_file_name    = '';
50
+
51
+	protected string $_folder_name  = '';
52
+
53
+	protected string $_folder_path  = '';
54
+
55
+	protected string $_wp_page_slug = '';
56
+
57
+	public string    $hook_file     = '';
58
+
59
+	public string    $menu_slug     = '';
60
+
61
+	/**
62
+	 * @deprecated
63
+	 */
64
+	public string   $menu_label    = '';
65
+
66
+	protected array $_files_hooked = [];
67
+
68
+	protected array $_hook_paths   = [];
69
+
70
+
71
+	/**
72
+	 * @throws InvalidArgumentException
73
+	 * @throws InvalidDataTypeException
74
+	 * @throws InvalidInterfaceException
75
+	 */
76
+	public function __construct(RequestInterface $request = null)
77
+	{
78
+		$this->loader  = LoaderFactory::getLoader();
79
+		$this->request = $request instanceof RequestInterface
80
+			? $request
81
+			: $this->loader->getShared(RequestInterface::class);
82
+		// set global defaults
83
+		$this->_set_defaults();
84
+		// set properties that are always available with objects.
85
+		$this->_set_init_properties();
86
+		// global styles/scripts across all wp admin pages
87
+		add_action('admin_enqueue_scripts', [$this, 'load_wp_global_scripts_styles'], 5);
88
+		// load initial stuff.
89
+		$this->_set_file_and_folder_name();
90
+	}
91
+
92
+
93
+	/**
94
+	 * _set_init_properties
95
+	 * Child classes use to set the following properties:
96
+	 * $label
97
+	 *
98
+	 * @abstract
99
+	 * @return void
100
+	 */
101
+	abstract protected function _set_init_properties();
102
+
103
+
104
+	/**
105
+	 * @return AdminMenuItem|null
106
+	 * @since       4.4.0
107
+	 * @deprecated  5.0.0.p
108
+	 */
109
+	public function get_menu_map()
110
+	{
111
+		return $this->adminMenu();
112
+	}
113
+
114
+
115
+	/**
116
+	 * _set_menu_map is a function that child classes use to set the menu_map property (which should be an instance of
117
+	 * EE_Admin_Page_Menu_Map.  Their menu can either be EE_Admin_Page_Main_Menu or AdminMenuSubItem.
118
+	 *
119
+	 * @since       4.4.0
120
+	 * @deprecated  5.0.0.p
121
+	 */
122
+	protected function _set_menu_map()
123
+	{
124
+	}
125
+
126
+
127
+	/**
128
+	 * @since   5.0.0.p
129
+	 */
130
+	public function setupLegacyAdminMenuItem()
131
+	{
132
+		// will be overridden by child classes not using new system
133
+		$this->_set_menu_map();
134
+	}
135
+
136
+
137
+	/**
138
+	 * Child classes should return an array of properties used to construct the AdminMenuItem
139
+	 *
140
+	 * @return array
141
+	 * @since 5.0.0.p
142
+	 */
143
+	public function getMenuProperties(): array
144
+	{
145
+		return [];
146
+	}
147
+
148
+
149
+	/**
150
+	 * @param AdminMenuItem $menu
151
+	 * @return void
152
+	 * @since 5.0.0.p
153
+	 */
154
+	public function setAdminMenu(AdminMenuItem $menu): void
155
+	{
156
+		$this->_menu_map = $menu;
157
+	}
158
+
159
+
160
+	/**
161
+	 * returns the menu map for this admin page
162
+	 *
163
+	 * @return AdminMenuItem|null
164
+	 * @since 5.0.0.p
165
+	 */
166
+	public function adminMenu(): ?AdminMenuItem
167
+	{
168
+		return $this->_menu_map;
169
+	}
170
+
171
+
172
+	/**
173
+	 * @param string $wp_page_slug
174
+	 * @since 5.0.0.p
175
+	 */
176
+	public function setWpPageSlug(string $wp_page_slug): void
177
+	{
178
+		$this->_wp_page_slug = $wp_page_slug;
179
+	}
180
+
181
+
182
+	/**
183
+	 * This loads scripts and styles for the EE_Admin system
184
+	 * that must be available on ALL WP admin pages (i.e. EE_menu items)
185
+	 *
186
+	 * @return void
187
+	 */
188
+	public function load_wp_global_scripts_styles()
189
+	{
190
+		wp_register_style(
191
+			'espresso_admin_base',
192
+			EE_ADMIN_URL . 'assets/ee-admin-base.css',
193
+			['dashicons'],
194
+			EVENT_ESPRESSO_VERSION
195
+		);
196
+		wp_register_style(
197
+			'espresso_menu',
198
+			EE_ADMIN_URL . 'assets/ee-admin-menu.css',
199
+			['espresso_admin_base'],
200
+			EVENT_ESPRESSO_VERSION
201
+		);
202
+		wp_enqueue_style('espresso_admin_base');
203
+		wp_enqueue_style('espresso_menu');
204
+	}
205
+
206
+
207
+	/**
208
+	 * this sets default properties (might be overridden in _set_init_properties);
209
+	 *
210
+	 * @return  void
211
+	 */
212
+	private function _set_defaults()
213
+	{
214
+		$this->_file_name    = '';
215
+		$this->_folder_name  = '';
216
+		$this->_wp_page_slug = '';
217
+		$this->capability    = '';
218
+		$this->_routing      = true;
219
+		$this->_load_page    = false;
220
+		$this->_files_hooked = [];
221
+		$this->_hook_paths   = [];
222
+	}
223
+
224
+
225
+	public function setCapability($capability, $menu_slug)
226
+	{
227
+		$this->capability = apply_filters('FHEE_' . $menu_slug . '_capability', $capability);
228
+	}
229
+
230
+
231
+	/**
232
+	 * @deprecated 5.0.0.p
233
+	 */
234
+	protected function _set_capability()
235
+	{
236
+		if ($this->_menu_map instanceof AdminMenuItem) {
237
+			$this->setCapability($this->_menu_map->capability(), $this->_menu_map->menuSlug());
238
+		}
239
+	}
240
+
241
+
242
+	/**
243
+	 * initialize_admin_page
244
+	 * This method is what executes the loading of the specific page class for the given dir_name as called by the
245
+	 * EE_Admin_Init class.
246
+	 *
247
+	 * @return void
248
+	 * @throws EE_Error
249
+	 * @throws ReflectionException
250
+	 */
251
+	public function initialize_admin_page()
252
+	{
253
+		// let's check user access first
254
+		$this->_check_user_access();
255
+		if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
256
+			return;
257
+		}
258
+		$this->_loaded_page_object->route_admin_request();
259
+	}
260
+
261
+
262
+	/**
263
+	 * @param string $wp_page_slug
264
+	 * @throws EE_Error
265
+	 */
266
+	public function set_page_dependencies(string $wp_page_slug)
267
+	{
268
+		if (! $this->_load_page) {
269
+			return;
270
+		}
271
+		if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
272
+			$msg[] = esc_html__(
273
+				'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
274
+				'event_espresso'
275
+			);
276
+			$msg[] = $msg[0] . "\r\n"
277
+					 . sprintf(
278
+						 esc_html__(
279
+							 'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
280
+							 'event_espresso'
281
+						 ),
282
+						 $this->_file_name,
283
+						 $this->_file_name,
284
+						 $this->_folder_path . $this->_file_name,
285
+						 $this->_menu_map->menuSlug()
286
+					 );
287
+			throw new EE_Error(implode('||', $msg));
288
+		}
289
+		$this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
290
+		$page_hook = "load-$wp_page_slug";
291
+		// hook into page load hook so all page specific stuff gets loaded.
292
+		if (! empty($wp_page_slug)) {
293
+			add_action($page_hook, [$this->_loaded_page_object, 'load_page_dependencies']);
294
+		}
295
+	}
296
+
297
+
298
+	/**
299
+	 * This executes the initial page loads for EE_Admin pages to take care of any ajax or other code needing to run
300
+	 * before the load-page... hook. Note, the page loads are happening around the wp_init hook.
301
+	 *
302
+	 * @return void
303
+	 * @throws InvalidArgumentException
304
+	 * @throws InvalidDataTypeException
305
+	 * @throws InvalidInterfaceException
306
+	 * @throws EE_Error
307
+	 * @throws ReflectionException
308
+	 */
309
+	public function do_initial_loads()
310
+	{
311
+		// no loading or initializing if menu map is setup incorrectly.
312
+		if (! $this->_menu_map instanceof AdminMenuItem) {
313
+			return;
314
+		}
315
+		$this->_initialize_admin_page();
316
+	}
317
+
318
+
319
+	/**
320
+	 * all we're doing here is setting the $_file_name property for later use.
321
+	 *
322
+	 * @return void
323
+	 */
324
+	private function _set_file_and_folder_name()
325
+	{
326
+		$bt = debug_backtrace();
327
+		// for more reliable determination of folder name
328
+		// we're using this to get the actual folder name of the CALLING class (i.e. the child class that extends this).  Why?  Because $this->menu_slug may be different than the folder name (to avoid conflicts with other plugins)
329
+		$class = get_class($this);
330
+		foreach ($bt as $index => $values) {
331
+			if (isset($values['class']) && $values['class'] == $class) {
332
+				$file_index         = $index - 1;
333
+				$this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
334
+				if (! empty($this->_folder_name)) {
335
+					break;
336
+				}
337
+			}
338
+		}
339
+		$this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
340
+		$this->_file_name   = preg_replace('/^ee/', 'EE', $this->_folder_name);
341
+		$this->_file_name   = ucwords(str_replace('_', ' ', $this->_file_name));
342
+		$this->_file_name   = str_replace(' ', '_', $this->_file_name);
343
+	}
344
+
345
+
346
+	/**
347
+	 * This automatically checks if we have a hook class in the loaded child directory.  If we DO then we will register
348
+	 * it with the appropriate pages.  That way all we have to do is make sure the file is named correctly and
349
+	 * "dropped" in. Example: if we wanted to set this up for Messages hooking into Events then we would do:
350
+	 * events_Messages_Hooks.class.php
351
+	 *
352
+	 * @param bool $extend This indicates whether we're checking the extend directory for any register_hooks
353
+	 *                     files/classes
354
+	 * @return array
355
+	 */
356
+	public function register_hooks(bool $extend = false): array
357
+	{
358
+		// get a list of files in the directory that have the "Hook" in their name an
359
+		// if this is an extended check (i.e. caf is active) then we will scan the caffeinated/extend directory first and any hook files that are found will be have their reference added to the $_files_hook array property.  Then, we make sure that when we loop through the core decaf directories to find hook files that we skip over any hooks files that have already been set by caf.
360
+		if ($extend) {
361
+			$hook_files_glob_path = apply_filters(
362
+				'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path__extend',
363
+				EE_CORE_CAF_ADMIN_EXTEND
364
+				. $this->_folder_name
365
+				. '/*'
366
+				. $this->_file_name
367
+				. '_Hooks_Extend.class.php'
368
+			);
369
+			$this->_hook_paths    = $this->_register_hook_files($hook_files_glob_path, $extend);
370
+		}
371
+		// loop through decaf folders
372
+		$hook_files_glob_path = apply_filters(
373
+			'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
374
+			$this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
375
+		);
376
+		$this->_hook_paths    = array_merge(
377
+			$this->_register_hook_files($hook_files_glob_path),
378
+			$this->_hook_paths
379
+		);  // making sure any extended hook paths are later in the array than the core hook paths!
380
+		return $this->_hook_paths;
381
+	}
382
+
383
+
384
+	protected function _register_hook_files($hook_files_glob_path, $extend = false): array
385
+	{
386
+		$hook_paths = glob($hook_files_glob_path);
387
+		if (empty($hook_paths)) {
388
+			return [];
389
+		}
390
+		foreach ($hook_paths as $file) {
391
+			// lets get the linked admin.
392
+			$hook_file = $extend
393
+				? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
394
+				: str_replace($this->_folder_path, '', $file);
395
+			$replace   = $extend
396
+				? '_' . $this->_file_name . '_Hooks_Extend.class.php'
397
+				: '_' . $this->_file_name . '_Hooks.class.php';
398
+			$rel_admin = str_replace($replace, '', $hook_file);
399
+			$rel_admin = strtolower($rel_admin);
400
+			// make sure we haven't already got a hook setup for this page path
401
+			if (in_array($rel_admin, $this->_files_hooked)) {
402
+				continue;
403
+			}
404
+			require_once $file;
405
+			$this->hook_file = $hook_file;
406
+			$rel_admin_hook  = 'FHEE_do_other_page_hooks_' . $rel_admin;
407
+			add_filter($rel_admin_hook, [$this, 'load_admin_hook']);
408
+			$this->_files_hooked[] = $rel_admin;
409
+		}
410
+		return $hook_paths;
411
+	}
412
+
413
+
414
+	public function load_admin_hook($registered_pages)
415
+	{
416
+		return array_merge((array) $this->hook_file, $registered_pages);
417
+	}
418
+
419
+
420
+	/**
421
+	 * _initialize_admin_page
422
+	 *
423
+	 * @throws EE_Error
424
+	 * @throws ReflectionException
425
+	 * @see  initialize_admin_page() for info
426
+	 */
427
+	protected function _initialize_admin_page()
428
+	{
429
+		// JUST CHECK WE'RE ON RIGHT PAGE.
430
+		$page      = $this->request->getRequestParam('page');
431
+		$page      = $this->request->getRequestParam('current_page', $page);
432
+		$menu_slug = $this->_menu_map->menuSlug();
433
+
434
+		// leaving the following in for the time being
435
+		// because not sure if preventing multiple admin page loading will result in bad things happening
436
+		$darren_logic                       = false;  // true    false
437
+		$not_the_droids_you_are_looking_for = $darren_logic
438
+			? $this->_routing && ($page === '' || $page !== $menu_slug)
439
+			: $page === '' || $page !== $menu_slug;
440
+		if ($not_the_droids_you_are_looking_for) {
441
+			// not on the right page so let's get out.
442
+			return;
443
+		}
444
+		$this->_load_page = true;
445
+
446
+		// we don't need to do a page_request check here because it's only called via WP menu system.
447
+		$admin_page  = $this->_file_name . '_Admin_Page';
448
+		$hook_suffix = "{$menu_slug}_$admin_page";
449
+		$admin_page  = apply_filters(
450
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__$hook_suffix",
451
+			$admin_page
452
+		);
453
+		if (empty($admin_page)) {
454
+			return;
455
+		}
456
+		// define requested admin page class name then load the file and instantiate
457
+		$path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path . $admin_page . '.core.php');
458
+		// so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be:
459
+		// FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
460
+		$path_to_file = apply_filters(
461
+			"FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__$hook_suffix",
462
+			$path_to_file
463
+		);
464
+		if (! is_readable($path_to_file)) {
465
+			return;
466
+		}
467
+		// This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
468
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__before_initialization');
469
+		do_action("AHEE__EE_Admin_Page___initialize_admin_page__before_initialization_$menu_slug");
470
+		require_once($path_to_file);
471
+		$this->_loaded_page_object = $this->loader->getShared($admin_page, [$this->_routing]);
472
+		$this->_loaded_page_object->initializePage();
473
+
474
+		do_action('AHEE__EE_Admin_Page___initialize_admin_page__after_initialization');
475
+		do_action("AHEE__EE_Admin_Page___initialize_admin_page__after_initialization_$menu_slug");
476
+	}
477
+
478
+
479
+	public function get_admin_page_name(): string
480
+	{
481
+		return $this->_file_name . '_Admin_Page';
482
+	}
483
+
484
+
485
+	/**
486
+	 * @return EE_Admin_Page|null
487
+	 */
488
+	public function loaded_page_object(): ?EE_Admin_Page
489
+	{
490
+		return $this->_loaded_page_object;
491
+	}
492
+
493
+
494
+	/**
495
+	 * _check_user_access
496
+	 * verifies user access for this admin page.  If no user access is available then let's gracefully exit with a
497
+	 * WordPress die message.
498
+	 *
499
+	 * @return void  wp_die if fail
500
+	 */
501
+	private function _check_user_access()
502
+	{
503
+		if (! $this->_menu_map->currentUserHasAccess()) {
504
+			wp_die(
505
+				esc_html__('You don\'t have access to this page.', 'event_espresso'),
506
+				'',
507
+				['back_link' => true]
508
+			);
509
+		}
510
+	}
511 511
 }
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -189,13 +189,13 @@  discard block
 block discarded – undo
189 189
     {
190 190
         wp_register_style(
191 191
             'espresso_admin_base',
192
-            EE_ADMIN_URL . 'assets/ee-admin-base.css',
192
+            EE_ADMIN_URL.'assets/ee-admin-base.css',
193 193
             ['dashicons'],
194 194
             EVENT_ESPRESSO_VERSION
195 195
         );
196 196
         wp_register_style(
197 197
             'espresso_menu',
198
-            EE_ADMIN_URL . 'assets/ee-admin-menu.css',
198
+            EE_ADMIN_URL.'assets/ee-admin-menu.css',
199 199
             ['espresso_admin_base'],
200 200
             EVENT_ESPRESSO_VERSION
201 201
         );
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 
225 225
     public function setCapability($capability, $menu_slug)
226 226
     {
227
-        $this->capability = apply_filters('FHEE_' . $menu_slug . '_capability', $capability);
227
+        $this->capability = apply_filters('FHEE_'.$menu_slug.'_capability', $capability);
228 228
     }
229 229
 
230 230
 
@@ -252,7 +252,7 @@  discard block
 block discarded – undo
252 252
     {
253 253
         // let's check user access first
254 254
         $this->_check_user_access();
255
-        if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
255
+        if ( ! $this->_loaded_page_object instanceof EE_Admin_Page) {
256 256
             return;
257 257
         }
258 258
         $this->_loaded_page_object->route_admin_request();
@@ -265,15 +265,15 @@  discard block
 block discarded – undo
265 265
      */
266 266
     public function set_page_dependencies(string $wp_page_slug)
267 267
     {
268
-        if (! $this->_load_page) {
268
+        if ( ! $this->_load_page) {
269 269
             return;
270 270
         }
271
-        if (! $this->_loaded_page_object instanceof EE_Admin_Page) {
271
+        if ( ! $this->_loaded_page_object instanceof EE_Admin_Page) {
272 272
             $msg[] = esc_html__(
273 273
                 'We can\'t load the page because we\'re missing a valid page object that tells us what to load',
274 274
                 'event_espresso'
275 275
             );
276
-            $msg[] = $msg[0] . "\r\n"
276
+            $msg[] = $msg[0]."\r\n"
277 277
                      . sprintf(
278 278
                          esc_html__(
279 279
                              'The custom slug you have set for this page is %s. This means we\'re looking for the class %s_Admin_Page (found in %s_Admin_Page.core.php) within your %s directory',
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
                          ),
282 282
                          $this->_file_name,
283 283
                          $this->_file_name,
284
-                         $this->_folder_path . $this->_file_name,
284
+                         $this->_folder_path.$this->_file_name,
285 285
                          $this->_menu_map->menuSlug()
286 286
                      );
287 287
             throw new EE_Error(implode('||', $msg));
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
         $this->_loaded_page_object->set_wp_page_slug($wp_page_slug);
290 290
         $page_hook = "load-$wp_page_slug";
291 291
         // hook into page load hook so all page specific stuff gets loaded.
292
-        if (! empty($wp_page_slug)) {
292
+        if ( ! empty($wp_page_slug)) {
293 293
             add_action($page_hook, [$this->_loaded_page_object, 'load_page_dependencies']);
294 294
         }
295 295
     }
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
     public function do_initial_loads()
310 310
     {
311 311
         // no loading or initializing if menu map is setup incorrectly.
312
-        if (! $this->_menu_map instanceof AdminMenuItem) {
312
+        if ( ! $this->_menu_map instanceof AdminMenuItem) {
313 313
             return;
314 314
         }
315 315
         $this->_initialize_admin_page();
@@ -330,13 +330,13 @@  discard block
 block discarded – undo
330 330
         foreach ($bt as $index => $values) {
331 331
             if (isset($values['class']) && $values['class'] == $class) {
332 332
                 $file_index         = $index - 1;
333
-                $this->_folder_name = basename(dirname($bt[ $file_index ]['file']));
334
-                if (! empty($this->_folder_name)) {
333
+                $this->_folder_name = basename(dirname($bt[$file_index]['file']));
334
+                if ( ! empty($this->_folder_name)) {
335 335
                     break;
336 336
                 }
337 337
             }
338 338
         }
339
-        $this->_folder_path = EE_ADMIN_PAGES . $this->_folder_name . '/';
339
+        $this->_folder_path = EE_ADMIN_PAGES.$this->_folder_name.'/';
340 340
         $this->_file_name   = preg_replace('/^ee/', 'EE', $this->_folder_name);
341 341
         $this->_file_name   = ucwords(str_replace('_', ' ', $this->_file_name));
342 342
         $this->_file_name   = str_replace(' ', '_', $this->_file_name);
@@ -366,17 +366,17 @@  discard block
 block discarded – undo
366 366
                 . $this->_file_name
367 367
                 . '_Hooks_Extend.class.php'
368 368
             );
369
-            $this->_hook_paths    = $this->_register_hook_files($hook_files_glob_path, $extend);
369
+            $this->_hook_paths = $this->_register_hook_files($hook_files_glob_path, $extend);
370 370
         }
371 371
         // loop through decaf folders
372 372
         $hook_files_glob_path = apply_filters(
373 373
             'FHEE__EE_Admin_Page_Init__register_hooks__hook_files_glob_path',
374
-            $this->_folder_path . '*' . $this->_file_name . '_Hooks.class.php'
374
+            $this->_folder_path.'*'.$this->_file_name.'_Hooks.class.php'
375 375
         );
376
-        $this->_hook_paths    = array_merge(
376
+        $this->_hook_paths = array_merge(
377 377
             $this->_register_hook_files($hook_files_glob_path),
378 378
             $this->_hook_paths
379
-        );  // making sure any extended hook paths are later in the array than the core hook paths!
379
+        ); // making sure any extended hook paths are later in the array than the core hook paths!
380 380
         return $this->_hook_paths;
381 381
     }
382 382
 
@@ -390,11 +390,11 @@  discard block
 block discarded – undo
390 390
         foreach ($hook_paths as $file) {
391 391
             // lets get the linked admin.
392 392
             $hook_file = $extend
393
-                ? str_replace(EE_CORE_CAF_ADMIN_EXTEND . $this->_folder_name . '/', '', $file)
393
+                ? str_replace(EE_CORE_CAF_ADMIN_EXTEND.$this->_folder_name.'/', '', $file)
394 394
                 : str_replace($this->_folder_path, '', $file);
395 395
             $replace   = $extend
396
-                ? '_' . $this->_file_name . '_Hooks_Extend.class.php'
397
-                : '_' . $this->_file_name . '_Hooks.class.php';
396
+                ? '_'.$this->_file_name.'_Hooks_Extend.class.php'
397
+                : '_'.$this->_file_name.'_Hooks.class.php';
398 398
             $rel_admin = str_replace($replace, '', $hook_file);
399 399
             $rel_admin = strtolower($rel_admin);
400 400
             // make sure we haven't already got a hook setup for this page path
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
             }
404 404
             require_once $file;
405 405
             $this->hook_file = $hook_file;
406
-            $rel_admin_hook  = 'FHEE_do_other_page_hooks_' . $rel_admin;
406
+            $rel_admin_hook  = 'FHEE_do_other_page_hooks_'.$rel_admin;
407 407
             add_filter($rel_admin_hook, [$this, 'load_admin_hook']);
408 408
             $this->_files_hooked[] = $rel_admin;
409 409
         }
@@ -433,7 +433,7 @@  discard block
 block discarded – undo
433 433
 
434 434
         // leaving the following in for the time being
435 435
         // because not sure if preventing multiple admin page loading will result in bad things happening
436
-        $darren_logic                       = false;  // true    false
436
+        $darren_logic                       = false; // true    false
437 437
         $not_the_droids_you_are_looking_for = $darren_logic
438 438
             ? $this->_routing && ($page === '' || $page !== $menu_slug)
439 439
             : $page === '' || $page !== $menu_slug;
@@ -444,7 +444,7 @@  discard block
 block discarded – undo
444 444
         $this->_load_page = true;
445 445
 
446 446
         // we don't need to do a page_request check here because it's only called via WP menu system.
447
-        $admin_page  = $this->_file_name . '_Admin_Page';
447
+        $admin_page  = $this->_file_name.'_Admin_Page';
448 448
         $hook_suffix = "{$menu_slug}_$admin_page";
449 449
         $admin_page  = apply_filters(
450 450
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__admin_page__$hook_suffix",
@@ -454,14 +454,14 @@  discard block
 block discarded – undo
454 454
             return;
455 455
         }
456 456
         // define requested admin page class name then load the file and instantiate
457
-        $path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path . $admin_page . '.core.php');
457
+        $path_to_file = str_replace(['\\', '/'], '/', $this->_folder_path.$admin_page.'.core.php');
458 458
         // so if the file would be in EE_ADMIN/attendees/Attendee_Admin_Page.core.php, the filter would be:
459 459
         // FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__attendees_Attendee_Admin_Page
460 460
         $path_to_file = apply_filters(
461 461
             "FHEE__EE_Admin_Page_Init___initialize_admin_page__path_to_file__$hook_suffix",
462 462
             $path_to_file
463 463
         );
464
-        if (! is_readable($path_to_file)) {
464
+        if ( ! is_readable($path_to_file)) {
465 465
             return;
466 466
         }
467 467
         // This is a place where EE plugins can hook in to make sure their own files are required in the appropriate place
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
 
479 479
     public function get_admin_page_name(): string
480 480
     {
481
-        return $this->_file_name . '_Admin_Page';
481
+        return $this->_file_name.'_Admin_Page';
482 482
     }
483 483
 
484 484
 
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
      */
501 501
     private function _check_user_access()
502 502
     {
503
-        if (! $this->_menu_map->currentUserHasAccess()) {
503
+        if ( ! $this->_menu_map->currentUserHasAccess()) {
504 504
             wp_die(
505 505
                 esc_html__('You don\'t have access to this page.', 'event_espresso'),
506 506
                 '',
Please login to merge, or discard this patch.
core/admin/EE_Admin.core.php 2 patches
Indentation   +987 added lines, -987 removed lines patch added patch discarded remove patch
@@ -20,991 +20,991 @@
 block discarded – undo
20 20
  */
21 21
 final class EE_Admin implements InterminableInterface
22 22
 {
23
-    private static ?EE_Admin $_instance = null;
24
-
25
-    private ?PersistentAdminNoticeManager $persistent_admin_notice_manager = null;
26
-
27
-    protected LoaderInterface $loader;
28
-
29
-    protected RequestInterface $request;
30
-
31
-
32
-    /**
33
-     * @singleton method used to instantiate class object
34
-     * @param LoaderInterface|null  $loader
35
-     * @param RequestInterface|null $request
36
-     * @return EE_Admin|null
37
-     * @throws EE_Error
38
-     */
39
-    public static function instance(?LoaderInterface $loader = null, ?RequestInterface $request = null): ?EE_Admin
40
-    {
41
-        // check if class object is instantiated
42
-        if (! EE_Admin::$_instance instanceof EE_Admin) {
43
-            EE_Admin::$_instance = new EE_Admin($loader, $request);
44
-        }
45
-        return EE_Admin::$_instance;
46
-    }
47
-
48
-
49
-    /**
50
-     * @return EE_Admin|null
51
-     * @throws EE_Error
52
-     */
53
-    public static function reset(): ?EE_Admin
54
-    {
55
-        EE_Admin::$_instance = null;
56
-        $loader = LoaderFactory::getLoader();
57
-        $request = $loader->getShared('EventEspresso\core\services\request\Request');
58
-        return EE_Admin::instance($loader, $request);
59
-    }
60
-
61
-
62
-    /**
63
-     * @param LoaderInterface  $loader
64
-     * @param RequestInterface $request
65
-     * @throws EE_Error
66
-     * @throws InvalidDataTypeException
67
-     * @throws InvalidInterfaceException
68
-     * @throws InvalidArgumentException
69
-     */
70
-    protected function __construct(LoaderInterface $loader, RequestInterface $request)
71
-    {
72
-        $this->loader = $loader;
73
-        $this->request = $request;
74
-        // define global EE_Admin constants
75
-        $this->_define_all_constants();
76
-        // set autoloaders for our admin page classes based on included path information
77
-        EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
78
-        // reset Environment config (we only do this on admin page loads);
79
-        EE_Registry::instance()->CFG->environment->recheck_values();
80
-        // load EE_Request_Handler early
81
-        add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
82
-        add_action('admin_init', [$this, 'admin_init'], 100);
83
-        if (! $this->request->isAjax()) {
84
-            // admin hooks
85
-            add_action('admin_notices', [$this, 'display_admin_notices']);
86
-            add_action('network_admin_notices', [$this, 'display_admin_notices']);
87
-            add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
88
-            add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
89
-            add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
90
-            add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
91
-            add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
92
-        }
93
-        do_action('AHEE__EE_Admin__loaded');
94
-    }
95
-
96
-
97
-    /**
98
-     * _define_all_constants
99
-     * define constants that are set globally for all admin pages
100
-     *
101
-     * @return void
102
-     */
103
-    private function _define_all_constants()
104
-    {
105
-        if (! defined('EE_ADMIN_URL')) {
106
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
107
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
108
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
109
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
110
-            define('WP_AJAX_URL', admin_url('admin-ajax.php'));
111
-        }
112
-    }
113
-
114
-
115
-    /**
116
-     * filter_plugin_actions - adds links to the Plugins page listing
117
-     *
118
-     * @param array  $links
119
-     * @param string $plugin
120
-     * @return    array
121
-     */
122
-    public function filter_plugin_actions($links, $plugin)
123
-    {
124
-        // set $main_file in stone
125
-        static $main_file;
126
-        // if $main_file is not set yet
127
-        if (! $main_file) {
128
-            $main_file = EE_PLUGIN_BASENAME;
129
-        }
130
-        if ($plugin === $main_file) {
131
-            // compare current plugin to this one
132
-            if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
133
-                $maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
134
-                                    . ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
135
-                                    . esc_html__('Maintenance Mode Active', 'event_espresso')
136
-                                    . '</a>';
137
-                array_unshift($links, $maintenance_link);
138
-            } else {
139
-                $org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
140
-                                     . esc_html__('Settings', 'event_espresso')
141
-                                     . '</a>';
142
-                $events_link       = '<a href="admin.php?page=espresso_events">'
143
-                                     . esc_html__('Events', 'event_espresso')
144
-                                     . '</a>';
145
-                // add before other links
146
-                array_unshift($links, $org_settings_link, $events_link);
147
-            }
148
-        }
149
-        return $links;
150
-    }
151
-
152
-
153
-    /**
154
-     * hide_admin_pages_except_maintenance_mode
155
-     *
156
-     * @param array $admin_page_folder_names
157
-     * @return array
158
-     */
159
-    public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
160
-    {
161
-        return [
162
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
163
-            'about'       => EE_ADMIN_PAGES . 'about/',
164
-            'support'     => EE_ADMIN_PAGES . 'support/',
165
-        ];
166
-    }
167
-
168
-
169
-    /**
170
-     * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
171
-     * EE_Front_Controller's init phases have run
172
-     *
173
-     * @return void
174
-     * @throws EE_Error
175
-     * @throws InvalidArgumentException
176
-     * @throws InvalidDataTypeException
177
-     * @throws InvalidInterfaceException
178
-     * @throws ReflectionException
179
-     * @throws ServiceNotFoundException
180
-     */
181
-    public function init()
182
-    {
183
-        // only enable most of the EE_Admin IF we're not in full maintenance mode
184
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
185
-            $this->initModelsReady();
186
-        }
187
-        // run the admin page factory but ONLY if:
188
-        // - it is a regular non ajax admin request
189
-        // - we are doing an ee admin ajax request
190
-        if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
191
-            try {
192
-                // this loads the controller for the admin pages which will setup routing etc
193
-                $admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
194
-                /** @var EE_Admin_Page_Loader $admin_page_loader */
195
-                $admin_page_loader->init();
196
-            } catch (EE_Error $e) {
197
-                $e->get_error();
198
-            }
199
-        }
200
-        if ($this->request->isAjax()) {
201
-            return;
202
-        }
203
-        add_filter('content_save_pre', [$this, 'its_eSpresso']);
204
-        // make sure our CPTs and custom taxonomy metaboxes get shown for first time users
205
-        add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes']);
206
-        add_action('admin_head', [$this, 'register_custom_nav_menu_boxes']);
207
-        // exclude EE critical pages from all nav menus and wp_list_pages
208
-        add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu']);
209
-    }
210
-
211
-
212
-    /**
213
-     * Gets the loader (and if it wasn't previously set, sets it)
214
-     *
215
-     * @return LoaderInterface
216
-     * @throws InvalidArgumentException
217
-     * @throws InvalidDataTypeException
218
-     * @throws InvalidInterfaceException
219
-     */
220
-    protected function getLoader()
221
-    {
222
-        return $this->loader;
223
-    }
224
-
225
-
226
-    /**
227
-     * Method that's fired on admin requests (including admin ajax) but only when the models are usable
228
-     * (ie, the site isn't in maintenance mode)
229
-     *
230
-     * @return void
231
-     * @throws EE_Error
232
-     * @since 4.9.63.p
233
-     */
234
-    protected function initModelsReady()
235
-    {
236
-        // ok so we want to enable the entire admin
237
-        $this->persistent_admin_notice_manager = $this->loader->getShared(
238
-            'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
239
-        );
240
-        $this->persistent_admin_notice_manager->setReturnUrl(
241
-            EE_Admin_Page::add_query_args_and_nonce(
242
-                [
243
-                    'page'   => $this->request->getRequestParam('page', ''),
244
-                    'action' => $this->request->getRequestParam('action', ''),
245
-                ],
246
-                EE_ADMIN_URL
247
-            )
248
-        );
249
-        $this->maybeSetDatetimeWarningNotice();
250
-        // at a glance dashboard widget
251
-        add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items']);
252
-        // filter for get_edit_post_link used on comments for custom post types
253
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
254
-    }
255
-
256
-
257
-    /**
258
-     *    get_persistent_admin_notices
259
-     *
260
-     * @access    public
261
-     * @return void
262
-     * @throws EE_Error
263
-     * @throws InvalidArgumentException
264
-     * @throws InvalidDataTypeException
265
-     * @throws InvalidInterfaceException
266
-     * @throws ReflectionException
267
-     */
268
-    public function maybeSetDatetimeWarningNotice()
269
-    {
270
-        // add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
271
-        // @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
272
-        // with this.  But after enough time (indeterminate at this point) we can just remove this notice.
273
-        // this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
274
-        if (
275
-            apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
276
-            && ! get_option('timezone_string')
277
-            && EEM_Event::instance()->count() > 0
278
-        ) {
279
-            new PersistentAdminNotice(
280
-                'datetime_fix_notice',
281
-                sprintf(
282
-                    esc_html__(
283
-                        '%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
284
-                        'event_espresso'
285
-                    ),
286
-                    '<strong>',
287
-                    '</strong>',
288
-                    '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
289
-                    '</a>',
290
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
291
-                        [
292
-                            'page'   => 'espresso_maintenance_settings',
293
-                            'action' => 'datetime_tools',
294
-                        ],
295
-                        admin_url('admin.php')
296
-                    ) . '">'
297
-                ),
298
-                false,
299
-                'manage_options',
300
-                'datetime_fix_persistent_notice'
301
-            );
302
-        }
303
-    }
304
-
305
-
306
-    /**
307
-     * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
308
-     * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
309
-     * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
310
-     * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
311
-     * normal property on the post_type object.  It's found ONLY in this particular context.
312
-     *
313
-     * @param WP_Post $post_type WP post type object
314
-     * @return WP_Post
315
-     * @throws InvalidArgumentException
316
-     * @throws InvalidDataTypeException
317
-     * @throws InvalidInterfaceException
318
-     */
319
-    public function remove_pages_from_nav_menu($post_type)
320
-    {
321
-        // if this isn't the "pages" post type let's get out
322
-        if ($post_type->name !== 'page') {
323
-            return $post_type;
324
-        }
325
-        $critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
326
-        $post_type->_default_query = [
327
-            'post__not_in' => $critical_pages,
328
-        ];
329
-        return $post_type;
330
-    }
331
-
332
-
333
-    /**
334
-     * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
335
-     * We want to make sure our metaboxes get shown as well
336
-     *
337
-     * @return void
338
-     */
339
-    public function enable_hidden_ee_nav_menu_metaboxes()
340
-    {
341
-        global $wp_meta_boxes, $pagenow;
342
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
343
-            return;
344
-        }
345
-        $user = wp_get_current_user();
346
-        // has this been done yet?
347
-        if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
348
-            return;
349
-        }
350
-
351
-        $hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
352
-        $initial_meta_boxes = apply_filters(
353
-            'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
354
-            [
355
-                'nav-menu-theme-locations',
356
-                'add-page',
357
-                'add-custom-links',
358
-                'add-category',
359
-                'add-espresso_events',
360
-                'add-espresso_venues',
361
-                'add-espresso_event_categories',
362
-                'add-espresso_venue_categories',
363
-                'add-post-type-post',
364
-                'add-post-type-page',
365
-            ]
366
-        );
367
-
368
-        if (is_array($hidden_meta_boxes)) {
369
-            foreach ($hidden_meta_boxes as $key => $meta_box_id) {
370
-                if (in_array($meta_box_id, $initial_meta_boxes, true)) {
371
-                    unset($hidden_meta_boxes[ $key ]);
372
-                }
373
-            }
374
-        }
375
-        update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
376
-        update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
377
-    }
378
-
379
-
380
-    /**
381
-     * This method simply registers custom nav menu boxes for "nav_menus.php route"
382
-     * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
383
-     *
384
-     * @return void
385
-     * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
386
-     *         addons etc.
387
-     */
388
-    public function register_custom_nav_menu_boxes()
389
-    {
390
-        add_meta_box(
391
-            'add-extra-nav-menu-pages',
392
-            esc_html__('Event Espresso Pages', 'event_espresso'),
393
-            [$this, 'ee_cpt_archive_pages'],
394
-            'nav-menus',
395
-            'side',
396
-            'core'
397
-        );
398
-        add_filter(
399
-            "postbox_classes_nav-menus_add-extra-nav-menu-pages",
400
-            function ($classes) {
401
-                $classes[] = 'ee-admin-container';
402
-                return $classes;
403
-            }
404
-        );
405
-    }
406
-
407
-
408
-    /**
409
-     * Use this to edit the post link for our cpts so that the edit link points to the correct page.
410
-     *
411
-     * @param string $link the original link generated by wp
412
-     * @param int    $id   post id
413
-     * @return string  the (maybe) modified link
414
-     * @since   4.3.0
415
-     */
416
-    public function modify_edit_post_link($link, $id)
417
-    {
418
-        if (! $post = get_post($id)) {
419
-            return $link;
420
-        }
421
-        if ($post->post_type === 'espresso_attendees') {
422
-            $query_args = [
423
-                'action' => 'edit_attendee',
424
-                'post'   => $id,
425
-            ];
426
-            return EEH_URL::add_query_args_and_nonce(
427
-                $query_args,
428
-                admin_url('admin.php?page=espresso_registrations')
429
-            );
430
-        }
431
-        return $link;
432
-    }
433
-
434
-
435
-    public function ee_cpt_archive_pages()
436
-    {
437
-        global $nav_menu_selected_id;
438
-        $removed_args = [
439
-            'action',
440
-            'customlink-tab',
441
-            'edit-menu-item',
442
-            'menu-item',
443
-            'page-tab',
444
-            '_wpnonce',
445
-        ];
446
-        $nav_tab_link = $nav_menu_selected_id
447
-            ? esc_url(
448
-                add_query_arg(
449
-                    'extra-nav-menu-pages-tab',
450
-                    'event-archives',
451
-                    remove_query_arg($removed_args)
452
-                )
453
-            )
454
-            : '';
455
-        $select_all_link = esc_url(
456
-            add_query_arg(
457
-                [
458
-                    'extra-nav-menu-pages-tab' => 'event-archives',
459
-                    'selectall'                => 1,
460
-                ],
461
-                remove_query_arg($removed_args)
462
-            )
463
-        );
464
-        $pages = $this->_get_extra_nav_menu_pages_items();
465
-        $args['walker'] = new Walker_Nav_Menu_Checklist(false);
466
-        $nav_menu_pages_items = walk_nav_menu_tree(
467
-            array_map(
468
-                [$this, '_setup_extra_nav_menu_pages_items'],
469
-                $pages
470
-            ),
471
-            0,
472
-            (object) $args
473
-        );
474
-        EEH_Template::display_template(
475
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
476
-            [
477
-                'nav_menu_selected_id' => $nav_menu_selected_id,
478
-                'nav_menu_pages_items' => $nav_menu_pages_items,
479
-                'nav_tab_link'         => $nav_tab_link,
480
-                'select_all_link'      => $select_all_link,
481
-            ]
482
-        );
483
-    }
484
-
485
-
486
-    /**
487
-     * Returns an array of event archive nav items.
488
-     *
489
-     * @return array
490
-     * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
491
-     *        method we use for getting the extra nav menu items
492
-     */
493
-    private function _get_extra_nav_menu_pages_items()
494
-    {
495
-        $menuitems[] = [
496
-            'title'       => esc_html__('Event List', 'event_espresso'),
497
-            'url'         => get_post_type_archive_link('espresso_events'),
498
-            'description' => esc_html__('Archive page for all events.', 'event_espresso'),
499
-        ];
500
-        return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
501
-    }
502
-
503
-
504
-    /**
505
-     * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
506
-     * the properties and converts it to the menu item object.
507
-     *
508
-     * @param $menu_item_values
509
-     * @return stdClass
510
-     * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
511
-     */
512
-    private function _setup_extra_nav_menu_pages_items($menu_item_values)
513
-    {
514
-        $menu_item = new stdClass();
515
-        $keys      = [
516
-            'ID'               => 0,
517
-            'db_id'            => 0,
518
-            'menu_item_parent' => 0,
519
-            'object_id'        => -1,
520
-            'post_parent'      => 0,
521
-            'type'             => 'custom',
522
-            'object'           => '',
523
-            'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
524
-            'title'            => '',
525
-            'url'              => '',
526
-            'target'           => '',
527
-            'attr_title'       => '',
528
-            'description'      => '',
529
-            'classes'          => [],
530
-            'xfn'              => '',
531
-        ];
532
-        foreach ($keys as $key => $value) {
533
-            $menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
534
-        }
535
-        return $menu_item;
536
-    }
537
-
538
-
539
-    /**
540
-     * admin_init
541
-     *
542
-     * @return void
543
-     * @throws InvalidArgumentException
544
-     * @throws InvalidDataTypeException
545
-     * @throws InvalidInterfaceException
546
-     */
547
-    public function admin_init()
548
-    {
549
-        /**
550
-         * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
551
-         * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
552
-         * - check if doing post processing.
553
-         * - check if doing post processing of one of EE CPTs
554
-         * - instantiate the corresponding EE CPT model for the post_type being processed.
555
-         */
556
-        $action    = $this->request->getRequestParam('action');
557
-        $post_type = $this->request->getRequestParam('post_type');
558
-        if ($post_type && $action === 'editpost') {
559
-            /** @var CustomPostTypeDefinitions $custom_post_types */
560
-            $custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
561
-            $custom_post_types->getCustomPostTypeModels($post_type);
562
-        }
563
-
564
-
565
-        if (! $this->request->isAjax()) {
566
-            /**
567
-             * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
568
-             * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
569
-             * Pages" tab in the EE General Settings Admin page.
570
-             * This is for user-proofing.
571
-             */
572
-            add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
573
-            if (EE_Maintenance_Mode::instance()->models_can_query()) {
574
-                $this->adminInitModelsReady();
575
-            }
576
-        }
577
-    }
578
-
579
-
580
-    /**
581
-     * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
582
-     */
583
-    protected function adminInitModelsReady()
584
-    {
585
-        if (function_exists('wp_add_privacy_policy_content')) {
586
-            $this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
587
-        }
588
-    }
589
-
590
-
591
-    /**
592
-     * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
593
-     *
594
-     * @param string $output Current output.
595
-     * @return string
596
-     * @throws InvalidArgumentException
597
-     * @throws InvalidDataTypeException
598
-     * @throws InvalidInterfaceException
599
-     */
600
-    public function modify_dropdown_pages($output)
601
-    {
602
-        // get critical pages
603
-        $critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
604
-
605
-        // split current output by line break for easier parsing.
606
-        $split_output = explode("\n", $output);
607
-
608
-        // loop through to remove any critical pages from the array.
609
-        foreach ($critical_pages as $page_id) {
610
-            $needle = 'value="' . $page_id . '"';
611
-            foreach ($split_output as $key => $haystack) {
612
-                if (strpos($haystack, $needle) !== false) {
613
-                    unset($split_output[ $key ]);
614
-                }
615
-            }
616
-        }
617
-        // replace output with the new contents
618
-        return implode("\n", $split_output);
619
-    }
620
-
621
-
622
-    /**
623
-     * display_admin_notices
624
-     *
625
-     * @return void
626
-     */
627
-    public function display_admin_notices()
628
-    {
629
-        echo EE_Error::get_notices(); // already escaped
630
-    }
631
-
632
-
633
-    /**
634
-     * @param array $elements
635
-     * @return array
636
-     * @throws EE_Error
637
-     * @throws InvalidArgumentException
638
-     * @throws InvalidDataTypeException
639
-     * @throws InvalidInterfaceException
640
-     * @throws ReflectionException
641
-     */
642
-    public function dashboard_glance_items($elements)
643
-    {
644
-        $elements                        = is_array($elements) ? $elements : [$elements];
645
-        $events                          = EEM_Event::instance()->count();
646
-        $items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
647
-            ['page' => 'espresso_events'],
648
-            admin_url('admin.php')
649
-        );
650
-        $items['events']['text']         = sprintf(
651
-            esc_html(
652
-                _n('%s Event', '%s Events', $events, 'event_espresso')
653
-            ),
654
-            number_format_i18n($events)
655
-        );
656
-        $items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
657
-        $registrations                   = EEM_Registration::instance()->count(
658
-            [
659
-                [
660
-                    'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
661
-                ],
662
-            ]
663
-        );
664
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
665
-            ['page' => 'espresso_registrations'],
666
-            admin_url('admin.php')
667
-        );
668
-        $items['registrations']['text']  = sprintf(
669
-            esc_html(
670
-                _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
671
-            ),
672
-            number_format_i18n($registrations)
673
-        );
674
-        $items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
675
-
676
-        $items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
677
-
678
-        foreach ($items as $type => $item_properties) {
679
-            $elements[] = sprintf(
680
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
681
-                $item_properties['url'],
682
-                $item_properties['title'],
683
-                $item_properties['text']
684
-            );
685
-        }
686
-        return $elements;
687
-    }
688
-
689
-
690
-    /**
691
-     * check_for_invalid_datetime_formats
692
-     * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
693
-     * their selected format can be parsed by PHP
694
-     *
695
-     * @param    $value
696
-     * @param    $option
697
-     * @return    string
698
-     */
699
-    public function check_for_invalid_datetime_formats($value, $option)
700
-    {
701
-        // check for date_format or time_format
702
-        switch ($option) {
703
-            case 'date_format':
704
-                $date_time_format = $value . ' ' . get_option('time_format');
705
-                break;
706
-            case 'time_format':
707
-                $date_time_format = get_option('date_format') . ' ' . $value;
708
-                break;
709
-            default:
710
-                $date_time_format = false;
711
-        }
712
-        // do we have a date_time format to check ?
713
-        if ($date_time_format) {
714
-            $error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
715
-
716
-            if (is_array($error_msg)) {
717
-                $msg = '<p>'
718
-                       . sprintf(
719
-                           esc_html__(
720
-                               'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
721
-                               'event_espresso'
722
-                           ),
723
-                           date($date_time_format),
724
-                           $date_time_format
725
-                       )
726
-                       . '</p><p><ul>';
727
-
728
-
729
-                foreach ($error_msg as $error) {
730
-                    $msg .= '<li>' . $error . '</li>';
731
-                }
732
-
733
-                $msg .= '</ul></p><p>'
734
-                        . sprintf(
735
-                            esc_html__(
736
-                                '%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
737
-                                'event_espresso'
738
-                            ),
739
-                            '<span style="color:#D54E21;">',
740
-                            '</span>'
741
-                        )
742
-                        . '</p>';
743
-
744
-                // trigger WP settings error
745
-                add_settings_error(
746
-                    'date_format',
747
-                    'date_format',
748
-                    $msg
749
-                );
750
-
751
-                // set format to something valid
752
-                switch ($option) {
753
-                    case 'date_format':
754
-                        $value = 'F j, Y';
755
-                        break;
756
-                    case 'time_format':
757
-                        $value = 'g:i a';
758
-                        break;
759
-                }
760
-            }
761
-        }
762
-        return $value;
763
-    }
764
-
765
-
766
-    /**
767
-     * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
768
-     *
769
-     * @param $content
770
-     * @return    string
771
-     */
772
-    public function its_eSpresso($content)
773
-    {
774
-        return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
775
-    }
776
-
777
-
778
-    /**
779
-     * espresso_admin_footer
780
-     *
781
-     * @return    string
782
-     */
783
-    public function espresso_admin_footer()
784
-    {
785
-        return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
786
-    }
787
-
788
-
789
-    /**
790
-     * Hooks into the "post states" filter in a wp post type list table.
791
-     *
792
-     * @param array   $post_states
793
-     * @param WP_Post $post
794
-     * @return array
795
-     * @throws InvalidArgumentException
796
-     * @throws InvalidDataTypeException
797
-     * @throws InvalidInterfaceException
798
-     */
799
-    public function displayStateForCriticalPages($post_states, $post)
800
-    {
801
-        $post_states = (array) $post_states;
802
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
803
-            return $post_states;
804
-        }
805
-        /** @var EE_Core_Config $config */
806
-        $config = $this->loader->getShared('EE_Config')->core;
807
-        if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
808
-            $post_states[] = sprintf(
809
-            /* Translators: Using company name - Event Espresso Critical Page */
810
-                esc_html__('%s Critical Page', 'event_espresso'),
811
-                'Event Espresso'
812
-            );
813
-        }
814
-        return $post_states;
815
-    }
816
-
817
-
818
-    /**
819
-     * Show documentation links on the plugins page
820
-     *
821
-     * @param mixed $meta Plugin Row Meta
822
-     * @param mixed $file Plugin Base file
823
-     * @return array
824
-     */
825
-    public function addLinksToPluginRowMeta($meta, $file)
826
-    {
827
-        if (EE_PLUGIN_BASENAME === $file) {
828
-            $row_meta = [
829
-                'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
830
-                          . ' aria-label="'
831
-                          . esc_attr__('View Event Espresso documentation', 'event_espresso')
832
-                          . '">'
833
-                          . esc_html__('Docs', 'event_espresso')
834
-                          . '</a>',
835
-                'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
836
-                          . ' aria-label="'
837
-                          . esc_attr__('View Event Espresso API docs', 'event_espresso')
838
-                          . '">'
839
-                          . esc_html__('API docs', 'event_espresso')
840
-                          . '</a>',
841
-            ];
842
-            return array_merge($meta, $row_meta);
843
-        }
844
-        return (array) $meta;
845
-    }
846
-
847
-     /**************************************************************************************/
848
-     /************************************* DEPRECATED *************************************/
849
-     /**************************************************************************************/
850
-
851
-
852
-    /**
853
-     * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
854
-     * EE_Admin_Page route is called.
855
-     *
856
-     * @return void
857
-     */
858
-    public function route_admin_request()
859
-    {
860
-    }
861
-
862
-
863
-    /**
864
-     * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
865
-     *
866
-     * @return void
867
-     */
868
-    public function wp_loaded()
869
-    {
870
-    }
871
-
872
-
873
-    /**
874
-     * static method for registering ee admin page.
875
-     * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
876
-     *
877
-     * @param       $page_basename
878
-     * @param       $page_path
879
-     * @param array $config
880
-     * @return void
881
-     * @throws EE_Error
882
-     * @see        EE_Register_Admin_Page::register()
883
-     * @since      4.3.0
884
-     * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
885
-     */
886
-    public static function register_ee_admin_page($page_basename, $page_path, $config = [])
887
-    {
888
-        EE_Error::doing_it_wrong(
889
-            __METHOD__,
890
-            sprintf(
891
-                esc_html__(
892
-                    'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
893
-                    'event_espresso'
894
-                ),
895
-                $page_basename
896
-            ),
897
-            '4.3'
898
-        );
899
-        if (class_exists('EE_Register_Admin_Page')) {
900
-            $config['page_path'] = $page_path;
901
-        }
902
-        EE_Register_Admin_Page::register($page_basename, $config);
903
-    }
904
-
905
-
906
-    /**
907
-     * @param int     $post_ID
908
-     * @param WP_Post $post
909
-     * @return void
910
-     * @deprecated 4.8.41
911
-     */
912
-    public static function parse_post_content_on_save($post_ID, $post)
913
-    {
914
-        EE_Error::doing_it_wrong(
915
-            __METHOD__,
916
-            esc_html__('Usage is deprecated', 'event_espresso'),
917
-            '4.8.41'
918
-        );
919
-    }
920
-
921
-
922
-    /**
923
-     * @param  $option
924
-     * @param  $old_value
925
-     * @param  $value
926
-     * @return void
927
-     * @deprecated 4.8.41
928
-     */
929
-    public function reset_page_for_posts_on_change($option, $old_value, $value)
930
-    {
931
-        EE_Error::doing_it_wrong(
932
-            __METHOD__,
933
-            esc_html__('Usage is deprecated', 'event_espresso'),
934
-            '4.8.41'
935
-        );
936
-    }
937
-
938
-
939
-    /**
940
-     * @return void
941
-     * @deprecated 4.9.27
942
-     */
943
-    public function get_persistent_admin_notices()
944
-    {
945
-        EE_Error::doing_it_wrong(
946
-            __METHOD__,
947
-            sprintf(
948
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
949
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
950
-            ),
951
-            '4.9.27'
952
-        );
953
-    }
954
-
955
-
956
-    /**
957
-     * @throws InvalidInterfaceException
958
-     * @throws InvalidDataTypeException
959
-     * @throws DomainException
960
-     * @deprecated 4.9.27
961
-     */
962
-    public function dismiss_ee_nag_notice_callback()
963
-    {
964
-        EE_Error::doing_it_wrong(
965
-            __METHOD__,
966
-            sprintf(
967
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
968
-                '\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
969
-            ),
970
-            '4.9.27'
971
-        );
972
-        $this->persistent_admin_notice_manager->dismissNotice();
973
-    }
974
-
975
-
976
-    /**
977
-     * @return void
978
-     * @deprecated 5.0.0.p
979
-     */
980
-    public function enqueue_admin_scripts()
981
-    {
982
-    }
983
-
984
-
985
-
986
-    /**
987
-     * @return RequestInterface
988
-     * @deprecated 5.0.0.p
989
-     */
990
-    public function get_request()
991
-    {
992
-        EE_Error::doing_it_wrong(
993
-            __METHOD__,
994
-            sprintf(
995
-                esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
996
-                'EventEspresso\core\services\request\Request'
997
-            ),
998
-            '5.0.0.p'
999
-        );
1000
-        return $this->request;
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * @deprecated 5.0.0.p
1006
-     */
1007
-    public function hookIntoWpPluginsPage()
1008
-    {
1009
-    }
23
+	private static ?EE_Admin $_instance = null;
24
+
25
+	private ?PersistentAdminNoticeManager $persistent_admin_notice_manager = null;
26
+
27
+	protected LoaderInterface $loader;
28
+
29
+	protected RequestInterface $request;
30
+
31
+
32
+	/**
33
+	 * @singleton method used to instantiate class object
34
+	 * @param LoaderInterface|null  $loader
35
+	 * @param RequestInterface|null $request
36
+	 * @return EE_Admin|null
37
+	 * @throws EE_Error
38
+	 */
39
+	public static function instance(?LoaderInterface $loader = null, ?RequestInterface $request = null): ?EE_Admin
40
+	{
41
+		// check if class object is instantiated
42
+		if (! EE_Admin::$_instance instanceof EE_Admin) {
43
+			EE_Admin::$_instance = new EE_Admin($loader, $request);
44
+		}
45
+		return EE_Admin::$_instance;
46
+	}
47
+
48
+
49
+	/**
50
+	 * @return EE_Admin|null
51
+	 * @throws EE_Error
52
+	 */
53
+	public static function reset(): ?EE_Admin
54
+	{
55
+		EE_Admin::$_instance = null;
56
+		$loader = LoaderFactory::getLoader();
57
+		$request = $loader->getShared('EventEspresso\core\services\request\Request');
58
+		return EE_Admin::instance($loader, $request);
59
+	}
60
+
61
+
62
+	/**
63
+	 * @param LoaderInterface  $loader
64
+	 * @param RequestInterface $request
65
+	 * @throws EE_Error
66
+	 * @throws InvalidDataTypeException
67
+	 * @throws InvalidInterfaceException
68
+	 * @throws InvalidArgumentException
69
+	 */
70
+	protected function __construct(LoaderInterface $loader, RequestInterface $request)
71
+	{
72
+		$this->loader = $loader;
73
+		$this->request = $request;
74
+		// define global EE_Admin constants
75
+		$this->_define_all_constants();
76
+		// set autoloaders for our admin page classes based on included path information
77
+		EEH_Autoloader::register_autoloaders_for_each_file_in_folder(EE_ADMIN);
78
+		// reset Environment config (we only do this on admin page loads);
79
+		EE_Registry::instance()->CFG->environment->recheck_values();
80
+		// load EE_Request_Handler early
81
+		add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
82
+		add_action('admin_init', [$this, 'admin_init'], 100);
83
+		if (! $this->request->isAjax()) {
84
+			// admin hooks
85
+			add_action('admin_notices', [$this, 'display_admin_notices']);
86
+			add_action('network_admin_notices', [$this, 'display_admin_notices']);
87
+			add_filter('pre_update_option', [$this, 'check_for_invalid_datetime_formats'], 100, 2);
88
+			add_filter('plugin_action_links', [$this, 'filter_plugin_actions'], 10, 2);
89
+			add_filter('admin_footer_text', [$this, 'espresso_admin_footer']);
90
+			add_action('display_post_states', [$this, 'displayStateForCriticalPages'], 10, 2);
91
+			add_filter('plugin_row_meta', [$this, 'addLinksToPluginRowMeta'], 10, 2);
92
+		}
93
+		do_action('AHEE__EE_Admin__loaded');
94
+	}
95
+
96
+
97
+	/**
98
+	 * _define_all_constants
99
+	 * define constants that are set globally for all admin pages
100
+	 *
101
+	 * @return void
102
+	 */
103
+	private function _define_all_constants()
104
+	{
105
+		if (! defined('EE_ADMIN_URL')) {
106
+			define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
107
+			define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
108
+			define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
109
+			define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
110
+			define('WP_AJAX_URL', admin_url('admin-ajax.php'));
111
+		}
112
+	}
113
+
114
+
115
+	/**
116
+	 * filter_plugin_actions - adds links to the Plugins page listing
117
+	 *
118
+	 * @param array  $links
119
+	 * @param string $plugin
120
+	 * @return    array
121
+	 */
122
+	public function filter_plugin_actions($links, $plugin)
123
+	{
124
+		// set $main_file in stone
125
+		static $main_file;
126
+		// if $main_file is not set yet
127
+		if (! $main_file) {
128
+			$main_file = EE_PLUGIN_BASENAME;
129
+		}
130
+		if ($plugin === $main_file) {
131
+			// compare current plugin to this one
132
+			if (EE_Maintenance_Mode::instance()->level() === EE_Maintenance_Mode::level_2_complete_maintenance) {
133
+				$maintenance_link = '<a href="admin.php?page=espresso_maintenance_settings"'
134
+									. ' title="Event Espresso is in maintenance mode.  Click this link to learn why.">'
135
+									. esc_html__('Maintenance Mode Active', 'event_espresso')
136
+									. '</a>';
137
+				array_unshift($links, $maintenance_link);
138
+			} else {
139
+				$org_settings_link = '<a href="admin.php?page=espresso_general_settings">'
140
+									 . esc_html__('Settings', 'event_espresso')
141
+									 . '</a>';
142
+				$events_link       = '<a href="admin.php?page=espresso_events">'
143
+									 . esc_html__('Events', 'event_espresso')
144
+									 . '</a>';
145
+				// add before other links
146
+				array_unshift($links, $org_settings_link, $events_link);
147
+			}
148
+		}
149
+		return $links;
150
+	}
151
+
152
+
153
+	/**
154
+	 * hide_admin_pages_except_maintenance_mode
155
+	 *
156
+	 * @param array $admin_page_folder_names
157
+	 * @return array
158
+	 */
159
+	public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
160
+	{
161
+		return [
162
+			'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
163
+			'about'       => EE_ADMIN_PAGES . 'about/',
164
+			'support'     => EE_ADMIN_PAGES . 'support/',
165
+		];
166
+	}
167
+
168
+
169
+	/**
170
+	 * init- should fire after shortcode, module,  addon, other plugin (default priority), and even
171
+	 * EE_Front_Controller's init phases have run
172
+	 *
173
+	 * @return void
174
+	 * @throws EE_Error
175
+	 * @throws InvalidArgumentException
176
+	 * @throws InvalidDataTypeException
177
+	 * @throws InvalidInterfaceException
178
+	 * @throws ReflectionException
179
+	 * @throws ServiceNotFoundException
180
+	 */
181
+	public function init()
182
+	{
183
+		// only enable most of the EE_Admin IF we're not in full maintenance mode
184
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
185
+			$this->initModelsReady();
186
+		}
187
+		// run the admin page factory but ONLY if:
188
+		// - it is a regular non ajax admin request
189
+		// - we are doing an ee admin ajax request
190
+		if ($this->request->isAdmin() || $this->request->isAdminAjax() || $this->request->isActivation()) {
191
+			try {
192
+				// this loads the controller for the admin pages which will setup routing etc
193
+				$admin_page_loader = $this->loader->getShared('EE_Admin_Page_Loader', [$this->loader]);
194
+				/** @var EE_Admin_Page_Loader $admin_page_loader */
195
+				$admin_page_loader->init();
196
+			} catch (EE_Error $e) {
197
+				$e->get_error();
198
+			}
199
+		}
200
+		if ($this->request->isAjax()) {
201
+			return;
202
+		}
203
+		add_filter('content_save_pre', [$this, 'its_eSpresso']);
204
+		// make sure our CPTs and custom taxonomy metaboxes get shown for first time users
205
+		add_action('admin_head', [$this, 'enable_hidden_ee_nav_menu_metaboxes']);
206
+		add_action('admin_head', [$this, 'register_custom_nav_menu_boxes']);
207
+		// exclude EE critical pages from all nav menus and wp_list_pages
208
+		add_filter('nav_menu_meta_box_object', [$this, 'remove_pages_from_nav_menu']);
209
+	}
210
+
211
+
212
+	/**
213
+	 * Gets the loader (and if it wasn't previously set, sets it)
214
+	 *
215
+	 * @return LoaderInterface
216
+	 * @throws InvalidArgumentException
217
+	 * @throws InvalidDataTypeException
218
+	 * @throws InvalidInterfaceException
219
+	 */
220
+	protected function getLoader()
221
+	{
222
+		return $this->loader;
223
+	}
224
+
225
+
226
+	/**
227
+	 * Method that's fired on admin requests (including admin ajax) but only when the models are usable
228
+	 * (ie, the site isn't in maintenance mode)
229
+	 *
230
+	 * @return void
231
+	 * @throws EE_Error
232
+	 * @since 4.9.63.p
233
+	 */
234
+	protected function initModelsReady()
235
+	{
236
+		// ok so we want to enable the entire admin
237
+		$this->persistent_admin_notice_manager = $this->loader->getShared(
238
+			'EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
239
+		);
240
+		$this->persistent_admin_notice_manager->setReturnUrl(
241
+			EE_Admin_Page::add_query_args_and_nonce(
242
+				[
243
+					'page'   => $this->request->getRequestParam('page', ''),
244
+					'action' => $this->request->getRequestParam('action', ''),
245
+				],
246
+				EE_ADMIN_URL
247
+			)
248
+		);
249
+		$this->maybeSetDatetimeWarningNotice();
250
+		// at a glance dashboard widget
251
+		add_filter('dashboard_glance_items', [$this, 'dashboard_glance_items']);
252
+		// filter for get_edit_post_link used on comments for custom post types
253
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
254
+	}
255
+
256
+
257
+	/**
258
+	 *    get_persistent_admin_notices
259
+	 *
260
+	 * @access    public
261
+	 * @return void
262
+	 * @throws EE_Error
263
+	 * @throws InvalidArgumentException
264
+	 * @throws InvalidDataTypeException
265
+	 * @throws InvalidInterfaceException
266
+	 * @throws ReflectionException
267
+	 */
268
+	public function maybeSetDatetimeWarningNotice()
269
+	{
270
+		// add dismissible notice for datetime changes.  Only valid if site does not have a timezone_string set.
271
+		// @todo This needs to stay in core for a bit to catch anyone upgrading from a version without this to a version
272
+		// with this.  But after enough time (indeterminate at this point) we can just remove this notice.
273
+		// this was added with https://events.codebasehq.com/projects/event-espresso/tickets/10626
274
+		if (
275
+			apply_filters('FHEE__EE_Admin__maybeSetDatetimeWarningNotice', true)
276
+			&& ! get_option('timezone_string')
277
+			&& EEM_Event::instance()->count() > 0
278
+		) {
279
+			new PersistentAdminNotice(
280
+				'datetime_fix_notice',
281
+				sprintf(
282
+					esc_html__(
283
+						'%1$sImportant announcement related to your install of Event Espresso%2$s: There are some changes made to your site that could affect how dates display for your events and other related items with dates and times.  Read more about it %3$shere%4$s. If your dates and times are displaying incorrectly (incorrect offset), you can fix it using the tool on %5$sthis page%4$s.',
284
+						'event_espresso'
285
+					),
286
+					'<strong>',
287
+					'</strong>',
288
+					'<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
289
+					'</a>',
290
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
291
+						[
292
+							'page'   => 'espresso_maintenance_settings',
293
+							'action' => 'datetime_tools',
294
+						],
295
+						admin_url('admin.php')
296
+					) . '">'
297
+				),
298
+				false,
299
+				'manage_options',
300
+				'datetime_fix_persistent_notice'
301
+			);
302
+		}
303
+	}
304
+
305
+
306
+	/**
307
+	 * this simply hooks into the nav menu setup of pages metabox and makes sure that we remove EE critical pages from
308
+	 * the list of options. the wp function "wp_nav_menu_item_post_type_meta_box" found in
309
+	 * wp-admin/includes/nav-menu.php looks for the "_default_query" property on the post_type object and it uses that
310
+	 * to override any queries found in the existing query for the given post type.  Note that _default_query is not a
311
+	 * normal property on the post_type object.  It's found ONLY in this particular context.
312
+	 *
313
+	 * @param WP_Post $post_type WP post type object
314
+	 * @return WP_Post
315
+	 * @throws InvalidArgumentException
316
+	 * @throws InvalidDataTypeException
317
+	 * @throws InvalidInterfaceException
318
+	 */
319
+	public function remove_pages_from_nav_menu($post_type)
320
+	{
321
+		// if this isn't the "pages" post type let's get out
322
+		if ($post_type->name !== 'page') {
323
+			return $post_type;
324
+		}
325
+		$critical_pages            = EE_Registry::instance()->CFG->core->get_critical_pages_array();
326
+		$post_type->_default_query = [
327
+			'post__not_in' => $critical_pages,
328
+		];
329
+		return $post_type;
330
+	}
331
+
332
+
333
+	/**
334
+	 * WP by default only shows three metaboxes in "nav-menus.php" for first times users.
335
+	 * We want to make sure our metaboxes get shown as well
336
+	 *
337
+	 * @return void
338
+	 */
339
+	public function enable_hidden_ee_nav_menu_metaboxes()
340
+	{
341
+		global $wp_meta_boxes, $pagenow;
342
+		if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
343
+			return;
344
+		}
345
+		$user = wp_get_current_user();
346
+		// has this been done yet?
347
+		if (get_user_option('ee_nav_menu_initialized', $user->ID)) {
348
+			return;
349
+		}
350
+
351
+		$hidden_meta_boxes  = get_user_option('metaboxhidden_nav-menus', $user->ID);
352
+		$initial_meta_boxes = apply_filters(
353
+			'FHEE__EE_Admin__enable_hidden_ee_nav_menu_boxes__initial_meta_boxes',
354
+			[
355
+				'nav-menu-theme-locations',
356
+				'add-page',
357
+				'add-custom-links',
358
+				'add-category',
359
+				'add-espresso_events',
360
+				'add-espresso_venues',
361
+				'add-espresso_event_categories',
362
+				'add-espresso_venue_categories',
363
+				'add-post-type-post',
364
+				'add-post-type-page',
365
+			]
366
+		);
367
+
368
+		if (is_array($hidden_meta_boxes)) {
369
+			foreach ($hidden_meta_boxes as $key => $meta_box_id) {
370
+				if (in_array($meta_box_id, $initial_meta_boxes, true)) {
371
+					unset($hidden_meta_boxes[ $key ]);
372
+				}
373
+			}
374
+		}
375
+		update_user_option($user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true);
376
+		update_user_option($user->ID, 'ee_nav_menu_initialized', 1, true);
377
+	}
378
+
379
+
380
+	/**
381
+	 * This method simply registers custom nav menu boxes for "nav_menus.php route"
382
+	 * Currently EE is using this to make sure there are menu options for our CPT archive page routes.
383
+	 *
384
+	 * @return void
385
+	 * @todo   modify this so its more dynamic and automatic for all ee CPTs and setups and can also be hooked into by
386
+	 *         addons etc.
387
+	 */
388
+	public function register_custom_nav_menu_boxes()
389
+	{
390
+		add_meta_box(
391
+			'add-extra-nav-menu-pages',
392
+			esc_html__('Event Espresso Pages', 'event_espresso'),
393
+			[$this, 'ee_cpt_archive_pages'],
394
+			'nav-menus',
395
+			'side',
396
+			'core'
397
+		);
398
+		add_filter(
399
+			"postbox_classes_nav-menus_add-extra-nav-menu-pages",
400
+			function ($classes) {
401
+				$classes[] = 'ee-admin-container';
402
+				return $classes;
403
+			}
404
+		);
405
+	}
406
+
407
+
408
+	/**
409
+	 * Use this to edit the post link for our cpts so that the edit link points to the correct page.
410
+	 *
411
+	 * @param string $link the original link generated by wp
412
+	 * @param int    $id   post id
413
+	 * @return string  the (maybe) modified link
414
+	 * @since   4.3.0
415
+	 */
416
+	public function modify_edit_post_link($link, $id)
417
+	{
418
+		if (! $post = get_post($id)) {
419
+			return $link;
420
+		}
421
+		if ($post->post_type === 'espresso_attendees') {
422
+			$query_args = [
423
+				'action' => 'edit_attendee',
424
+				'post'   => $id,
425
+			];
426
+			return EEH_URL::add_query_args_and_nonce(
427
+				$query_args,
428
+				admin_url('admin.php?page=espresso_registrations')
429
+			);
430
+		}
431
+		return $link;
432
+	}
433
+
434
+
435
+	public function ee_cpt_archive_pages()
436
+	{
437
+		global $nav_menu_selected_id;
438
+		$removed_args = [
439
+			'action',
440
+			'customlink-tab',
441
+			'edit-menu-item',
442
+			'menu-item',
443
+			'page-tab',
444
+			'_wpnonce',
445
+		];
446
+		$nav_tab_link = $nav_menu_selected_id
447
+			? esc_url(
448
+				add_query_arg(
449
+					'extra-nav-menu-pages-tab',
450
+					'event-archives',
451
+					remove_query_arg($removed_args)
452
+				)
453
+			)
454
+			: '';
455
+		$select_all_link = esc_url(
456
+			add_query_arg(
457
+				[
458
+					'extra-nav-menu-pages-tab' => 'event-archives',
459
+					'selectall'                => 1,
460
+				],
461
+				remove_query_arg($removed_args)
462
+			)
463
+		);
464
+		$pages = $this->_get_extra_nav_menu_pages_items();
465
+		$args['walker'] = new Walker_Nav_Menu_Checklist(false);
466
+		$nav_menu_pages_items = walk_nav_menu_tree(
467
+			array_map(
468
+				[$this, '_setup_extra_nav_menu_pages_items'],
469
+				$pages
470
+			),
471
+			0,
472
+			(object) $args
473
+		);
474
+		EEH_Template::display_template(
475
+			EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
476
+			[
477
+				'nav_menu_selected_id' => $nav_menu_selected_id,
478
+				'nav_menu_pages_items' => $nav_menu_pages_items,
479
+				'nav_tab_link'         => $nav_tab_link,
480
+				'select_all_link'      => $select_all_link,
481
+			]
482
+		);
483
+	}
484
+
485
+
486
+	/**
487
+	 * Returns an array of event archive nav items.
488
+	 *
489
+	 * @return array
490
+	 * @todo  for now this method is just in place so when it gets abstracted further we can substitute in whatever
491
+	 *        method we use for getting the extra nav menu items
492
+	 */
493
+	private function _get_extra_nav_menu_pages_items()
494
+	{
495
+		$menuitems[] = [
496
+			'title'       => esc_html__('Event List', 'event_espresso'),
497
+			'url'         => get_post_type_archive_link('espresso_events'),
498
+			'description' => esc_html__('Archive page for all events.', 'event_espresso'),
499
+		];
500
+		return apply_filters('FHEE__EE_Admin__get_extra_nav_menu_pages_items', $menuitems);
501
+	}
502
+
503
+
504
+	/**
505
+	 * Setup nav menu walker item for usage in the event archive nav menu metabox.  It receives a menu_item array with
506
+	 * the properties and converts it to the menu item object.
507
+	 *
508
+	 * @param $menu_item_values
509
+	 * @return stdClass
510
+	 * @see wp_setup_nav_menu_item() in wp-includes/nav-menu.php
511
+	 */
512
+	private function _setup_extra_nav_menu_pages_items($menu_item_values)
513
+	{
514
+		$menu_item = new stdClass();
515
+		$keys      = [
516
+			'ID'               => 0,
517
+			'db_id'            => 0,
518
+			'menu_item_parent' => 0,
519
+			'object_id'        => -1,
520
+			'post_parent'      => 0,
521
+			'type'             => 'custom',
522
+			'object'           => '',
523
+			'type_label'       => esc_html__('Extra Nav Menu Item', 'event_espresso'),
524
+			'title'            => '',
525
+			'url'              => '',
526
+			'target'           => '',
527
+			'attr_title'       => '',
528
+			'description'      => '',
529
+			'classes'          => [],
530
+			'xfn'              => '',
531
+		];
532
+		foreach ($keys as $key => $value) {
533
+			$menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
534
+		}
535
+		return $menu_item;
536
+	}
537
+
538
+
539
+	/**
540
+	 * admin_init
541
+	 *
542
+	 * @return void
543
+	 * @throws InvalidArgumentException
544
+	 * @throws InvalidDataTypeException
545
+	 * @throws InvalidInterfaceException
546
+	 */
547
+	public function admin_init()
548
+	{
549
+		/**
550
+		 * our cpt models must be instantiated on WordPress post processing routes (wp-admin/post.php),
551
+		 * so any hooking into core WP routes is taken care of.  So in this next few lines of code:
552
+		 * - check if doing post processing.
553
+		 * - check if doing post processing of one of EE CPTs
554
+		 * - instantiate the corresponding EE CPT model for the post_type being processed.
555
+		 */
556
+		$action    = $this->request->getRequestParam('action');
557
+		$post_type = $this->request->getRequestParam('post_type');
558
+		if ($post_type && $action === 'editpost') {
559
+			/** @var CustomPostTypeDefinitions $custom_post_types */
560
+			$custom_post_types = $this->loader->getShared(CustomPostTypeDefinitions::class);
561
+			$custom_post_types->getCustomPostTypeModels($post_type);
562
+		}
563
+
564
+
565
+		if (! $this->request->isAjax()) {
566
+			/**
567
+			 * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
568
+			 * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
569
+			 * Pages" tab in the EE General Settings Admin page.
570
+			 * This is for user-proofing.
571
+			 */
572
+			add_filter('wp_dropdown_pages', [$this, 'modify_dropdown_pages']);
573
+			if (EE_Maintenance_Mode::instance()->models_can_query()) {
574
+				$this->adminInitModelsReady();
575
+			}
576
+		}
577
+	}
578
+
579
+
580
+	/**
581
+	 * Runs on admin_init but only if models are usable (ie, we're not in maintenance mode)
582
+	 */
583
+	protected function adminInitModelsReady()
584
+	{
585
+		if (function_exists('wp_add_privacy_policy_content')) {
586
+			$this->loader->getShared('EventEspresso\core\services\privacy\policy\PrivacyPolicyManager');
587
+		}
588
+	}
589
+
590
+
591
+	/**
592
+	 * Callback for wp_dropdown_pages hook to remove ee critical pages from the dropdown selection.
593
+	 *
594
+	 * @param string $output Current output.
595
+	 * @return string
596
+	 * @throws InvalidArgumentException
597
+	 * @throws InvalidDataTypeException
598
+	 * @throws InvalidInterfaceException
599
+	 */
600
+	public function modify_dropdown_pages($output)
601
+	{
602
+		// get critical pages
603
+		$critical_pages = EE_Registry::instance()->CFG->core->get_critical_pages_array();
604
+
605
+		// split current output by line break for easier parsing.
606
+		$split_output = explode("\n", $output);
607
+
608
+		// loop through to remove any critical pages from the array.
609
+		foreach ($critical_pages as $page_id) {
610
+			$needle = 'value="' . $page_id . '"';
611
+			foreach ($split_output as $key => $haystack) {
612
+				if (strpos($haystack, $needle) !== false) {
613
+					unset($split_output[ $key ]);
614
+				}
615
+			}
616
+		}
617
+		// replace output with the new contents
618
+		return implode("\n", $split_output);
619
+	}
620
+
621
+
622
+	/**
623
+	 * display_admin_notices
624
+	 *
625
+	 * @return void
626
+	 */
627
+	public function display_admin_notices()
628
+	{
629
+		echo EE_Error::get_notices(); // already escaped
630
+	}
631
+
632
+
633
+	/**
634
+	 * @param array $elements
635
+	 * @return array
636
+	 * @throws EE_Error
637
+	 * @throws InvalidArgumentException
638
+	 * @throws InvalidDataTypeException
639
+	 * @throws InvalidInterfaceException
640
+	 * @throws ReflectionException
641
+	 */
642
+	public function dashboard_glance_items($elements)
643
+	{
644
+		$elements                        = is_array($elements) ? $elements : [$elements];
645
+		$events                          = EEM_Event::instance()->count();
646
+		$items['events']['url']          = EE_Admin_Page::add_query_args_and_nonce(
647
+			['page' => 'espresso_events'],
648
+			admin_url('admin.php')
649
+		);
650
+		$items['events']['text']         = sprintf(
651
+			esc_html(
652
+				_n('%s Event', '%s Events', $events, 'event_espresso')
653
+			),
654
+			number_format_i18n($events)
655
+		);
656
+		$items['events']['title']        = esc_html__('Click to view all Events', 'event_espresso');
657
+		$registrations                   = EEM_Registration::instance()->count(
658
+			[
659
+				[
660
+					'STS_ID' => ['!=', EEM_Registration::status_id_incomplete],
661
+				],
662
+			]
663
+		);
664
+		$items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
665
+			['page' => 'espresso_registrations'],
666
+			admin_url('admin.php')
667
+		);
668
+		$items['registrations']['text']  = sprintf(
669
+			esc_html(
670
+				_n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
671
+			),
672
+			number_format_i18n($registrations)
673
+		);
674
+		$items['registrations']['title'] = esc_html__('Click to view all registrations', 'event_espresso');
675
+
676
+		$items = (array) apply_filters('FHEE__EE_Admin__dashboard_glance_items__items', $items);
677
+
678
+		foreach ($items as $type => $item_properties) {
679
+			$elements[] = sprintf(
680
+				'<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
681
+				$item_properties['url'],
682
+				$item_properties['title'],
683
+				$item_properties['text']
684
+			);
685
+		}
686
+		return $elements;
687
+	}
688
+
689
+
690
+	/**
691
+	 * check_for_invalid_datetime_formats
692
+	 * if an admin changes their date or time format settings on the WP General Settings admin page, verify that
693
+	 * their selected format can be parsed by PHP
694
+	 *
695
+	 * @param    $value
696
+	 * @param    $option
697
+	 * @return    string
698
+	 */
699
+	public function check_for_invalid_datetime_formats($value, $option)
700
+	{
701
+		// check for date_format or time_format
702
+		switch ($option) {
703
+			case 'date_format':
704
+				$date_time_format = $value . ' ' . get_option('time_format');
705
+				break;
706
+			case 'time_format':
707
+				$date_time_format = get_option('date_format') . ' ' . $value;
708
+				break;
709
+			default:
710
+				$date_time_format = false;
711
+		}
712
+		// do we have a date_time format to check ?
713
+		if ($date_time_format) {
714
+			$error_msg = EEH_DTT_Helper::validate_format_string($date_time_format);
715
+
716
+			if (is_array($error_msg)) {
717
+				$msg = '<p>'
718
+					   . sprintf(
719
+						   esc_html__(
720
+							   'The following date time "%s" ( %s ) is difficult to be properly parsed by PHP for the following reasons:',
721
+							   'event_espresso'
722
+						   ),
723
+						   date($date_time_format),
724
+						   $date_time_format
725
+					   )
726
+					   . '</p><p><ul>';
727
+
728
+
729
+				foreach ($error_msg as $error) {
730
+					$msg .= '<li>' . $error . '</li>';
731
+				}
732
+
733
+				$msg .= '</ul></p><p>'
734
+						. sprintf(
735
+							esc_html__(
736
+								'%sPlease note that your date and time formats have been reset to "F j, Y" and "g:i a" respectively.%s',
737
+								'event_espresso'
738
+							),
739
+							'<span style="color:#D54E21;">',
740
+							'</span>'
741
+						)
742
+						. '</p>';
743
+
744
+				// trigger WP settings error
745
+				add_settings_error(
746
+					'date_format',
747
+					'date_format',
748
+					$msg
749
+				);
750
+
751
+				// set format to something valid
752
+				switch ($option) {
753
+					case 'date_format':
754
+						$value = 'F j, Y';
755
+						break;
756
+					case 'time_format':
757
+						$value = 'g:i a';
758
+						break;
759
+				}
760
+			}
761
+		}
762
+		return $value;
763
+	}
764
+
765
+
766
+	/**
767
+	 * its_eSpresso - converts the less commonly used spelling of "Expresso" to "Espresso"
768
+	 *
769
+	 * @param $content
770
+	 * @return    string
771
+	 */
772
+	public function its_eSpresso($content)
773
+	{
774
+		return str_replace('[EXPRESSO_', '[ESPRESSO_', $content);
775
+	}
776
+
777
+
778
+	/**
779
+	 * espresso_admin_footer
780
+	 *
781
+	 * @return    string
782
+	 */
783
+	public function espresso_admin_footer()
784
+	{
785
+		return EEH_Template::powered_by_event_espresso('aln-cntr', '', ['utm_content' => 'admin_footer']);
786
+	}
787
+
788
+
789
+	/**
790
+	 * Hooks into the "post states" filter in a wp post type list table.
791
+	 *
792
+	 * @param array   $post_states
793
+	 * @param WP_Post $post
794
+	 * @return array
795
+	 * @throws InvalidArgumentException
796
+	 * @throws InvalidDataTypeException
797
+	 * @throws InvalidInterfaceException
798
+	 */
799
+	public function displayStateForCriticalPages($post_states, $post)
800
+	{
801
+		$post_states = (array) $post_states;
802
+		if (! $post instanceof WP_Post || $post->post_type !== 'page') {
803
+			return $post_states;
804
+		}
805
+		/** @var EE_Core_Config $config */
806
+		$config = $this->loader->getShared('EE_Config')->core;
807
+		if (in_array($post->ID, $config->get_critical_pages_array(), true)) {
808
+			$post_states[] = sprintf(
809
+			/* Translators: Using company name - Event Espresso Critical Page */
810
+				esc_html__('%s Critical Page', 'event_espresso'),
811
+				'Event Espresso'
812
+			);
813
+		}
814
+		return $post_states;
815
+	}
816
+
817
+
818
+	/**
819
+	 * Show documentation links on the plugins page
820
+	 *
821
+	 * @param mixed $meta Plugin Row Meta
822
+	 * @param mixed $file Plugin Base file
823
+	 * @return array
824
+	 */
825
+	public function addLinksToPluginRowMeta($meta, $file)
826
+	{
827
+		if (EE_PLUGIN_BASENAME === $file) {
828
+			$row_meta = [
829
+				'docs' => '<a href="https://eventespresso.com/support/documentation/versioned-docs/?doc_ver=ee4"'
830
+						  . ' aria-label="'
831
+						  . esc_attr__('View Event Espresso documentation', 'event_espresso')
832
+						  . '">'
833
+						  . esc_html__('Docs', 'event_espresso')
834
+						  . '</a>',
835
+				'api'  => '<a href="https://github.com/eventespresso/event-espresso-core/tree/master/docs/C--REST-API"'
836
+						  . ' aria-label="'
837
+						  . esc_attr__('View Event Espresso API docs', 'event_espresso')
838
+						  . '">'
839
+						  . esc_html__('API docs', 'event_espresso')
840
+						  . '</a>',
841
+			];
842
+			return array_merge($meta, $row_meta);
843
+		}
844
+		return (array) $meta;
845
+	}
846
+
847
+	 /**************************************************************************************/
848
+	 /************************************* DEPRECATED *************************************/
849
+	 /**************************************************************************************/
850
+
851
+
852
+	/**
853
+	 * This is the action hook for the AHEE__EE_Admin_Page__route_admin_request hook that fires off right before an
854
+	 * EE_Admin_Page route is called.
855
+	 *
856
+	 * @return void
857
+	 */
858
+	public function route_admin_request()
859
+	{
860
+	}
861
+
862
+
863
+	/**
864
+	 * wp_loaded should fire on the WordPress wp_loaded hook.  This fires on a VERY late priority.
865
+	 *
866
+	 * @return void
867
+	 */
868
+	public function wp_loaded()
869
+	{
870
+	}
871
+
872
+
873
+	/**
874
+	 * static method for registering ee admin page.
875
+	 * This method is deprecated in favor of the new location in EE_Register_Admin_Page::register.
876
+	 *
877
+	 * @param       $page_basename
878
+	 * @param       $page_path
879
+	 * @param array $config
880
+	 * @return void
881
+	 * @throws EE_Error
882
+	 * @see        EE_Register_Admin_Page::register()
883
+	 * @since      4.3.0
884
+	 * @deprecated 4.3.0    Use EE_Register_Admin_Page::register() instead
885
+	 */
886
+	public static function register_ee_admin_page($page_basename, $page_path, $config = [])
887
+	{
888
+		EE_Error::doing_it_wrong(
889
+			__METHOD__,
890
+			sprintf(
891
+				esc_html__(
892
+					'Usage is deprecated.  Use EE_Register_Admin_Page::register() for registering the %s admin page.',
893
+					'event_espresso'
894
+				),
895
+				$page_basename
896
+			),
897
+			'4.3'
898
+		);
899
+		if (class_exists('EE_Register_Admin_Page')) {
900
+			$config['page_path'] = $page_path;
901
+		}
902
+		EE_Register_Admin_Page::register($page_basename, $config);
903
+	}
904
+
905
+
906
+	/**
907
+	 * @param int     $post_ID
908
+	 * @param WP_Post $post
909
+	 * @return void
910
+	 * @deprecated 4.8.41
911
+	 */
912
+	public static function parse_post_content_on_save($post_ID, $post)
913
+	{
914
+		EE_Error::doing_it_wrong(
915
+			__METHOD__,
916
+			esc_html__('Usage is deprecated', 'event_espresso'),
917
+			'4.8.41'
918
+		);
919
+	}
920
+
921
+
922
+	/**
923
+	 * @param  $option
924
+	 * @param  $old_value
925
+	 * @param  $value
926
+	 * @return void
927
+	 * @deprecated 4.8.41
928
+	 */
929
+	public function reset_page_for_posts_on_change($option, $old_value, $value)
930
+	{
931
+		EE_Error::doing_it_wrong(
932
+			__METHOD__,
933
+			esc_html__('Usage is deprecated', 'event_espresso'),
934
+			'4.8.41'
935
+		);
936
+	}
937
+
938
+
939
+	/**
940
+	 * @return void
941
+	 * @deprecated 4.9.27
942
+	 */
943
+	public function get_persistent_admin_notices()
944
+	{
945
+		EE_Error::doing_it_wrong(
946
+			__METHOD__,
947
+			sprintf(
948
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
949
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
950
+			),
951
+			'4.9.27'
952
+		);
953
+	}
954
+
955
+
956
+	/**
957
+	 * @throws InvalidInterfaceException
958
+	 * @throws InvalidDataTypeException
959
+	 * @throws DomainException
960
+	 * @deprecated 4.9.27
961
+	 */
962
+	public function dismiss_ee_nag_notice_callback()
963
+	{
964
+		EE_Error::doing_it_wrong(
965
+			__METHOD__,
966
+			sprintf(
967
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
968
+				'\EventEspresso\core\services\notifications\PersistentAdminNoticeManager'
969
+			),
970
+			'4.9.27'
971
+		);
972
+		$this->persistent_admin_notice_manager->dismissNotice();
973
+	}
974
+
975
+
976
+	/**
977
+	 * @return void
978
+	 * @deprecated 5.0.0.p
979
+	 */
980
+	public function enqueue_admin_scripts()
981
+	{
982
+	}
983
+
984
+
985
+
986
+	/**
987
+	 * @return RequestInterface
988
+	 * @deprecated 5.0.0.p
989
+	 */
990
+	public function get_request()
991
+	{
992
+		EE_Error::doing_it_wrong(
993
+			__METHOD__,
994
+			sprintf(
995
+				esc_html__('Usage is deprecated. Use "%1$s" instead.', 'event_espresso'),
996
+				'EventEspresso\core\services\request\Request'
997
+			),
998
+			'5.0.0.p'
999
+		);
1000
+		return $this->request;
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * @deprecated 5.0.0.p
1006
+	 */
1007
+	public function hookIntoWpPluginsPage()
1008
+	{
1009
+	}
1010 1010
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -39,7 +39,7 @@  discard block
 block discarded – undo
39 39
     public static function instance(?LoaderInterface $loader = null, ?RequestInterface $request = null): ?EE_Admin
40 40
     {
41 41
         // check if class object is instantiated
42
-        if (! EE_Admin::$_instance instanceof EE_Admin) {
42
+        if ( ! EE_Admin::$_instance instanceof EE_Admin) {
43 43
             EE_Admin::$_instance = new EE_Admin($loader, $request);
44 44
         }
45 45
         return EE_Admin::$_instance;
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
         // load EE_Request_Handler early
81 81
         add_action('AHEE__EE_System__initialize_last', [$this, 'init']);
82 82
         add_action('admin_init', [$this, 'admin_init'], 100);
83
-        if (! $this->request->isAjax()) {
83
+        if ( ! $this->request->isAjax()) {
84 84
             // admin hooks
85 85
             add_action('admin_notices', [$this, 'display_admin_notices']);
86 86
             add_action('network_admin_notices', [$this, 'display_admin_notices']);
@@ -102,11 +102,11 @@  discard block
 block discarded – undo
102 102
      */
103 103
     private function _define_all_constants()
104 104
     {
105
-        if (! defined('EE_ADMIN_URL')) {
106
-            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL . 'core/admin/');
107
-            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL . 'admin_pages/');
108
-            define('EE_ADMIN_TEMPLATE', EE_ADMIN . 'templates/');
109
-            define('WP_ADMIN_PATH', ABSPATH . 'wp-admin/');
105
+        if ( ! defined('EE_ADMIN_URL')) {
106
+            define('EE_ADMIN_URL', EE_PLUGIN_DIR_URL.'core/admin/');
107
+            define('EE_ADMIN_PAGES_URL', EE_PLUGIN_DIR_URL.'admin_pages/');
108
+            define('EE_ADMIN_TEMPLATE', EE_ADMIN.'templates/');
109
+            define('WP_ADMIN_PATH', ABSPATH.'wp-admin/');
110 110
             define('WP_AJAX_URL', admin_url('admin-ajax.php'));
111 111
         }
112 112
     }
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
         // set $main_file in stone
125 125
         static $main_file;
126 126
         // if $main_file is not set yet
127
-        if (! $main_file) {
127
+        if ( ! $main_file) {
128 128
             $main_file = EE_PLUGIN_BASENAME;
129 129
         }
130 130
         if ($plugin === $main_file) {
@@ -159,9 +159,9 @@  discard block
 block discarded – undo
159 159
     public function hide_admin_pages_except_maintenance_mode($admin_page_folder_names = [])
160 160
     {
161 161
         return [
162
-            'maintenance' => EE_ADMIN_PAGES . 'maintenance/',
163
-            'about'       => EE_ADMIN_PAGES . 'about/',
164
-            'support'     => EE_ADMIN_PAGES . 'support/',
162
+            'maintenance' => EE_ADMIN_PAGES.'maintenance/',
163
+            'about'       => EE_ADMIN_PAGES.'about/',
164
+            'support'     => EE_ADMIN_PAGES.'support/',
165 165
         ];
166 166
     }
167 167
 
@@ -287,13 +287,13 @@  discard block
 block discarded – undo
287 287
                     '</strong>',
288 288
                     '<a href="https://eventespresso.com/2017/08/important-upcoming-changes-dates-times">',
289 289
                     '</a>',
290
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
290
+                    '<a href="'.EE_Admin_Page::add_query_args_and_nonce(
291 291
                         [
292 292
                             'page'   => 'espresso_maintenance_settings',
293 293
                             'action' => 'datetime_tools',
294 294
                         ],
295 295
                         admin_url('admin.php')
296
-                    ) . '">'
296
+                    ).'">'
297 297
                 ),
298 298
                 false,
299 299
                 'manage_options',
@@ -339,7 +339,7 @@  discard block
 block discarded – undo
339 339
     public function enable_hidden_ee_nav_menu_metaboxes()
340 340
     {
341 341
         global $wp_meta_boxes, $pagenow;
342
-        if (! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
342
+        if ( ! is_array($wp_meta_boxes) || $pagenow !== 'nav-menus.php') {
343 343
             return;
344 344
         }
345 345
         $user = wp_get_current_user();
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
         if (is_array($hidden_meta_boxes)) {
369 369
             foreach ($hidden_meta_boxes as $key => $meta_box_id) {
370 370
                 if (in_array($meta_box_id, $initial_meta_boxes, true)) {
371
-                    unset($hidden_meta_boxes[ $key ]);
371
+                    unset($hidden_meta_boxes[$key]);
372 372
                 }
373 373
             }
374 374
         }
@@ -397,7 +397,7 @@  discard block
 block discarded – undo
397 397
         );
398 398
         add_filter(
399 399
             "postbox_classes_nav-menus_add-extra-nav-menu-pages",
400
-            function ($classes) {
400
+            function($classes) {
401 401
                 $classes[] = 'ee-admin-container';
402 402
                 return $classes;
403 403
             }
@@ -415,7 +415,7 @@  discard block
 block discarded – undo
415 415
      */
416 416
     public function modify_edit_post_link($link, $id)
417 417
     {
418
-        if (! $post = get_post($id)) {
418
+        if ( ! $post = get_post($id)) {
419 419
             return $link;
420 420
         }
421 421
         if ($post->post_type === 'espresso_attendees') {
@@ -472,7 +472,7 @@  discard block
 block discarded – undo
472 472
             (object) $args
473 473
         );
474 474
         EEH_Template::display_template(
475
-            EE_ADMIN_TEMPLATE . 'cpt_archive_page.template.php',
475
+            EE_ADMIN_TEMPLATE.'cpt_archive_page.template.php',
476 476
             [
477 477
                 'nav_menu_selected_id' => $nav_menu_selected_id,
478 478
                 'nav_menu_pages_items' => $nav_menu_pages_items,
@@ -530,7 +530,7 @@  discard block
 block discarded – undo
530 530
             'xfn'              => '',
531 531
         ];
532 532
         foreach ($keys as $key => $value) {
533
-            $menu_item->{$key} = $menu_item_values[ $key ] ?? $value;
533
+            $menu_item->{$key} = $menu_item_values[$key] ?? $value;
534 534
         }
535 535
         return $menu_item;
536 536
     }
@@ -562,7 +562,7 @@  discard block
 block discarded – undo
562 562
         }
563 563
 
564 564
 
565
-        if (! $this->request->isAjax()) {
565
+        if ( ! $this->request->isAjax()) {
566 566
             /**
567 567
              * This code excludes EE critical pages anywhere `wp_dropdown_pages` is used to create a dropdown for selecting
568 568
              * critical pages.  The only place critical pages need included in a generated dropdown is on the "Critical
@@ -607,10 +607,10 @@  discard block
 block discarded – undo
607 607
 
608 608
         // loop through to remove any critical pages from the array.
609 609
         foreach ($critical_pages as $page_id) {
610
-            $needle = 'value="' . $page_id . '"';
610
+            $needle = 'value="'.$page_id.'"';
611 611
             foreach ($split_output as $key => $haystack) {
612 612
                 if (strpos($haystack, $needle) !== false) {
613
-                    unset($split_output[ $key ]);
613
+                    unset($split_output[$key]);
614 614
                 }
615 615
             }
616 616
         }
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
             ['page' => 'espresso_events'],
648 648
             admin_url('admin.php')
649 649
         );
650
-        $items['events']['text']         = sprintf(
650
+        $items['events']['text'] = sprintf(
651 651
             esc_html(
652 652
                 _n('%s Event', '%s Events', $events, 'event_espresso')
653 653
             ),
@@ -661,11 +661,11 @@  discard block
 block discarded – undo
661 661
                 ],
662 662
             ]
663 663
         );
664
-        $items['registrations']['url']   = EE_Admin_Page::add_query_args_and_nonce(
664
+        $items['registrations']['url'] = EE_Admin_Page::add_query_args_and_nonce(
665 665
             ['page' => 'espresso_registrations'],
666 666
             admin_url('admin.php')
667 667
         );
668
-        $items['registrations']['text']  = sprintf(
668
+        $items['registrations']['text'] = sprintf(
669 669
             esc_html(
670 670
                 _n('%s Registration', '%s Registrations', $registrations, 'event_espresso')
671 671
             ),
@@ -677,7 +677,7 @@  discard block
 block discarded – undo
677 677
 
678 678
         foreach ($items as $type => $item_properties) {
679 679
             $elements[] = sprintf(
680
-                '<a class="ee-dashboard-link-' . $type . '" href="%s" title="%s">%s</a>',
680
+                '<a class="ee-dashboard-link-'.$type.'" href="%s" title="%s">%s</a>',
681 681
                 $item_properties['url'],
682 682
                 $item_properties['title'],
683 683
                 $item_properties['text']
@@ -701,10 +701,10 @@  discard block
 block discarded – undo
701 701
         // check for date_format or time_format
702 702
         switch ($option) {
703 703
             case 'date_format':
704
-                $date_time_format = $value . ' ' . get_option('time_format');
704
+                $date_time_format = $value.' '.get_option('time_format');
705 705
                 break;
706 706
             case 'time_format':
707
-                $date_time_format = get_option('date_format') . ' ' . $value;
707
+                $date_time_format = get_option('date_format').' '.$value;
708 708
                 break;
709 709
             default:
710 710
                 $date_time_format = false;
@@ -727,7 +727,7 @@  discard block
 block discarded – undo
727 727
 
728 728
 
729 729
                 foreach ($error_msg as $error) {
730
-                    $msg .= '<li>' . $error . '</li>';
730
+                    $msg .= '<li>'.$error.'</li>';
731 731
                 }
732 732
 
733 733
                 $msg .= '</ul></p><p>'
@@ -799,7 +799,7 @@  discard block
 block discarded – undo
799 799
     public function displayStateForCriticalPages($post_states, $post)
800 800
     {
801 801
         $post_states = (array) $post_states;
802
-        if (! $post instanceof WP_Post || $post->post_type !== 'page') {
802
+        if ( ! $post instanceof WP_Post || $post->post_type !== 'page') {
803 803
             return $post_states;
804 804
         }
805 805
         /** @var EE_Core_Config $config */
Please login to merge, or discard this patch.
core/admin/EE_Admin_Hooks.core.php 2 patches
Indentation   +714 added lines, -714 removed lines patch added patch discarded remove patch
@@ -15,718 +15,718 @@
 block discarded – undo
15 15
 abstract class EE_Admin_Hooks extends EE_Base
16 16
 {
17 17
 
18
-    /**
19
-     * This just holds an instance of the page object for this hook
20
-     *
21
-     * @var EE_Admin_Page|EE_Admin_Page_CPT|null
22
-     * @deprecated  5.0.8.p
23
-     */
24
-    protected $_page_object = null;
25
-
26
-    /**
27
-     * This holds the EE_Admin_Page object from the calling admin page that this object hooks into.
28
-     *
29
-     * @var EE_Admin_Page|EE_Admin_Page_CPT|null
30
-     */
31
-    protected                   $_adminpage_obj = null;
32
-
33
-    protected ?EE_Registry      $EE             = null;
34
-
35
-    protected ?RequestInterface $request        = null;
36
-
37
-    /**
38
-     * This is set by child classes and is an associative array of ajax hooks in the format:
39
-     * array(
40
-     *    'ajax_action_ref' => 'executing_method'; //must be public
41
-     * )
42
-     */
43
-    protected array $_ajax_func = [];
44
-
45
-    /**
46
-     * This is an array of methods that get executed on a page routes admin_init hook. Use the following format:
47
-     * array(
48
-     *    'page_route' => 'executing_method' //must be public
49
-     * )
50
-     */
51
-    protected array $_init_func = [];
52
-
53
-    /**
54
-     * This is an array of methods that output metabox content for the given page route.  Use the following format:
55
-     * [
56
-     *      0 => [
57
-     *          'page_route' => 'string_for_page_route',    must correspond to a page route in the class being connected
58
-     *                                                      with (i.e. "edit_event") If this is in an array then the
59
-     *                                                      same params below will be used but the metabox will be
60
-     *                                                      added to each route.
61
-     *          'func' =>  'executing_method',              must be public (i.e. public function executing_method
62
-     *                                                      ($post, $callback_args){} ).
63
-     *                                                      Note if you include callback args in the array then you
64
-     *                                                      need to declare them in the method arguments.
65
-     *          'id' => 'identifier_for_metabox',           so it can be removed by addons
66
-     *                                                      (optional, class will set it automatically)
67
-     *          'priority' => 'default',                    default 'default' (optional)
68
-     *          'label' => esc_html__('Localized Title', 'event_espresso'),
69
-     *          'context' => 'advanced'                     advanced is default (optional),
70
-     *      ]
71
-     *      'callback_args' => array() //any callback args to include (optional)
72
-     * ]
73
-     * Why are we indexing numerically?  Because it's possible there may be more than one metabox per page_route.
74
-     */
75
-    protected array $_metaboxes = [];
76
-
77
-    /**
78
-     * This is an array of values that indicate any metaboxes we want removed from a given page route.  Usually this is
79
-     * used when caffeinated functionality is replacing decaffeinated functionality.  Use the following format for the
80
-     * array: array(
81
-     *    0 => array(
82
-     *        'page_route' => 'string_for_page_route' //can be string or array of strings that match a page_route(s)
83
-     *        that are in the class being connected with (i.e. 'edit', or 'create_new').
84
-     *        'id' => 'identifier_for_metabox', //what the id is of the metabox being removed
85
-     *        'context' => 'normal', //the context for the metabox being removed (has to match)
86
-     *        'screen' => 'screen_id', //(optional), if not included then this class will attempt to remove the metabox
87
-     *        using the currently loaded screen object->id  however, there may be cases where you have to specify the
88
-     *        id for the screen the metabox is on.
89
-     *    )
90
-     * )
91
-     */
92
-    protected array $_remove_metaboxes = [];
93
-
94
-    protected array $_req_data         = [];
95
-
96
-    /**
97
-     * This parent class takes care of loading the scripts and styles if the child class has set the properties for
98
-     * them in the following format.  Note, the first array index ('register') is for defining all the registers.  The
99
-     * second array index is for indicating what routes each script/style loads on. array(
100
-     * 'registers' => array(
101
-     *        'script_ref' => array( // if more than one script is to be loaded its best to use the 'dependency'
102
-     *        argument to link scripts together.
103
-     *            'type' => 'js' // 'js' or 'css' (defaults to js).  This tells us what type of wp_function to use
104
-     *            'url' => 'http://urltoscript.css.js',
105
-     *            'depends' => array('jquery'), //an array of dependencies for the scripts. REMEMBER, if a script has
106
-     *            already been registered elsewhere in the system.  You can just use the depends array to make sure it
107
-     *            gets loaded before the one you are setting here.
108
-     *            'footer' => TRUE //defaults to true (styles don't use this parameter)
109
-     *        ),
110
-     *    'enqueues' => array( //this time each key corresponds to the script ref followed by an array of page routes
111
-     *    the script gets enqueued on.
112
-     *        'script_ref' => array('route_one', 'route_two')
113
-     *    ),
114
-     *    'localize' => array( //this allows you to set a localized object.  Indicate which script the object is being
115
-     *    attached to and then include an array indexed by the name of the object and the array of key/value pairs for
116
-     *    the object.
117
-     *        'scrip_ref' => array(
118
-     *            'NAME_OF_JS_OBJECT' => array(
119
-     *                'translate_ref' => esc_html__('localized_string', 'event_espresso'),
120
-     *                'some_data' => 5
121
-     *            )
122
-     *        )
123
-     *    )
124
-     * )
125
-     */
126
-    protected array $_scripts_styles = [];
127
-
128
-    protected array $_scripts        = [];
129
-
130
-    protected array $_styles         = [];
131
-
132
-    /**
133
-     * this optional property can be set by child classes to override the priority for the automatic action/filter hook
134
-     * loading in the `_load_routed_hooks()` method.  Please follow this format: array(
135
-     *    'wp_hook_reference' => 1
136
-     *    )
137
-     * )
138
-     */
139
-    protected array $_wp_action_filters_priority = [];
140
-
141
-    /**
142
-     * this is just a flag set automatically to indicate whether we've got an extended hook class running (i.e.
143
-     * espresso_events_Registration_Form_Hooks_Extend extends espresso_events_Registration_Form_Hooks).  This flag is
144
-     * used later to make sure we require the needed files.
145
-     */
146
-    protected bool $_extend = false;
147
-
148
-    /**
149
-     * we're just going to use this to hold the name of the caller class (child class name)
150
-     */
151
-    public string    $caller         = '';
152
-
153
-    protected string $_current_route = '';
154
-
155
-
156
-    /**
157
-     * child classes MUST set this property so that the page object can be loaded correctly
158
-     */
159
-    protected string $_name = '';
160
-
161
-
162
-    /**
163
-     * constructor
164
-     *
165
-     * @param EE_Admin_Page $admin_page
166
-     * @throws EE_Error
167
-     * @throws ReflectionException
168
-     */
169
-    public function __construct(EE_Admin_Page $admin_page)
170
-    {
171
-        $this->_adminpage_obj = $admin_page;
172
-        $this->request        = LoaderFactory::getLoader()->getShared(RequestInterface::class);
173
-        $this->_req_data      = $this->request->requestParams();
174
-        $current_page         = $this->request->getRequestParam('page');
175
-        $current_page         = $this->request->getRequestParam('current_page', $current_page);
176
-        // first let's verify we're on the right page
177
-        if ($current_page !== $this->_adminpage_obj->page_slug) {
178
-            return;
179
-        }
180
-        $this->_set_defaults();
181
-        $this->_set_hooks_properties();
182
-        // get out nothing more to be done here.
183
-        // allow for extends to modify properties
184
-        if (method_exists($this, '_extend_properties')) {
185
-            $this->_extend_properties();
186
-        }
187
-        // $this->_set_page_object();
188
-        $this->_init_hooks();
189
-        $this->_load_custom_methods();
190
-        $this->_load_routed_hooks();
191
-        add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
192
-        add_action('admin_enqueue_scripts', [$this, 'add_metaboxes'], 20);
193
-        add_action('admin_enqueue_scripts', [$this, 'remove_metaboxes'], 15);
194
-        $this->_ajax_hooks();
195
-    }
196
-
197
-
198
-    /**
199
-     * used by child classes to set the following properties:
200
-     * $_ajax_func (optional)
201
-     * $_init_func (optional)
202
-     * $_metaboxes (optional)
203
-     * $_scripts (optional)
204
-     * $_styles (optional)
205
-     * $_name (required)
206
-     * Also in this method will be registered any scripts or styles loaded on the targeted page (as indicated in the
207
-     * _scripts/_styles properties) Also children should place in this method any filters/actions that have to happen
208
-     * really early on page load (just after admin_init) if they want to have them registered for handling early.
209
-     *
210
-     * @abstract
211
-     * @return void
212
-     */
213
-    abstract protected function _set_hooks_properties();
214
-
215
-
216
-    /**
217
-     * The hooks for enqueue_scripts and enqueue_styles will be run in here.  Child classes need to define their
218
-     * scripts and styles in the relevant $_scripts and $_styles properties.  Child classes must have also already
219
-     * registered the scripts and styles using wp_register_script and wp_register_style functions.
220
-     *
221
-     * @return void
222
-     * @throws EE_Error
223
-     */
224
-    public function enqueue_scripts_styles()
225
-    {
226
-        if (! empty($this->_scripts_styles)) {
227
-            // first let's do all the registrations
228
-            if (! isset($this->_scripts_styles['registers'])) {
229
-                $msg[] = esc_html__(
230
-                    'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
231
-                    'event_espresso'
232
-                );
233
-                $msg[] = sprintf(
234
-                    esc_html__(
235
-                        'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
236
-                        'event_espresso'
237
-                    ),
238
-                    '<strong>' . $this->caller . '</strong>'
239
-                );
240
-                throw new EE_Error(implode('||', $msg));
241
-            }
242
-            $defaults = [
243
-                'type'    => 'js',
244
-                'url'     => '',
245
-                'depends' => [],
246
-                'version' => EVENT_ESPRESSO_VERSION,
247
-                'footer'  => true,
248
-            ];
249
-            foreach ($this->_scripts_styles['registers'] as $ref => $details) {
250
-                $details = wp_parse_args($details, $defaults);
251
-                $type    = $details['type'];
252
-                $url     = $details['url'];
253
-                $depends = $details['depends'];
254
-                $version = $details['version'];
255
-                $footer  = $details['footer'];
256
-                // let's make sure that we set the 'registers' type if it's not set!
257
-                // We need it later to determine which enqueue we do
258
-                $this->_scripts_styles['registers'][ $ref ]['type'] = $type;
259
-                // let's make sure we're not missing any REQUIRED parameters
260
-                if (empty($url)) {
261
-                    $msg[] = sprintf(
262
-                        esc_html__('Missing the url for the requested %s', 'event_espresso'),
263
-                        $type == 'js' ? 'script' : 'stylesheet'
264
-                    );
265
-                    $msg[] = sprintf(
266
-                        esc_html__(
267
-                            'Double-check your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
268
-                            'event_espresso'
269
-                        ),
270
-                        '<strong>' . $this->caller . '</strong>',
271
-                        $ref
272
-                    );
273
-                    throw new EE_Error(implode('||', $msg));
274
-                }
275
-                // made it here so let's do the appropriate registration
276
-                $type == 'js'
277
-                    ? wp_register_script($ref, $url, $depends, $version, $footer)
278
-                    : wp_register_style(
279
-                    $ref,
280
-                    $url,
281
-                    $depends,
282
-                    $version
283
-                );
284
-            }
285
-            // k now let's do the enqueues
286
-            if (! isset($this->_scripts_styles['enqueues'])) {
287
-                return;
288
-            }  //not sure if we should throw an error here or not.
289
-
290
-            foreach ($this->_scripts_styles['enqueues'] as $ref => $routes) {
291
-                // make sure $routes is an array
292
-                $routes = (array) $routes;
293
-                if (in_array($this->_current_route, $routes)) {
294
-                    $this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
295
-                        : wp_enqueue_style($ref);
296
-                    // if we have a localization for the script let's do that too.
297
-                    if (isset($this->_scripts_styles['localize'][ $ref ])) {
298
-                        foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
299
-                            wp_localize_script(
300
-                                $ref,
301
-                                $object_name,
302
-                                $this->_scripts_styles['localize'][ $ref ][ $object_name ]
303
-                            );
304
-                        }
305
-                    }
306
-                }
307
-            }
308
-            // let's do the deregisters
309
-            if (! isset($this->_scripts_styles['deregisters'])) {
310
-                return;
311
-            }
312
-            foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
313
-                $defaults = ['type' => 'js'];
314
-                $details  = wp_parse_args($details, $defaults);
315
-                $details['type'] === 'js' ? wp_deregister_script($ref) : wp_deregister_style($ref);
316
-            }
317
-        }
318
-    }
319
-
320
-
321
-    /**
322
-     * just set the defaults for the hooks properties.
323
-     *
324
-     * @return void
325
-     */
326
-    private function _set_defaults()
327
-    {
328
-        $this->_ajax_func                  = [];
329
-        $this->_init_func                  = [];
330
-        $this->_metaboxes                  = [];
331
-        $this->_scripts                    = [];
332
-        $this->_styles                     = [];
333
-        $this->_wp_action_filters_priority = [];
334
-        $this->_current_route              = $this->getCurrentRoute();
335
-        $this->caller                      = get_class($this);
336
-        $this->_extend                     = (bool) stripos($this->caller, 'Extend');
337
-    }
338
-
339
-
340
-    /**
341
-     * A helper for determining the current route.
342
-     *
343
-     * @return string
344
-     */
345
-    private function getCurrentRoute(): string
346
-    {
347
-        $action = $this->request->getRequestParam('action');
348
-        // list tables do something else with 'action' for bulk actions.
349
-        $action = $action !== '-1' && $action !== '' ? $action : 'default';
350
-        $route  = $this->request->getRequestParam('route');
351
-        // we set a 'route' variable in some cases where action is being used by something else.
352
-        return $action === 'default' && $route !== '' ? $route : $action;
353
-    }
354
-
355
-
356
-    /**
357
-     * this sets the _page_object property
358
-     *
359
-     * @return void
360
-     * @throws EE_Error
361
-     * @throws ReflectionException
362
-     * @throws Throwable
363
-     * @deprecated  5.0.8.p
364
-     */
365
-    protected function _set_page_object()
366
-    {
367
-        if ($this->_page_object instanceof EE_Admin_Page) {
368
-            return;
369
-        }
370
-        // first make sure $this->_name is set
371
-        if (empty($this->_name)) {
372
-            $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
373
-            $msg[] = sprintf(
374
-                esc_html__("This is because the %s child class has not set the '_name' property", 'event_espresso'),
375
-                $this->caller
376
-            );
377
-            throw new EE_Error(implode('||', $msg));
378
-        }
379
-        // change "the_message" to "the message"
380
-        $class_name = str_replace('_', ' ', $this->_name);
381
-        // change "the message" to "The_Message_Admin_Page"
382
-        $class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
383
-        // first default file (if exists)
384
-        $decaf_file = EE_ADMIN_PAGES . "$this->_name/$class_name.core.php";
385
-        if (is_readable($decaf_file)) {
386
-            require_once($decaf_file);
387
-        }
388
-        // now we have to do require for extended file (if needed)
389
-        if ($this->_extend) {
390
-            require_once EE_CORE_CAF_ADMIN_EXTEND . "$this->_name/Extend_$class_name.core.php";
391
-            // and extend the class name as well
392
-            $class_name = 'Extend_' . $class_name;
393
-        }
394
-        // let's make sure the class exists
395
-        if (! class_exists($class_name)) {
396
-            $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
397
-            $msg[] = sprintf(
398
-                esc_html__(
399
-                    'The class name that was given is %s. Check the spelling and make sure its correct, also there needs to be an autoloader setup for the class',
400
-                    'event_espresso'
401
-                ),
402
-                $class_name
403
-            );
404
-            throw new EE_Error(implode('||', $msg));
405
-        }
406
-        // do NOT load admin pages that are ALREADY LOADED!!!
407
-        if ($class_name !== $this->_adminpage_obj->class_name) {
408
-            return;
409
-        }
410
-        $this->_page_object = LoaderFactory::getLoader()->getShared($class_name, [false]);
411
-        $this->_page_object->initializePage();
412
-    }
413
-
414
-
415
-    /**
416
-     * Child "hook" classes can declare any methods that they want executed when a specific page route is loaded.  The
417
-     * advantage of this is when doing things like running our own db interactions on saves etc.  Remember that
418
-     * $this->_req_data (all the _POST and _GET data) is available to your methods.
419
-     *
420
-     * @return void
421
-     */
422
-    private function _load_custom_methods()
423
-    {
424
-        /**
425
-         * method cannot be named 'default' (@see http://us3.php
426
-         * .net/manual/en/reserved.keywords.php) so need to
427
-         * handle routes that are "default"
428
-         *
429
-         * @since 4.3.0
430
-         */
431
-        $method_callback = $this->_current_route == 'default' ? 'default_callback' : $this->_current_route;
432
-        // these run before the Admin_Page route executes.
433
-        if (is_callable($this, $method_callback)) {
434
-            call_user_func([$this, $method_callback]);
435
-        }
436
-        // these run via the _redirect_after_action method in EE_Admin_Page which usually happens after non_UI methods in EE_Admin_Page classes.  There are two redirect actions, the first fires before $query_args might be manipulated by "save and close" actions and the second fires right before the actual redirect happens.
437
-        // first the actions
438
-        // note that these action hooks will have the $query_args value available.
439
-        $admin_class_name = get_class($this->_adminpage_obj);
440
-        if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
441
-            add_action(
442
-                'AHEE__'
443
-                . $admin_class_name
444
-                . '___redirect_after_action__before_redirect_modification_'
445
-                . $this->_current_route,
446
-                [$this, '_redirect_action_early_' . $this->_current_route]
447
-            );
448
-        }
449
-        if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
450
-            add_action(
451
-                'AHEE_redirect_' . $admin_class_name . $this->_current_route,
452
-                [$this, '_redirect_action_' . $this->_current_route]
453
-            );
454
-        }
455
-        // let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
456
-        if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
457
-            add_filter(
458
-                'FHEE_redirect_' . $admin_class_name . $this->_current_route,
459
-                [$this, '_redirect_filter_' . $this->_current_route],
460
-                10,
461
-                2
462
-            );
463
-        }
464
-    }
465
-
466
-
467
-    /**
468
-     * This method will search for a corresponding method with a name matching the route and the wp_hook to run.  This
469
-     * allows child hook classes to target hooking into a specific wp action or filter hook ONLY on a certain route.
470
-     * just remember, methods MUST be public Future hooks should be added in here to be access by child classes.
471
-     *
472
-     * @return void
473
-     */
474
-    private function _load_routed_hooks()
475
-    {
476
-        // this array provides the hook action names that will be referenced.  Key is the action. Value is an array with the type (action or filter) and the number of parameters for the hook.  We'll default all priorities for automatic hooks to 10.
477
-        $hook_filter_array = [
478
-            'admin_footer'                                                                            => [
479
-                'type'     => 'action',
480
-                'argnum'   => 1,
481
-                'priority' => 10,
482
-            ],
483
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
484
-                'type'     => 'filter',
485
-                'argnum'   => 1,
486
-                'priority' => 10,
487
-            ],
488
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
489
-                'type'     => 'filter',
490
-                'argnum'   => 1,
491
-                'priority' => 10,
492
-            ],
493
-            'FHEE_list_table_views'                                                                   => [
494
-                'type'     => 'filter',
495
-                'argnum'   => 1,
496
-                'priority' => 10,
497
-            ],
498
-            'AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes'                              => [
499
-                'type'     => 'action',
500
-                'argnum'   => 1,
501
-                'priority' => 10,
502
-            ],
503
-        ];
504
-        foreach ($hook_filter_array as $hook => $args) {
505
-            if (method_exists($this, $this->_current_route . '_' . $hook)) {
506
-                if (isset($this->_wp_action_filters_priority[ $hook ])) {
507
-                    $args['priority'] = $this->_wp_action_filters_priority[ $hook ];
508
-                }
509
-                if ($args['type'] == 'action') {
510
-                    add_action(
511
-                        $hook,
512
-                        [$this, $this->_current_route . '_' . $hook],
513
-                        $args['priority'],
514
-                        $args['argnum']
515
-                    );
516
-                } else {
517
-                    add_filter(
518
-                        $hook,
519
-                        [$this, $this->_current_route . '_' . $hook],
520
-                        $args['priority'],
521
-                        $args['argnum']
522
-                    );
523
-                }
524
-            }
525
-        }
526
-    }
527
-
528
-
529
-    /**
530
-     * Loop through the $_ajax_func array and add_actions for the array.
531
-     *
532
-     * @return void
533
-     * @throws EE_Error
534
-     */
535
-    private function _ajax_hooks()
536
-    {
537
-        if (empty($this->_ajax_func)) {
538
-            return;
539
-        } //get out there's nothing to take care of.
540
-        foreach ($this->_ajax_func as $action => $method) {
541
-            // make sure method exists
542
-            if (! method_exists($this, $method)) {
543
-                $msg[] = esc_html__(
544
-                             'There is no corresponding method for the hook labeled in the _ajax_func array',
545
-                             'event_espresso'
546
-                         ) . '<br />';
547
-                $msg[] = sprintf(
548
-                    esc_html__(
549
-                        'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
550
-                        'event_espresso'
551
-                    ),
552
-                    $method,
553
-                    $this->caller
554
-                );
555
-                throw new EE_Error(implode('||', $msg));
556
-            }
557
-            add_action('wp_ajax_' . $action, [$this, $method]);
558
-        }
559
-    }
560
-
561
-
562
-    /**
563
-     * Loop through the $_init_func array and add_actions for the array.
564
-     *
565
-     * @return void
566
-     * @throws EE_Error
567
-     */
568
-    protected function _init_hooks()
569
-    {
570
-        if (empty($this->_init_func)) {
571
-            return;
572
-        }
573
-        // get out there's nothing to take care of.
574
-        // We need to determine what page_route we are on!
575
-        foreach ($this->_init_func as $route => $method) {
576
-            // make sure method exists
577
-            if (! method_exists($this, $method)) {
578
-                $msg[] = esc_html__(
579
-                             'There is no corresponding method for the hook labeled in the _init_func array',
580
-                             'event_espresso'
581
-                         ) . '<br />';
582
-                $msg[] = sprintf(
583
-                    esc_html__(
584
-                        'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
585
-                        'event_espresso'
586
-                    ),
587
-                    $method,
588
-                    $this->caller
589
-                );
590
-                throw new EE_Error(implode('||', $msg));
591
-            }
592
-            if ($route == $this->_current_route) {
593
-                add_action('admin_init', [$this, $method]);
594
-            }
595
-        }
596
-    }
597
-
598
-
599
-    /**
600
-     * Loop through the _metaboxes property and add_metaboxes accordingly
601
-     * //todo we could eventually make this a config component class (i.e. new EE_Metabox);
602
-     *
603
-     * @return void
604
-     * @throws EE_Error
605
-     */
606
-    public function add_metaboxes()
607
-    {
608
-        if (empty($this->_metaboxes)) {
609
-            return;
610
-        } //get out we don't have any metaboxes to set for this connection
611
-        $this->_handle_metabox_array($this->_metaboxes);
612
-    }
613
-
614
-
615
-    /**
616
-     * @param array     $boxes
617
-     * @param bool|null $add
618
-     * @throws EE_Error
619
-     */
620
-    private function _handle_metabox_array(array $boxes, ?bool $add = true)
621
-    {
622
-        foreach ($boxes as $box) {
623
-            if (! isset($box['page_route'])) {
624
-                continue;
625
-            }
626
-            // we don't have a valid array
627
-            // let's make sure $box['page_route'] is an array so the "foreach" will work.
628
-            $box['page_route'] = (array) $box['page_route'];
629
-            foreach ($box['page_route'] as $route) {
630
-                if ($route != $this->_current_route) {
631
-                    continue;
632
-                } //get out we only add metaboxes for set route.
633
-                if ($add) {
634
-                    $this->_add_metabox($box);
635
-                } else {
636
-                    $this->_remove_metabox($box);
637
-                }
638
-            }
639
-        }
640
-    }
641
-
642
-
643
-    /**
644
-     * Loop through the _remove_metaboxes property and remove metaboxes accordingly.
645
-     *
646
-     * @return void
647
-     * @throws EE_Error
648
-     */
649
-    public function remove_metaboxes()
650
-    {
651
-        if (empty($this->_remove_metaboxes)) {
652
-            return;
653
-        } //get out there are no metaboxes to remove
654
-        $this->_handle_metabox_array($this->_remove_metaboxes, false);
655
-    }
656
-
657
-
658
-    /**
659
-     * This just handles adding a metabox
660
-     *
661
-     * @param array $args an array of args that have been set for this metabox by the child class
662
-     * @throws EE_Error
663
-     */
664
-    private function _add_metabox(array $args)
665
-    {
666
-        $current_screen    = get_current_screen();
667
-        $screen_id         = is_object($current_screen) ? $current_screen->id : null;
668
-        $callback          = $args['func'] ?? 'some_invalid_callback';
669
-        $callback_function = is_array($callback) ? end($callback) : $callback;
670
-        // set defaults
671
-        $defaults      = [
672
-            'callback_args' => [],
673
-            'context'       => 'advanced',
674
-            'func'          => $callback,
675
-            'id'            => $this->caller . '_' . $callback_function . '_metabox',
676
-            'label'         => $this->caller,
677
-            'page'          => $args['page'] ?? $screen_id,
678
-            'priority'      => 'default',
679
-        ];
680
-        $args          = wp_parse_args($args, $defaults);
681
-        $callback_args = $args['callback_args'];
682
-        $context       = $args['context'];
683
-        $id            = $args['id'];
684
-        $label         = $args['label'];
685
-        $page          = $args['page'];
686
-        $priority      = $args['priority'];
687
-        // make sure method exists
688
-        if (! method_exists($this, $callback_function)) {
689
-            $msg[] =
690
-                esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
691
-                . '<br />';
692
-            $msg[] = sprintf(
693
-                esc_html__(
694
-                    'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
695
-                    'event_espresso'
696
-                ),
697
-                $callback_function,
698
-                $this->caller
699
-            );
700
-            throw new EE_Error(implode('||', $msg));
701
-        }
702
-        // everything checks out so let's add the metabox
703
-        add_meta_box($id, $label, [$this, $callback_function], $page, $context, $priority, $callback_args);
704
-        add_filter(
705
-            "postbox_classes_{$page}_$id",
706
-            function ($classes) {
707
-                $classes[] = 'ee-admin-container';
708
-                return $classes;
709
-            }
710
-        );
711
-    }
712
-
713
-
714
-    private function _remove_metabox($args)
715
-    {
716
-        $current_screen = get_current_screen();
717
-        $screen_id      = is_object($current_screen) ? $current_screen->id : null;
718
-        $func           = $args['func'] ?? 'some_invalid_callback';
719
-        // set defaults
720
-        $defaults = [
721
-            'context' => 'default',
722
-            'id'      => $args['id'] ?? "{$this->_current_route}_{$this->caller}_{$func}_metabox",
723
-            'screen'  => $args['screen'] ?? $screen_id,
724
-        ];
725
-        $args     = wp_parse_args($args, $defaults);
726
-        $context  = $args['context'];
727
-        $id       = $args['id'];
728
-        $screen   = $args['screen'];
729
-        // everything checks out so lets remove the box!
730
-        remove_meta_box($id, $screen, $context);
731
-    }
18
+	/**
19
+	 * This just holds an instance of the page object for this hook
20
+	 *
21
+	 * @var EE_Admin_Page|EE_Admin_Page_CPT|null
22
+	 * @deprecated  5.0.8.p
23
+	 */
24
+	protected $_page_object = null;
25
+
26
+	/**
27
+	 * This holds the EE_Admin_Page object from the calling admin page that this object hooks into.
28
+	 *
29
+	 * @var EE_Admin_Page|EE_Admin_Page_CPT|null
30
+	 */
31
+	protected                   $_adminpage_obj = null;
32
+
33
+	protected ?EE_Registry      $EE             = null;
34
+
35
+	protected ?RequestInterface $request        = null;
36
+
37
+	/**
38
+	 * This is set by child classes and is an associative array of ajax hooks in the format:
39
+	 * array(
40
+	 *    'ajax_action_ref' => 'executing_method'; //must be public
41
+	 * )
42
+	 */
43
+	protected array $_ajax_func = [];
44
+
45
+	/**
46
+	 * This is an array of methods that get executed on a page routes admin_init hook. Use the following format:
47
+	 * array(
48
+	 *    'page_route' => 'executing_method' //must be public
49
+	 * )
50
+	 */
51
+	protected array $_init_func = [];
52
+
53
+	/**
54
+	 * This is an array of methods that output metabox content for the given page route.  Use the following format:
55
+	 * [
56
+	 *      0 => [
57
+	 *          'page_route' => 'string_for_page_route',    must correspond to a page route in the class being connected
58
+	 *                                                      with (i.e. "edit_event") If this is in an array then the
59
+	 *                                                      same params below will be used but the metabox will be
60
+	 *                                                      added to each route.
61
+	 *          'func' =>  'executing_method',              must be public (i.e. public function executing_method
62
+	 *                                                      ($post, $callback_args){} ).
63
+	 *                                                      Note if you include callback args in the array then you
64
+	 *                                                      need to declare them in the method arguments.
65
+	 *          'id' => 'identifier_for_metabox',           so it can be removed by addons
66
+	 *                                                      (optional, class will set it automatically)
67
+	 *          'priority' => 'default',                    default 'default' (optional)
68
+	 *          'label' => esc_html__('Localized Title', 'event_espresso'),
69
+	 *          'context' => 'advanced'                     advanced is default (optional),
70
+	 *      ]
71
+	 *      'callback_args' => array() //any callback args to include (optional)
72
+	 * ]
73
+	 * Why are we indexing numerically?  Because it's possible there may be more than one metabox per page_route.
74
+	 */
75
+	protected array $_metaboxes = [];
76
+
77
+	/**
78
+	 * This is an array of values that indicate any metaboxes we want removed from a given page route.  Usually this is
79
+	 * used when caffeinated functionality is replacing decaffeinated functionality.  Use the following format for the
80
+	 * array: array(
81
+	 *    0 => array(
82
+	 *        'page_route' => 'string_for_page_route' //can be string or array of strings that match a page_route(s)
83
+	 *        that are in the class being connected with (i.e. 'edit', or 'create_new').
84
+	 *        'id' => 'identifier_for_metabox', //what the id is of the metabox being removed
85
+	 *        'context' => 'normal', //the context for the metabox being removed (has to match)
86
+	 *        'screen' => 'screen_id', //(optional), if not included then this class will attempt to remove the metabox
87
+	 *        using the currently loaded screen object->id  however, there may be cases where you have to specify the
88
+	 *        id for the screen the metabox is on.
89
+	 *    )
90
+	 * )
91
+	 */
92
+	protected array $_remove_metaboxes = [];
93
+
94
+	protected array $_req_data         = [];
95
+
96
+	/**
97
+	 * This parent class takes care of loading the scripts and styles if the child class has set the properties for
98
+	 * them in the following format.  Note, the first array index ('register') is for defining all the registers.  The
99
+	 * second array index is for indicating what routes each script/style loads on. array(
100
+	 * 'registers' => array(
101
+	 *        'script_ref' => array( // if more than one script is to be loaded its best to use the 'dependency'
102
+	 *        argument to link scripts together.
103
+	 *            'type' => 'js' // 'js' or 'css' (defaults to js).  This tells us what type of wp_function to use
104
+	 *            'url' => 'http://urltoscript.css.js',
105
+	 *            'depends' => array('jquery'), //an array of dependencies for the scripts. REMEMBER, if a script has
106
+	 *            already been registered elsewhere in the system.  You can just use the depends array to make sure it
107
+	 *            gets loaded before the one you are setting here.
108
+	 *            'footer' => TRUE //defaults to true (styles don't use this parameter)
109
+	 *        ),
110
+	 *    'enqueues' => array( //this time each key corresponds to the script ref followed by an array of page routes
111
+	 *    the script gets enqueued on.
112
+	 *        'script_ref' => array('route_one', 'route_two')
113
+	 *    ),
114
+	 *    'localize' => array( //this allows you to set a localized object.  Indicate which script the object is being
115
+	 *    attached to and then include an array indexed by the name of the object and the array of key/value pairs for
116
+	 *    the object.
117
+	 *        'scrip_ref' => array(
118
+	 *            'NAME_OF_JS_OBJECT' => array(
119
+	 *                'translate_ref' => esc_html__('localized_string', 'event_espresso'),
120
+	 *                'some_data' => 5
121
+	 *            )
122
+	 *        )
123
+	 *    )
124
+	 * )
125
+	 */
126
+	protected array $_scripts_styles = [];
127
+
128
+	protected array $_scripts        = [];
129
+
130
+	protected array $_styles         = [];
131
+
132
+	/**
133
+	 * this optional property can be set by child classes to override the priority for the automatic action/filter hook
134
+	 * loading in the `_load_routed_hooks()` method.  Please follow this format: array(
135
+	 *    'wp_hook_reference' => 1
136
+	 *    )
137
+	 * )
138
+	 */
139
+	protected array $_wp_action_filters_priority = [];
140
+
141
+	/**
142
+	 * this is just a flag set automatically to indicate whether we've got an extended hook class running (i.e.
143
+	 * espresso_events_Registration_Form_Hooks_Extend extends espresso_events_Registration_Form_Hooks).  This flag is
144
+	 * used later to make sure we require the needed files.
145
+	 */
146
+	protected bool $_extend = false;
147
+
148
+	/**
149
+	 * we're just going to use this to hold the name of the caller class (child class name)
150
+	 */
151
+	public string    $caller         = '';
152
+
153
+	protected string $_current_route = '';
154
+
155
+
156
+	/**
157
+	 * child classes MUST set this property so that the page object can be loaded correctly
158
+	 */
159
+	protected string $_name = '';
160
+
161
+
162
+	/**
163
+	 * constructor
164
+	 *
165
+	 * @param EE_Admin_Page $admin_page
166
+	 * @throws EE_Error
167
+	 * @throws ReflectionException
168
+	 */
169
+	public function __construct(EE_Admin_Page $admin_page)
170
+	{
171
+		$this->_adminpage_obj = $admin_page;
172
+		$this->request        = LoaderFactory::getLoader()->getShared(RequestInterface::class);
173
+		$this->_req_data      = $this->request->requestParams();
174
+		$current_page         = $this->request->getRequestParam('page');
175
+		$current_page         = $this->request->getRequestParam('current_page', $current_page);
176
+		// first let's verify we're on the right page
177
+		if ($current_page !== $this->_adminpage_obj->page_slug) {
178
+			return;
179
+		}
180
+		$this->_set_defaults();
181
+		$this->_set_hooks_properties();
182
+		// get out nothing more to be done here.
183
+		// allow for extends to modify properties
184
+		if (method_exists($this, '_extend_properties')) {
185
+			$this->_extend_properties();
186
+		}
187
+		// $this->_set_page_object();
188
+		$this->_init_hooks();
189
+		$this->_load_custom_methods();
190
+		$this->_load_routed_hooks();
191
+		add_action('admin_enqueue_scripts', [$this, 'enqueue_scripts_styles']);
192
+		add_action('admin_enqueue_scripts', [$this, 'add_metaboxes'], 20);
193
+		add_action('admin_enqueue_scripts', [$this, 'remove_metaboxes'], 15);
194
+		$this->_ajax_hooks();
195
+	}
196
+
197
+
198
+	/**
199
+	 * used by child classes to set the following properties:
200
+	 * $_ajax_func (optional)
201
+	 * $_init_func (optional)
202
+	 * $_metaboxes (optional)
203
+	 * $_scripts (optional)
204
+	 * $_styles (optional)
205
+	 * $_name (required)
206
+	 * Also in this method will be registered any scripts or styles loaded on the targeted page (as indicated in the
207
+	 * _scripts/_styles properties) Also children should place in this method any filters/actions that have to happen
208
+	 * really early on page load (just after admin_init) if they want to have them registered for handling early.
209
+	 *
210
+	 * @abstract
211
+	 * @return void
212
+	 */
213
+	abstract protected function _set_hooks_properties();
214
+
215
+
216
+	/**
217
+	 * The hooks for enqueue_scripts and enqueue_styles will be run in here.  Child classes need to define their
218
+	 * scripts and styles in the relevant $_scripts and $_styles properties.  Child classes must have also already
219
+	 * registered the scripts and styles using wp_register_script and wp_register_style functions.
220
+	 *
221
+	 * @return void
222
+	 * @throws EE_Error
223
+	 */
224
+	public function enqueue_scripts_styles()
225
+	{
226
+		if (! empty($this->_scripts_styles)) {
227
+			// first let's do all the registrations
228
+			if (! isset($this->_scripts_styles['registers'])) {
229
+				$msg[] = esc_html__(
230
+					'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
231
+					'event_espresso'
232
+				);
233
+				$msg[] = sprintf(
234
+					esc_html__(
235
+						'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
236
+						'event_espresso'
237
+					),
238
+					'<strong>' . $this->caller . '</strong>'
239
+				);
240
+				throw new EE_Error(implode('||', $msg));
241
+			}
242
+			$defaults = [
243
+				'type'    => 'js',
244
+				'url'     => '',
245
+				'depends' => [],
246
+				'version' => EVENT_ESPRESSO_VERSION,
247
+				'footer'  => true,
248
+			];
249
+			foreach ($this->_scripts_styles['registers'] as $ref => $details) {
250
+				$details = wp_parse_args($details, $defaults);
251
+				$type    = $details['type'];
252
+				$url     = $details['url'];
253
+				$depends = $details['depends'];
254
+				$version = $details['version'];
255
+				$footer  = $details['footer'];
256
+				// let's make sure that we set the 'registers' type if it's not set!
257
+				// We need it later to determine which enqueue we do
258
+				$this->_scripts_styles['registers'][ $ref ]['type'] = $type;
259
+				// let's make sure we're not missing any REQUIRED parameters
260
+				if (empty($url)) {
261
+					$msg[] = sprintf(
262
+						esc_html__('Missing the url for the requested %s', 'event_espresso'),
263
+						$type == 'js' ? 'script' : 'stylesheet'
264
+					);
265
+					$msg[] = sprintf(
266
+						esc_html__(
267
+							'Double-check your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
268
+							'event_espresso'
269
+						),
270
+						'<strong>' . $this->caller . '</strong>',
271
+						$ref
272
+					);
273
+					throw new EE_Error(implode('||', $msg));
274
+				}
275
+				// made it here so let's do the appropriate registration
276
+				$type == 'js'
277
+					? wp_register_script($ref, $url, $depends, $version, $footer)
278
+					: wp_register_style(
279
+					$ref,
280
+					$url,
281
+					$depends,
282
+					$version
283
+				);
284
+			}
285
+			// k now let's do the enqueues
286
+			if (! isset($this->_scripts_styles['enqueues'])) {
287
+				return;
288
+			}  //not sure if we should throw an error here or not.
289
+
290
+			foreach ($this->_scripts_styles['enqueues'] as $ref => $routes) {
291
+				// make sure $routes is an array
292
+				$routes = (array) $routes;
293
+				if (in_array($this->_current_route, $routes)) {
294
+					$this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
295
+						: wp_enqueue_style($ref);
296
+					// if we have a localization for the script let's do that too.
297
+					if (isset($this->_scripts_styles['localize'][ $ref ])) {
298
+						foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
299
+							wp_localize_script(
300
+								$ref,
301
+								$object_name,
302
+								$this->_scripts_styles['localize'][ $ref ][ $object_name ]
303
+							);
304
+						}
305
+					}
306
+				}
307
+			}
308
+			// let's do the deregisters
309
+			if (! isset($this->_scripts_styles['deregisters'])) {
310
+				return;
311
+			}
312
+			foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
313
+				$defaults = ['type' => 'js'];
314
+				$details  = wp_parse_args($details, $defaults);
315
+				$details['type'] === 'js' ? wp_deregister_script($ref) : wp_deregister_style($ref);
316
+			}
317
+		}
318
+	}
319
+
320
+
321
+	/**
322
+	 * just set the defaults for the hooks properties.
323
+	 *
324
+	 * @return void
325
+	 */
326
+	private function _set_defaults()
327
+	{
328
+		$this->_ajax_func                  = [];
329
+		$this->_init_func                  = [];
330
+		$this->_metaboxes                  = [];
331
+		$this->_scripts                    = [];
332
+		$this->_styles                     = [];
333
+		$this->_wp_action_filters_priority = [];
334
+		$this->_current_route              = $this->getCurrentRoute();
335
+		$this->caller                      = get_class($this);
336
+		$this->_extend                     = (bool) stripos($this->caller, 'Extend');
337
+	}
338
+
339
+
340
+	/**
341
+	 * A helper for determining the current route.
342
+	 *
343
+	 * @return string
344
+	 */
345
+	private function getCurrentRoute(): string
346
+	{
347
+		$action = $this->request->getRequestParam('action');
348
+		// list tables do something else with 'action' for bulk actions.
349
+		$action = $action !== '-1' && $action !== '' ? $action : 'default';
350
+		$route  = $this->request->getRequestParam('route');
351
+		// we set a 'route' variable in some cases where action is being used by something else.
352
+		return $action === 'default' && $route !== '' ? $route : $action;
353
+	}
354
+
355
+
356
+	/**
357
+	 * this sets the _page_object property
358
+	 *
359
+	 * @return void
360
+	 * @throws EE_Error
361
+	 * @throws ReflectionException
362
+	 * @throws Throwable
363
+	 * @deprecated  5.0.8.p
364
+	 */
365
+	protected function _set_page_object()
366
+	{
367
+		if ($this->_page_object instanceof EE_Admin_Page) {
368
+			return;
369
+		}
370
+		// first make sure $this->_name is set
371
+		if (empty($this->_name)) {
372
+			$msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
373
+			$msg[] = sprintf(
374
+				esc_html__("This is because the %s child class has not set the '_name' property", 'event_espresso'),
375
+				$this->caller
376
+			);
377
+			throw new EE_Error(implode('||', $msg));
378
+		}
379
+		// change "the_message" to "the message"
380
+		$class_name = str_replace('_', ' ', $this->_name);
381
+		// change "the message" to "The_Message_Admin_Page"
382
+		$class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
383
+		// first default file (if exists)
384
+		$decaf_file = EE_ADMIN_PAGES . "$this->_name/$class_name.core.php";
385
+		if (is_readable($decaf_file)) {
386
+			require_once($decaf_file);
387
+		}
388
+		// now we have to do require for extended file (if needed)
389
+		if ($this->_extend) {
390
+			require_once EE_CORE_CAF_ADMIN_EXTEND . "$this->_name/Extend_$class_name.core.php";
391
+			// and extend the class name as well
392
+			$class_name = 'Extend_' . $class_name;
393
+		}
394
+		// let's make sure the class exists
395
+		if (! class_exists($class_name)) {
396
+			$msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
397
+			$msg[] = sprintf(
398
+				esc_html__(
399
+					'The class name that was given is %s. Check the spelling and make sure its correct, also there needs to be an autoloader setup for the class',
400
+					'event_espresso'
401
+				),
402
+				$class_name
403
+			);
404
+			throw new EE_Error(implode('||', $msg));
405
+		}
406
+		// do NOT load admin pages that are ALREADY LOADED!!!
407
+		if ($class_name !== $this->_adminpage_obj->class_name) {
408
+			return;
409
+		}
410
+		$this->_page_object = LoaderFactory::getLoader()->getShared($class_name, [false]);
411
+		$this->_page_object->initializePage();
412
+	}
413
+
414
+
415
+	/**
416
+	 * Child "hook" classes can declare any methods that they want executed when a specific page route is loaded.  The
417
+	 * advantage of this is when doing things like running our own db interactions on saves etc.  Remember that
418
+	 * $this->_req_data (all the _POST and _GET data) is available to your methods.
419
+	 *
420
+	 * @return void
421
+	 */
422
+	private function _load_custom_methods()
423
+	{
424
+		/**
425
+		 * method cannot be named 'default' (@see http://us3.php
426
+		 * .net/manual/en/reserved.keywords.php) so need to
427
+		 * handle routes that are "default"
428
+		 *
429
+		 * @since 4.3.0
430
+		 */
431
+		$method_callback = $this->_current_route == 'default' ? 'default_callback' : $this->_current_route;
432
+		// these run before the Admin_Page route executes.
433
+		if (is_callable($this, $method_callback)) {
434
+			call_user_func([$this, $method_callback]);
435
+		}
436
+		// these run via the _redirect_after_action method in EE_Admin_Page which usually happens after non_UI methods in EE_Admin_Page classes.  There are two redirect actions, the first fires before $query_args might be manipulated by "save and close" actions and the second fires right before the actual redirect happens.
437
+		// first the actions
438
+		// note that these action hooks will have the $query_args value available.
439
+		$admin_class_name = get_class($this->_adminpage_obj);
440
+		if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
441
+			add_action(
442
+				'AHEE__'
443
+				. $admin_class_name
444
+				. '___redirect_after_action__before_redirect_modification_'
445
+				. $this->_current_route,
446
+				[$this, '_redirect_action_early_' . $this->_current_route]
447
+			);
448
+		}
449
+		if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
450
+			add_action(
451
+				'AHEE_redirect_' . $admin_class_name . $this->_current_route,
452
+				[$this, '_redirect_action_' . $this->_current_route]
453
+			);
454
+		}
455
+		// let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
456
+		if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
457
+			add_filter(
458
+				'FHEE_redirect_' . $admin_class_name . $this->_current_route,
459
+				[$this, '_redirect_filter_' . $this->_current_route],
460
+				10,
461
+				2
462
+			);
463
+		}
464
+	}
465
+
466
+
467
+	/**
468
+	 * This method will search for a corresponding method with a name matching the route and the wp_hook to run.  This
469
+	 * allows child hook classes to target hooking into a specific wp action or filter hook ONLY on a certain route.
470
+	 * just remember, methods MUST be public Future hooks should be added in here to be access by child classes.
471
+	 *
472
+	 * @return void
473
+	 */
474
+	private function _load_routed_hooks()
475
+	{
476
+		// this array provides the hook action names that will be referenced.  Key is the action. Value is an array with the type (action or filter) and the number of parameters for the hook.  We'll default all priorities for automatic hooks to 10.
477
+		$hook_filter_array = [
478
+			'admin_footer'                                                                            => [
479
+				'type'     => 'action',
480
+				'argnum'   => 1,
481
+				'priority' => 10,
482
+			],
483
+			'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
484
+				'type'     => 'filter',
485
+				'argnum'   => 1,
486
+				'priority' => 10,
487
+			],
488
+			'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
489
+				'type'     => 'filter',
490
+				'argnum'   => 1,
491
+				'priority' => 10,
492
+			],
493
+			'FHEE_list_table_views'                                                                   => [
494
+				'type'     => 'filter',
495
+				'argnum'   => 1,
496
+				'priority' => 10,
497
+			],
498
+			'AHEE__EE_Admin_Page___display_admin_page__modify_metaboxes'                              => [
499
+				'type'     => 'action',
500
+				'argnum'   => 1,
501
+				'priority' => 10,
502
+			],
503
+		];
504
+		foreach ($hook_filter_array as $hook => $args) {
505
+			if (method_exists($this, $this->_current_route . '_' . $hook)) {
506
+				if (isset($this->_wp_action_filters_priority[ $hook ])) {
507
+					$args['priority'] = $this->_wp_action_filters_priority[ $hook ];
508
+				}
509
+				if ($args['type'] == 'action') {
510
+					add_action(
511
+						$hook,
512
+						[$this, $this->_current_route . '_' . $hook],
513
+						$args['priority'],
514
+						$args['argnum']
515
+					);
516
+				} else {
517
+					add_filter(
518
+						$hook,
519
+						[$this, $this->_current_route . '_' . $hook],
520
+						$args['priority'],
521
+						$args['argnum']
522
+					);
523
+				}
524
+			}
525
+		}
526
+	}
527
+
528
+
529
+	/**
530
+	 * Loop through the $_ajax_func array and add_actions for the array.
531
+	 *
532
+	 * @return void
533
+	 * @throws EE_Error
534
+	 */
535
+	private function _ajax_hooks()
536
+	{
537
+		if (empty($this->_ajax_func)) {
538
+			return;
539
+		} //get out there's nothing to take care of.
540
+		foreach ($this->_ajax_func as $action => $method) {
541
+			// make sure method exists
542
+			if (! method_exists($this, $method)) {
543
+				$msg[] = esc_html__(
544
+							 'There is no corresponding method for the hook labeled in the _ajax_func array',
545
+							 'event_espresso'
546
+						 ) . '<br />';
547
+				$msg[] = sprintf(
548
+					esc_html__(
549
+						'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
550
+						'event_espresso'
551
+					),
552
+					$method,
553
+					$this->caller
554
+				);
555
+				throw new EE_Error(implode('||', $msg));
556
+			}
557
+			add_action('wp_ajax_' . $action, [$this, $method]);
558
+		}
559
+	}
560
+
561
+
562
+	/**
563
+	 * Loop through the $_init_func array and add_actions for the array.
564
+	 *
565
+	 * @return void
566
+	 * @throws EE_Error
567
+	 */
568
+	protected function _init_hooks()
569
+	{
570
+		if (empty($this->_init_func)) {
571
+			return;
572
+		}
573
+		// get out there's nothing to take care of.
574
+		// We need to determine what page_route we are on!
575
+		foreach ($this->_init_func as $route => $method) {
576
+			// make sure method exists
577
+			if (! method_exists($this, $method)) {
578
+				$msg[] = esc_html__(
579
+							 'There is no corresponding method for the hook labeled in the _init_func array',
580
+							 'event_espresso'
581
+						 ) . '<br />';
582
+				$msg[] = sprintf(
583
+					esc_html__(
584
+						'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
585
+						'event_espresso'
586
+					),
587
+					$method,
588
+					$this->caller
589
+				);
590
+				throw new EE_Error(implode('||', $msg));
591
+			}
592
+			if ($route == $this->_current_route) {
593
+				add_action('admin_init', [$this, $method]);
594
+			}
595
+		}
596
+	}
597
+
598
+
599
+	/**
600
+	 * Loop through the _metaboxes property and add_metaboxes accordingly
601
+	 * //todo we could eventually make this a config component class (i.e. new EE_Metabox);
602
+	 *
603
+	 * @return void
604
+	 * @throws EE_Error
605
+	 */
606
+	public function add_metaboxes()
607
+	{
608
+		if (empty($this->_metaboxes)) {
609
+			return;
610
+		} //get out we don't have any metaboxes to set for this connection
611
+		$this->_handle_metabox_array($this->_metaboxes);
612
+	}
613
+
614
+
615
+	/**
616
+	 * @param array     $boxes
617
+	 * @param bool|null $add
618
+	 * @throws EE_Error
619
+	 */
620
+	private function _handle_metabox_array(array $boxes, ?bool $add = true)
621
+	{
622
+		foreach ($boxes as $box) {
623
+			if (! isset($box['page_route'])) {
624
+				continue;
625
+			}
626
+			// we don't have a valid array
627
+			// let's make sure $box['page_route'] is an array so the "foreach" will work.
628
+			$box['page_route'] = (array) $box['page_route'];
629
+			foreach ($box['page_route'] as $route) {
630
+				if ($route != $this->_current_route) {
631
+					continue;
632
+				} //get out we only add metaboxes for set route.
633
+				if ($add) {
634
+					$this->_add_metabox($box);
635
+				} else {
636
+					$this->_remove_metabox($box);
637
+				}
638
+			}
639
+		}
640
+	}
641
+
642
+
643
+	/**
644
+	 * Loop through the _remove_metaboxes property and remove metaboxes accordingly.
645
+	 *
646
+	 * @return void
647
+	 * @throws EE_Error
648
+	 */
649
+	public function remove_metaboxes()
650
+	{
651
+		if (empty($this->_remove_metaboxes)) {
652
+			return;
653
+		} //get out there are no metaboxes to remove
654
+		$this->_handle_metabox_array($this->_remove_metaboxes, false);
655
+	}
656
+
657
+
658
+	/**
659
+	 * This just handles adding a metabox
660
+	 *
661
+	 * @param array $args an array of args that have been set for this metabox by the child class
662
+	 * @throws EE_Error
663
+	 */
664
+	private function _add_metabox(array $args)
665
+	{
666
+		$current_screen    = get_current_screen();
667
+		$screen_id         = is_object($current_screen) ? $current_screen->id : null;
668
+		$callback          = $args['func'] ?? 'some_invalid_callback';
669
+		$callback_function = is_array($callback) ? end($callback) : $callback;
670
+		// set defaults
671
+		$defaults      = [
672
+			'callback_args' => [],
673
+			'context'       => 'advanced',
674
+			'func'          => $callback,
675
+			'id'            => $this->caller . '_' . $callback_function . '_metabox',
676
+			'label'         => $this->caller,
677
+			'page'          => $args['page'] ?? $screen_id,
678
+			'priority'      => 'default',
679
+		];
680
+		$args          = wp_parse_args($args, $defaults);
681
+		$callback_args = $args['callback_args'];
682
+		$context       = $args['context'];
683
+		$id            = $args['id'];
684
+		$label         = $args['label'];
685
+		$page          = $args['page'];
686
+		$priority      = $args['priority'];
687
+		// make sure method exists
688
+		if (! method_exists($this, $callback_function)) {
689
+			$msg[] =
690
+				esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
691
+				. '<br />';
692
+			$msg[] = sprintf(
693
+				esc_html__(
694
+					'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
695
+					'event_espresso'
696
+				),
697
+				$callback_function,
698
+				$this->caller
699
+			);
700
+			throw new EE_Error(implode('||', $msg));
701
+		}
702
+		// everything checks out so let's add the metabox
703
+		add_meta_box($id, $label, [$this, $callback_function], $page, $context, $priority, $callback_args);
704
+		add_filter(
705
+			"postbox_classes_{$page}_$id",
706
+			function ($classes) {
707
+				$classes[] = 'ee-admin-container';
708
+				return $classes;
709
+			}
710
+		);
711
+	}
712
+
713
+
714
+	private function _remove_metabox($args)
715
+	{
716
+		$current_screen = get_current_screen();
717
+		$screen_id      = is_object($current_screen) ? $current_screen->id : null;
718
+		$func           = $args['func'] ?? 'some_invalid_callback';
719
+		// set defaults
720
+		$defaults = [
721
+			'context' => 'default',
722
+			'id'      => $args['id'] ?? "{$this->_current_route}_{$this->caller}_{$func}_metabox",
723
+			'screen'  => $args['screen'] ?? $screen_id,
724
+		];
725
+		$args     = wp_parse_args($args, $defaults);
726
+		$context  = $args['context'];
727
+		$id       = $args['id'];
728
+		$screen   = $args['screen'];
729
+		// everything checks out so lets remove the box!
730
+		remove_meta_box($id, $screen, $context);
731
+	}
732 732
 }
Please login to merge, or discard this patch.
Spacing   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -223,9 +223,9 @@  discard block
 block discarded – undo
223 223
      */
224 224
     public function enqueue_scripts_styles()
225 225
     {
226
-        if (! empty($this->_scripts_styles)) {
226
+        if ( ! empty($this->_scripts_styles)) {
227 227
             // first let's do all the registrations
228
-            if (! isset($this->_scripts_styles['registers'])) {
228
+            if ( ! isset($this->_scripts_styles['registers'])) {
229 229
                 $msg[] = esc_html__(
230 230
                     'There is no "registers" index in the <code>$this->_scripts_styles</code> property.',
231 231
                     'event_espresso'
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
                         'Make sure you read the phpdoc comments above the definition of the $_scripts_styles property in the <code>EE_Admin_Hooks</code> class and modify according in the %s child',
236 236
                         'event_espresso'
237 237
                     ),
238
-                    '<strong>' . $this->caller . '</strong>'
238
+                    '<strong>'.$this->caller.'</strong>'
239 239
                 );
240 240
                 throw new EE_Error(implode('||', $msg));
241 241
             }
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
                 $footer  = $details['footer'];
256 256
                 // let's make sure that we set the 'registers' type if it's not set!
257 257
                 // We need it later to determine which enqueue we do
258
-                $this->_scripts_styles['registers'][ $ref ]['type'] = $type;
258
+                $this->_scripts_styles['registers'][$ref]['type'] = $type;
259 259
                 // let's make sure we're not missing any REQUIRED parameters
260 260
                 if (empty($url)) {
261 261
                     $msg[] = sprintf(
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
                             'Double-check your <code>$this->_scripts_styles</code> array in %s and make sure that there is a "url" set for the %s ref',
268 268
                             'event_espresso'
269 269
                         ),
270
-                        '<strong>' . $this->caller . '</strong>',
270
+                        '<strong>'.$this->caller.'</strong>',
271 271
                         $ref
272 272
                     );
273 273
                     throw new EE_Error(implode('||', $msg));
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
                 );
284 284
             }
285 285
             // k now let's do the enqueues
286
-            if (! isset($this->_scripts_styles['enqueues'])) {
286
+            if ( ! isset($this->_scripts_styles['enqueues'])) {
287 287
                 return;
288 288
             }  //not sure if we should throw an error here or not.
289 289
 
@@ -291,22 +291,22 @@  discard block
 block discarded – undo
291 291
                 // make sure $routes is an array
292 292
                 $routes = (array) $routes;
293 293
                 if (in_array($this->_current_route, $routes)) {
294
-                    $this->_scripts_styles['registers'][ $ref ]['type'] == 'js' ? wp_enqueue_script($ref)
294
+                    $this->_scripts_styles['registers'][$ref]['type'] == 'js' ? wp_enqueue_script($ref)
295 295
                         : wp_enqueue_style($ref);
296 296
                     // if we have a localization for the script let's do that too.
297
-                    if (isset($this->_scripts_styles['localize'][ $ref ])) {
298
-                        foreach ($this->_scripts_styles['localize'][ $ref ] as $object_name => $indexes) {
297
+                    if (isset($this->_scripts_styles['localize'][$ref])) {
298
+                        foreach ($this->_scripts_styles['localize'][$ref] as $object_name => $indexes) {
299 299
                             wp_localize_script(
300 300
                                 $ref,
301 301
                                 $object_name,
302
-                                $this->_scripts_styles['localize'][ $ref ][ $object_name ]
302
+                                $this->_scripts_styles['localize'][$ref][$object_name]
303 303
                             );
304 304
                         }
305 305
                     }
306 306
                 }
307 307
             }
308 308
             // let's do the deregisters
309
-            if (! isset($this->_scripts_styles['deregisters'])) {
309
+            if ( ! isset($this->_scripts_styles['deregisters'])) {
310 310
                 return;
311 311
             }
312 312
             foreach ($this->_scripts_styles['deregisters'] as $ref => $details) {
@@ -379,20 +379,20 @@  discard block
 block discarded – undo
379 379
         // change "the_message" to "the message"
380 380
         $class_name = str_replace('_', ' ', $this->_name);
381 381
         // change "the message" to "The_Message_Admin_Page"
382
-        $class_name = str_replace(' ', '_', ucwords($class_name)) . '_Admin_Page';
382
+        $class_name = str_replace(' ', '_', ucwords($class_name)).'_Admin_Page';
383 383
         // first default file (if exists)
384
-        $decaf_file = EE_ADMIN_PAGES . "$this->_name/$class_name.core.php";
384
+        $decaf_file = EE_ADMIN_PAGES."$this->_name/$class_name.core.php";
385 385
         if (is_readable($decaf_file)) {
386 386
             require_once($decaf_file);
387 387
         }
388 388
         // now we have to do require for extended file (if needed)
389 389
         if ($this->_extend) {
390
-            require_once EE_CORE_CAF_ADMIN_EXTEND . "$this->_name/Extend_$class_name.core.php";
390
+            require_once EE_CORE_CAF_ADMIN_EXTEND."$this->_name/Extend_$class_name.core.php";
391 391
             // and extend the class name as well
392
-            $class_name = 'Extend_' . $class_name;
392
+            $class_name = 'Extend_'.$class_name;
393 393
         }
394 394
         // let's make sure the class exists
395
-        if (! class_exists($class_name)) {
395
+        if ( ! class_exists($class_name)) {
396 396
             $msg[] = esc_html__('We can\'t load the page object', 'event_espresso');
397 397
             $msg[] = sprintf(
398 398
                 esc_html__(
@@ -437,26 +437,26 @@  discard block
 block discarded – undo
437 437
         // first the actions
438 438
         // note that these action hooks will have the $query_args value available.
439 439
         $admin_class_name = get_class($this->_adminpage_obj);
440
-        if (method_exists($this, '_redirect_action_early_' . $this->_current_route)) {
440
+        if (method_exists($this, '_redirect_action_early_'.$this->_current_route)) {
441 441
             add_action(
442 442
                 'AHEE__'
443 443
                 . $admin_class_name
444 444
                 . '___redirect_after_action__before_redirect_modification_'
445 445
                 . $this->_current_route,
446
-                [$this, '_redirect_action_early_' . $this->_current_route]
446
+                [$this, '_redirect_action_early_'.$this->_current_route]
447 447
             );
448 448
         }
449
-        if (method_exists($this, '_redirect_action_' . $this->_current_route)) {
449
+        if (method_exists($this, '_redirect_action_'.$this->_current_route)) {
450 450
             add_action(
451
-                'AHEE_redirect_' . $admin_class_name . $this->_current_route,
452
-                [$this, '_redirect_action_' . $this->_current_route]
451
+                'AHEE_redirect_'.$admin_class_name.$this->_current_route,
452
+                [$this, '_redirect_action_'.$this->_current_route]
453 453
             );
454 454
         }
455 455
         // let's hook into the _redirect itself and allow for changing where the user goes after redirect.  This will have $query_args and $redirect_url available.
456
-        if (method_exists($this, '_redirect_filter_' . $this->_current_route)) {
456
+        if (method_exists($this, '_redirect_filter_'.$this->_current_route)) {
457 457
             add_filter(
458
-                'FHEE_redirect_' . $admin_class_name . $this->_current_route,
459
-                [$this, '_redirect_filter_' . $this->_current_route],
458
+                'FHEE_redirect_'.$admin_class_name.$this->_current_route,
459
+                [$this, '_redirect_filter_'.$this->_current_route],
460 460
                 10,
461 461
                 2
462 462
             );
@@ -480,12 +480,12 @@  discard block
 block discarded – undo
480 480
                 'argnum'   => 1,
481 481
                 'priority' => 10,
482 482
             ],
483
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug . '_' . $this->_current_route => [
483
+            'FHEE_list_table_views_'.$this->_adminpage_obj->page_slug.'_'.$this->_current_route => [
484 484
                 'type'     => 'filter',
485 485
                 'argnum'   => 1,
486 486
                 'priority' => 10,
487 487
             ],
488
-            'FHEE_list_table_views_' . $this->_adminpage_obj->page_slug                               => [
488
+            'FHEE_list_table_views_'.$this->_adminpage_obj->page_slug                               => [
489 489
                 'type'     => 'filter',
490 490
                 'argnum'   => 1,
491 491
                 'priority' => 10,
@@ -502,21 +502,21 @@  discard block
 block discarded – undo
502 502
             ],
503 503
         ];
504 504
         foreach ($hook_filter_array as $hook => $args) {
505
-            if (method_exists($this, $this->_current_route . '_' . $hook)) {
506
-                if (isset($this->_wp_action_filters_priority[ $hook ])) {
507
-                    $args['priority'] = $this->_wp_action_filters_priority[ $hook ];
505
+            if (method_exists($this, $this->_current_route.'_'.$hook)) {
506
+                if (isset($this->_wp_action_filters_priority[$hook])) {
507
+                    $args['priority'] = $this->_wp_action_filters_priority[$hook];
508 508
                 }
509 509
                 if ($args['type'] == 'action') {
510 510
                     add_action(
511 511
                         $hook,
512
-                        [$this, $this->_current_route . '_' . $hook],
512
+                        [$this, $this->_current_route.'_'.$hook],
513 513
                         $args['priority'],
514 514
                         $args['argnum']
515 515
                     );
516 516
                 } else {
517 517
                     add_filter(
518 518
                         $hook,
519
-                        [$this, $this->_current_route . '_' . $hook],
519
+                        [$this, $this->_current_route.'_'.$hook],
520 520
                         $args['priority'],
521 521
                         $args['argnum']
522 522
                     );
@@ -539,11 +539,11 @@  discard block
 block discarded – undo
539 539
         } //get out there's nothing to take care of.
540 540
         foreach ($this->_ajax_func as $action => $method) {
541 541
             // make sure method exists
542
-            if (! method_exists($this, $method)) {
542
+            if ( ! method_exists($this, $method)) {
543 543
                 $msg[] = esc_html__(
544 544
                              'There is no corresponding method for the hook labeled in the _ajax_func array',
545 545
                              'event_espresso'
546
-                         ) . '<br />';
546
+                         ).'<br />';
547 547
                 $msg[] = sprintf(
548 548
                     esc_html__(
549 549
                         'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
@@ -554,7 +554,7 @@  discard block
 block discarded – undo
554 554
                 );
555 555
                 throw new EE_Error(implode('||', $msg));
556 556
             }
557
-            add_action('wp_ajax_' . $action, [$this, $method]);
557
+            add_action('wp_ajax_'.$action, [$this, $method]);
558 558
         }
559 559
     }
560 560
 
@@ -574,11 +574,11 @@  discard block
 block discarded – undo
574 574
         // We need to determine what page_route we are on!
575 575
         foreach ($this->_init_func as $route => $method) {
576 576
             // make sure method exists
577
-            if (! method_exists($this, $method)) {
577
+            if ( ! method_exists($this, $method)) {
578 578
                 $msg[] = esc_html__(
579 579
                              'There is no corresponding method for the hook labeled in the _init_func array',
580 580
                              'event_espresso'
581
-                         ) . '<br />';
581
+                         ).'<br />';
582 582
                 $msg[] = sprintf(
583 583
                     esc_html__(
584 584
                         'The method name given in the array is %s, check the spelling and make sure it exists in the %s class',
@@ -620,7 +620,7 @@  discard block
 block discarded – undo
620 620
     private function _handle_metabox_array(array $boxes, ?bool $add = true)
621 621
     {
622 622
         foreach ($boxes as $box) {
623
-            if (! isset($box['page_route'])) {
623
+            if ( ! isset($box['page_route'])) {
624 624
                 continue;
625 625
             }
626 626
             // we don't have a valid array
@@ -668,11 +668,11 @@  discard block
 block discarded – undo
668 668
         $callback          = $args['func'] ?? 'some_invalid_callback';
669 669
         $callback_function = is_array($callback) ? end($callback) : $callback;
670 670
         // set defaults
671
-        $defaults      = [
671
+        $defaults = [
672 672
             'callback_args' => [],
673 673
             'context'       => 'advanced',
674 674
             'func'          => $callback,
675
-            'id'            => $this->caller . '_' . $callback_function . '_metabox',
675
+            'id'            => $this->caller.'_'.$callback_function.'_metabox',
676 676
             'label'         => $this->caller,
677 677
             'page'          => $args['page'] ?? $screen_id,
678 678
             'priority'      => 'default',
@@ -685,7 +685,7 @@  discard block
 block discarded – undo
685 685
         $page          = $args['page'];
686 686
         $priority      = $args['priority'];
687 687
         // make sure method exists
688
-        if (! method_exists($this, $callback_function)) {
688
+        if ( ! method_exists($this, $callback_function)) {
689 689
             $msg[] =
690 690
                 esc_html__('There is no corresponding method to display the metabox content', 'event_espresso')
691 691
                 . '<br />';
@@ -703,7 +703,7 @@  discard block
 block discarded – undo
703 703
         add_meta_box($id, $label, [$this, $callback_function], $page, $context, $priority, $callback_args);
704 704
         add_filter(
705 705
             "postbox_classes_{$page}_$id",
706
-            function ($classes) {
706
+            function($classes) {
707 707
                 $classes[] = 'ee-admin-container';
708 708
                 return $classes;
709 709
             }
Please login to merge, or discard this patch.
core/admin/EE_Admin_Page_CPT.core.php 2 patches
Indentation   +1424 added lines, -1424 removed lines patch added patch discarded remove patch
@@ -31,449 +31,449 @@  discard block
 block discarded – undo
31 31
  */
32 32
 abstract class EE_Admin_Page_CPT extends EE_Admin_Page
33 33
 {
34
-    /**
35
-     * @var EE_CPT_Base|null
36
-     */
37
-    protected $_cpt_model_obj;
38
-
39
-    protected ?WP_Post_Type $_cpt_object = null;
40
-
41
-
42
-    /**
43
-     * This property allows cpt classes to define multiple routes as cpt routes.
44
-     * //in this array we define what the custom post type for this route is.
45
-     * array(
46
-     * 'route_name' => 'custom_post_type_slug'
47
-     * )
48
-     *
49
-     * @var array
50
-     */
51
-    protected array $_cpt_routes = [];
52
-
53
-
54
-    /**
55
-     * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
56
-     * in this format:
57
-     * array(
58
-     * 'post_type_slug' => 'edit_route'
59
-     * )
60
-     *
61
-     * @var array
62
-     */
63
-    protected array $_cpt_edit_routes = [];
64
-
65
-
66
-    /**
67
-     * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
68
-     * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
69
-     * _cpt_model_names property should be in the following format: array(
70
-     * 'route_defined_by_action_param' => 'Model_Name')
71
-     *
72
-     * @var array $_cpt_model_names
73
-     */
74
-    protected array $_cpt_model_names = [];
75
-
76
-
77
-    /**
78
-     * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
79
-     * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
80
-     * the _register_autosave_containers() method so that we don't override any other containers already registered.
81
-     * Registration of containers should be done before load_page_dependencies() is run.
82
-     *
83
-     * @var array
84
-     */
85
-    protected array $_autosave_containers = [];
86
-
87
-    protected array $_autosave_fields     = [];
88
-
89
-    /**
90
-     * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
91
-     * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
92
-     *
93
-     * @var array
94
-     */
95
-    protected array $_pagenow_map= [];
96
-
97
-
98
-    /**
99
-     * This is the route that will be used for the edit post route.
100
-     *
101
-     * @var string
102
-     */
103
-    protected string $cpt_editpost_route = 'edit';
104
-
105
-
106
-    /**
107
-     * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
108
-     * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
109
-     * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
110
-     * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
111
-     * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
112
-     *
113
-     * @abstract
114
-     * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
115
-     * @param WP_Post $post    The post object of the cpt that was saved.
116
-     * @return void
117
-     */
118
-    abstract protected function _insert_update_cpt_item($post_id, $post);
119
-
120
-
121
-    /**
122
-     * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
123
-     *
124
-     * @abstract
125
-     * @param string $post_id The ID of the cpt that was trashed
126
-     * @return void
127
-     */
128
-    abstract public function trash_cpt_item($post_id);
129
-
130
-
131
-    /**
132
-     * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
133
-     *
134
-     * @param string $post_id theID of the cpt that was untrashed
135
-     * @return void
136
-     */
137
-    abstract public function restore_cpt_item($post_id);
138
-
139
-
140
-    /**
141
-     * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
142
-     * from the db
143
-     *
144
-     * @param string $post_id the ID of the cpt that was deleted
145
-     * @return void
146
-     */
147
-    abstract public function delete_cpt_item($post_id);
148
-
149
-
150
-    /**
151
-     * @return LoaderInterface
152
-     * @throws InvalidArgumentException
153
-     * @throws InvalidDataTypeException
154
-     * @throws InvalidInterfaceException
155
-     */
156
-    protected function getLoader(): LoaderInterface
157
-    {
158
-        if (! $this->loader instanceof LoaderInterface) {
159
-            $this->loader = LoaderFactory::getLoader();
160
-        }
161
-        return $this->loader;
162
-    }
163
-
164
-
165
-    /**
166
-     * Just utilizing the method EE_Admin exposes for doing things before page setup.
167
-     *
168
-     * @return void
169
-     */
170
-    protected function _before_page_setup()
171
-    {
172
-        $this->raw_req_action = $this->request->getRequestParam('action');
173
-        $this->raw_req_page   = $this->request->getRequestParam('page');
174
-        $this->_cpt_routes    = array_merge(
175
-            [
176
-                'create_new' => $this->page_slug,
177
-                'edit'       => $this->page_slug,
178
-                'trash'      => $this->page_slug,
179
-            ],
180
-            $this->_cpt_routes
181
-        );
182
-        $cpt_route_action     = $this->_cpt_routes[ $this->raw_req_action ] ?? null;
183
-        // let's see if the current route has a value for cpt_object_slug. if it does, we use that instead of the page
184
-        $page              = $this->raw_req_page ?: $this->page_slug;
185
-        $page              = $cpt_route_action ?: $page;
186
-        $this->_cpt_object = get_post_type_object($page);
187
-        // tweak pagenow for page loading.
188
-        if (empty($this->_pagenow_map)) {
189
-            $this->_pagenow_map = [
190
-                'create_new' => 'post-new.php',
191
-                'edit'       => 'post.php',
192
-                'trash'      => 'post.php',
193
-            ];
194
-        }
195
-        add_action('current_screen', [$this, 'modify_pagenow']);
196
-        // TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
197
-        // get current page from autosave
198
-        $current_page        = $this->request->getRequestParam('ee_autosave_data[ee-cpt-hidden-inputs][current_page]');
199
-        $this->_current_page = $this->request->getRequestParam('current_page', $current_page);
200
-    }
201
-
202
-
203
-    /**
204
-     * Simply ensure that we simulate the correct post route for cpt screens
205
-     *
206
-     * @param WP_Screen|null $current_screen
207
-     * @return void
208
-     */
209
-    public function modify_pagenow(?WP_Screen $current_screen)
210
-    {
211
-        // possibly reset pagenow.
212
-        if (
213
-            $this->page_slug === $this->raw_req_page
214
-            && isset($this->_pagenow_map[ $this->raw_req_action ])
215
-        ) {
216
-            global $pagenow, $hook_suffix;
217
-            $pagenow     = $this->_pagenow_map[ $this->raw_req_action ];
218
-            $hook_suffix = $pagenow;
219
-        }
220
-    }
221
-
222
-
223
-    /**
224
-     * This method is used to register additional autosave containers to the _autosave_containers property.
225
-     *
226
-     * @param array $ids  an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
227
-     *                    you would send along the id of a metabox container.
228
-     * @return void
229
-     * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
230
-     *                    automatically register the id for the post metabox as a container.
231
-     */
232
-    protected function _register_autosave_containers($ids)
233
-    {
234
-        $this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
235
-    }
236
-
237
-
238
-    /**
239
-     * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
240
-     * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
241
-     */
242
-    protected function _set_autosave_containers()
243
-    {
244
-        global $wp_meta_boxes;
245
-        $containers = [];
246
-        if (empty($wp_meta_boxes)) {
247
-            return;
248
-        }
249
-        $current_metaboxes = $wp_meta_boxes[ $this->page_slug ] ?? [];
250
-        foreach ($current_metaboxes as $box_context) {
251
-            foreach ($box_context as $box_details) {
252
-                foreach ($box_details as $box) {
253
-                    if (
254
-                        is_array($box) && is_array($box['callback'])
255
-                        && (
256
-                            $box['callback'][0] instanceof EE_Admin_Page
257
-                            || $box['callback'][0] instanceof EE_Admin_Hooks
258
-                        )
259
-                    ) {
260
-                        $containers[] = $box['id'];
261
-                    }
262
-                }
263
-            }
264
-        }
265
-        $this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
266
-        // add hidden inputs container
267
-        $this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
268
-    }
269
-
270
-
271
-    protected function _load_autosave_scripts_styles()
272
-    {
273
-        /*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
34
+	/**
35
+	 * @var EE_CPT_Base|null
36
+	 */
37
+	protected $_cpt_model_obj;
38
+
39
+	protected ?WP_Post_Type $_cpt_object = null;
40
+
41
+
42
+	/**
43
+	 * This property allows cpt classes to define multiple routes as cpt routes.
44
+	 * //in this array we define what the custom post type for this route is.
45
+	 * array(
46
+	 * 'route_name' => 'custom_post_type_slug'
47
+	 * )
48
+	 *
49
+	 * @var array
50
+	 */
51
+	protected array $_cpt_routes = [];
52
+
53
+
54
+	/**
55
+	 * This simply defines what the corresponding routes WP will be redirected to after completing a post save/update.
56
+	 * in this format:
57
+	 * array(
58
+	 * 'post_type_slug' => 'edit_route'
59
+	 * )
60
+	 *
61
+	 * @var array
62
+	 */
63
+	protected array $_cpt_edit_routes = [];
64
+
65
+
66
+	/**
67
+	 * If child classes set the name of their main model via the $_cpt_obj_models property, EE_Admin_Page_CPT will
68
+	 * attempt to retrieve the related object model for the edit pages and assign it to _cpt_page_object. the
69
+	 * _cpt_model_names property should be in the following format: array(
70
+	 * 'route_defined_by_action_param' => 'Model_Name')
71
+	 *
72
+	 * @var array $_cpt_model_names
73
+	 */
74
+	protected array $_cpt_model_names = [];
75
+
76
+
77
+	/**
78
+	 * This will hold an array of autosave containers that will be used to obtain input values and hook into the WP
79
+	 * autosave so we can save our inputs on the save_post hook!  Children classes should add to this array by using
80
+	 * the _register_autosave_containers() method so that we don't override any other containers already registered.
81
+	 * Registration of containers should be done before load_page_dependencies() is run.
82
+	 *
83
+	 * @var array
84
+	 */
85
+	protected array $_autosave_containers = [];
86
+
87
+	protected array $_autosave_fields     = [];
88
+
89
+	/**
90
+	 * Array mapping from admin actions to their equivalent wp core pages for custom post types. So when a user visits
91
+	 * a page for an action, it will appear as if they were visiting the wp core page for that custom post type
92
+	 *
93
+	 * @var array
94
+	 */
95
+	protected array $_pagenow_map= [];
96
+
97
+
98
+	/**
99
+	 * This is the route that will be used for the edit post route.
100
+	 *
101
+	 * @var string
102
+	 */
103
+	protected string $cpt_editpost_route = 'edit';
104
+
105
+
106
+	/**
107
+	 * This is hooked into the WordPress do_action('save_post') hook and runs after the custom post type has been
108
+	 * saved.  Child classes are required to declare this method.  Typically you would use this to save any additional
109
+	 * data. Keep in mind also that "save_post" runs on EVERY post update to the database. ALSO very important.  When a
110
+	 * post transitions from scheduled to published, the save_post action is fired but you will NOT have any _POST data
111
+	 * containing any extra info you may have from other meta saves.  So MAKE sure that you handle this accordingly.
112
+	 *
113
+	 * @abstract
114
+	 * @param string  $post_id The ID of the cpt that was saved (so you can link relationally)
115
+	 * @param WP_Post $post    The post object of the cpt that was saved.
116
+	 * @return void
117
+	 */
118
+	abstract protected function _insert_update_cpt_item($post_id, $post);
119
+
120
+
121
+	/**
122
+	 * This is hooked into the WordPress do_action('trashed_post') hook and runs after a cpt has been trashed.
123
+	 *
124
+	 * @abstract
125
+	 * @param string $post_id The ID of the cpt that was trashed
126
+	 * @return void
127
+	 */
128
+	abstract public function trash_cpt_item($post_id);
129
+
130
+
131
+	/**
132
+	 * This is hooked into the WordPress do_action('untrashed_post') hook and runs after a cpt has been untrashed
133
+	 *
134
+	 * @param string $post_id theID of the cpt that was untrashed
135
+	 * @return void
136
+	 */
137
+	abstract public function restore_cpt_item($post_id);
138
+
139
+
140
+	/**
141
+	 * This is hooked into the WordPress do_action('delete_cpt_item') hook and runs after a cpt has been fully deleted
142
+	 * from the db
143
+	 *
144
+	 * @param string $post_id the ID of the cpt that was deleted
145
+	 * @return void
146
+	 */
147
+	abstract public function delete_cpt_item($post_id);
148
+
149
+
150
+	/**
151
+	 * @return LoaderInterface
152
+	 * @throws InvalidArgumentException
153
+	 * @throws InvalidDataTypeException
154
+	 * @throws InvalidInterfaceException
155
+	 */
156
+	protected function getLoader(): LoaderInterface
157
+	{
158
+		if (! $this->loader instanceof LoaderInterface) {
159
+			$this->loader = LoaderFactory::getLoader();
160
+		}
161
+		return $this->loader;
162
+	}
163
+
164
+
165
+	/**
166
+	 * Just utilizing the method EE_Admin exposes for doing things before page setup.
167
+	 *
168
+	 * @return void
169
+	 */
170
+	protected function _before_page_setup()
171
+	{
172
+		$this->raw_req_action = $this->request->getRequestParam('action');
173
+		$this->raw_req_page   = $this->request->getRequestParam('page');
174
+		$this->_cpt_routes    = array_merge(
175
+			[
176
+				'create_new' => $this->page_slug,
177
+				'edit'       => $this->page_slug,
178
+				'trash'      => $this->page_slug,
179
+			],
180
+			$this->_cpt_routes
181
+		);
182
+		$cpt_route_action     = $this->_cpt_routes[ $this->raw_req_action ] ?? null;
183
+		// let's see if the current route has a value for cpt_object_slug. if it does, we use that instead of the page
184
+		$page              = $this->raw_req_page ?: $this->page_slug;
185
+		$page              = $cpt_route_action ?: $page;
186
+		$this->_cpt_object = get_post_type_object($page);
187
+		// tweak pagenow for page loading.
188
+		if (empty($this->_pagenow_map)) {
189
+			$this->_pagenow_map = [
190
+				'create_new' => 'post-new.php',
191
+				'edit'       => 'post.php',
192
+				'trash'      => 'post.php',
193
+			];
194
+		}
195
+		add_action('current_screen', [$this, 'modify_pagenow']);
196
+		// TODO the below will need to be reworked to account for the cpt routes that are NOT based off of page but action param.
197
+		// get current page from autosave
198
+		$current_page        = $this->request->getRequestParam('ee_autosave_data[ee-cpt-hidden-inputs][current_page]');
199
+		$this->_current_page = $this->request->getRequestParam('current_page', $current_page);
200
+	}
201
+
202
+
203
+	/**
204
+	 * Simply ensure that we simulate the correct post route for cpt screens
205
+	 *
206
+	 * @param WP_Screen|null $current_screen
207
+	 * @return void
208
+	 */
209
+	public function modify_pagenow(?WP_Screen $current_screen)
210
+	{
211
+		// possibly reset pagenow.
212
+		if (
213
+			$this->page_slug === $this->raw_req_page
214
+			&& isset($this->_pagenow_map[ $this->raw_req_action ])
215
+		) {
216
+			global $pagenow, $hook_suffix;
217
+			$pagenow     = $this->_pagenow_map[ $this->raw_req_action ];
218
+			$hook_suffix = $pagenow;
219
+		}
220
+	}
221
+
222
+
223
+	/**
224
+	 * This method is used to register additional autosave containers to the _autosave_containers property.
225
+	 *
226
+	 * @param array $ids  an array of ids for containers that hold form inputs we want autosave to pickup.  Typically
227
+	 *                    you would send along the id of a metabox container.
228
+	 * @return void
229
+	 * @todo We should automate this at some point by creating a wrapper for add_post_metabox and in our wrapper we
230
+	 *                    automatically register the id for the post metabox as a container.
231
+	 */
232
+	protected function _register_autosave_containers($ids)
233
+	{
234
+		$this->_autosave_containers = array_merge($this->_autosave_fields, (array) $ids);
235
+	}
236
+
237
+
238
+	/**
239
+	 * Something nifty.  We're going to loop through all the registered metaboxes and if the CALLBACK is an instance of
240
+	 * EE_Admin_Page OR EE_Admin_Hooks, then we'll add the id to our _autosave_containers array.
241
+	 */
242
+	protected function _set_autosave_containers()
243
+	{
244
+		global $wp_meta_boxes;
245
+		$containers = [];
246
+		if (empty($wp_meta_boxes)) {
247
+			return;
248
+		}
249
+		$current_metaboxes = $wp_meta_boxes[ $this->page_slug ] ?? [];
250
+		foreach ($current_metaboxes as $box_context) {
251
+			foreach ($box_context as $box_details) {
252
+				foreach ($box_details as $box) {
253
+					if (
254
+						is_array($box) && is_array($box['callback'])
255
+						&& (
256
+							$box['callback'][0] instanceof EE_Admin_Page
257
+							|| $box['callback'][0] instanceof EE_Admin_Hooks
258
+						)
259
+					) {
260
+						$containers[] = $box['id'];
261
+					}
262
+				}
263
+			}
264
+		}
265
+		$this->_autosave_containers = array_merge($this->_autosave_containers, $containers);
266
+		// add hidden inputs container
267
+		$this->_autosave_containers[] = 'ee-cpt-hidden-inputs';
268
+	}
269
+
270
+
271
+	protected function _load_autosave_scripts_styles()
272
+	{
273
+		/*wp_register_script('cpt-autosave', EE_ADMIN_URL . 'assets/ee-cpt-autosave.js', array('ee-serialize-full-array', 'event_editor_js'), EVENT_ESPRESSO_VERSION, TRUE );
274 274
         wp_enqueue_script('cpt-autosave');/**/ // todo re-enable when we start doing autosave again in 4.2
275 275
 
276
-        // filter _autosave_containers
277
-        $containers = apply_filters(
278
-            'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
279
-            $this->_autosave_containers,
280
-            $this
281
-        );
282
-        $containers = apply_filters(
283
-            'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
284
-            $containers,
285
-            $this
286
-        );
287
-
288
-        wp_localize_script(
289
-            'event_editor_js',
290
-            'EE_AUTOSAVE_IDS',
291
-            $containers
292
-        ); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
293
-
294
-        $unsaved_data_msg = [
295
-            'eventmsg'     => sprintf(
296
-                wp_strip_all_tags(
297
-                    __(
298
-                        "The changes you made to this %s will be lost if you navigate away from this page.",
299
-                        'event_espresso'
300
-                    )
301
-                ),
302
-                $this->_cpt_object->labels->singular_name
303
-            ),
304
-            'inputChanged' => 0,
305
-        ];
306
-        wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
307
-    }
308
-
309
-
310
-    /**
311
-     * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
312
-     *
313
-     * @return void
314
-     * @throws EE_Error
315
-     * @throws ReflectionException
316
-     * @throws Throwable
317
-     */
318
-    protected function _load_page_dependencies()
319
-    {
320
-        // we only add stuff if this is a cpt_route!
321
-        if (! $this->_cpt_route) {
322
-            parent::_load_page_dependencies();
323
-            return;
324
-        }
325
-        // now let's do some automatic filters into the wp_system
326
-        // and we'll check to make sure the CHILD class
327
-        // automatically has the required methods in place.
328
-        // the following filters are for setting all the redirects
329
-        // on DEFAULT WP custom post type actions
330
-        // let's add a hidden input to the post-edit form
331
-        // so we know when we have to trigger our custom redirects!
332
-        // Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
-        add_action('edit_form_after_title', [$this, 'cpt_post_form_hidden_input']);
334
-        // inject our Admin page nav tabs...
335
-        // let's make sure the nav tabs are set if they aren't already
336
-        // if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
-        add_action('edit_form_top', [$this, 'inject_nav_tabs']);
338
-        // modify the post_updated messages array
339
-        add_action('post_updated_messages', [$this, 'post_update_messages']);
340
-        // This basically allows us to change the title of the "publish" metabox area
341
-        // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
342
-        $screen = $this->_cpt_routes[ $this->_req_action ];
343
-        if (! empty($this->_labels['publishbox'])) {
344
-            $this->addMetaBox(
345
-                'submitdiv',
346
-                $this->getPublishBoxTitle(),
347
-                'post_submit_meta_box',
348
-                $screen,
349
-                'side',
350
-                'core'
351
-            );
352
-        }
353
-        // let's add page_templates metabox if this cpt added support for it.
354
-        if ($this->_supports_page_templates($this->_cpt_object->name)) {
355
-            $this->addMetaBox(
356
-                'page_templates',
357
-                esc_html__('Page Template', 'event_espresso'),
358
-                [$this, 'page_template_meta_box'],
359
-                $screen,
360
-                'side'
361
-            );
362
-        }
363
-        // add preview button
364
-        add_filter('get_sample_permalink_html', [PreviewButton::class, 'addButton'], 5, 2);
365
-        // add shortlink button to cpt edit screens.
366
-        //  We can do this as a universal thing BECAUSE, cpts use the same format for shortlinks as posts!
367
-        add_filter('get_sample_permalink_html', [EventShortlinkButton::class, 'addButton'], 10, 2);
368
-        // this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
369
-        add_filter('get_sample_permalink_html', [TicketSelectorShortcodeButton::class, 'addButton'], 12, 4);
370
-        // insert our own post_stati dropdown
371
-        add_action('post_submitbox_misc_actions', [$this, 'custom_post_stati_dropdown']);
372
-        // This allows adding additional information to the publish post submitbox on the wp post edit form
373
-        if (method_exists($this, 'extra_misc_actions_publish_box')) {
374
-            add_action('post_submitbox_misc_actions', [$this, 'extra_misc_actions_publish_box']);
375
-        }
376
-        // This allows for adding additional stuff after the title field on the wp post edit form.
377
-        // This is also before the wp_editor for post description field.
378
-        if (method_exists($this, 'edit_form_after_title')) {
379
-            add_action('edit_form_after_title', [$this, 'edit_form_after_title']);
380
-        }
381
-        /**
382
-         * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
383
-         */
384
-        add_filter('clean_url', [$this, 'switch_core_wp_urls_with_ours']);
385
-        parent::_load_page_dependencies();
386
-        // notice we are ALSO going to load the pagenow hook set for this route
387
-        // (see _before_page_setup for the reset of the pagenow global ).
388
-        // This is for any plugins that are doing things properly
389
-        // and hooking into the load page hook for core wp cpt routes.
390
-        global $pagenow;
391
-        add_action('load-' . $pagenow, [$this, 'modify_current_screen'], 20);
392
-        do_action('load-' . $pagenow);
393
-        add_action('admin_enqueue_scripts', [$this, 'setup_autosave_hooks'], 30);
394
-        // we route REALLY early.
395
-        try {
396
-            $this->_route_admin_request();
397
-        } catch (EE_Error $e) {
398
-            $e->get_error();
399
-        }
400
-    }
401
-
402
-
403
-    /**
404
-     * Since we don't want users going to default core wp routes, this will check any wp urls run through the
405
-     * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
406
-     * route instead.
407
-     *
408
-     * @param string $good_protocol_url The escaped url.
409
-     * @return string possibly a new url for our route.
410
-     */
411
-    public function switch_core_wp_urls_with_ours(string $good_protocol_url): string
412
-    {
413
-        $routes_to_match = [
414
-            0 => [
415
-                'edit.php?post_type=espresso_attendees',
416
-                'admin.php?page=espresso_registrations&action=contact_list',
417
-            ],
418
-            1 => [
419
-                'edit.php?post_type=' . $this->_cpt_object->name,
420
-                'admin.php?page=' . $this->_cpt_object->name,
421
-            ],
422
-        ];
423
-        foreach ($routes_to_match as $route_matches) {
424
-            if (strpos($good_protocol_url, $route_matches[0]) !== false) {
425
-                return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
426
-            }
427
-        }
428
-        return $good_protocol_url;
429
-    }
430
-
431
-
432
-    /**
433
-     * Determine whether the current cpt supports page templates or not.
434
-     *
435
-     * @param string $cpt_name The cpt slug we're checking on.
436
-     * @return bool True supported, false not.
437
-     * @throws InvalidArgumentException
438
-     * @throws InvalidDataTypeException
439
-     * @throws InvalidInterfaceException
440
-     * @since %VER%
441
-     */
442
-    private function _supports_page_templates(string $cpt_name): bool
443
-    {
444
-        /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
445
-        $custom_post_types = $this->loader->getShared(
446
-            'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
447
-        );
448
-        $cpt_args          = $custom_post_types->getDefinitions();
449
-        $cpt_args          = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : [];
450
-        $cpt_has_support   = ! empty($cpt_args['page_templates']);
451
-
452
-        $post_templates = wp_get_theme()->get_post_templates();
453
-        // if there are $post_templates for this cpt, then we return false for this method because
454
-        // that means we aren't going to load our page template manager and leave that up to the native
455
-        // cpt template manager.
456
-        return ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
457
-    }
458
-
459
-
460
-    /**
461
-     * Callback for the page_templates metabox selector.
462
-     *
463
-     * @return void
464
-     * @since %VER%
465
-     */
466
-    public function page_template_meta_box()
467
-    {
468
-        global $post;
469
-        $template = '';
470
-
471
-        $page_template_count = count(get_page_templates());
472
-        if ($page_template_count) {
473
-            $page_template = get_post_meta($post->ID, '_wp_page_template', true);
474
-            $template      = ! empty($page_template) ? $page_template : '';
475
-        }
476
-        ?>
276
+		// filter _autosave_containers
277
+		$containers = apply_filters(
278
+			'FHEE__EE_Admin_Page_CPT___load_autosave_scripts_styles__containers',
279
+			$this->_autosave_containers,
280
+			$this
281
+		);
282
+		$containers = apply_filters(
283
+			'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
284
+			$containers,
285
+			$this
286
+		);
287
+
288
+		wp_localize_script(
289
+			'event_editor_js',
290
+			'EE_AUTOSAVE_IDS',
291
+			$containers
292
+		); // todo once we enable autosaves, this needs to be switched to localize with "cpt-autosave"
293
+
294
+		$unsaved_data_msg = [
295
+			'eventmsg'     => sprintf(
296
+				wp_strip_all_tags(
297
+					__(
298
+						"The changes you made to this %s will be lost if you navigate away from this page.",
299
+						'event_espresso'
300
+					)
301
+				),
302
+				$this->_cpt_object->labels->singular_name
303
+			),
304
+			'inputChanged' => 0,
305
+		];
306
+		wp_localize_script('event_editor_js', 'UNSAVED_DATA_MSG', $unsaved_data_msg);
307
+	}
308
+
309
+
310
+	/**
311
+	 * overloading the EE_Admin_Page parent load_page_dependencies so we can get the cpt stuff added in appropriately
312
+	 *
313
+	 * @return void
314
+	 * @throws EE_Error
315
+	 * @throws ReflectionException
316
+	 * @throws Throwable
317
+	 */
318
+	protected function _load_page_dependencies()
319
+	{
320
+		// we only add stuff if this is a cpt_route!
321
+		if (! $this->_cpt_route) {
322
+			parent::_load_page_dependencies();
323
+			return;
324
+		}
325
+		// now let's do some automatic filters into the wp_system
326
+		// and we'll check to make sure the CHILD class
327
+		// automatically has the required methods in place.
328
+		// the following filters are for setting all the redirects
329
+		// on DEFAULT WP custom post type actions
330
+		// let's add a hidden input to the post-edit form
331
+		// so we know when we have to trigger our custom redirects!
332
+		// Otherwise the redirects will happen on ALL post saves which wouldn't be good of course!
333
+		add_action('edit_form_after_title', [$this, 'cpt_post_form_hidden_input']);
334
+		// inject our Admin page nav tabs...
335
+		// let's make sure the nav tabs are set if they aren't already
336
+		// if ( empty( $this->_nav_tabs ) ) $this->_set_nav_tabs();
337
+		add_action('edit_form_top', [$this, 'inject_nav_tabs']);
338
+		// modify the post_updated messages array
339
+		add_action('post_updated_messages', [$this, 'post_update_messages']);
340
+		// This basically allows us to change the title of the "publish" metabox area
341
+		// on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
342
+		$screen = $this->_cpt_routes[ $this->_req_action ];
343
+		if (! empty($this->_labels['publishbox'])) {
344
+			$this->addMetaBox(
345
+				'submitdiv',
346
+				$this->getPublishBoxTitle(),
347
+				'post_submit_meta_box',
348
+				$screen,
349
+				'side',
350
+				'core'
351
+			);
352
+		}
353
+		// let's add page_templates metabox if this cpt added support for it.
354
+		if ($this->_supports_page_templates($this->_cpt_object->name)) {
355
+			$this->addMetaBox(
356
+				'page_templates',
357
+				esc_html__('Page Template', 'event_espresso'),
358
+				[$this, 'page_template_meta_box'],
359
+				$screen,
360
+				'side'
361
+			);
362
+		}
363
+		// add preview button
364
+		add_filter('get_sample_permalink_html', [PreviewButton::class, 'addButton'], 5, 2);
365
+		// add shortlink button to cpt edit screens.
366
+		//  We can do this as a universal thing BECAUSE, cpts use the same format for shortlinks as posts!
367
+		add_filter('get_sample_permalink_html', [EventShortlinkButton::class, 'addButton'], 10, 2);
368
+		// this is a filter that allows the addition of extra html after the permalink field on the wp post edit-form
369
+		add_filter('get_sample_permalink_html', [TicketSelectorShortcodeButton::class, 'addButton'], 12, 4);
370
+		// insert our own post_stati dropdown
371
+		add_action('post_submitbox_misc_actions', [$this, 'custom_post_stati_dropdown']);
372
+		// This allows adding additional information to the publish post submitbox on the wp post edit form
373
+		if (method_exists($this, 'extra_misc_actions_publish_box')) {
374
+			add_action('post_submitbox_misc_actions', [$this, 'extra_misc_actions_publish_box']);
375
+		}
376
+		// This allows for adding additional stuff after the title field on the wp post edit form.
377
+		// This is also before the wp_editor for post description field.
378
+		if (method_exists($this, 'edit_form_after_title')) {
379
+			add_action('edit_form_after_title', [$this, 'edit_form_after_title']);
380
+		}
381
+		/**
382
+		 * Filtering WP's esc_url to capture urls pointing to core wp routes so they point to our route.
383
+		 */
384
+		add_filter('clean_url', [$this, 'switch_core_wp_urls_with_ours']);
385
+		parent::_load_page_dependencies();
386
+		// notice we are ALSO going to load the pagenow hook set for this route
387
+		// (see _before_page_setup for the reset of the pagenow global ).
388
+		// This is for any plugins that are doing things properly
389
+		// and hooking into the load page hook for core wp cpt routes.
390
+		global $pagenow;
391
+		add_action('load-' . $pagenow, [$this, 'modify_current_screen'], 20);
392
+		do_action('load-' . $pagenow);
393
+		add_action('admin_enqueue_scripts', [$this, 'setup_autosave_hooks'], 30);
394
+		// we route REALLY early.
395
+		try {
396
+			$this->_route_admin_request();
397
+		} catch (EE_Error $e) {
398
+			$e->get_error();
399
+		}
400
+	}
401
+
402
+
403
+	/**
404
+	 * Since we don't want users going to default core wp routes, this will check any wp urls run through the
405
+	 * esc_url() method and if we see a url matching a pattern for our routes, we'll modify it to point to OUR
406
+	 * route instead.
407
+	 *
408
+	 * @param string $good_protocol_url The escaped url.
409
+	 * @return string possibly a new url for our route.
410
+	 */
411
+	public function switch_core_wp_urls_with_ours(string $good_protocol_url): string
412
+	{
413
+		$routes_to_match = [
414
+			0 => [
415
+				'edit.php?post_type=espresso_attendees',
416
+				'admin.php?page=espresso_registrations&action=contact_list',
417
+			],
418
+			1 => [
419
+				'edit.php?post_type=' . $this->_cpt_object->name,
420
+				'admin.php?page=' . $this->_cpt_object->name,
421
+			],
422
+		];
423
+		foreach ($routes_to_match as $route_matches) {
424
+			if (strpos($good_protocol_url, $route_matches[0]) !== false) {
425
+				return str_replace($route_matches[0], $route_matches[1], $good_protocol_url);
426
+			}
427
+		}
428
+		return $good_protocol_url;
429
+	}
430
+
431
+
432
+	/**
433
+	 * Determine whether the current cpt supports page templates or not.
434
+	 *
435
+	 * @param string $cpt_name The cpt slug we're checking on.
436
+	 * @return bool True supported, false not.
437
+	 * @throws InvalidArgumentException
438
+	 * @throws InvalidDataTypeException
439
+	 * @throws InvalidInterfaceException
440
+	 * @since %VER%
441
+	 */
442
+	private function _supports_page_templates(string $cpt_name): bool
443
+	{
444
+		/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
445
+		$custom_post_types = $this->loader->getShared(
446
+			'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
447
+		);
448
+		$cpt_args          = $custom_post_types->getDefinitions();
449
+		$cpt_args          = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : [];
450
+		$cpt_has_support   = ! empty($cpt_args['page_templates']);
451
+
452
+		$post_templates = wp_get_theme()->get_post_templates();
453
+		// if there are $post_templates for this cpt, then we return false for this method because
454
+		// that means we aren't going to load our page template manager and leave that up to the native
455
+		// cpt template manager.
456
+		return ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
457
+	}
458
+
459
+
460
+	/**
461
+	 * Callback for the page_templates metabox selector.
462
+	 *
463
+	 * @return void
464
+	 * @since %VER%
465
+	 */
466
+	public function page_template_meta_box()
467
+	{
468
+		global $post;
469
+		$template = '';
470
+
471
+		$page_template_count = count(get_page_templates());
472
+		if ($page_template_count) {
473
+			$page_template = get_post_meta($post->ID, '_wp_page_template', true);
474
+			$template      = ! empty($page_template) ? $page_template : '';
475
+		}
476
+		?>
477 477
         <p><strong><?php esc_html_e('Template', 'event_espresso') ?></strong></p>
478 478
         <label class="screen-reader-text" for="page_template">
479 479
             <?php esc_html_e('Page Template', 'event_espresso') ?>
@@ -483,457 +483,457 @@  discard block
 block discarded – undo
483 483
             <?php page_template_dropdown($template); ?>
484 484
         </select>
485 485
         <?php
486
-    }
487
-
488
-
489
-    /**
490
-     * if this post is a draft or scheduled post then we provide a preview button for user to click
491
-     * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
492
-     *
493
-     * @param string $return    the current html
494
-     * @param int    $id        the post id for the page
495
-     * @return string            The new html string for the permalink area
496
-     * @deprecated 5.0.0.p
497
-     * @see PreviewButton::addButton()
498
-     */
499
-    public function preview_button_html(string $return, int $id): string
500
-    {
501
-        return PreviewButton::addButton($return, $id);
502
-    }
503
-
504
-
505
-    /**
506
-     * add our custom post status dropdown on the wp post page for this cpt
507
-     *
508
-     * @return void
509
-     */
510
-    public function custom_post_stati_dropdown()
511
-    {
512
-        $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
513
-        $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
514
-            ? $statuses[ $this->_cpt_model_obj->status() ]
515
-            : '';
516
-        $template_args    = [
517
-            'cur_status'            => $this->_cpt_model_obj->status(),
518
-            'statuses'              => $statuses,
519
-            'cur_status_label'      => $cur_status_label,
520
-            'localized_status_save' => sprintf(esc_html__('Save %s', 'event_espresso'), $cur_status_label),
521
-        ];
522
-        // we'll add a trash post status (WP doesn't add one for some reason)
523
-        if ($this->_cpt_model_obj->status() === 'trash') {
524
-            $template_args['cur_status_label'] = esc_html__('Trashed', 'event_espresso');
525
-            $statuses['trash']                 = esc_html__('Trashed', 'event_espresso');
526
-            $template_args['statuses']         = $statuses;
527
-        }
528
-
529
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
530
-        EEH_Template::display_template($template, $template_args);
531
-    }
532
-
533
-
534
-    public function setup_autosave_hooks()
535
-    {
536
-        $this->_set_autosave_containers();
537
-        $this->_load_autosave_scripts_styles();
538
-    }
539
-
540
-
541
-    /**
542
-     * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a post object (available
543
-     * in request data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
544
-     * for the nonce in here, but then this method looks for two things:
545
-     * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
546
-     * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
547
-     * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
548
-     * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
549
-     * template args.
550
-     *    1. $template_args['error'] = IF there is an error you can add the message in here.
551
-     *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
552
-     *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
553
-     *    $this->_template_args['data']['items'] = array(
554
-     *        'event-datetime-ids' => '1,2,3';
555
-     *    );
556
-     *    Keep in mind the following things:
557
-     *    - "where" index is for the input with the id as that string.
558
-     *    - "what" index is what will be used for the value of that input.
559
-     *
560
-     * @return void
561
-     * @throws EE_Error
562
-     */
563
-    public function do_extra_autosave_stuff()
564
-    {
565
-        // next let's check for the autosave nonce (we'll use _verify_nonce )
566
-        $nonce = $this->request->getRequestParam('autosavenonce');
567
-        $this->_verify_nonce($nonce, 'autosave');
568
-        // make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
569
-        if (! defined('DOING_AUTOSAVE')) {
570
-            define('DOING_AUTOSAVE', true);
571
-        }
572
-        // if we made it here then the nonce checked out.  Let's run our methods and actions
573
-        $autosave = "_ee_autosave_$this->_current_view";
574
-        if (method_exists($this, $autosave)) {
575
-            $this->$autosave();
576
-        } else {
577
-            $this->_template_args['success'] = true;
578
-        }
579
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
580
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
581
-        // now let's return json
582
-        $this->_return_json();
583
-    }
584
-
585
-
586
-    /**
587
-     * This takes care of setting up default routes and pages that utilize the core WP admin pages.
588
-     * Child classes can override the defaults (in cases for adding metaboxes etc.)
589
-     * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
590
-     *
591
-     * @return void
592
-     * @throws EE_Error
593
-     * @throws ReflectionException
594
-     */
595
-    protected function _extend_page_config_for_cpt()
596
-    {
597
-        // before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
598
-        if ($this->raw_req_page !== $this->page_slug) {
599
-            return;
600
-        }
601
-        // set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
602
-        if (! empty($this->_cpt_object)) {
603
-            $this->_page_routes = array_merge(
604
-                [
605
-                    'create_new' => [$this, '_create_new_cpt_item'],
606
-                    'edit'       => [$this, '_edit_cpt_item'],
607
-                ],
608
-                $this->_page_routes
609
-            );
610
-            $this->_page_config = array_merge(
611
-                [
612
-                    'create_new' => [
613
-                        'nav'           => [
614
-                            'label' => $this->_cpt_object->labels->add_new_item,
615
-                            'order' => 5,
616
-                        ],
617
-                        'require_nonce' => false,
618
-                    ],
619
-                    'edit'       => [
620
-                        'nav'           => [
621
-                            'label'      => $this->_cpt_object->labels->edit_item,
622
-                            'order'      => 5,
623
-                            'persistent' => false,
624
-                            'url'        => '',
625
-                        ],
626
-                        'require_nonce' => false,
627
-                    ],
628
-                ],
629
-                $this->_page_config
630
-            );
631
-        }
632
-        // load the next section only if this is a matching cpt route as set in the cpt routes array.
633
-        if (! isset($this->_cpt_routes[ $this->_req_action ])) {
634
-            return;
635
-        }
636
-        $this->_cpt_route = true;
637
-        // $this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]);
638
-        // add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
639
-        if (empty($this->_cpt_object)) {
640
-            $msg = sprintf(
641
-                esc_html__(
642
-                    'This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).',
643
-                    'event_espresso'
644
-                ),
645
-                $this->page_slug,
646
-                $this->_req_action,
647
-                get_class($this)
648
-            );
649
-            throw new EE_Error($msg);
650
-        }
651
-        $this->_set_model_object($this->request->getRequestParam('post', 0, DataType::INT));
652
-    }
653
-
654
-
655
-    /**
656
-     * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
657
-     *
658
-     * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
659
-     * @param bool   $ignore_route_check
660
-     * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
661
-     * @throws EE_Error
662
-     * @throws InvalidArgumentException
663
-     * @throws InvalidDataTypeException
664
-     * @throws InvalidInterfaceException
665
-     * @throws ReflectionException
666
-     */
667
-    protected function _set_model_object(int $id = 0, bool $ignore_route_check = false, string $req_type = '')
668
-    {
669
-        $model = null;
670
-        if (
671
-            empty($this->_cpt_model_names)
672
-            || (
673
-                ! $ignore_route_check
674
-                && ! isset($this->_cpt_routes[ $this->_req_action ])
675
-            )
676
-            || (
677
-                $this->_cpt_model_obj instanceof EE_CPT_Base
678
-                && $this->_cpt_model_obj->ID() === $id
679
-            )
680
-        ) {
681
-            // get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
682
-            return;
683
-        }
684
-        // if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
685
-        if ($ignore_route_check) {
686
-            $post_type = get_post_type($id);
687
-            /** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
688
-            $custom_post_types = $this->loader->getShared(
689
-                'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
690
-            );
691
-            $model_names       = $custom_post_types->getCustomPostTypeModelNames($post_type);
692
-            if (isset($model_names[ $post_type ])) {
693
-                $model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
694
-            }
695
-        } else {
696
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
697
-        }
698
-        if ($model instanceof EEM_Base) {
699
-            $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
700
-        }
701
-        do_action(
702
-            'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
703
-            $this->_cpt_model_obj,
704
-            $req_type
705
-        );
706
-    }
707
-
708
-
709
-    /**
710
-     * admin_init_global
711
-     * This runs all the code that we want executed within the WP admin_init hook.
712
-     * This method executes for ALL EE Admin pages.
713
-     *
714
-     * @return void
715
-     */
716
-    public function admin_init_global()
717
-    {
718
-        $post_ID = $this->request->getRequestParam('post', 0, DataType::INT);
719
-        // its possible this is a new save so let's catch that instead
720
-        $post_ID        = $this->request->getRequestParam('post_ID', $post_ID, DataType::INT);
721
-        $post           = get_post($post_ID);
722
-        $post_type      = $post instanceof WP_Post ? $post->post_type : false;
723
-        $current_route  = $this->request->getRequestParam('current_route', 'shouldneverwork');
724
-        $route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
725
-            ? $this->_cpt_routes[ $current_route ]
726
-            : '';
727
-        add_filter('get_delete_post_link', [$this, 'modify_delete_post_link'], 10, 2);
728
-        add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
729
-        if ($post_type === $route_to_check) {
730
-            add_filter('redirect_post_location', [$this, 'cpt_post_location_redirect'], 10, 2);
731
-        }
732
-        // now let's filter redirect if we're on a revision page and the revision is for an event CPT.
733
-        $revision = $this->request->getRequestParam('revision');
734
-        if (! empty($revision)) {
735
-            $action = $this->request->getRequestParam('action');
736
-            // doing a restore?
737
-            if (! empty($action) && $action === 'restore') {
738
-                // get post for revision
739
-                $rev_post   = get_post($revision);
740
-                $rev_parent = get_post($rev_post->post_parent);
741
-                // only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
742
-                if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
743
-                    add_filter('wp_redirect', [$this, 'revision_redirect']);
744
-                    // restores of revisions
745
-                    add_action('wp_restore_post_revision', [$this, 'restore_revision'], 10, 2);
746
-                }
747
-            }
748
-        }
749
-        // NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
750
-        if ($post_type && $post_type === $route_to_check) {
751
-            // $post_id, $post
752
-            add_action('save_post', [$this, 'insert_update'], 10, 3);
753
-            // $post_id
754
-            add_action('trashed_post', [$this, 'before_trash_cpt_item']);
755
-            add_action('trashed_post', [$this, 'dont_permanently_delete_ee_cpts']);
756
-            add_action('untrashed_post', [$this, 'before_restore_cpt_item']);
757
-            add_action('after_delete_post', [$this, 'before_delete_cpt_item']);
758
-        }
759
-    }
760
-
761
-
762
-    /**
763
-     * Callback for the WordPress trashed_post hook.
764
-     * Execute some basic checks before calling the trash_cpt_item declared in the child class.
765
-     *
766
-     * @param int $post_id
767
-     * @throws EE_Error
768
-     * @throws ReflectionException
769
-     */
770
-    public function before_trash_cpt_item(int $post_id)
771
-    {
772
-        $this->_set_model_object($post_id, true, 'trash');
773
-        // if our cpt object isn't existent then get out immediately.
774
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
775
-            return;
776
-        }
777
-        $this->trash_cpt_item($post_id);
778
-    }
779
-
780
-
781
-    /**
782
-     * Callback for the WordPress untrashed_post hook.
783
-     * Execute some basic checks before calling the restore_cpt_method in the child class.
784
-     *
785
-     * @param $post_id
786
-     * @throws EE_Error
787
-     * @throws ReflectionException
788
-     */
789
-    public function before_restore_cpt_item($post_id)
790
-    {
791
-        $this->_set_model_object($post_id, true, 'restore');
792
-        // if our cpt object isn't existent then get out immediately.
793
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
794
-            return;
795
-        }
796
-        $this->restore_cpt_item($post_id);
797
-    }
798
-
799
-
800
-    /**
801
-     * Callback for the WordPress after_delete_post hook.
802
-     * Execute some basic checks before calling the delete_cpt_item method in the child class.
803
-     *
804
-     * @param $post_id
805
-     * @throws EE_Error
806
-     * @throws ReflectionException
807
-     */
808
-    public function before_delete_cpt_item($post_id)
809
-    {
810
-        $this->_set_model_object($post_id, true, 'delete');
811
-        // if our cpt object isn't existent then get out immediately.
812
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
813
-            return;
814
-        }
815
-        $this->delete_cpt_item($post_id);
816
-    }
817
-
818
-
819
-    /**
820
-     * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
821
-     * accordingly.
822
-     *
823
-     * @return void
824
-     * @throws EE_Error
825
-     * @throws ReflectionException
826
-     */
827
-    public function verify_cpt_object()
828
-    {
829
-        $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
830
-        // verify event object
831
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
832
-            throw new EE_Error(
833
-                sprintf(
834
-                    esc_html__(
835
-                        'Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
836
-                        'event_espresso'
837
-                    ),
838
-                    $label
839
-                )
840
-            );
841
-        }
842
-        // if auto-draft then throw an error
843
-        if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
844
-            EE_Error::overwrite_errors();
845
-            EE_Error::add_error(
846
-                sprintf(
847
-                    esc_html__(
848
-                        'This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.',
849
-                        'event_espresso'
850
-                    ),
851
-                    $label
852
-                ),
853
-                __FILE__,
854
-                __FUNCTION__,
855
-                __LINE__
856
-            );
857
-        }
858
-    }
859
-
860
-
861
-    /**
862
-     * admin_footer_scripts_global
863
-     * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
864
-     * will apply on ALL EE_Admin pages.
865
-     *
866
-     * @return void
867
-     */
868
-    public function admin_footer_scripts_global()
869
-    {
870
-        $this->_add_admin_page_ajax_loading_img();
871
-        $this->_add_admin_page_overlay();
872
-    }
873
-
874
-
875
-    /**
876
-     * add in any global scripts for cpt routes
877
-     *
878
-     * @return void
879
-     */
880
-    public function load_global_scripts_styles()
881
-    {
882
-        parent::load_global_scripts_styles();
883
-        if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
884
-            // setup custom post status object for localize script but only if we've got a cpt object
885
-            $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
886
-            if (! empty($statuses)) {
887
-                // get ALL statuses!
888
-                $statuses = $this->_cpt_model_obj->get_all_post_statuses();
889
-                // setup object
890
-                $ee_cpt_statuses = [];
891
-                foreach ($statuses as $status => $label) {
892
-                    $ee_cpt_statuses[ $status ] = [
893
-                        'label'      => $label,
894
-                        'save_label' => sprintf(
895
-                            wp_strip_all_tags(__('Save as %s', 'event_espresso')),
896
-                            $label
897
-                        ),
898
-                    ];
899
-                }
900
-                wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
901
-            }
902
-        }
903
-    }
904
-
905
-
906
-    /**
907
-     * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
908
-     * insert/updates
909
-     *
910
-     * @param int     $post_id ID of post being updated
911
-     * @param WP_Post $post    Post object from WP
912
-     * @param bool    $update  Whether this is an update or a new save.
913
-     * @return void
914
-     * @throws EE_Error
915
-     * @throws ReflectionException
916
-     */
917
-    public function insert_update(int $post_id, WP_Post $post, bool $update)
918
-    {
919
-        // make sure that if this is a revision OR trash action that we don't do any updates!
920
-        $action = $this->request->getRequestParam('action');
921
-        if ($action === 'restore' || $action === 'trash') {
922
-            return;
923
-        }
924
-        $this->_set_model_object($post_id, true, 'insert_update');
925
-        // if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
926
-        if (
927
-            $update
928
-            && (
929
-                ! $this->_cpt_model_obj instanceof EE_CPT_Base
930
-                || $this->_cpt_model_obj->ID() !== $post_id
931
-            )
932
-        ) {
933
-            return;
934
-        }
935
-        // check for autosave and update our req_data property accordingly.
936
-        /*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
486
+	}
487
+
488
+
489
+	/**
490
+	 * if this post is a draft or scheduled post then we provide a preview button for user to click
491
+	 * Method is called from parent and is hooked into the wp 'get_sample_permalink_html' filter.
492
+	 *
493
+	 * @param string $return    the current html
494
+	 * @param int    $id        the post id for the page
495
+	 * @return string            The new html string for the permalink area
496
+	 * @deprecated 5.0.0.p
497
+	 * @see PreviewButton::addButton()
498
+	 */
499
+	public function preview_button_html(string $return, int $id): string
500
+	{
501
+		return PreviewButton::addButton($return, $id);
502
+	}
503
+
504
+
505
+	/**
506
+	 * add our custom post status dropdown on the wp post page for this cpt
507
+	 *
508
+	 * @return void
509
+	 */
510
+	public function custom_post_stati_dropdown()
511
+	{
512
+		$statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
513
+		$cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
514
+			? $statuses[ $this->_cpt_model_obj->status() ]
515
+			: '';
516
+		$template_args    = [
517
+			'cur_status'            => $this->_cpt_model_obj->status(),
518
+			'statuses'              => $statuses,
519
+			'cur_status_label'      => $cur_status_label,
520
+			'localized_status_save' => sprintf(esc_html__('Save %s', 'event_espresso'), $cur_status_label),
521
+		];
522
+		// we'll add a trash post status (WP doesn't add one for some reason)
523
+		if ($this->_cpt_model_obj->status() === 'trash') {
524
+			$template_args['cur_status_label'] = esc_html__('Trashed', 'event_espresso');
525
+			$statuses['trash']                 = esc_html__('Trashed', 'event_espresso');
526
+			$template_args['statuses']         = $statuses;
527
+		}
528
+
529
+		$template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
530
+		EEH_Template::display_template($template, $template_args);
531
+	}
532
+
533
+
534
+	public function setup_autosave_hooks()
535
+	{
536
+		$this->_set_autosave_containers();
537
+		$this->_load_autosave_scripts_styles();
538
+	}
539
+
540
+
541
+	/**
542
+	 * This is run on all WordPress autosaves AFTER the autosave is complete and sends along a post object (available
543
+	 * in request data) containing: post_ID of the saved post autosavenonce for the saved post We'll do the check
544
+	 * for the nonce in here, but then this method looks for two things:
545
+	 * 1. Execute a method (if exists) matching 'ee_autosave_' and appended with the given route. OR
546
+	 * 2. do_actions() for global or class specific actions that have been registered (for plugins/addons not in an
547
+	 * EE_Admin_Page class. PLEASE NOTE: Data will be returned using the _return_json() object and so the
548
+	 * $_template_args property should be used to hold the $data array.  We're expecting the following things set in
549
+	 * template args.
550
+	 *    1. $template_args['error'] = IF there is an error you can add the message in here.
551
+	 *    2. $template_args['data']['items'] = an array of items that are setup in key index pairs of 'where_values_go'
552
+	 *    => 'values_to_add'.  In other words, for the datetime metabox we'll have something like
553
+	 *    $this->_template_args['data']['items'] = array(
554
+	 *        'event-datetime-ids' => '1,2,3';
555
+	 *    );
556
+	 *    Keep in mind the following things:
557
+	 *    - "where" index is for the input with the id as that string.
558
+	 *    - "what" index is what will be used for the value of that input.
559
+	 *
560
+	 * @return void
561
+	 * @throws EE_Error
562
+	 */
563
+	public function do_extra_autosave_stuff()
564
+	{
565
+		// next let's check for the autosave nonce (we'll use _verify_nonce )
566
+		$nonce = $this->request->getRequestParam('autosavenonce');
567
+		$this->_verify_nonce($nonce, 'autosave');
568
+		// make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
569
+		if (! defined('DOING_AUTOSAVE')) {
570
+			define('DOING_AUTOSAVE', true);
571
+		}
572
+		// if we made it here then the nonce checked out.  Let's run our methods and actions
573
+		$autosave = "_ee_autosave_$this->_current_view";
574
+		if (method_exists($this, $autosave)) {
575
+			$this->$autosave();
576
+		} else {
577
+			$this->_template_args['success'] = true;
578
+		}
579
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
580
+		do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
581
+		// now let's return json
582
+		$this->_return_json();
583
+	}
584
+
585
+
586
+	/**
587
+	 * This takes care of setting up default routes and pages that utilize the core WP admin pages.
588
+	 * Child classes can override the defaults (in cases for adding metaboxes etc.)
589
+	 * but take care that you include the defaults here otherwise your core WP admin pages for the cpt won't work!
590
+	 *
591
+	 * @return void
592
+	 * @throws EE_Error
593
+	 * @throws ReflectionException
594
+	 */
595
+	protected function _extend_page_config_for_cpt()
596
+	{
597
+		// before doing anything we need to make sure this runs ONLY when the loaded page matches the set page_slug
598
+		if ($this->raw_req_page !== $this->page_slug) {
599
+			return;
600
+		}
601
+		// set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
602
+		if (! empty($this->_cpt_object)) {
603
+			$this->_page_routes = array_merge(
604
+				[
605
+					'create_new' => [$this, '_create_new_cpt_item'],
606
+					'edit'       => [$this, '_edit_cpt_item'],
607
+				],
608
+				$this->_page_routes
609
+			);
610
+			$this->_page_config = array_merge(
611
+				[
612
+					'create_new' => [
613
+						'nav'           => [
614
+							'label' => $this->_cpt_object->labels->add_new_item,
615
+							'order' => 5,
616
+						],
617
+						'require_nonce' => false,
618
+					],
619
+					'edit'       => [
620
+						'nav'           => [
621
+							'label'      => $this->_cpt_object->labels->edit_item,
622
+							'order'      => 5,
623
+							'persistent' => false,
624
+							'url'        => '',
625
+						],
626
+						'require_nonce' => false,
627
+					],
628
+				],
629
+				$this->_page_config
630
+			);
631
+		}
632
+		// load the next section only if this is a matching cpt route as set in the cpt routes array.
633
+		if (! isset($this->_cpt_routes[ $this->_req_action ])) {
634
+			return;
635
+		}
636
+		$this->_cpt_route = true;
637
+		// $this->_cpt_route = isset($this->_cpt_routes[ $this->_req_action ]);
638
+		// add_action('FHEE__EE_Admin_Page___load_page_dependencies__after_load', array( $this, 'modify_current_screen') );
639
+		if (empty($this->_cpt_object)) {
640
+			$msg = sprintf(
641
+				esc_html__(
642
+					'This page has been set as being related to a registered custom post type, however, the custom post type object could not be retrieved. There are two possible reasons for this:  1. The "%s" does not match a registered post type. or 2. The custom post type is not registered for the "%s" action as indexed in the "$_cpt_routes" property on this class (%s).',
643
+					'event_espresso'
644
+				),
645
+				$this->page_slug,
646
+				$this->_req_action,
647
+				get_class($this)
648
+			);
649
+			throw new EE_Error($msg);
650
+		}
651
+		$this->_set_model_object($this->request->getRequestParam('post', 0, DataType::INT));
652
+	}
653
+
654
+
655
+	/**
656
+	 * Sets the _cpt_model_object property using what has been set for the _cpt_model_name and a given id.
657
+	 *
658
+	 * @param int    $id       The id to retrieve the model object for. If empty we set a default object.
659
+	 * @param bool   $ignore_route_check
660
+	 * @param string $req_type whether the current route is for inserting, updating, or deleting the CPT
661
+	 * @throws EE_Error
662
+	 * @throws InvalidArgumentException
663
+	 * @throws InvalidDataTypeException
664
+	 * @throws InvalidInterfaceException
665
+	 * @throws ReflectionException
666
+	 */
667
+	protected function _set_model_object(int $id = 0, bool $ignore_route_check = false, string $req_type = '')
668
+	{
669
+		$model = null;
670
+		if (
671
+			empty($this->_cpt_model_names)
672
+			|| (
673
+				! $ignore_route_check
674
+				&& ! isset($this->_cpt_routes[ $this->_req_action ])
675
+			)
676
+			|| (
677
+				$this->_cpt_model_obj instanceof EE_CPT_Base
678
+				&& $this->_cpt_model_obj->ID() === $id
679
+			)
680
+		) {
681
+			// get out cuz we either don't have a model name OR the object has already been set and it has the same id as what has been sent.
682
+			return;
683
+		}
684
+		// if ignore_route_check is true, then get the model name via CustomPostTypeDefinitions
685
+		if ($ignore_route_check) {
686
+			$post_type = get_post_type($id);
687
+			/** @var EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions $custom_post_types */
688
+			$custom_post_types = $this->loader->getShared(
689
+				'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
690
+			);
691
+			$model_names       = $custom_post_types->getCustomPostTypeModelNames($post_type);
692
+			if (isset($model_names[ $post_type ])) {
693
+				$model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
694
+			}
695
+		} else {
696
+			$model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
697
+		}
698
+		if ($model instanceof EEM_Base) {
699
+			$this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
700
+		}
701
+		do_action(
702
+			'AHEE__EE_Admin_Page_CPT__set_model_object__after_set_object',
703
+			$this->_cpt_model_obj,
704
+			$req_type
705
+		);
706
+	}
707
+
708
+
709
+	/**
710
+	 * admin_init_global
711
+	 * This runs all the code that we want executed within the WP admin_init hook.
712
+	 * This method executes for ALL EE Admin pages.
713
+	 *
714
+	 * @return void
715
+	 */
716
+	public function admin_init_global()
717
+	{
718
+		$post_ID = $this->request->getRequestParam('post', 0, DataType::INT);
719
+		// its possible this is a new save so let's catch that instead
720
+		$post_ID        = $this->request->getRequestParam('post_ID', $post_ID, DataType::INT);
721
+		$post           = get_post($post_ID);
722
+		$post_type      = $post instanceof WP_Post ? $post->post_type : false;
723
+		$current_route  = $this->request->getRequestParam('current_route', 'shouldneverwork');
724
+		$route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
725
+			? $this->_cpt_routes[ $current_route ]
726
+			: '';
727
+		add_filter('get_delete_post_link', [$this, 'modify_delete_post_link'], 10, 2);
728
+		add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
729
+		if ($post_type === $route_to_check) {
730
+			add_filter('redirect_post_location', [$this, 'cpt_post_location_redirect'], 10, 2);
731
+		}
732
+		// now let's filter redirect if we're on a revision page and the revision is for an event CPT.
733
+		$revision = $this->request->getRequestParam('revision');
734
+		if (! empty($revision)) {
735
+			$action = $this->request->getRequestParam('action');
736
+			// doing a restore?
737
+			if (! empty($action) && $action === 'restore') {
738
+				// get post for revision
739
+				$rev_post   = get_post($revision);
740
+				$rev_parent = get_post($rev_post->post_parent);
741
+				// only do our redirect filter AND our restore revision action if the post_type for the parent is one of our cpts.
742
+				if ($rev_parent && $rev_parent->post_type === $this->page_slug) {
743
+					add_filter('wp_redirect', [$this, 'revision_redirect']);
744
+					// restores of revisions
745
+					add_action('wp_restore_post_revision', [$this, 'restore_revision'], 10, 2);
746
+				}
747
+			}
748
+		}
749
+		// NOTE we ONLY want to run these hooks if we're on the right class for the given post type.  Otherwise we could see some really freaky things happen!
750
+		if ($post_type && $post_type === $route_to_check) {
751
+			// $post_id, $post
752
+			add_action('save_post', [$this, 'insert_update'], 10, 3);
753
+			// $post_id
754
+			add_action('trashed_post', [$this, 'before_trash_cpt_item']);
755
+			add_action('trashed_post', [$this, 'dont_permanently_delete_ee_cpts']);
756
+			add_action('untrashed_post', [$this, 'before_restore_cpt_item']);
757
+			add_action('after_delete_post', [$this, 'before_delete_cpt_item']);
758
+		}
759
+	}
760
+
761
+
762
+	/**
763
+	 * Callback for the WordPress trashed_post hook.
764
+	 * Execute some basic checks before calling the trash_cpt_item declared in the child class.
765
+	 *
766
+	 * @param int $post_id
767
+	 * @throws EE_Error
768
+	 * @throws ReflectionException
769
+	 */
770
+	public function before_trash_cpt_item(int $post_id)
771
+	{
772
+		$this->_set_model_object($post_id, true, 'trash');
773
+		// if our cpt object isn't existent then get out immediately.
774
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
775
+			return;
776
+		}
777
+		$this->trash_cpt_item($post_id);
778
+	}
779
+
780
+
781
+	/**
782
+	 * Callback for the WordPress untrashed_post hook.
783
+	 * Execute some basic checks before calling the restore_cpt_method in the child class.
784
+	 *
785
+	 * @param $post_id
786
+	 * @throws EE_Error
787
+	 * @throws ReflectionException
788
+	 */
789
+	public function before_restore_cpt_item($post_id)
790
+	{
791
+		$this->_set_model_object($post_id, true, 'restore');
792
+		// if our cpt object isn't existent then get out immediately.
793
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
794
+			return;
795
+		}
796
+		$this->restore_cpt_item($post_id);
797
+	}
798
+
799
+
800
+	/**
801
+	 * Callback for the WordPress after_delete_post hook.
802
+	 * Execute some basic checks before calling the delete_cpt_item method in the child class.
803
+	 *
804
+	 * @param $post_id
805
+	 * @throws EE_Error
806
+	 * @throws ReflectionException
807
+	 */
808
+	public function before_delete_cpt_item($post_id)
809
+	{
810
+		$this->_set_model_object($post_id, true, 'delete');
811
+		// if our cpt object isn't existent then get out immediately.
812
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
813
+			return;
814
+		}
815
+		$this->delete_cpt_item($post_id);
816
+	}
817
+
818
+
819
+	/**
820
+	 * This simply verifies if the cpt_model_object is instantiated for the given page and throws an error message
821
+	 * accordingly.
822
+	 *
823
+	 * @return void
824
+	 * @throws EE_Error
825
+	 * @throws ReflectionException
826
+	 */
827
+	public function verify_cpt_object()
828
+	{
829
+		$label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
830
+		// verify event object
831
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
832
+			throw new EE_Error(
833
+				sprintf(
834
+					esc_html__(
835
+						'Something has gone wrong with the page load because we are unable to set up the object for the %1$s.  This usually happens when the given id for the page route is NOT for the correct custom post type for this page',
836
+						'event_espresso'
837
+					),
838
+					$label
839
+				)
840
+			);
841
+		}
842
+		// if auto-draft then throw an error
843
+		if ($this->_cpt_model_obj->get('status') === 'auto-draft') {
844
+			EE_Error::overwrite_errors();
845
+			EE_Error::add_error(
846
+				sprintf(
847
+					esc_html__(
848
+						'This %1$s was saved without a title, description, or excerpt which means that none of the extra details you added were saved properly.  All autodrafts will show up in the "draft" view of your event list table.  You can delete them from there. Please click the "Add %1$s" button to refresh and restart.',
849
+						'event_espresso'
850
+					),
851
+					$label
852
+				),
853
+				__FILE__,
854
+				__FUNCTION__,
855
+				__LINE__
856
+			);
857
+		}
858
+	}
859
+
860
+
861
+	/**
862
+	 * admin_footer_scripts_global
863
+	 * Anything triggered by the 'admin_print_footer_scripts' WP hook should be put in here. This particular method
864
+	 * will apply on ALL EE_Admin pages.
865
+	 *
866
+	 * @return void
867
+	 */
868
+	public function admin_footer_scripts_global()
869
+	{
870
+		$this->_add_admin_page_ajax_loading_img();
871
+		$this->_add_admin_page_overlay();
872
+	}
873
+
874
+
875
+	/**
876
+	 * add in any global scripts for cpt routes
877
+	 *
878
+	 * @return void
879
+	 */
880
+	public function load_global_scripts_styles()
881
+	{
882
+		parent::load_global_scripts_styles();
883
+		if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
884
+			// setup custom post status object for localize script but only if we've got a cpt object
885
+			$statuses = $this->_cpt_model_obj->get_custom_post_statuses();
886
+			if (! empty($statuses)) {
887
+				// get ALL statuses!
888
+				$statuses = $this->_cpt_model_obj->get_all_post_statuses();
889
+				// setup object
890
+				$ee_cpt_statuses = [];
891
+				foreach ($statuses as $status => $label) {
892
+					$ee_cpt_statuses[ $status ] = [
893
+						'label'      => $label,
894
+						'save_label' => sprintf(
895
+							wp_strip_all_tags(__('Save as %s', 'event_espresso')),
896
+							$label
897
+						),
898
+					];
899
+				}
900
+				wp_localize_script('ee_admin_js', 'eeCPTstatuses', $ee_cpt_statuses);
901
+			}
902
+		}
903
+	}
904
+
905
+
906
+	/**
907
+	 * This is a wrapper for the insert/update routes for cpt items so we can add things that are common to ALL
908
+	 * insert/updates
909
+	 *
910
+	 * @param int     $post_id ID of post being updated
911
+	 * @param WP_Post $post    Post object from WP
912
+	 * @param bool    $update  Whether this is an update or a new save.
913
+	 * @return void
914
+	 * @throws EE_Error
915
+	 * @throws ReflectionException
916
+	 */
917
+	public function insert_update(int $post_id, WP_Post $post, bool $update)
918
+	{
919
+		// make sure that if this is a revision OR trash action that we don't do any updates!
920
+		$action = $this->request->getRequestParam('action');
921
+		if ($action === 'restore' || $action === 'trash') {
922
+			return;
923
+		}
924
+		$this->_set_model_object($post_id, true, 'insert_update');
925
+		// if our cpt object is not instantiated and its NOT the same post_id as what is triggering this callback, then exit.
926
+		if (
927
+			$update
928
+			&& (
929
+				! $this->_cpt_model_obj instanceof EE_CPT_Base
930
+				|| $this->_cpt_model_obj->ID() !== $post_id
931
+			)
932
+		) {
933
+			return;
934
+		}
935
+		// check for autosave and update our req_data property accordingly.
936
+		/*if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE && isset( $this->_req_data['ee_autosave_data'] ) ) {
937 937
             foreach( (array) $this->_req_data['ee_autosave_data'] as $id => $values ) {
938 938
 
939 939
                 foreach ( (array) $values as $key => $value ) {
@@ -943,549 +943,549 @@  discard block
 block discarded – undo
943 943
 
944 944
         }/**/ // TODO reactivate after autosave is implemented in 4.2
945 945
 
946
-        // take care of updating any selected page_template IF this cpt supports it.
947
-
948
-        $page_template = $this->request->getRequestParam('page_template');
949
-        if ($this->_supports_page_templates($post->post_type) && ! empty($page_template)) {
950
-            // wp version aware.
951
-            if (RecommendedVersions::compareWordPressVersion('4.7')) {
952
-                $page_templates = wp_get_theme()->get_page_templates();
953
-            } else {
954
-                $post->page_template = $page_template;
955
-                $page_templates      = wp_get_theme()->get_page_templates($post);
956
-            }
957
-            if ($page_template !== 'default' && ! isset($page_templates[ $page_template ])) {
958
-                EE_Error::add_error(
959
-                    esc_html__('Invalid Page Template.', 'event_espresso'),
960
-                    __FILE__,
961
-                    __FUNCTION__,
962
-                    __LINE__
963
-                );
964
-            } else {
965
-                update_post_meta($post_id, '_wp_page_template', $page_template);
966
-            }
967
-        }
968
-        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
969
-            return;
970
-        } //TODO we'll remove this after reimplementing autosave in 4.2
971
-        $this->_insert_update_cpt_item($post_id, $post);
972
-    }
973
-
974
-
975
-    /**
976
-     * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
977
-     * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
978
-     * so we don't have to check for our CPT.
979
-     *
980
-     * @param int $post_id ID of the post
981
-     * @return void
982
-     */
983
-    public function dont_permanently_delete_ee_cpts(int $post_id)
984
-    {
985
-        // only do this if we're actually processing one of our CPTs
986
-        // if our cpt object isn't existent then get out immediately.
987
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
988
-            return;
989
-        }
990
-        delete_post_meta($post_id, '_wp_trash_meta_status');
991
-        delete_post_meta($post_id, '_wp_trash_meta_time');
992
-        // our cpts may have comments so let's take care of that too
993
-        delete_post_meta($post_id, '_wp_trash_meta_comments_status');
994
-    }
995
-
996
-
997
-    /**
998
-     * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
-     * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
-     * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
-     *
1002
-     * @param int $post_id     ID of cpt item
1003
-     * @param int $revision_id ID of revision being restored
1004
-     * @return void
1005
-     */
1006
-    public function restore_revision(int $post_id, int $revision_id)
1007
-    {
1008
-        $this->_restore_cpt_item($post_id, $revision_id);
1009
-        // global action
1010
-        do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
-        // class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
-    }
1014
-
1015
-
1016
-    /**
1017
-     * @param int $post_id     ID of cpt item
1018
-     * @param int $revision_id ID of revision for item
1019
-     * @return void
1020
-     * @see restore_revision() for details
1021
-     */
1022
-    abstract protected function _restore_cpt_item(int $post_id, int $revision_id);
1023
-
1024
-
1025
-    /**
1026
-     * Execution of this method is added to the end of the load_page_dependencies method in the parent
1027
-     * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1028
-     * To fix we have to reset the current_screen using the page_slug
1029
-     * (which is identical - or should be - to our registered_post_type id.)
1030
-     * Also, since the core WP file loads the admin_header.php for WP
1031
-     * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1032
-     * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1033
-     *
1034
-     * @return void
1035
-     * @throws EE_Error
1036
-     * @throws ReflectionException
1037
-     */
1038
-    public function modify_current_screen()
1039
-    {
1040
-        // ONLY do this if the current page_route IS a cpt route
1041
-        if (! $this->_cpt_route) {
1042
-            return;
1043
-        }
1044
-        // routing things REALLY early b/c this is a cpt admin page
1045
-        set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1046
-        $this->_current_screen       = get_current_screen();
1047
-        $this->_current_screen->base = 'event-espresso';
1048
-        $this->_add_help_tabs(); // we make sure we add any help tabs back in!
1049
-        /*try {
946
+		// take care of updating any selected page_template IF this cpt supports it.
947
+
948
+		$page_template = $this->request->getRequestParam('page_template');
949
+		if ($this->_supports_page_templates($post->post_type) && ! empty($page_template)) {
950
+			// wp version aware.
951
+			if (RecommendedVersions::compareWordPressVersion('4.7')) {
952
+				$page_templates = wp_get_theme()->get_page_templates();
953
+			} else {
954
+				$post->page_template = $page_template;
955
+				$page_templates      = wp_get_theme()->get_page_templates($post);
956
+			}
957
+			if ($page_template !== 'default' && ! isset($page_templates[ $page_template ])) {
958
+				EE_Error::add_error(
959
+					esc_html__('Invalid Page Template.', 'event_espresso'),
960
+					__FILE__,
961
+					__FUNCTION__,
962
+					__LINE__
963
+				);
964
+			} else {
965
+				update_post_meta($post_id, '_wp_page_template', $page_template);
966
+			}
967
+		}
968
+		if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
969
+			return;
970
+		} //TODO we'll remove this after reimplementing autosave in 4.2
971
+		$this->_insert_update_cpt_item($post_id, $post);
972
+	}
973
+
974
+
975
+	/**
976
+	 * This hooks into the wp_trash_post() function and removes the `_wp_trash_meta_status` and `_wp_trash_meta_time`
977
+	 * post meta IF the trashed post is one of our CPT's - note this method should only be called with our cpt routes
978
+	 * so we don't have to check for our CPT.
979
+	 *
980
+	 * @param int $post_id ID of the post
981
+	 * @return void
982
+	 */
983
+	public function dont_permanently_delete_ee_cpts(int $post_id)
984
+	{
985
+		// only do this if we're actually processing one of our CPTs
986
+		// if our cpt object isn't existent then get out immediately.
987
+		if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
988
+			return;
989
+		}
990
+		delete_post_meta($post_id, '_wp_trash_meta_status');
991
+		delete_post_meta($post_id, '_wp_trash_meta_time');
992
+		// our cpts may have comments so let's take care of that too
993
+		delete_post_meta($post_id, '_wp_trash_meta_comments_status');
994
+	}
995
+
996
+
997
+	/**
998
+	 * This is a wrapper for the restore_cpt_revision route for cpt items so we can make sure that when a revision is
999
+	 * triggered that we restore related items.  In order to work cpt classes MUST have a restore_cpt_revision method
1000
+	 * in them. We also have our OWN action in here so addons can hook into the restore process easily.
1001
+	 *
1002
+	 * @param int $post_id     ID of cpt item
1003
+	 * @param int $revision_id ID of revision being restored
1004
+	 * @return void
1005
+	 */
1006
+	public function restore_revision(int $post_id, int $revision_id)
1007
+	{
1008
+		$this->_restore_cpt_item($post_id, $revision_id);
1009
+		// global action
1010
+		do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011
+		// class specific action so you can limit hooking into a specific page.
1012
+		do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1013
+	}
1014
+
1015
+
1016
+	/**
1017
+	 * @param int $post_id     ID of cpt item
1018
+	 * @param int $revision_id ID of revision for item
1019
+	 * @return void
1020
+	 * @see restore_revision() for details
1021
+	 */
1022
+	abstract protected function _restore_cpt_item(int $post_id, int $revision_id);
1023
+
1024
+
1025
+	/**
1026
+	 * Execution of this method is added to the end of the load_page_dependencies method in the parent
1027
+	 * so that we can fix a bug where default core metaboxes were not being called in the sidebar.
1028
+	 * To fix we have to reset the current_screen using the page_slug
1029
+	 * (which is identical - or should be - to our registered_post_type id.)
1030
+	 * Also, since the core WP file loads the admin_header.php for WP
1031
+	 * (and there are a bunch of other things edit-form-advanced.php loads that need to happen really early)
1032
+	 * we need to load it NOW, hence our _route_admin_request in here. (Otherwise screen options won't be set).
1033
+	 *
1034
+	 * @return void
1035
+	 * @throws EE_Error
1036
+	 * @throws ReflectionException
1037
+	 */
1038
+	public function modify_current_screen()
1039
+	{
1040
+		// ONLY do this if the current page_route IS a cpt route
1041
+		if (! $this->_cpt_route) {
1042
+			return;
1043
+		}
1044
+		// routing things REALLY early b/c this is a cpt admin page
1045
+		set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1046
+		$this->_current_screen       = get_current_screen();
1047
+		$this->_current_screen->base = 'event-espresso';
1048
+		$this->_add_help_tabs(); // we make sure we add any help tabs back in!
1049
+		/*try {
1050 1050
             $this->_route_admin_request();
1051 1051
         } catch ( EE_Error $e ) {
1052 1052
             $e->get_error();
1053 1053
         }/**/
1054
-    }
1055
-
1056
-
1057
-    /**
1058
-     * This allows child classes to modify the default editor title that appears when people add a new or edit an
1059
-     * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1060
-     * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1061
-     * default to be.
1062
-     *
1063
-     * @param string|null $title The new title (or existing if there is no editor_title defined)
1064
-     * @return string|null
1065
-     */
1066
-    public function add_custom_editor_default_title(?string $title): ?string
1067
-    {
1068
-        return $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ] ?? $title;
1069
-    }
1070
-
1071
-
1072
-    /**
1073
-     * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1074
-     *
1075
-     * @param string $shortlink   The already generated shortlink
1076
-     * @param int    $id          Post ID for this item
1077
-     * @return string
1078
-     * @deprecated 5.0.0.p
1079
-     * @see EventShortlinkButton::addButton()
1080
-     */
1081
-    public function add_shortlink_button_to_editor(string $shortlink, int $id): string
1082
-    {
1083
-        return EventShortlinkButton::addButton($shortlink, $id);
1084
-    }
1085
-
1086
-
1087
-    /**
1088
-     * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1089
-     * already run in modify_current_screen())
1090
-     *
1091
-     * @return void
1092
-     * @throws EE_Error
1093
-     * @throws ReflectionException
1094
-     * @throws Throwable
1095
-     */
1096
-    public function route_admin_request()
1097
-    {
1098
-        if ($this->_cpt_route) {
1099
-            return;
1100
-        }
1101
-        try {
1102
-            $this->_route_admin_request();
1103
-        } catch (EE_Error $e) {
1104
-            $e->get_error();
1105
-        }
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1111
-     *
1112
-     * @return void
1113
-     */
1114
-    public function cpt_post_form_hidden_input()
1115
-    {
1116
-        // we're also going to add the route value and the current page so we can direct autosave parsing correctly
1117
-        echo '
1054
+	}
1055
+
1056
+
1057
+	/**
1058
+	 * This allows child classes to modify the default editor title that appears when people add a new or edit an
1059
+	 * existing CPT item.     * This uses the _labels property set by the child class via _define_page_props. Just make
1060
+	 * sure you have a key in _labels property that equals 'editor_title' and the value can be whatever you want the
1061
+	 * default to be.
1062
+	 *
1063
+	 * @param string|null $title The new title (or existing if there is no editor_title defined)
1064
+	 * @return string|null
1065
+	 */
1066
+	public function add_custom_editor_default_title(?string $title): ?string
1067
+	{
1068
+		return $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ] ?? $title;
1069
+	}
1070
+
1071
+
1072
+	/**
1073
+	 * hooks into the wp_get_shortlink button and makes sure that the shortlink gets generated
1074
+	 *
1075
+	 * @param string $shortlink   The already generated shortlink
1076
+	 * @param int    $id          Post ID for this item
1077
+	 * @return string
1078
+	 * @deprecated 5.0.0.p
1079
+	 * @see EventShortlinkButton::addButton()
1080
+	 */
1081
+	public function add_shortlink_button_to_editor(string $shortlink, int $id): string
1082
+	{
1083
+		return EventShortlinkButton::addButton($shortlink, $id);
1084
+	}
1085
+
1086
+
1087
+	/**
1088
+	 * overriding the parent route_admin_request method so we DON'T run the route twice on cpt core page loads (it's
1089
+	 * already run in modify_current_screen())
1090
+	 *
1091
+	 * @return void
1092
+	 * @throws EE_Error
1093
+	 * @throws ReflectionException
1094
+	 * @throws Throwable
1095
+	 */
1096
+	public function route_admin_request()
1097
+	{
1098
+		if ($this->_cpt_route) {
1099
+			return;
1100
+		}
1101
+		try {
1102
+			$this->_route_admin_request();
1103
+		} catch (EE_Error $e) {
1104
+			$e->get_error();
1105
+		}
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * Add a hidden form input to cpt core pages so that we know to do redirects to our routes on saves
1111
+	 *
1112
+	 * @return void
1113
+	 */
1114
+	public function cpt_post_form_hidden_input()
1115
+	{
1116
+		// we're also going to add the route value and the current page so we can direct autosave parsing correctly
1117
+		echo '
1118 1118
         <input type="hidden" name="ee_cpt_item_redirect_url" value="' . esc_url_raw($this->_admin_base_url) . '"/>
1119 1119
         <div id="ee-cpt-hidden-inputs">
1120 1120
             <input type="hidden" id="current_route" name="current_route" value="' . esc_attr($this->_current_view) . '"/>
1121 1121
             <input type="hidden" id="current_page" name="current_page" value="' . esc_attr($this->page_slug) . '"/>
1122 1122
         </div>';
1123
-    }
1124
-
1125
-
1126
-    /**
1127
-     * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1128
-     *
1129
-     * @param string $location Original location url
1130
-     * @return string           new (or original) url to redirect to.
1131
-     * @throws EE_Error
1132
-     */
1133
-    public function revision_redirect(string $location): string
1134
-    {
1135
-        // get revision
1136
-        $revision = $this->request->getRequestParam('revision');
1137
-        // can't do anything without revision so let's get out if not present
1138
-        if (empty($revision)) {
1139
-            return $location;
1140
-        }
1141
-        // get rev_post_data
1142
-        $rev        = get_post($revision);
1143
-        $admin_url  = $this->_admin_base_url;
1144
-        $query_args = [
1145
-            'action'   => 'edit',
1146
-            'post'     => $rev->post_parent,
1147
-            'revision' => $revision,
1148
-            'message'  => 5,
1149
-        ];
1150
-        $this->_process_notices($query_args, true);
1151
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $admin_url);
1152
-    }
1153
-
1154
-
1155
-    /**
1156
-     * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1157
-     *
1158
-     * @param string $link    the original generated link
1159
-     * @param int    $id      post id
1160
-     * @return string          the link
1161
-     */
1162
-    public function modify_edit_post_link(string $link, int $id): string
1163
-    {
1164
-        $post = get_post($id);
1165
-        $action = $this->request->getRequestParam('action');
1166
-        if (
1167
-            empty($action)
1168
-            || ! isset($this->_cpt_routes[ $action ])
1169
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1170
-        ) {
1171
-            return $link;
1172
-        }
1173
-        $query_args = [
1174
-            'action' => $this->_cpt_edit_routes[ $post->post_type ] ?? 'edit',
1175
-            'post'   => $id,
1176
-        ];
1177
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1178
-    }
1179
-
1180
-
1181
-    /**
1182
-     * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1183
-     * our routes.
1184
-     *
1185
-     * @param string $delete_link  original delete link
1186
-     * @param int    $post_id      id of cpt object
1187
-     * @return string new delete link
1188
-     * @throws EE_Error
1189
-     * @throws ReflectionException
1190
-     */
1191
-    public function modify_delete_post_link(string $delete_link, int $post_id): string
1192
-    {
1193
-        $post = get_post($post_id);
1194
-        $action = $this->request->getRequestParam('action');
1195
-        if (
1196
-            ! $post instanceof WP_Post
1197
-            || empty($action)
1198
-            || ! isset($this->_cpt_routes[ $action ])
1199
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1200
-        ) {
1201
-            return $delete_link;
1202
-        }
1203
-        $this->_set_model_object($post->ID, true);
1204
-
1205
-        // returns something like `trash_event` or `trash_attendee` or `trash_venue`
1206
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1207
-
1208
-        return EE_Admin_Page::add_query_args_and_nonce(
1209
-            [
1210
-                'page'   => $this->request->getRequestParam('page'),
1211
-                'action' => $action,
1212
-                $this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() => $post->ID,
1213
-            ],
1214
-            admin_url()
1215
-        );
1216
-    }
1217
-
1218
-
1219
-    /**
1220
-     * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1221
-     * so that we can hijack the default redirect locations for wp custom post types
1222
-     * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1223
-     *
1224
-     * @param string $location This is the incoming currently set redirect location
1225
-     * @param string $post_id  This is the 'ID' value of the wp_posts table
1226
-     * @return string           the new location to redirect to
1227
-     * @throws EE_Error
1228
-     */
1229
-    public function cpt_post_location_redirect(string $location, string $post_id): string
1230
-    {
1231
-        // we DO have a match so let's setup the url
1232
-        // we have to get the post to determine our route
1233
-        $post       = get_post($post_id);
1234
-        $edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1235
-        // shared query_args
1236
-        $query_args = ['action' => $edit_route, 'post' => $post_id];
1237
-
1238
-        $save = $this->request->getRequestParam('save');
1239
-        $publish = $this->request->getRequestParam('publish');
1240
-        $add_meta = $this->request->getRequestParam('addmeta');
1241
-        $delete_meta = $this->request->getRequestParam('deletemeta');
1242
-        if ($save || $publish) {
1243
-            $status = get_post_status($post_id);
1244
-            if ($publish) {
1245
-                switch ($status) {
1246
-                    case 'pending':
1247
-                        $message = 8;
1248
-                        break;
1249
-                    case 'future':
1250
-                        $message = 9;
1251
-                        break;
1252
-                    default:
1253
-                        $message = 6;
1254
-                }
1255
-            } else {
1256
-                $message = 'draft' === $status ? 10 : 1;
1257
-            }
1258
-        } elseif ($add_meta) {
1259
-            $message = 2;
1260
-        } elseif ($delete_meta) {
1261
-            $message = 3;
1262
-        } elseif ($this->request->getRequestParam('action') === 'post-quickpress-save-cont') {
1263
-            $message = 7;
1264
-        } else {
1265
-            $message = 4;
1266
-        }
1267
-        // change the message if the post type is not viewable on the frontend
1268
-        $this->_cpt_object = get_post_type_object($post->post_type);
1269
-
1270
-        $query_args['message'] = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1271
-        $this->_process_notices($query_args, true);
1272
-        return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1273
-    }
1274
-
1275
-
1276
-    /**
1277
-     * This method is called to inject nav tabs on core WP cpt pages
1278
-     *
1279
-     * @return void
1280
-     * @throws EE_Error
1281
-     */
1282
-    public function inject_nav_tabs()
1283
-    {
1284
-        echo wp_kses($this->_get_main_nav_tabs(), AllowedTags::getWithFormTags());
1285
-    }
1286
-
1287
-
1288
-    /**
1289
-     * This just sets up the post update messages when an update form is loaded
1290
-     *
1291
-     * @param array $messages the original messages array
1292
-     * @return array           the new messages array
1293
-     */
1294
-    public function post_update_messages(array $messages): array
1295
-    {
1296
-        global $post;
1297
-        $id       = $this->request->getRequestParam('post');
1298
-        $id       = empty($id) && is_object($post) ? $post->ID : null;
1299
-        $revision = $this->request->getRequestParam('revision', 0, 'int');
1300
-
1301
-        $messages[ $post->post_type ] = [
1302
-            0  => '', // Unused. Messages start at index 1.
1303
-            1  => sprintf(
1304
-                esc_html__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1305
-                $this->_cpt_object->labels->singular_name,
1306
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1307
-                '</a>'
1308
-            ),
1309
-            2  => esc_html__('Custom field updated', 'event_espresso'),
1310
-            3  => esc_html__('Custom field deleted.', 'event_espresso'),
1311
-            4  => sprintf(esc_html__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1312
-            5  => $revision
1313
-                ? sprintf(
1314
-                    esc_html__('%s restored to revision from %s', 'event_espresso'),
1315
-                    $this->_cpt_object->labels->singular_name,
1316
-                    wp_post_revision_title($revision, false)
1317
-                )
1318
-                : false,
1319
-            6  => sprintf(
1320
-                esc_html__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1321
-                $this->_cpt_object->labels->singular_name,
1322
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1323
-                '</a>'
1324
-            ),
1325
-            7  => sprintf(esc_html__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1326
-            8  => sprintf(
1327
-                esc_html__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1328
-                $this->_cpt_object->labels->singular_name,
1329
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1330
-                '</a>'
1331
-            ),
1332
-            9  => sprintf(
1333
-                esc_html__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1334
-                $this->_cpt_object->labels->singular_name,
1335
-                '<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1336
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1337
-                '</a>'
1338
-            ),
1339
-            10 => sprintf(
1340
-                esc_html__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1341
-                $this->_cpt_object->labels->singular_name,
1342
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1343
-                '</a>'
1344
-            ),
1345
-        ];
1346
-        return $messages;
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * default method for the 'create_new' route for cpt admin pages.
1352
-     * For reference what to include in here, see wp-admin/post-new.php
1353
-     *
1354
-     * @return void
1355
-     */
1356
-    protected function _create_new_cpt_item()
1357
-    {
1358
-        // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1359
-        global $post, $title, $post_type, $post_type_object;
1360
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1361
-        $post_type_object = $this->_cpt_object;
1362
-        $title            = $post_type_object->labels->add_new_item;
1363
-        $post             = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1364
-        add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1365
-        // modify the default editor title field with default title.
1366
-        add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1367
-        $this->loadEditorTemplate();
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     * Enqueues auto-save and loads the editor template
1373
-     *
1374
-     * @param bool $creating
1375
-     */
1376
-    private function loadEditorTemplate(bool $creating = true)
1377
-    {
1378
-        if ($this->admin_config && ! $this->admin_config->useAdvancedEditor()) {
1379
-            add_filter('admin_body_class', function($classes)
1380
-            {
1381
-                $classes .= ' espresso-legacy-editor';
1382
-                return $classes;
1383
-            });
1384
-        }
1385
-
1386
-        global $post, $title, $is_IE, $post_type, $post_type_object;
1387
-        // these vars are used by the template
1388
-        $editing = true;
1389
-        $post_ID = $post->ID;
1390
-        if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1391
-            // only enqueue autosave when creating event (necessary to get permalink/url generated)
1392
-            // otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1393
-            $action = $this->request->getRequestParam('action');
1394
-            if ($creating) {
1395
-                wp_enqueue_script('autosave');
1396
-            } elseif (
1397
-                isset($this->_cpt_routes[ $action ])
1398
-                && ! isset($this->_labels['hide_add_button_on_cpt_route'][ $action ])
1399
-            ) {
1400
-                $create_new_action = apply_filters(
1401
-                    'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1402
-                    'create_new',
1403
-                    $this
1404
-                );
1405
-                $post_new_file     = EE_Admin_Page::add_query_args_and_nonce(
1406
-                    [
1407
-                        'action' => $create_new_action,
1408
-                        'page'   => $this->page_slug,
1409
-                    ],
1410
-                    'admin.php'
1411
-                );
1412
-            }
1413
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1414
-        }
1415
-    }
1416
-
1417
-
1418
-    public function add_new_admin_page_global()
1419
-    {
1420
-        $admin_page = $this->request->getRequestParam('post', 0, DataType::INT) !== 0
1421
-            ? 'post-php'
1422
-            : 'post-new-php';
1423
-        ?>
1123
+	}
1124
+
1125
+
1126
+	/**
1127
+	 * This allows us to redirect the location of revision restores when they happen so it goes to our CPT routes.
1128
+	 *
1129
+	 * @param string $location Original location url
1130
+	 * @return string           new (or original) url to redirect to.
1131
+	 * @throws EE_Error
1132
+	 */
1133
+	public function revision_redirect(string $location): string
1134
+	{
1135
+		// get revision
1136
+		$revision = $this->request->getRequestParam('revision');
1137
+		// can't do anything without revision so let's get out if not present
1138
+		if (empty($revision)) {
1139
+			return $location;
1140
+		}
1141
+		// get rev_post_data
1142
+		$rev        = get_post($revision);
1143
+		$admin_url  = $this->_admin_base_url;
1144
+		$query_args = [
1145
+			'action'   => 'edit',
1146
+			'post'     => $rev->post_parent,
1147
+			'revision' => $revision,
1148
+			'message'  => 5,
1149
+		];
1150
+		$this->_process_notices($query_args, true);
1151
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $admin_url);
1152
+	}
1153
+
1154
+
1155
+	/**
1156
+	 * Modify the edit post link generated by wp core function so that EE CPTs get setup differently.
1157
+	 *
1158
+	 * @param string $link    the original generated link
1159
+	 * @param int    $id      post id
1160
+	 * @return string          the link
1161
+	 */
1162
+	public function modify_edit_post_link(string $link, int $id): string
1163
+	{
1164
+		$post = get_post($id);
1165
+		$action = $this->request->getRequestParam('action');
1166
+		if (
1167
+			empty($action)
1168
+			|| ! isset($this->_cpt_routes[ $action ])
1169
+			|| $post->post_type !== $this->_cpt_routes[ $action ]
1170
+		) {
1171
+			return $link;
1172
+		}
1173
+		$query_args = [
1174
+			'action' => $this->_cpt_edit_routes[ $post->post_type ] ?? 'edit',
1175
+			'post'   => $id,
1176
+		];
1177
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1178
+	}
1179
+
1180
+
1181
+	/**
1182
+	 * Modify the trash link on our cpt edit pages so it has the required query var for triggering redirect properly on
1183
+	 * our routes.
1184
+	 *
1185
+	 * @param string $delete_link  original delete link
1186
+	 * @param int    $post_id      id of cpt object
1187
+	 * @return string new delete link
1188
+	 * @throws EE_Error
1189
+	 * @throws ReflectionException
1190
+	 */
1191
+	public function modify_delete_post_link(string $delete_link, int $post_id): string
1192
+	{
1193
+		$post = get_post($post_id);
1194
+		$action = $this->request->getRequestParam('action');
1195
+		if (
1196
+			! $post instanceof WP_Post
1197
+			|| empty($action)
1198
+			|| ! isset($this->_cpt_routes[ $action ])
1199
+			|| $post->post_type !== $this->_cpt_routes[ $action ]
1200
+		) {
1201
+			return $delete_link;
1202
+		}
1203
+		$this->_set_model_object($post->ID, true);
1204
+
1205
+		// returns something like `trash_event` or `trash_attendee` or `trash_venue`
1206
+		$action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1207
+
1208
+		return EE_Admin_Page::add_query_args_and_nonce(
1209
+			[
1210
+				'page'   => $this->request->getRequestParam('page'),
1211
+				'action' => $action,
1212
+				$this->_cpt_model_obj->get_model()->get_primary_key_field()->get_name() => $post->ID,
1213
+			],
1214
+			admin_url()
1215
+		);
1216
+	}
1217
+
1218
+
1219
+	/**
1220
+	 * This is the callback for the 'redirect_post_location' filter in wp-admin/post.php
1221
+	 * so that we can hijack the default redirect locations for wp custom post types
1222
+	 * that WE'RE using and send back to OUR routes.  This should only be hooked in on the right route.
1223
+	 *
1224
+	 * @param string $location This is the incoming currently set redirect location
1225
+	 * @param string $post_id  This is the 'ID' value of the wp_posts table
1226
+	 * @return string           the new location to redirect to
1227
+	 * @throws EE_Error
1228
+	 */
1229
+	public function cpt_post_location_redirect(string $location, string $post_id): string
1230
+	{
1231
+		// we DO have a match so let's setup the url
1232
+		// we have to get the post to determine our route
1233
+		$post       = get_post($post_id);
1234
+		$edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1235
+		// shared query_args
1236
+		$query_args = ['action' => $edit_route, 'post' => $post_id];
1237
+
1238
+		$save = $this->request->getRequestParam('save');
1239
+		$publish = $this->request->getRequestParam('publish');
1240
+		$add_meta = $this->request->getRequestParam('addmeta');
1241
+		$delete_meta = $this->request->getRequestParam('deletemeta');
1242
+		if ($save || $publish) {
1243
+			$status = get_post_status($post_id);
1244
+			if ($publish) {
1245
+				switch ($status) {
1246
+					case 'pending':
1247
+						$message = 8;
1248
+						break;
1249
+					case 'future':
1250
+						$message = 9;
1251
+						break;
1252
+					default:
1253
+						$message = 6;
1254
+				}
1255
+			} else {
1256
+				$message = 'draft' === $status ? 10 : 1;
1257
+			}
1258
+		} elseif ($add_meta) {
1259
+			$message = 2;
1260
+		} elseif ($delete_meta) {
1261
+			$message = 3;
1262
+		} elseif ($this->request->getRequestParam('action') === 'post-quickpress-save-cont') {
1263
+			$message = 7;
1264
+		} else {
1265
+			$message = 4;
1266
+		}
1267
+		// change the message if the post type is not viewable on the frontend
1268
+		$this->_cpt_object = get_post_type_object($post->post_type);
1269
+
1270
+		$query_args['message'] = $message === 1 && ! $this->_cpt_object->publicly_queryable ? 4 : $message;
1271
+		$this->_process_notices($query_args, true);
1272
+		return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
1273
+	}
1274
+
1275
+
1276
+	/**
1277
+	 * This method is called to inject nav tabs on core WP cpt pages
1278
+	 *
1279
+	 * @return void
1280
+	 * @throws EE_Error
1281
+	 */
1282
+	public function inject_nav_tabs()
1283
+	{
1284
+		echo wp_kses($this->_get_main_nav_tabs(), AllowedTags::getWithFormTags());
1285
+	}
1286
+
1287
+
1288
+	/**
1289
+	 * This just sets up the post update messages when an update form is loaded
1290
+	 *
1291
+	 * @param array $messages the original messages array
1292
+	 * @return array           the new messages array
1293
+	 */
1294
+	public function post_update_messages(array $messages): array
1295
+	{
1296
+		global $post;
1297
+		$id       = $this->request->getRequestParam('post');
1298
+		$id       = empty($id) && is_object($post) ? $post->ID : null;
1299
+		$revision = $this->request->getRequestParam('revision', 0, 'int');
1300
+
1301
+		$messages[ $post->post_type ] = [
1302
+			0  => '', // Unused. Messages start at index 1.
1303
+			1  => sprintf(
1304
+				esc_html__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1305
+				$this->_cpt_object->labels->singular_name,
1306
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1307
+				'</a>'
1308
+			),
1309
+			2  => esc_html__('Custom field updated', 'event_espresso'),
1310
+			3  => esc_html__('Custom field deleted.', 'event_espresso'),
1311
+			4  => sprintf(esc_html__('%1$s updated.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1312
+			5  => $revision
1313
+				? sprintf(
1314
+					esc_html__('%s restored to revision from %s', 'event_espresso'),
1315
+					$this->_cpt_object->labels->singular_name,
1316
+					wp_post_revision_title($revision, false)
1317
+				)
1318
+				: false,
1319
+			6  => sprintf(
1320
+				esc_html__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1321
+				$this->_cpt_object->labels->singular_name,
1322
+				'<a href="' . esc_url(get_permalink($id)) . '">',
1323
+				'</a>'
1324
+			),
1325
+			7  => sprintf(esc_html__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1326
+			8  => sprintf(
1327
+				esc_html__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1328
+				$this->_cpt_object->labels->singular_name,
1329
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1330
+				'</a>'
1331
+			),
1332
+			9  => sprintf(
1333
+				esc_html__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1334
+				$this->_cpt_object->labels->singular_name,
1335
+				'<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1336
+				'<a target="_blank" href="' . esc_url(get_permalink($id)),
1337
+				'</a>'
1338
+			),
1339
+			10 => sprintf(
1340
+				esc_html__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1341
+				$this->_cpt_object->labels->singular_name,
1342
+				'<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1343
+				'</a>'
1344
+			),
1345
+		];
1346
+		return $messages;
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * default method for the 'create_new' route for cpt admin pages.
1352
+	 * For reference what to include in here, see wp-admin/post-new.php
1353
+	 *
1354
+	 * @return void
1355
+	 */
1356
+	protected function _create_new_cpt_item()
1357
+	{
1358
+		// gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1359
+		global $post, $title, $post_type, $post_type_object;
1360
+		$post_type        = $this->_cpt_routes[ $this->_req_action ];
1361
+		$post_type_object = $this->_cpt_object;
1362
+		$title            = $post_type_object->labels->add_new_item;
1363
+		$post             = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1364
+		add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1365
+		// modify the default editor title field with default title.
1366
+		add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1367
+		$this->loadEditorTemplate();
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 * Enqueues auto-save and loads the editor template
1373
+	 *
1374
+	 * @param bool $creating
1375
+	 */
1376
+	private function loadEditorTemplate(bool $creating = true)
1377
+	{
1378
+		if ($this->admin_config && ! $this->admin_config->useAdvancedEditor()) {
1379
+			add_filter('admin_body_class', function($classes)
1380
+			{
1381
+				$classes .= ' espresso-legacy-editor';
1382
+				return $classes;
1383
+			});
1384
+		}
1385
+
1386
+		global $post, $title, $is_IE, $post_type, $post_type_object;
1387
+		// these vars are used by the template
1388
+		$editing = true;
1389
+		$post_ID = $post->ID;
1390
+		if (apply_filters('FHEE__EE_Admin_Page_CPT___create_new_cpt_item__replace_editor', false, $post) === false) {
1391
+			// only enqueue autosave when creating event (necessary to get permalink/url generated)
1392
+			// otherwise EE doesn't support autosave fully, so to prevent user confusion we disable it in edit context.
1393
+			$action = $this->request->getRequestParam('action');
1394
+			if ($creating) {
1395
+				wp_enqueue_script('autosave');
1396
+			} elseif (
1397
+				isset($this->_cpt_routes[ $action ])
1398
+				&& ! isset($this->_labels['hide_add_button_on_cpt_route'][ $action ])
1399
+			) {
1400
+				$create_new_action = apply_filters(
1401
+					'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1402
+					'create_new',
1403
+					$this
1404
+				);
1405
+				$post_new_file     = EE_Admin_Page::add_query_args_and_nonce(
1406
+					[
1407
+						'action' => $create_new_action,
1408
+						'page'   => $this->page_slug,
1409
+					],
1410
+					'admin.php'
1411
+				);
1412
+			}
1413
+			include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1414
+		}
1415
+	}
1416
+
1417
+
1418
+	public function add_new_admin_page_global()
1419
+	{
1420
+		$admin_page = $this->request->getRequestParam('post', 0, DataType::INT) !== 0
1421
+			? 'post-php'
1422
+			: 'post-new-php';
1423
+		?>
1424 1424
         <script type="text/javascript">
1425 1425
             adminpage = '<?php echo esc_js($admin_page); ?>';
1426 1426
         </script>
1427 1427
         <?php
1428
-    }
1429
-
1430
-
1431
-    /**
1432
-     * default method for the 'edit' route for cpt admin pages
1433
-     * For reference on what to put in here, refer to wp-admin/post.php
1434
-     *
1435
-     * @return void
1436
-     */
1437
-    protected function _edit_cpt_item()
1438
-    {
1439
-        global $post, $post_type, $post_type_object, $title;
1440
-        $post_id = $this->request->getRequestParam('post', 0, DataType::INT);
1441
-        $post    = $post_id ? get_post($post_id, OBJECT, 'edit') : null;
1442
-        if (empty($post)) {
1443
-            wp_die(
1444
-                esc_html__(
1445
-                    "You attempted to edit an item that doesn't exist. Perhaps it was deleted?",
1446
-                    'event_espresso'
1447
-                )
1448
-            );
1449
-        }
1450
-
1451
-        $post_lock = $this->request->getRequestParam('get-post-lock');
1452
-        if ($post_lock) {
1453
-            wp_set_post_lock($post_id);
1454
-            EEH_URL::safeRedirectAndExit(get_edit_post_link($post_id, 'url'));
1455
-        }
1456
-
1457
-        // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1458
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1459
-        $post_type_object = $this->_cpt_object;
1460
-        $title = $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1461
-                 ?? $post_type_object->labels->edit_item;
1462
-
1463
-        if (! wp_check_post_lock($post->ID)) {
1464
-            wp_set_post_lock($post->ID);
1465
-        }
1466
-        add_action('admin_footer', '_admin_notice_post_locked');
1467
-        if (post_type_supports($this->_cpt_routes[ $this->_req_action ], 'comments')) {
1468
-            wp_enqueue_script('admin-comments');
1469
-            enqueue_comment_hotkeys_js();
1470
-        }
1471
-        add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1472
-        // modify the default editor title field with default title.
1473
-        add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1474
-        $this->loadEditorTemplate(false);
1475
-    }
1476
-
1477
-
1478
-
1479
-    /**
1480
-     * some getters
1481
-     */
1482
-    /**
1483
-     * This returns the protected _cpt_model_obj property
1484
-     *
1485
-     * @return EE_CPT_Base|null
1486
-     */
1487
-    public function get_cpt_model_obj(): ?EE_CPT_Base
1488
-    {
1489
-        return $this->_cpt_model_obj;
1490
-    }
1428
+	}
1429
+
1430
+
1431
+	/**
1432
+	 * default method for the 'edit' route for cpt admin pages
1433
+	 * For reference on what to put in here, refer to wp-admin/post.php
1434
+	 *
1435
+	 * @return void
1436
+	 */
1437
+	protected function _edit_cpt_item()
1438
+	{
1439
+		global $post, $post_type, $post_type_object, $title;
1440
+		$post_id = $this->request->getRequestParam('post', 0, DataType::INT);
1441
+		$post    = $post_id ? get_post($post_id, OBJECT, 'edit') : null;
1442
+		if (empty($post)) {
1443
+			wp_die(
1444
+				esc_html__(
1445
+					"You attempted to edit an item that doesn't exist. Perhaps it was deleted?",
1446
+					'event_espresso'
1447
+				)
1448
+			);
1449
+		}
1450
+
1451
+		$post_lock = $this->request->getRequestParam('get-post-lock');
1452
+		if ($post_lock) {
1453
+			wp_set_post_lock($post_id);
1454
+			EEH_URL::safeRedirectAndExit(get_edit_post_link($post_id, 'url'));
1455
+		}
1456
+
1457
+		// template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1458
+		$post_type        = $this->_cpt_routes[ $this->_req_action ];
1459
+		$post_type_object = $this->_cpt_object;
1460
+		$title = $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1461
+				 ?? $post_type_object->labels->edit_item;
1462
+
1463
+		if (! wp_check_post_lock($post->ID)) {
1464
+			wp_set_post_lock($post->ID);
1465
+		}
1466
+		add_action('admin_footer', '_admin_notice_post_locked');
1467
+		if (post_type_supports($this->_cpt_routes[ $this->_req_action ], 'comments')) {
1468
+			wp_enqueue_script('admin-comments');
1469
+			enqueue_comment_hotkeys_js();
1470
+		}
1471
+		add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1472
+		// modify the default editor title field with default title.
1473
+		add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
1474
+		$this->loadEditorTemplate(false);
1475
+	}
1476
+
1477
+
1478
+
1479
+	/**
1480
+	 * some getters
1481
+	 */
1482
+	/**
1483
+	 * This returns the protected _cpt_model_obj property
1484
+	 *
1485
+	 * @return EE_CPT_Base|null
1486
+	 */
1487
+	public function get_cpt_model_obj(): ?EE_CPT_Base
1488
+	{
1489
+		return $this->_cpt_model_obj;
1490
+	}
1491 1491
 }
Please login to merge, or discard this patch.
Spacing   +69 added lines, -69 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
      *
93 93
      * @var array
94 94
      */
95
-    protected array $_pagenow_map= [];
95
+    protected array $_pagenow_map = [];
96 96
 
97 97
 
98 98
     /**
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
      */
156 156
     protected function getLoader(): LoaderInterface
157 157
     {
158
-        if (! $this->loader instanceof LoaderInterface) {
158
+        if ( ! $this->loader instanceof LoaderInterface) {
159 159
             $this->loader = LoaderFactory::getLoader();
160 160
         }
161 161
         return $this->loader;
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
             ],
180 180
             $this->_cpt_routes
181 181
         );
182
-        $cpt_route_action     = $this->_cpt_routes[ $this->raw_req_action ] ?? null;
182
+        $cpt_route_action = $this->_cpt_routes[$this->raw_req_action] ?? null;
183 183
         // let's see if the current route has a value for cpt_object_slug. if it does, we use that instead of the page
184 184
         $page              = $this->raw_req_page ?: $this->page_slug;
185 185
         $page              = $cpt_route_action ?: $page;
@@ -211,10 +211,10 @@  discard block
 block discarded – undo
211 211
         // possibly reset pagenow.
212 212
         if (
213 213
             $this->page_slug === $this->raw_req_page
214
-            && isset($this->_pagenow_map[ $this->raw_req_action ])
214
+            && isset($this->_pagenow_map[$this->raw_req_action])
215 215
         ) {
216 216
             global $pagenow, $hook_suffix;
217
-            $pagenow     = $this->_pagenow_map[ $this->raw_req_action ];
217
+            $pagenow     = $this->_pagenow_map[$this->raw_req_action];
218 218
             $hook_suffix = $pagenow;
219 219
         }
220 220
     }
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
         if (empty($wp_meta_boxes)) {
247 247
             return;
248 248
         }
249
-        $current_metaboxes = $wp_meta_boxes[ $this->page_slug ] ?? [];
249
+        $current_metaboxes = $wp_meta_boxes[$this->page_slug] ?? [];
250 250
         foreach ($current_metaboxes as $box_context) {
251 251
             foreach ($box_context as $box_details) {
252 252
                 foreach ($box_details as $box) {
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
             $this
281 281
         );
282 282
         $containers = apply_filters(
283
-            'FHEE__EE_Admin_Page_CPT__' . get_class($this) . '___load_autosave_scripts_styles__containers',
283
+            'FHEE__EE_Admin_Page_CPT__'.get_class($this).'___load_autosave_scripts_styles__containers',
284 284
             $containers,
285 285
             $this
286 286
         );
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
     protected function _load_page_dependencies()
319 319
     {
320 320
         // we only add stuff if this is a cpt_route!
321
-        if (! $this->_cpt_route) {
321
+        if ( ! $this->_cpt_route) {
322 322
             parent::_load_page_dependencies();
323 323
             return;
324 324
         }
@@ -339,8 +339,8 @@  discard block
 block discarded – undo
339 339
         add_action('post_updated_messages', [$this, 'post_update_messages']);
340 340
         // This basically allows us to change the title of the "publish" metabox area
341 341
         // on CPT pages by setting a 'publishbox' value in the $_labels property array in the child class.
342
-        $screen = $this->_cpt_routes[ $this->_req_action ];
343
-        if (! empty($this->_labels['publishbox'])) {
342
+        $screen = $this->_cpt_routes[$this->_req_action];
343
+        if ( ! empty($this->_labels['publishbox'])) {
344 344
             $this->addMetaBox(
345 345
                 'submitdiv',
346 346
                 $this->getPublishBoxTitle(),
@@ -388,8 +388,8 @@  discard block
 block discarded – undo
388 388
         // This is for any plugins that are doing things properly
389 389
         // and hooking into the load page hook for core wp cpt routes.
390 390
         global $pagenow;
391
-        add_action('load-' . $pagenow, [$this, 'modify_current_screen'], 20);
392
-        do_action('load-' . $pagenow);
391
+        add_action('load-'.$pagenow, [$this, 'modify_current_screen'], 20);
392
+        do_action('load-'.$pagenow);
393 393
         add_action('admin_enqueue_scripts', [$this, 'setup_autosave_hooks'], 30);
394 394
         // we route REALLY early.
395 395
         try {
@@ -416,8 +416,8 @@  discard block
 block discarded – undo
416 416
                 'admin.php?page=espresso_registrations&action=contact_list',
417 417
             ],
418 418
             1 => [
419
-                'edit.php?post_type=' . $this->_cpt_object->name,
420
-                'admin.php?page=' . $this->_cpt_object->name,
419
+                'edit.php?post_type='.$this->_cpt_object->name,
420
+                'admin.php?page='.$this->_cpt_object->name,
421 421
             ],
422 422
         ];
423 423
         foreach ($routes_to_match as $route_matches) {
@@ -446,14 +446,14 @@  discard block
 block discarded – undo
446 446
             'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
447 447
         );
448 448
         $cpt_args          = $custom_post_types->getDefinitions();
449
-        $cpt_args          = isset($cpt_args[ $cpt_name ]) ? $cpt_args[ $cpt_name ]['args'] : [];
449
+        $cpt_args          = isset($cpt_args[$cpt_name]) ? $cpt_args[$cpt_name]['args'] : [];
450 450
         $cpt_has_support   = ! empty($cpt_args['page_templates']);
451 451
 
452 452
         $post_templates = wp_get_theme()->get_post_templates();
453 453
         // if there are $post_templates for this cpt, then we return false for this method because
454 454
         // that means we aren't going to load our page template manager and leave that up to the native
455 455
         // cpt template manager.
456
-        return ! isset($post_templates[ $cpt_name ]) ? $cpt_has_support : false;
456
+        return ! isset($post_templates[$cpt_name]) ? $cpt_has_support : false;
457 457
     }
458 458
 
459 459
 
@@ -511,7 +511,7 @@  discard block
 block discarded – undo
511 511
     {
512 512
         $statuses         = $this->_cpt_model_obj->get_custom_post_statuses();
513 513
         $cur_status_label = array_key_exists($this->_cpt_model_obj->status(), $statuses)
514
-            ? $statuses[ $this->_cpt_model_obj->status() ]
514
+            ? $statuses[$this->_cpt_model_obj->status()]
515 515
             : '';
516 516
         $template_args    = [
517 517
             'cur_status'            => $this->_cpt_model_obj->status(),
@@ -526,7 +526,7 @@  discard block
 block discarded – undo
526 526
             $template_args['statuses']         = $statuses;
527 527
         }
528 528
 
529
-        $template = EE_ADMIN_TEMPLATE . 'status_dropdown.template.php';
529
+        $template = EE_ADMIN_TEMPLATE.'status_dropdown.template.php';
530 530
         EEH_Template::display_template($template, $template_args);
531 531
     }
532 532
 
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
         $nonce = $this->request->getRequestParam('autosavenonce');
567 567
         $this->_verify_nonce($nonce, 'autosave');
568 568
         // make sure we define doing autosave (cause WP isn't triggering this we want to make sure we define it)
569
-        if (! defined('DOING_AUTOSAVE')) {
569
+        if ( ! defined('DOING_AUTOSAVE')) {
570 570
             define('DOING_AUTOSAVE', true);
571 571
         }
572 572
         // if we made it here then the nonce checked out.  Let's run our methods and actions
@@ -577,7 +577,7 @@  discard block
 block discarded – undo
577 577
             $this->_template_args['success'] = true;
578 578
         }
579 579
         do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__global_after', $this);
580
-        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_' . get_class($this), $this);
580
+        do_action('AHEE__EE_Admin_Page_CPT__do_extra_autosave_stuff__after_'.get_class($this), $this);
581 581
         // now let's return json
582 582
         $this->_return_json();
583 583
     }
@@ -599,7 +599,7 @@  discard block
 block discarded – undo
599 599
             return;
600 600
         }
601 601
         // set page routes and page config but ONLY if we're not viewing a custom setup cpt route as defined in _cpt_routes
602
-        if (! empty($this->_cpt_object)) {
602
+        if ( ! empty($this->_cpt_object)) {
603 603
             $this->_page_routes = array_merge(
604 604
                 [
605 605
                     'create_new' => [$this, '_create_new_cpt_item'],
@@ -630,7 +630,7 @@  discard block
 block discarded – undo
630 630
             );
631 631
         }
632 632
         // load the next section only if this is a matching cpt route as set in the cpt routes array.
633
-        if (! isset($this->_cpt_routes[ $this->_req_action ])) {
633
+        if ( ! isset($this->_cpt_routes[$this->_req_action])) {
634 634
             return;
635 635
         }
636 636
         $this->_cpt_route = true;
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
             empty($this->_cpt_model_names)
672 672
             || (
673 673
                 ! $ignore_route_check
674
-                && ! isset($this->_cpt_routes[ $this->_req_action ])
674
+                && ! isset($this->_cpt_routes[$this->_req_action])
675 675
             )
676 676
             || (
677 677
                 $this->_cpt_model_obj instanceof EE_CPT_Base
@@ -689,11 +689,11 @@  discard block
 block discarded – undo
689 689
                 'EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions'
690 690
             );
691 691
             $model_names       = $custom_post_types->getCustomPostTypeModelNames($post_type);
692
-            if (isset($model_names[ $post_type ])) {
693
-                $model = EE_Registry::instance()->load_model($model_names[ $post_type ]);
692
+            if (isset($model_names[$post_type])) {
693
+                $model = EE_Registry::instance()->load_model($model_names[$post_type]);
694 694
             }
695 695
         } else {
696
-            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[ $this->_req_action ]);
696
+            $model = EE_Registry::instance()->load_model($this->_cpt_model_names[$this->_req_action]);
697 697
         }
698 698
         if ($model instanceof EEM_Base) {
699 699
             $this->_cpt_model_obj = ! empty($id) ? $model->get_one_by_ID($id) : $model->create_default_object();
@@ -721,8 +721,8 @@  discard block
 block discarded – undo
721 721
         $post           = get_post($post_ID);
722 722
         $post_type      = $post instanceof WP_Post ? $post->post_type : false;
723 723
         $current_route  = $this->request->getRequestParam('current_route', 'shouldneverwork');
724
-        $route_to_check = $post_type && isset($this->_cpt_routes[ $current_route ])
725
-            ? $this->_cpt_routes[ $current_route ]
724
+        $route_to_check = $post_type && isset($this->_cpt_routes[$current_route])
725
+            ? $this->_cpt_routes[$current_route]
726 726
             : '';
727 727
         add_filter('get_delete_post_link', [$this, 'modify_delete_post_link'], 10, 2);
728 728
         add_filter('get_edit_post_link', [$this, 'modify_edit_post_link'], 10, 2);
@@ -731,10 +731,10 @@  discard block
 block discarded – undo
731 731
         }
732 732
         // now let's filter redirect if we're on a revision page and the revision is for an event CPT.
733 733
         $revision = $this->request->getRequestParam('revision');
734
-        if (! empty($revision)) {
734
+        if ( ! empty($revision)) {
735 735
             $action = $this->request->getRequestParam('action');
736 736
             // doing a restore?
737
-            if (! empty($action) && $action === 'restore') {
737
+            if ( ! empty($action) && $action === 'restore') {
738 738
                 // get post for revision
739 739
                 $rev_post   = get_post($revision);
740 740
                 $rev_parent = get_post($rev_post->post_parent);
@@ -771,7 +771,7 @@  discard block
 block discarded – undo
771 771
     {
772 772
         $this->_set_model_object($post_id, true, 'trash');
773 773
         // if our cpt object isn't existent then get out immediately.
774
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
774
+        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
775 775
             return;
776 776
         }
777 777
         $this->trash_cpt_item($post_id);
@@ -790,7 +790,7 @@  discard block
 block discarded – undo
790 790
     {
791 791
         $this->_set_model_object($post_id, true, 'restore');
792 792
         // if our cpt object isn't existent then get out immediately.
793
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
793
+        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
794 794
             return;
795 795
         }
796 796
         $this->restore_cpt_item($post_id);
@@ -809,7 +809,7 @@  discard block
 block discarded – undo
809 809
     {
810 810
         $this->_set_model_object($post_id, true, 'delete');
811 811
         // if our cpt object isn't existent then get out immediately.
812
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
812
+        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base || $this->_cpt_model_obj->ID() !== $post_id) {
813 813
             return;
814 814
         }
815 815
         $this->delete_cpt_item($post_id);
@@ -828,7 +828,7 @@  discard block
 block discarded – undo
828 828
     {
829 829
         $label = ! empty($this->_cpt_object) ? $this->_cpt_object->labels->singular_name : $this->page_label;
830 830
         // verify event object
831
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
831
+        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
832 832
             throw new EE_Error(
833 833
                 sprintf(
834 834
                     esc_html__(
@@ -883,13 +883,13 @@  discard block
 block discarded – undo
883 883
         if ($this->_cpt_model_obj instanceof EE_CPT_Base) {
884 884
             // setup custom post status object for localize script but only if we've got a cpt object
885 885
             $statuses = $this->_cpt_model_obj->get_custom_post_statuses();
886
-            if (! empty($statuses)) {
886
+            if ( ! empty($statuses)) {
887 887
                 // get ALL statuses!
888 888
                 $statuses = $this->_cpt_model_obj->get_all_post_statuses();
889 889
                 // setup object
890 890
                 $ee_cpt_statuses = [];
891 891
                 foreach ($statuses as $status => $label) {
892
-                    $ee_cpt_statuses[ $status ] = [
892
+                    $ee_cpt_statuses[$status] = [
893 893
                         'label'      => $label,
894 894
                         'save_label' => sprintf(
895 895
                             wp_strip_all_tags(__('Save as %s', 'event_espresso')),
@@ -954,7 +954,7 @@  discard block
 block discarded – undo
954 954
                 $post->page_template = $page_template;
955 955
                 $page_templates      = wp_get_theme()->get_page_templates($post);
956 956
             }
957
-            if ($page_template !== 'default' && ! isset($page_templates[ $page_template ])) {
957
+            if ($page_template !== 'default' && ! isset($page_templates[$page_template])) {
958 958
                 EE_Error::add_error(
959 959
                     esc_html__('Invalid Page Template.', 'event_espresso'),
960 960
                     __FILE__,
@@ -984,7 +984,7 @@  discard block
 block discarded – undo
984 984
     {
985 985
         // only do this if we're actually processing one of our CPTs
986 986
         // if our cpt object isn't existent then get out immediately.
987
-        if (! $this->_cpt_model_obj instanceof EE_CPT_Base) {
987
+        if ( ! $this->_cpt_model_obj instanceof EE_CPT_Base) {
988 988
             return;
989 989
         }
990 990
         delete_post_meta($post_id, '_wp_trash_meta_status');
@@ -1009,7 +1009,7 @@  discard block
 block discarded – undo
1009 1009
         // global action
1010 1010
         do_action('AHEE_EE_Admin_Page_CPT__restore_revision', $post_id, $revision_id);
1011 1011
         // class specific action so you can limit hooking into a specific page.
1012
-        do_action('AHEE_EE_Admin_Page_CPT_' . get_class($this) . '__restore_revision', $post_id, $revision_id);
1012
+        do_action('AHEE_EE_Admin_Page_CPT_'.get_class($this).'__restore_revision', $post_id, $revision_id);
1013 1013
     }
1014 1014
 
1015 1015
 
@@ -1038,11 +1038,11 @@  discard block
 block discarded – undo
1038 1038
     public function modify_current_screen()
1039 1039
     {
1040 1040
         // ONLY do this if the current page_route IS a cpt route
1041
-        if (! $this->_cpt_route) {
1041
+        if ( ! $this->_cpt_route) {
1042 1042
             return;
1043 1043
         }
1044 1044
         // routing things REALLY early b/c this is a cpt admin page
1045
-        set_current_screen($this->_cpt_routes[ $this->_req_action ]);
1045
+        set_current_screen($this->_cpt_routes[$this->_req_action]);
1046 1046
         $this->_current_screen       = get_current_screen();
1047 1047
         $this->_current_screen->base = 'event-espresso';
1048 1048
         $this->_add_help_tabs(); // we make sure we add any help tabs back in!
@@ -1065,7 +1065,7 @@  discard block
 block discarded – undo
1065 1065
      */
1066 1066
     public function add_custom_editor_default_title(?string $title): ?string
1067 1067
     {
1068
-        return $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ] ?? $title;
1068
+        return $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]] ?? $title;
1069 1069
     }
1070 1070
 
1071 1071
 
@@ -1115,10 +1115,10 @@  discard block
 block discarded – undo
1115 1115
     {
1116 1116
         // we're also going to add the route value and the current page so we can direct autosave parsing correctly
1117 1117
         echo '
1118
-        <input type="hidden" name="ee_cpt_item_redirect_url" value="' . esc_url_raw($this->_admin_base_url) . '"/>
1118
+        <input type="hidden" name="ee_cpt_item_redirect_url" value="' . esc_url_raw($this->_admin_base_url).'"/>
1119 1119
         <div id="ee-cpt-hidden-inputs">
1120
-            <input type="hidden" id="current_route" name="current_route" value="' . esc_attr($this->_current_view) . '"/>
1121
-            <input type="hidden" id="current_page" name="current_page" value="' . esc_attr($this->page_slug) . '"/>
1120
+            <input type="hidden" id="current_route" name="current_route" value="' . esc_attr($this->_current_view).'"/>
1121
+            <input type="hidden" id="current_page" name="current_page" value="' . esc_attr($this->page_slug).'"/>
1122 1122
         </div>';
1123 1123
     }
1124 1124
 
@@ -1165,13 +1165,13 @@  discard block
 block discarded – undo
1165 1165
         $action = $this->request->getRequestParam('action');
1166 1166
         if (
1167 1167
             empty($action)
1168
-            || ! isset($this->_cpt_routes[ $action ])
1169
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1168
+            || ! isset($this->_cpt_routes[$action])
1169
+            || $post->post_type !== $this->_cpt_routes[$action]
1170 1170
         ) {
1171 1171
             return $link;
1172 1172
         }
1173 1173
         $query_args = [
1174
-            'action' => $this->_cpt_edit_routes[ $post->post_type ] ?? 'edit',
1174
+            'action' => $this->_cpt_edit_routes[$post->post_type] ?? 'edit',
1175 1175
             'post'   => $id,
1176 1176
         ];
1177 1177
         return EE_Admin_Page_CPT::add_query_args_and_nonce($query_args, $this->_admin_base_url);
@@ -1195,15 +1195,15 @@  discard block
 block discarded – undo
1195 1195
         if (
1196 1196
             ! $post instanceof WP_Post
1197 1197
             || empty($action)
1198
-            || ! isset($this->_cpt_routes[ $action ])
1199
-            || $post->post_type !== $this->_cpt_routes[ $action ]
1198
+            || ! isset($this->_cpt_routes[$action])
1199
+            || $post->post_type !== $this->_cpt_routes[$action]
1200 1200
         ) {
1201 1201
             return $delete_link;
1202 1202
         }
1203 1203
         $this->_set_model_object($post->ID, true);
1204 1204
 
1205 1205
         // returns something like `trash_event` or `trash_attendee` or `trash_venue`
1206
-        $action = 'trash_' . str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1206
+        $action = 'trash_'.str_replace('ee_', '', strtolower(get_class($this->_cpt_model_obj)));
1207 1207
 
1208 1208
         return EE_Admin_Page::add_query_args_and_nonce(
1209 1209
             [
@@ -1231,7 +1231,7 @@  discard block
 block discarded – undo
1231 1231
         // we DO have a match so let's setup the url
1232 1232
         // we have to get the post to determine our route
1233 1233
         $post       = get_post($post_id);
1234
-        $edit_route = $this->_cpt_edit_routes[ $post->post_type ];
1234
+        $edit_route = $this->_cpt_edit_routes[$post->post_type];
1235 1235
         // shared query_args
1236 1236
         $query_args = ['action' => $edit_route, 'post' => $post_id];
1237 1237
 
@@ -1298,12 +1298,12 @@  discard block
 block discarded – undo
1298 1298
         $id       = empty($id) && is_object($post) ? $post->ID : null;
1299 1299
         $revision = $this->request->getRequestParam('revision', 0, 'int');
1300 1300
 
1301
-        $messages[ $post->post_type ] = [
1301
+        $messages[$post->post_type] = [
1302 1302
             0  => '', // Unused. Messages start at index 1.
1303 1303
             1  => sprintf(
1304 1304
                 esc_html__('%1$s updated. %2$sView %1$s%3$s', 'event_espresso'),
1305 1305
                 $this->_cpt_object->labels->singular_name,
1306
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1306
+                '<a href="'.esc_url(get_permalink($id)).'">',
1307 1307
                 '</a>'
1308 1308
             ),
1309 1309
             2  => esc_html__('Custom field updated', 'event_espresso'),
@@ -1319,27 +1319,27 @@  discard block
 block discarded – undo
1319 1319
             6  => sprintf(
1320 1320
                 esc_html__('%1$s published. %2$sView %1$s%3$s', 'event_espresso'),
1321 1321
                 $this->_cpt_object->labels->singular_name,
1322
-                '<a href="' . esc_url(get_permalink($id)) . '">',
1322
+                '<a href="'.esc_url(get_permalink($id)).'">',
1323 1323
                 '</a>'
1324 1324
             ),
1325 1325
             7  => sprintf(esc_html__('%1$s saved.', 'event_espresso'), $this->_cpt_object->labels->singular_name),
1326 1326
             8  => sprintf(
1327 1327
                 esc_html__('%1$s submitted. %2$sPreview %1$s%3$s', 'event_espresso'),
1328 1328
                 $this->_cpt_object->labels->singular_name,
1329
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))) . '">',
1329
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))).'">',
1330 1330
                 '</a>'
1331 1331
             ),
1332 1332
             9  => sprintf(
1333 1333
                 esc_html__('%1$s scheduled for: %2$s. %3$s">Preview %1$s%3$s', 'event_espresso'),
1334 1334
                 $this->_cpt_object->labels->singular_name,
1335
-                '<strong>' . date_i18n('M j, Y @ G:i', strtotime($post->post_date)) . '</strong>',
1336
-                '<a target="_blank" href="' . esc_url(get_permalink($id)),
1335
+                '<strong>'.date_i18n('M j, Y @ G:i', strtotime($post->post_date)).'</strong>',
1336
+                '<a target="_blank" href="'.esc_url(get_permalink($id)),
1337 1337
                 '</a>'
1338 1338
             ),
1339 1339
             10 => sprintf(
1340 1340
                 esc_html__('%1$s draft updated. %2$s">Preview page%3$s', 'event_espresso'),
1341 1341
                 $this->_cpt_object->labels->singular_name,
1342
-                '<a target="_blank" href="' . esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1342
+                '<a target="_blank" href="'.esc_url(add_query_arg('preview', 'true', get_permalink($id))),
1343 1343
                 '</a>'
1344 1344
             ),
1345 1345
         ];
@@ -1357,10 +1357,10 @@  discard block
 block discarded – undo
1357 1357
     {
1358 1358
         // gather template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1359 1359
         global $post, $title, $post_type, $post_type_object;
1360
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1360
+        $post_type        = $this->_cpt_routes[$this->_req_action];
1361 1361
         $post_type_object = $this->_cpt_object;
1362 1362
         $title            = $post_type_object->labels->add_new_item;
1363
-        $post             = $post = get_default_post_to_edit($this->_cpt_routes[ $this->_req_action ], true);
1363
+        $post             = $post = get_default_post_to_edit($this->_cpt_routes[$this->_req_action], true);
1364 1364
         add_action('admin_print_styles', [$this, 'add_new_admin_page_global']);
1365 1365
         // modify the default editor title field with default title.
1366 1366
         add_filter('enter_title_here', [$this, 'add_custom_editor_default_title']);
@@ -1394,15 +1394,15 @@  discard block
 block discarded – undo
1394 1394
             if ($creating) {
1395 1395
                 wp_enqueue_script('autosave');
1396 1396
             } elseif (
1397
-                isset($this->_cpt_routes[ $action ])
1398
-                && ! isset($this->_labels['hide_add_button_on_cpt_route'][ $action ])
1397
+                isset($this->_cpt_routes[$action])
1398
+                && ! isset($this->_labels['hide_add_button_on_cpt_route'][$action])
1399 1399
             ) {
1400 1400
                 $create_new_action = apply_filters(
1401 1401
                     'FHEE__EE_Admin_Page_CPT___edit_cpt_item__create_new_action',
1402 1402
                     'create_new',
1403 1403
                     $this
1404 1404
                 );
1405
-                $post_new_file     = EE_Admin_Page::add_query_args_and_nonce(
1405
+                $post_new_file = EE_Admin_Page::add_query_args_and_nonce(
1406 1406
                     [
1407 1407
                         'action' => $create_new_action,
1408 1408
                         'page'   => $this->page_slug,
@@ -1410,7 +1410,7 @@  discard block
 block discarded – undo
1410 1410
                     'admin.php'
1411 1411
                 );
1412 1412
             }
1413
-            include_once WP_ADMIN_PATH . 'edit-form-advanced.php';
1413
+            include_once WP_ADMIN_PATH.'edit-form-advanced.php';
1414 1414
         }
1415 1415
     }
1416 1416
 
@@ -1455,16 +1455,16 @@  discard block
 block discarded – undo
1455 1455
         }
1456 1456
 
1457 1457
         // template vars for WP_ADMIN_PATH . 'edit-form-advanced.php'
1458
-        $post_type        = $this->_cpt_routes[ $this->_req_action ];
1458
+        $post_type        = $this->_cpt_routes[$this->_req_action];
1459 1459
         $post_type_object = $this->_cpt_object;
1460
-        $title = $this->_labels['editor_title'][ $this->_cpt_routes[ $this->_req_action ] ]
1460
+        $title = $this->_labels['editor_title'][$this->_cpt_routes[$this->_req_action]]
1461 1461
                  ?? $post_type_object->labels->edit_item;
1462 1462
 
1463
-        if (! wp_check_post_lock($post->ID)) {
1463
+        if ( ! wp_check_post_lock($post->ID)) {
1464 1464
             wp_set_post_lock($post->ID);
1465 1465
         }
1466 1466
         add_action('admin_footer', '_admin_notice_post_locked');
1467
-        if (post_type_supports($this->_cpt_routes[ $this->_req_action ], 'comments')) {
1467
+        if (post_type_supports($this->_cpt_routes[$this->_req_action], 'comments')) {
1468 1468
             wp_enqueue_script('admin-comments');
1469 1469
             enqueue_comment_hotkeys_js();
1470 1470
         }
Please login to merge, or discard this patch.
core/admin/EE_Admin_List_Table.core.php 1 patch
Indentation   +946 added lines, -946 removed lines patch added patch discarded remove patch
@@ -5,7 +5,7 @@  discard block
 block discarded – undo
5 5
 use EventEspresso\core\services\request\sanitizers\AllowedTags;
6 6
 
7 7
 if (! class_exists('WP_List_Table')) {
8
-    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
8
+	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
9 9
 }
10 10
 
11 11
 
@@ -23,928 +23,928 @@  discard block
 block discarded – undo
23 23
  */
24 24
 abstract class EE_Admin_List_Table extends WP_List_Table
25 25
 {
26
-    const ACTION_COPY    = 'duplicate';
27
-
28
-    const ACTION_DELETE  = 'delete';
29
-
30
-    const ACTION_EDIT    = 'edit';
31
-
32
-    const ACTION_RESTORE = 'restore';
33
-
34
-    const ACTION_TRASH   = 'trash';
35
-
36
-    protected static $actions = [
37
-        self::ACTION_COPY,
38
-        self::ACTION_DELETE,
39
-        self::ACTION_EDIT,
40
-        self::ACTION_RESTORE,
41
-        self::ACTION_TRASH,
42
-    ];
43
-
44
-    /**
45
-     * holds the data that will be processed for the table
46
-     *
47
-     * @var array $_data
48
-     */
49
-    protected $_data;
50
-
51
-
52
-    /**
53
-     * This holds the value of all the data available for the given view (for all pages).
54
-     *
55
-     * @var int $_all_data_count
56
-     */
57
-    protected $_all_data_count;
58
-
59
-
60
-    /**
61
-     * Will contain the count of trashed items for the view label.
62
-     *
63
-     * @var int $_trashed_count
64
-     */
65
-    protected $_trashed_count;
66
-
67
-
68
-    /**
69
-     * This is what will be referenced as the slug for the current screen
70
-     *
71
-     * @var string $_screen
72
-     */
73
-    protected $_screen;
74
-
75
-
76
-    /**
77
-     * this is the EE_Admin_Page object
78
-     *
79
-     * @var EE_Admin_Page $_admin_page
80
-     */
81
-    protected $_admin_page;
82
-
83
-
84
-    /**
85
-     * The current view
86
-     *
87
-     * @var string $_view
88
-     */
89
-    protected $_view;
90
-
91
-
92
-    /**
93
-     * array of possible views for this table
94
-     *
95
-     * @var array $_views
96
-     */
97
-    protected $_views;
98
-
99
-
100
-    /**
101
-     * An array of key => value pairs containing information about the current table
102
-     * array(
103
-     *        'plural' => 'plural label',
104
-     *        'singular' => 'singular label',
105
-     *        'ajax' => false, //whether to use ajax or not
106
-     *        'screen' => null, //string used to reference what screen this is
107
-     *        (WP_List_table converts to screen object)
108
-     * )
109
-     *
110
-     * @var array $_wp_list_args
111
-     */
112
-    protected $_wp_list_args;
113
-
114
-    /**
115
-     * an array of column names
116
-     * array(
117
-     *    'internal-name' => 'Title'
118
-     * )
119
-     *
120
-     * @var array $_columns
121
-     */
122
-    protected $_columns;
123
-
124
-    /**
125
-     * An array of sortable columns
126
-     * array(
127
-     *    'internal-name' => 'orderby' //or
128
-     *    'internal-name' => array( 'orderby', true )
129
-     * )
130
-     *
131
-     * @var array $_sortable_columns
132
-     */
133
-    protected $_sortable_columns;
134
-
135
-    /**
136
-     * callback method used to perform AJAX row reordering
137
-     *
138
-     * @var string $_ajax_sorting_callback
139
-     */
140
-    protected $_ajax_sorting_callback;
141
-
142
-    /**
143
-     * An array of hidden columns (if needed)
144
-     * array('internal-name', 'internal-name')
145
-     *
146
-     * @var array $_hidden_columns
147
-     */
148
-    protected $_hidden_columns;
149
-
150
-    /**
151
-     * holds the per_page value
152
-     *
153
-     * @var int $_per_page
154
-     */
155
-    protected $_per_page;
156
-
157
-    /**
158
-     * holds what page number is currently being viewed
159
-     *
160
-     * @var int $_current_page
161
-     */
162
-    protected $_current_page;
163
-
164
-    /**
165
-     * the reference string for the nonce_action
166
-     *
167
-     * @var string $_nonce_action_ref
168
-     */
169
-    protected $_nonce_action_ref;
170
-
171
-    /**
172
-     * property to hold incoming request data (as set by the admin_page_core)
173
-     *
174
-     * @var array $_req_data
175
-     */
176
-    protected $_req_data;
177
-
178
-
179
-    /**
180
-     * yes / no array for admin form fields
181
-     *
182
-     * @var array $_yes_no
183
-     */
184
-    protected $_yes_no = [];
185
-
186
-    /**
187
-     * Array describing buttons that should appear at the bottom of the page
188
-     * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
189
-     * and the values are another array with the following keys
190
-     * array(
191
-     *    'route' => 'page_route',
192
-     *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
193
-     * )
194
-     *
195
-     * @var array $_bottom_buttons
196
-     */
197
-    protected $_bottom_buttons = [];
198
-
199
-
200
-    /**
201
-     * Used to indicate what should be the primary column for the list table.
202
-     * If not present then falls back to what WP calculates
203
-     * as the primary column.
204
-     *
205
-     * @type string $_primary_column
206
-     */
207
-    protected $_primary_column = '';
208
-
209
-
210
-    /**
211
-     * Used to indicate whether the table has a checkbox column or not.
212
-     *
213
-     * @type bool $_has_checkbox_column
214
-     */
215
-    protected $_has_checkbox_column = false;
216
-
217
-    /**
218
-     * @var AdminListTableFilters|null
219
-     */
220
-    protected ?AdminListTableFilters $admin_list_table_filters = null;
221
-
222
-
223
-    /**
224
-     * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
225
-     * @param AdminListTableFilters|null $filters    to display list table filters
226
-     */
227
-    public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
228
-    {
229
-        $this->_admin_page   = $admin_page;
230
-        $this->_req_data     = $this->_admin_page->get_request_data();
231
-        $this->_view         = $this->_admin_page->get_view();
232
-        $this->_views        = empty($this->_views) ? $this->_admin_page->get_list_table_view_RLs() : $this->_views;
233
-        $this->_current_page = $this->get_pagenum();
234
-        $this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
235
-        $this->_yes_no       = [
236
-            esc_html__('No', 'event_espresso'),
237
-            esc_html__('Yes', 'event_espresso')
238
-        ];
239
-
240
-        $this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
241
-
242
-        $this->admin_list_table_filters = $filters instanceof AdminListTableFilters
243
-            ? $filters
244
-            : LoaderFactory::getShared(AdminListTableFilters::class);
245
-
246
-        $this->_setup_data();
247
-        $this->_add_view_counts();
248
-
249
-        $this->_nonce_action_ref = $this->_view;
250
-
251
-        $this->_set_properties();
252
-
253
-        // set primary column
254
-        add_filter('list_table_primary_column', [$this, 'set_primary_column']);
255
-
256
-        // set parent defaults
257
-        parent::__construct($this->_wp_list_args);
258
-
259
-        $this->prepare_items();
260
-    }
261
-
262
-
263
-    /**
264
-     * _setup_data
265
-     * this method is used to setup the $_data, $_all_data_count, and _per_page properties
266
-     *
267
-     * @return void
268
-     * @uses $this->_admin_page
269
-     */
270
-    abstract protected function _setup_data();
271
-
272
-
273
-    /**
274
-     * set the properties that this class needs to be able to execute wp_list_table properly
275
-     * properties set:
276
-     * _wp_list_args = what the arguments required for the parent _wp_list_table.
277
-     * _columns = set the columns in an array.
278
-     * _sortable_columns = columns that are sortable (array).
279
-     * _hidden_columns = columns that are hidden (array)
280
-     * _default_orderby = the default orderby for sorting.
281
-     *
282
-     * @abstract
283
-     * @access protected
284
-     * @return void
285
-     */
286
-    abstract protected function _set_properties();
287
-
288
-
289
-    /**
290
-     * _get_table_filters
291
-     * We use this to assemble and return any filters that are associated with this table that help further refine what
292
-     * gets shown in the table.
293
-     *
294
-     * @abstract
295
-     * @access protected
296
-     * @return string[]
297
-     */
298
-    abstract protected function _get_table_filters();
299
-
300
-
301
-    /**
302
-     * this is a method that child class will do to add counts to the views array so when views are displayed the
303
-     * counts of the views is accurate.
304
-     *
305
-     * @abstract
306
-     * @access protected
307
-     * @return void
308
-     */
309
-    abstract protected function _add_view_counts();
310
-
311
-
312
-    /**
313
-     * _get_hidden_fields
314
-     * returns a html string of hidden fields so if any table filters are used the current view will be respected.
315
-     *
316
-     * @return string
317
-     */
318
-    protected function _get_hidden_fields()
319
-    {
320
-        $action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
321
-        $action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
322
-        // if action is STILL empty, then we set it to default
323
-        $action = empty($action) ? 'default' : $action;
324
-        $field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
325
-        $field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
326
-        $field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
327
-
328
-        $bulk_actions = $this->_get_bulk_actions();
329
-        foreach ($bulk_actions as $bulk_action => $label) {
330
-            $field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
331
-                      . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
332
-        }
333
-
334
-        return $field;
335
-    }
336
-
337
-
338
-    /**
339
-     * _set_column_info
340
-     * we're using this to set the column headers property.
341
-     *
342
-     * @access protected
343
-     * @return void
344
-     */
345
-    protected function _set_column_info()
346
-    {
347
-        $columns   = $this->get_columns();
348
-        $hidden    = $this->get_hidden_columns();
349
-        $_sortable = $this->get_sortable_columns();
350
-
351
-        /**
352
-         * Dynamic hook allowing for adding sortable columns in this list table.
353
-         * Note that $this->screen->id is in the format
354
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
355
-         * table it is: event-espresso_page_espresso_messages.
356
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
357
-         * hook prefix ("event-espresso") will be different.
358
-         *
359
-         * @var array
360
-         */
361
-        $_sortable = apply_filters(
362
-            "FHEE_manage_{$this->screen->id}_sortable_columns",
363
-            $_sortable,
364
-            $this->_screen,
365
-            $this
366
-        );
367
-
368
-        $sortable = [];
369
-        foreach ($_sortable as $id => $data) {
370
-            if (empty($data)) {
371
-                continue;
372
-            }
373
-            // fix for offset errors with WP_List_Table default get_columninfo()
374
-            if (is_array($data)) {
375
-                $_data[0] = key($data);
376
-                $_data[1] = isset($data[1]) ? $data[1] : false;
377
-            } else {
378
-                $_data[0] = $data;
379
-            }
380
-
381
-            $data = (array) $data;
382
-
383
-            if (! isset($data[1])) {
384
-                $_data[1] = false;
385
-            }
386
-
387
-            $sortable[ $id ] = $_data;
388
-        }
389
-        $primary               = $this->get_primary_column_name();
390
-        $this->_column_headers = [$columns, $hidden, $sortable, $primary];
391
-    }
392
-
393
-
394
-    /**
395
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
396
-     *
397
-     * @return string
398
-     */
399
-    protected function get_primary_column_name()
400
-    {
401
-        foreach (class_parents($this) as $parent) {
402
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
403
-                return parent::get_primary_column_name();
404
-            }
405
-        }
406
-        return $this->_primary_column;
407
-    }
408
-
409
-
410
-    /**
411
-     * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
412
-     *
413
-     * @param EE_Base_Class $item
414
-     * @param string        $column_name
415
-     * @param string        $primary
416
-     * @return string
417
-     */
418
-    protected function handle_row_actions($item, $column_name, $primary)
419
-    {
420
-        foreach (class_parents($this) as $parent) {
421
-            if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
422
-                return parent::handle_row_actions($item, $column_name, $primary);
423
-            }
424
-        }
425
-        return '';
426
-    }
427
-
428
-
429
-    /**
430
-     * _get_bulk_actions
431
-     * This is a wrapper called by WP_List_Table::get_bulk_actions()
432
-     *
433
-     * @access protected
434
-     * @return array bulk_actions
435
-     */
436
-    protected function _get_bulk_actions(): array
437
-    {
438
-        $actions = [];
439
-        // the _views property should have the bulk_actions, so let's go through and extract them into a properly
440
-        // formatted array for the wp_list_table();
441
-        foreach ($this->_views as $view => $args) {
442
-            if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
443
-                // each bulk action will correspond with a admin page route, so we can check whatever the capability is
444
-                // for that page route and skip adding the bulk action if no access for the current logged in user.
445
-                foreach ($args['bulk_action'] as $route => $label) {
446
-                    if ($this->_admin_page->check_user_access($route, true)) {
447
-                        $actions[ $route ] = $label;
448
-                    }
449
-                }
450
-            }
451
-        }
452
-        return $actions;
453
-    }
454
-
455
-
456
-    /**
457
-     * Generate the table navigation above or below the table.
458
-     * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
459
-     *
460
-     * @throws EE_Error
461
-     * @since 4.9.44.rc.001
462
-     */
463
-    public function display_tablenav($which)
464
-    {
465
-        if ('top' === $which) {
466
-            wp_nonce_field('bulk-' . $this->_args['plural']);
467
-        }
468
-        ?>
26
+	const ACTION_COPY    = 'duplicate';
27
+
28
+	const ACTION_DELETE  = 'delete';
29
+
30
+	const ACTION_EDIT    = 'edit';
31
+
32
+	const ACTION_RESTORE = 'restore';
33
+
34
+	const ACTION_TRASH   = 'trash';
35
+
36
+	protected static $actions = [
37
+		self::ACTION_COPY,
38
+		self::ACTION_DELETE,
39
+		self::ACTION_EDIT,
40
+		self::ACTION_RESTORE,
41
+		self::ACTION_TRASH,
42
+	];
43
+
44
+	/**
45
+	 * holds the data that will be processed for the table
46
+	 *
47
+	 * @var array $_data
48
+	 */
49
+	protected $_data;
50
+
51
+
52
+	/**
53
+	 * This holds the value of all the data available for the given view (for all pages).
54
+	 *
55
+	 * @var int $_all_data_count
56
+	 */
57
+	protected $_all_data_count;
58
+
59
+
60
+	/**
61
+	 * Will contain the count of trashed items for the view label.
62
+	 *
63
+	 * @var int $_trashed_count
64
+	 */
65
+	protected $_trashed_count;
66
+
67
+
68
+	/**
69
+	 * This is what will be referenced as the slug for the current screen
70
+	 *
71
+	 * @var string $_screen
72
+	 */
73
+	protected $_screen;
74
+
75
+
76
+	/**
77
+	 * this is the EE_Admin_Page object
78
+	 *
79
+	 * @var EE_Admin_Page $_admin_page
80
+	 */
81
+	protected $_admin_page;
82
+
83
+
84
+	/**
85
+	 * The current view
86
+	 *
87
+	 * @var string $_view
88
+	 */
89
+	protected $_view;
90
+
91
+
92
+	/**
93
+	 * array of possible views for this table
94
+	 *
95
+	 * @var array $_views
96
+	 */
97
+	protected $_views;
98
+
99
+
100
+	/**
101
+	 * An array of key => value pairs containing information about the current table
102
+	 * array(
103
+	 *        'plural' => 'plural label',
104
+	 *        'singular' => 'singular label',
105
+	 *        'ajax' => false, //whether to use ajax or not
106
+	 *        'screen' => null, //string used to reference what screen this is
107
+	 *        (WP_List_table converts to screen object)
108
+	 * )
109
+	 *
110
+	 * @var array $_wp_list_args
111
+	 */
112
+	protected $_wp_list_args;
113
+
114
+	/**
115
+	 * an array of column names
116
+	 * array(
117
+	 *    'internal-name' => 'Title'
118
+	 * )
119
+	 *
120
+	 * @var array $_columns
121
+	 */
122
+	protected $_columns;
123
+
124
+	/**
125
+	 * An array of sortable columns
126
+	 * array(
127
+	 *    'internal-name' => 'orderby' //or
128
+	 *    'internal-name' => array( 'orderby', true )
129
+	 * )
130
+	 *
131
+	 * @var array $_sortable_columns
132
+	 */
133
+	protected $_sortable_columns;
134
+
135
+	/**
136
+	 * callback method used to perform AJAX row reordering
137
+	 *
138
+	 * @var string $_ajax_sorting_callback
139
+	 */
140
+	protected $_ajax_sorting_callback;
141
+
142
+	/**
143
+	 * An array of hidden columns (if needed)
144
+	 * array('internal-name', 'internal-name')
145
+	 *
146
+	 * @var array $_hidden_columns
147
+	 */
148
+	protected $_hidden_columns;
149
+
150
+	/**
151
+	 * holds the per_page value
152
+	 *
153
+	 * @var int $_per_page
154
+	 */
155
+	protected $_per_page;
156
+
157
+	/**
158
+	 * holds what page number is currently being viewed
159
+	 *
160
+	 * @var int $_current_page
161
+	 */
162
+	protected $_current_page;
163
+
164
+	/**
165
+	 * the reference string for the nonce_action
166
+	 *
167
+	 * @var string $_nonce_action_ref
168
+	 */
169
+	protected $_nonce_action_ref;
170
+
171
+	/**
172
+	 * property to hold incoming request data (as set by the admin_page_core)
173
+	 *
174
+	 * @var array $_req_data
175
+	 */
176
+	protected $_req_data;
177
+
178
+
179
+	/**
180
+	 * yes / no array for admin form fields
181
+	 *
182
+	 * @var array $_yes_no
183
+	 */
184
+	protected $_yes_no = [];
185
+
186
+	/**
187
+	 * Array describing buttons that should appear at the bottom of the page
188
+	 * Keys are strings that represent the button's function (specifically a key in _labels['buttons']),
189
+	 * and the values are another array with the following keys
190
+	 * array(
191
+	 *    'route' => 'page_route',
192
+	 *    'extra_request' => array('evt_id' => 1 ); //extra request vars that need to be included in the button.
193
+	 * )
194
+	 *
195
+	 * @var array $_bottom_buttons
196
+	 */
197
+	protected $_bottom_buttons = [];
198
+
199
+
200
+	/**
201
+	 * Used to indicate what should be the primary column for the list table.
202
+	 * If not present then falls back to what WP calculates
203
+	 * as the primary column.
204
+	 *
205
+	 * @type string $_primary_column
206
+	 */
207
+	protected $_primary_column = '';
208
+
209
+
210
+	/**
211
+	 * Used to indicate whether the table has a checkbox column or not.
212
+	 *
213
+	 * @type bool $_has_checkbox_column
214
+	 */
215
+	protected $_has_checkbox_column = false;
216
+
217
+	/**
218
+	 * @var AdminListTableFilters|null
219
+	 */
220
+	protected ?AdminListTableFilters $admin_list_table_filters = null;
221
+
222
+
223
+	/**
224
+	 * @param EE_Admin_Page              $admin_page we use this for obtaining everything we need in the list table
225
+	 * @param AdminListTableFilters|null $filters    to display list table filters
226
+	 */
227
+	public function __construct(EE_Admin_Page $admin_page, ?AdminListTableFilters $filters = null)
228
+	{
229
+		$this->_admin_page   = $admin_page;
230
+		$this->_req_data     = $this->_admin_page->get_request_data();
231
+		$this->_view         = $this->_admin_page->get_view();
232
+		$this->_views        = empty($this->_views) ? $this->_admin_page->get_list_table_view_RLs() : $this->_views;
233
+		$this->_current_page = $this->get_pagenum();
234
+		$this->_screen       = $this->_admin_page->get_current_page() . '_' . $this->_admin_page->get_current_view();
235
+		$this->_yes_no       = [
236
+			esc_html__('No', 'event_espresso'),
237
+			esc_html__('Yes', 'event_espresso')
238
+		];
239
+
240
+		$this->_per_page = $this->get_items_per_page($this->_screen . '_per_page');
241
+
242
+		$this->admin_list_table_filters = $filters instanceof AdminListTableFilters
243
+			? $filters
244
+			: LoaderFactory::getShared(AdminListTableFilters::class);
245
+
246
+		$this->_setup_data();
247
+		$this->_add_view_counts();
248
+
249
+		$this->_nonce_action_ref = $this->_view;
250
+
251
+		$this->_set_properties();
252
+
253
+		// set primary column
254
+		add_filter('list_table_primary_column', [$this, 'set_primary_column']);
255
+
256
+		// set parent defaults
257
+		parent::__construct($this->_wp_list_args);
258
+
259
+		$this->prepare_items();
260
+	}
261
+
262
+
263
+	/**
264
+	 * _setup_data
265
+	 * this method is used to setup the $_data, $_all_data_count, and _per_page properties
266
+	 *
267
+	 * @return void
268
+	 * @uses $this->_admin_page
269
+	 */
270
+	abstract protected function _setup_data();
271
+
272
+
273
+	/**
274
+	 * set the properties that this class needs to be able to execute wp_list_table properly
275
+	 * properties set:
276
+	 * _wp_list_args = what the arguments required for the parent _wp_list_table.
277
+	 * _columns = set the columns in an array.
278
+	 * _sortable_columns = columns that are sortable (array).
279
+	 * _hidden_columns = columns that are hidden (array)
280
+	 * _default_orderby = the default orderby for sorting.
281
+	 *
282
+	 * @abstract
283
+	 * @access protected
284
+	 * @return void
285
+	 */
286
+	abstract protected function _set_properties();
287
+
288
+
289
+	/**
290
+	 * _get_table_filters
291
+	 * We use this to assemble and return any filters that are associated with this table that help further refine what
292
+	 * gets shown in the table.
293
+	 *
294
+	 * @abstract
295
+	 * @access protected
296
+	 * @return string[]
297
+	 */
298
+	abstract protected function _get_table_filters();
299
+
300
+
301
+	/**
302
+	 * this is a method that child class will do to add counts to the views array so when views are displayed the
303
+	 * counts of the views is accurate.
304
+	 *
305
+	 * @abstract
306
+	 * @access protected
307
+	 * @return void
308
+	 */
309
+	abstract protected function _add_view_counts();
310
+
311
+
312
+	/**
313
+	 * _get_hidden_fields
314
+	 * returns a html string of hidden fields so if any table filters are used the current view will be respected.
315
+	 *
316
+	 * @return string
317
+	 */
318
+	protected function _get_hidden_fields()
319
+	{
320
+		$action = isset($this->_req_data['route']) ? $this->_req_data['route'] : '';
321
+		$action = empty($action) && isset($this->_req_data['action']) ? $this->_req_data['action'] : $action;
322
+		// if action is STILL empty, then we set it to default
323
+		$action = empty($action) ? 'default' : $action;
324
+		$field  = '<input type="hidden" name="page" value="' . esc_attr($this->_req_data['page']) . '" />' . "\n";
325
+		$field  .= '<input type="hidden" name="route" value="' . esc_attr($action) . '" />' . "\n";
326
+		$field  .= '<input type="hidden" name="perpage" value="' . esc_attr($this->_per_page) . '" />' . "\n";
327
+
328
+		$bulk_actions = $this->_get_bulk_actions();
329
+		foreach ($bulk_actions as $bulk_action => $label) {
330
+			$field .= '<input type="hidden" name="' . $bulk_action . '_nonce"'
331
+					  . ' value="' . wp_create_nonce($bulk_action . '_nonce') . '" />' . "\n";
332
+		}
333
+
334
+		return $field;
335
+	}
336
+
337
+
338
+	/**
339
+	 * _set_column_info
340
+	 * we're using this to set the column headers property.
341
+	 *
342
+	 * @access protected
343
+	 * @return void
344
+	 */
345
+	protected function _set_column_info()
346
+	{
347
+		$columns   = $this->get_columns();
348
+		$hidden    = $this->get_hidden_columns();
349
+		$_sortable = $this->get_sortable_columns();
350
+
351
+		/**
352
+		 * Dynamic hook allowing for adding sortable columns in this list table.
353
+		 * Note that $this->screen->id is in the format
354
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
355
+		 * table it is: event-espresso_page_espresso_messages.
356
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
357
+		 * hook prefix ("event-espresso") will be different.
358
+		 *
359
+		 * @var array
360
+		 */
361
+		$_sortable = apply_filters(
362
+			"FHEE_manage_{$this->screen->id}_sortable_columns",
363
+			$_sortable,
364
+			$this->_screen,
365
+			$this
366
+		);
367
+
368
+		$sortable = [];
369
+		foreach ($_sortable as $id => $data) {
370
+			if (empty($data)) {
371
+				continue;
372
+			}
373
+			// fix for offset errors with WP_List_Table default get_columninfo()
374
+			if (is_array($data)) {
375
+				$_data[0] = key($data);
376
+				$_data[1] = isset($data[1]) ? $data[1] : false;
377
+			} else {
378
+				$_data[0] = $data;
379
+			}
380
+
381
+			$data = (array) $data;
382
+
383
+			if (! isset($data[1])) {
384
+				$_data[1] = false;
385
+			}
386
+
387
+			$sortable[ $id ] = $_data;
388
+		}
389
+		$primary               = $this->get_primary_column_name();
390
+		$this->_column_headers = [$columns, $hidden, $sortable, $primary];
391
+	}
392
+
393
+
394
+	/**
395
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
396
+	 *
397
+	 * @return string
398
+	 */
399
+	protected function get_primary_column_name()
400
+	{
401
+		foreach (class_parents($this) as $parent) {
402
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'get_primary_column_name')) {
403
+				return parent::get_primary_column_name();
404
+			}
405
+		}
406
+		return $this->_primary_column;
407
+	}
408
+
409
+
410
+	/**
411
+	 * Added for WP4.1 backward compat (@see https://events.codebasehq.com/projects/event-espresso/tickets/8814)
412
+	 *
413
+	 * @param EE_Base_Class $item
414
+	 * @param string        $column_name
415
+	 * @param string        $primary
416
+	 * @return string
417
+	 */
418
+	protected function handle_row_actions($item, $column_name, $primary)
419
+	{
420
+		foreach (class_parents($this) as $parent) {
421
+			if ($parent === 'WP_List_Table' && method_exists($parent, 'handle_row_actions')) {
422
+				return parent::handle_row_actions($item, $column_name, $primary);
423
+			}
424
+		}
425
+		return '';
426
+	}
427
+
428
+
429
+	/**
430
+	 * _get_bulk_actions
431
+	 * This is a wrapper called by WP_List_Table::get_bulk_actions()
432
+	 *
433
+	 * @access protected
434
+	 * @return array bulk_actions
435
+	 */
436
+	protected function _get_bulk_actions(): array
437
+	{
438
+		$actions = [];
439
+		// the _views property should have the bulk_actions, so let's go through and extract them into a properly
440
+		// formatted array for the wp_list_table();
441
+		foreach ($this->_views as $view => $args) {
442
+			if ($this->_view === $view && isset($args['bulk_action']) && is_array($args['bulk_action'])) {
443
+				// each bulk action will correspond with a admin page route, so we can check whatever the capability is
444
+				// for that page route and skip adding the bulk action if no access for the current logged in user.
445
+				foreach ($args['bulk_action'] as $route => $label) {
446
+					if ($this->_admin_page->check_user_access($route, true)) {
447
+						$actions[ $route ] = $label;
448
+					}
449
+				}
450
+			}
451
+		}
452
+		return $actions;
453
+	}
454
+
455
+
456
+	/**
457
+	 * Generate the table navigation above or below the table.
458
+	 * Overrides the parent table nav in WP_List_Table so we can hide the bulk action div if there are no bulk actions.
459
+	 *
460
+	 * @throws EE_Error
461
+	 * @since 4.9.44.rc.001
462
+	 */
463
+	public function display_tablenav($which)
464
+	{
465
+		if ('top' === $which) {
466
+			wp_nonce_field('bulk-' . $this->_args['plural']);
467
+		}
468
+		?>
469 469
         <div class="tablenav <?php echo esc_attr($which); ?>">
470 470
             <?php if ($this->_get_bulk_actions()) { ?>
471 471
                 <div class="alignleft actions bulkactions">
472 472
                     <?php $this->bulk_actions(); ?>
473 473
                 </div>
474 474
             <?php }
475
-            $this->extra_tablenav($which);
476
-            $this->pagination($which);
477
-            ?>
475
+			$this->extra_tablenav($which);
476
+			$this->pagination($which);
477
+			?>
478 478
 
479 479
             <br class="clear" />
480 480
         </div>
481 481
         <?php
482
-    }
483
-
484
-
485
-    /**
486
-     * _filters
487
-     * This receives the filters array from children _get_table_filters() and assembles the string including the filter
488
-     * button.
489
-     *
490
-     * @access private
491
-     * @return void  echos html showing filters
492
-     */
493
-    private function _filters(): void
494
-    {
495
-        $classname = get_class($this);
496
-        $filters   = apply_filters(
497
-            "FHEE__{$classname}__filters",
498
-            $this->_get_table_filters(),
499
-            $this,
500
-            $this->_screen
501
-        );
502
-
503
-        if (empty($filters)) {
504
-            return;
505
-        }
506
-
507
-        $this->admin_list_table_filters->filters(
508
-            $filters,
509
-            $this->get_admin_page()->get_current_page_view_url()
510
-        );
511
-    }
512
-
513
-
514
-    /**
515
-     * Callback for 'list_table_primary_column' WordPress filter
516
-     * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
517
-     * column when class is instantiated.
518
-     *
519
-     * @param string $column_name
520
-     * @return string
521
-     * @see WP_List_Table::get_primary_column_name
522
-     */
523
-    public function set_primary_column($column_name)
524
-    {
525
-        return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
526
-    }
527
-
528
-
529
-    /**
530
-     *
531
-     */
532
-    public function prepare_items()
533
-    {
534
-        $this->_set_column_info();
535
-        $this->process_bulk_action();
536
-
537
-        $this->items = $this->_data;
538
-        $this->set_pagination_args(
539
-            [
540
-                'total_items' => $this->_all_data_count,
541
-                'per_page'    => $this->_per_page,
542
-                'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
543
-            ]
544
-        );
545
-    }
546
-
547
-
548
-    /**
549
-     * @param object|array $item
550
-     * @return string html content for the column
551
-     */
552
-    protected function column_cb($item)
553
-    {
554
-        return '';
555
-    }
556
-
557
-
558
-    /**
559
-     * This column is the default for when there is no defined column method for a registered column.
560
-     * This can be overridden by child classes, but allows for hooking in for custom columns.
561
-     *
562
-     * @param EE_Base_Class $item
563
-     * @param string        $column_name The column being called.
564
-     * @return string html content for the column
565
-     */
566
-    public function column_default($item, $column_name)
567
-    {
568
-        /**
569
-         * Dynamic hook allowing for adding additional column content in this list table.
570
-         * Note that $this->screen->id is in the format
571
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
572
-         * table it is: event-espresso_page_espresso_messages.
573
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
574
-         * hook prefix ("event-espresso") will be different.
575
-         */
576
-        ob_start();
577
-        do_action(
578
-            'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
579
-            $item,
580
-            $this->_screen
581
-        );
582
-        $content = ob_get_clean();
583
-        return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
584
-    }
585
-
586
-
587
-    /**
588
-     * Get a list of columns. The format is:
589
-     * 'internal-name' => 'Title'
590
-     *
591
-     * @return array
592
-     * @since  3.1.0
593
-     * @access public
594
-     * @abstract
595
-     */
596
-    public function get_columns()
597
-    {
598
-        /**
599
-         * Dynamic hook allowing for adding additional columns in this list table.
600
-         * Note that $this->screen->id is in the format
601
-         * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
602
-         * table it is: event-espresso_page_espresso_messages.
603
-         * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
604
-         * hook prefix ("event-espresso") will be different.
605
-         *
606
-         * @var array
607
-         */
608
-        return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
609
-    }
610
-
611
-
612
-    /**
613
-     * Get an associative array ( id => link ) with the list
614
-     * of views available on this table.
615
-     *
616
-     * @return array
617
-     * @since  3.1.0
618
-     * @access protected
619
-     */
620
-    public function get_views()
621
-    {
622
-        return $this->_views;
623
-    }
624
-
625
-
626
-    /**
627
-     * Generate the views html.
628
-     */
629
-    public function display_views()
630
-    {
631
-        $views           = $this->get_views();
632
-        $assembled_views = [];
633
-
634
-        if (empty($views)) {
635
-            return;
636
-        }
637
-        echo "<ul class='subsubsub'>\n";
638
-        foreach ($views as $view) {
639
-            $count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
640
-            if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
641
-                $filter = "<li";
642
-                $filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
643
-                $filter .= ">";
644
-                $filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
645
-                $filter .= '<span class="count">(' . $count . ')</span>';
646
-                $filter .= '</li>';
647
-                $assembled_views[ $view['slug'] ] = $filter;
648
-            }
649
-        }
650
-
651
-        echo ! empty($assembled_views)
652
-            ? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
653
-            : '';
654
-        echo "</ul>";
655
-    }
656
-
657
-
658
-    /**
659
-     * Generates content for a single row of the table
660
-     *
661
-     * @param EE_Base_Class $item The current item
662
-     * @since  4.1
663
-     * @access public
664
-     */
665
-    public function single_row($item)
666
-    {
667
-        $row_class = $this->_get_row_class($item);
668
-        echo '<tr class="' . esc_attr($row_class) . '">';
669
-        $this->single_row_columns($item); // already escaped
670
-        echo '</tr>';
671
-    }
672
-
673
-
674
-    /**
675
-     * This simply sets up the row class for the table rows.
676
-     * Allows for easier overriding of child methods for setting up sorting.
677
-     *
678
-     * @param EE_Base_Class $item the current item
679
-     * @return string
680
-     */
681
-    protected function _get_row_class($item)
682
-    {
683
-        static $row_class = '';
684
-        $row_class = ($row_class === '' ? 'alternate' : '');
685
-
686
-        $new_row_class = $row_class;
687
-
688
-        if (! empty($this->_ajax_sorting_callback)) {
689
-            $new_row_class .= ' rowsortable';
690
-        }
691
-
692
-        return $new_row_class;
693
-    }
694
-
695
-
696
-    /**
697
-     * @return array
698
-     */
699
-    public function get_sortable_columns()
700
-    {
701
-        return (array) $this->_sortable_columns;
702
-    }
703
-
704
-
705
-    /**
706
-     * @return string
707
-     */
708
-    public function get_ajax_sorting_callback()
709
-    {
710
-        return $this->_ajax_sorting_callback;
711
-    }
712
-
713
-
714
-    /**
715
-     * @return array
716
-     */
717
-    public function get_hidden_columns()
718
-    {
719
-        $user_id     = get_current_user_id();
720
-        $has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
721
-        if (empty($has_default) && ! empty($this->_hidden_columns)) {
722
-            update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
723
-            update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
724
-        }
725
-        $ref = 'manage' . $this->screen->id . 'columnshidden';
726
-        return (array) get_user_option($ref, $user_id);
727
-    }
728
-
729
-
730
-    /**
731
-     * Generates the columns for a single row of the table.
732
-     * Overridden from wp_list_table so as to allow us to filter the column content for a given
733
-     * column.
734
-     *
735
-     * @param EE_Base_Class $item The current item
736
-     * @since 3.1.0
737
-     */
738
-    public function single_row_columns($item)
739
-    {
740
-        [$columns, $hidden, $sortable, $primary] = $this->get_column_info();
741
-
742
-        foreach ($columns as $column_name => $column_display_name) {
743
-
744
-            /**
745
-             * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
746
-             * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
747
-             */
748
-            $hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
749
-
750
-            $classes = $column_name . ' column-' . $column_name . $hidden_class;
751
-            if ($primary === $column_name) {
752
-                $classes .= ' has-row-actions column-primary';
753
-            }
754
-
755
-            $data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
756
-
757
-            $class = 'class="' . esc_attr($classes) . '"';
758
-
759
-            $attributes = "{$class}{$data}";
760
-
761
-            if ($column_name === 'cb') {
762
-                echo '<th scope="row" class="check-column">';
763
-                echo apply_filters(
764
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
765
-                    $this->column_cb($item), // already escaped
766
-                    $item,
767
-                    $this
768
-                );
769
-                echo '</th>';
770
-            } elseif (method_exists($this, "column_$column_name")) {
771
-                echo "<td $attributes>"; // already escaped
772
-                echo apply_filters(
773
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
774
-                    call_user_func([$this, "column_$column_name"], $item),
775
-                    $item,
776
-                    $this
777
-                );
778
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
779
-                echo "</td>";
780
-            } else {
781
-                echo "<td $attributes>"; // already escaped
782
-                echo apply_filters(
783
-                    'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
784
-                    $this->column_default($item, $column_name),
785
-                    $item,
786
-                    $column_name,
787
-                    $this
788
-                );
789
-                echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
790
-                echo "</td>";
791
-            }
792
-        }
793
-    }
794
-
795
-
796
-    /**
797
-     * Extra controls to be displayed between bulk actions and pagination
798
-     *
799
-     * @access public
800
-     * @param string $which
801
-     * @throws EE_Error
802
-     */
803
-    public function extra_tablenav($which)
804
-    {
805
-        if ($which === 'top') {
806
-            $this->_filters();
807
-            echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
808
-        } else {
809
-            echo '<div class="list-table-bottom-buttons alignleft actions">';
810
-            foreach ($this->_bottom_buttons as $type => $action) {
811
-                $route         = $action['route'] ?? '';
812
-                $extra_request = $action['extra_request'] ?? [];
813
-                $btn_class     = $action['btn_class'] ?? 'button button--secondary';
814
-                // already escaped
815
-                echo wp_kses($this->_admin_page->get_action_link_or_button(
816
-                    $route,
817
-                    $type,
818
-                    $extra_request,
819
-                    $btn_class
820
-                ), AllowedTags::getWithFormTags());
821
-            }
822
-            do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
823
-            echo '</div>';
824
-        }
825
-    }
826
-
827
-
828
-    /**
829
-     * Get an associative array ( option_name => option_title ) with the list
830
-     * of bulk actions available on this table.
831
-     *
832
-     * @return array
833
-     * @since  3.1.0
834
-     * @access protected
835
-     */
836
-    public function get_bulk_actions()
837
-    {
838
-        return (array) $this->_get_bulk_actions();
839
-    }
840
-
841
-
842
-    /**
843
-     * Processing bulk actions.
844
-     */
845
-    public function process_bulk_action()
846
-    {
847
-        // this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
848
-        // reference in case there is a case where it gets used.
849
-    }
850
-
851
-
852
-    /**
853
-     * returns the EE admin page this list table is associated with
854
-     *
855
-     * @return EE_Admin_Page
856
-     */
857
-    public function get_admin_page()
858
-    {
859
-        return $this->_admin_page;
860
-    }
861
-
862
-
863
-    /**
864
-     * A "helper" function for all children to provide an html string of
865
-     * actions to output in their content.  It is preferable for child classes
866
-     * to use this method for generating their actions content so that it's
867
-     * filterable by plugins
868
-     *
869
-     * @param string        $action_container           what are the html container
870
-     *                                                  elements for this actions string?
871
-     * @param string        $action_class               What class is for the container
872
-     *                                                  element.
873
-     * @param string        $action_items               The contents for the action items
874
-     *                                                  container.  This is filtered before
875
-     *                                                  returned.
876
-     * @param string        $action_id                  What id (optional) is used for the
877
-     *                                                  container element.
878
-     * @param EE_Base_Class $item                       The object for the column displaying
879
-     *                                                  the actions.
880
-     * @return string The assembled action elements container.
881
-     */
882
-    protected function _action_string(
883
-        $action_items,
884
-        $item,
885
-        $action_container = 'ul',
886
-        $action_class = '',
887
-        $action_id = ''
888
-    ) {
889
-        $action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
890
-        $action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
891
-        $open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
892
-        $close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
893
-        try {
894
-            $content = apply_filters(
895
-                'FHEE__EE_Admin_List_Table___action_string__action_items',
896
-                $action_items,
897
-                $item,
898
-                $this
899
-            );
900
-        } catch (Exception $e) {
901
-            if (WP_DEBUG) {
902
-                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
903
-            }
904
-            $content = $action_items;
905
-        }
906
-        return "{$open_tag}{$content}{$close_tag}";
907
-    }
908
-
909
-
910
-    /**
911
-     * @return string
912
-     */
913
-    protected function getReturnUrl()
914
-    {
915
-        $host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
916
-        $uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
917
-        return urlencode(esc_url_raw("//{$host}{$uri}"));
918
-    }
919
-
920
-
921
-    /**
922
-     * @param string $id
923
-     * @param string $content
924
-     * @param string $align     start (default), center, end
925
-     * @return string
926
-     * @since   5.0.0.p
927
-     */
928
-    protected function columnContent($id, $content, $align = 'start')
929
-    {
930
-        if (! isset($this->_columns[ $id ])) {
931
-            throw new DomainException('missing column id');
932
-        }
933
-        $heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
934
-        $align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
935
-        $align = "ee-responsive-table-cell--{$align}";
936
-
937
-        $html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>";
938
-        $html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>";
939
-        $html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>";
940
-        $html .= "</div>";
941
-        return $html;
942
-    }
943
-
944
-
945
-    protected function actionsModalMenu($actions): string
946
-    {
947
-        return '
482
+	}
483
+
484
+
485
+	/**
486
+	 * _filters
487
+	 * This receives the filters array from children _get_table_filters() and assembles the string including the filter
488
+	 * button.
489
+	 *
490
+	 * @access private
491
+	 * @return void  echos html showing filters
492
+	 */
493
+	private function _filters(): void
494
+	{
495
+		$classname = get_class($this);
496
+		$filters   = apply_filters(
497
+			"FHEE__{$classname}__filters",
498
+			$this->_get_table_filters(),
499
+			$this,
500
+			$this->_screen
501
+		);
502
+
503
+		if (empty($filters)) {
504
+			return;
505
+		}
506
+
507
+		$this->admin_list_table_filters->filters(
508
+			$filters,
509
+			$this->get_admin_page()->get_current_page_view_url()
510
+		);
511
+	}
512
+
513
+
514
+	/**
515
+	 * Callback for 'list_table_primary_column' WordPress filter
516
+	 * If child EE_Admin_List_Table classes set the _primary_column property then that will be set as the primary
517
+	 * column when class is instantiated.
518
+	 *
519
+	 * @param string $column_name
520
+	 * @return string
521
+	 * @see WP_List_Table::get_primary_column_name
522
+	 */
523
+	public function set_primary_column($column_name)
524
+	{
525
+		return ! empty($this->_primary_column) ? $this->_primary_column : $column_name;
526
+	}
527
+
528
+
529
+	/**
530
+	 *
531
+	 */
532
+	public function prepare_items()
533
+	{
534
+		$this->_set_column_info();
535
+		$this->process_bulk_action();
536
+
537
+		$this->items = $this->_data;
538
+		$this->set_pagination_args(
539
+			[
540
+				'total_items' => $this->_all_data_count,
541
+				'per_page'    => $this->_per_page,
542
+				'total_pages' => (int) ceil($this->_all_data_count / $this->_per_page),
543
+			]
544
+		);
545
+	}
546
+
547
+
548
+	/**
549
+	 * @param object|array $item
550
+	 * @return string html content for the column
551
+	 */
552
+	protected function column_cb($item)
553
+	{
554
+		return '';
555
+	}
556
+
557
+
558
+	/**
559
+	 * This column is the default for when there is no defined column method for a registered column.
560
+	 * This can be overridden by child classes, but allows for hooking in for custom columns.
561
+	 *
562
+	 * @param EE_Base_Class $item
563
+	 * @param string        $column_name The column being called.
564
+	 * @return string html content for the column
565
+	 */
566
+	public function column_default($item, $column_name)
567
+	{
568
+		/**
569
+		 * Dynamic hook allowing for adding additional column content in this list table.
570
+		 * Note that $this->screen->id is in the format
571
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
572
+		 * table it is: event-espresso_page_espresso_messages.
573
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
574
+		 * hook prefix ("event-espresso") will be different.
575
+		 */
576
+		ob_start();
577
+		do_action(
578
+			'AHEE__EE_Admin_List_Table__column_' . $column_name . '__' . $this->screen->id,
579
+			$item,
580
+			$this->_screen
581
+		);
582
+		$content = ob_get_clean();
583
+		return $column_name === 'actions' ? $this->actionsModalMenu($content) : $content;
584
+	}
585
+
586
+
587
+	/**
588
+	 * Get a list of columns. The format is:
589
+	 * 'internal-name' => 'Title'
590
+	 *
591
+	 * @return array
592
+	 * @since  3.1.0
593
+	 * @access public
594
+	 * @abstract
595
+	 */
596
+	public function get_columns()
597
+	{
598
+		/**
599
+		 * Dynamic hook allowing for adding additional columns in this list table.
600
+		 * Note that $this->screen->id is in the format
601
+		 * {sanitize_title($top_level_menu_label)}_page_{$espresso_admin_page_slug}.  So for the messages list
602
+		 * table it is: event-espresso_page_espresso_messages.
603
+		 * However, take note that if the top level menu label has been translated (i.e. "Event Espresso"). then the
604
+		 * hook prefix ("event-espresso") will be different.
605
+		 *
606
+		 * @var array
607
+		 */
608
+		return apply_filters("FHEE_manage_{$this->screen->id}_columns", $this->_columns, $this->_screen, $this);
609
+	}
610
+
611
+
612
+	/**
613
+	 * Get an associative array ( id => link ) with the list
614
+	 * of views available on this table.
615
+	 *
616
+	 * @return array
617
+	 * @since  3.1.0
618
+	 * @access protected
619
+	 */
620
+	public function get_views()
621
+	{
622
+		return $this->_views;
623
+	}
624
+
625
+
626
+	/**
627
+	 * Generate the views html.
628
+	 */
629
+	public function display_views()
630
+	{
631
+		$views           = $this->get_views();
632
+		$assembled_views = [];
633
+
634
+		if (empty($views)) {
635
+			return;
636
+		}
637
+		echo "<ul class='subsubsub'>\n";
638
+		foreach ($views as $view) {
639
+			$count = isset($view['count']) && ! empty($view['count']) ? absint($view['count']) : 0;
640
+			if (isset($view['slug'], $view['class'], $view['url'], $view['label'])) {
641
+				$filter = "<li";
642
+				$filter .= $view['class'] ? " class='" . esc_attr($view['class']) . "'" : '';
643
+				$filter .= ">";
644
+				$filter .= '<a href="' . esc_url_raw($view['url']) . '">' . esc_html($view['label']) . '</a>';
645
+				$filter .= '<span class="count">(' . $count . ')</span>';
646
+				$filter .= '</li>';
647
+				$assembled_views[ $view['slug'] ] = $filter;
648
+			}
649
+		}
650
+
651
+		echo ! empty($assembled_views)
652
+			? implode("<li style='margin:0 .5rem;'>|</li>", $assembled_views)
653
+			: '';
654
+		echo "</ul>";
655
+	}
656
+
657
+
658
+	/**
659
+	 * Generates content for a single row of the table
660
+	 *
661
+	 * @param EE_Base_Class $item The current item
662
+	 * @since  4.1
663
+	 * @access public
664
+	 */
665
+	public function single_row($item)
666
+	{
667
+		$row_class = $this->_get_row_class($item);
668
+		echo '<tr class="' . esc_attr($row_class) . '">';
669
+		$this->single_row_columns($item); // already escaped
670
+		echo '</tr>';
671
+	}
672
+
673
+
674
+	/**
675
+	 * This simply sets up the row class for the table rows.
676
+	 * Allows for easier overriding of child methods for setting up sorting.
677
+	 *
678
+	 * @param EE_Base_Class $item the current item
679
+	 * @return string
680
+	 */
681
+	protected function _get_row_class($item)
682
+	{
683
+		static $row_class = '';
684
+		$row_class = ($row_class === '' ? 'alternate' : '');
685
+
686
+		$new_row_class = $row_class;
687
+
688
+		if (! empty($this->_ajax_sorting_callback)) {
689
+			$new_row_class .= ' rowsortable';
690
+		}
691
+
692
+		return $new_row_class;
693
+	}
694
+
695
+
696
+	/**
697
+	 * @return array
698
+	 */
699
+	public function get_sortable_columns()
700
+	{
701
+		return (array) $this->_sortable_columns;
702
+	}
703
+
704
+
705
+	/**
706
+	 * @return string
707
+	 */
708
+	public function get_ajax_sorting_callback()
709
+	{
710
+		return $this->_ajax_sorting_callback;
711
+	}
712
+
713
+
714
+	/**
715
+	 * @return array
716
+	 */
717
+	public function get_hidden_columns()
718
+	{
719
+		$user_id     = get_current_user_id();
720
+		$has_default = get_user_option('default' . $this->screen->id . 'columnshidden', $user_id);
721
+		if (empty($has_default) && ! empty($this->_hidden_columns)) {
722
+			update_user_option($user_id, 'default' . $this->screen->id . 'columnshidden', true);
723
+			update_user_option($user_id, 'manage' . $this->screen->id . 'columnshidden', $this->_hidden_columns, true);
724
+		}
725
+		$ref = 'manage' . $this->screen->id . 'columnshidden';
726
+		return (array) get_user_option($ref, $user_id);
727
+	}
728
+
729
+
730
+	/**
731
+	 * Generates the columns for a single row of the table.
732
+	 * Overridden from wp_list_table so as to allow us to filter the column content for a given
733
+	 * column.
734
+	 *
735
+	 * @param EE_Base_Class $item The current item
736
+	 * @since 3.1.0
737
+	 */
738
+	public function single_row_columns($item)
739
+	{
740
+		[$columns, $hidden, $sortable, $primary] = $this->get_column_info();
741
+
742
+		foreach ($columns as $column_name => $column_display_name) {
743
+
744
+			/**
745
+			 * With WordPress version 4.3.RC+ WordPress started using the hidden css class to control whether columns
746
+			 * are hidden or not instead of using "display:none;".  This bit of code provides backward compat.
747
+			 */
748
+			$hidden_class = in_array($column_name, $hidden) ? ' hidden' : '';
749
+
750
+			$classes = $column_name . ' column-' . $column_name . $hidden_class;
751
+			if ($primary === $column_name) {
752
+				$classes .= ' has-row-actions column-primary';
753
+			}
754
+
755
+			$data = ' data-colname="' . wp_strip_all_tags($column_display_name) . '"';
756
+
757
+			$class = 'class="' . esc_attr($classes) . '"';
758
+
759
+			$attributes = "{$class}{$data}";
760
+
761
+			if ($column_name === 'cb') {
762
+				echo '<th scope="row" class="check-column">';
763
+				echo apply_filters(
764
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_cb_content',
765
+					$this->column_cb($item), // already escaped
766
+					$item,
767
+					$this
768
+				);
769
+				echo '</th>';
770
+			} elseif (method_exists($this, "column_$column_name")) {
771
+				echo "<td $attributes>"; // already escaped
772
+				echo apply_filters(
773
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_' . $column_name . '__column_content',
774
+					call_user_func([$this, "column_$column_name"], $item),
775
+					$item,
776
+					$this
777
+				);
778
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
779
+				echo "</td>";
780
+			} else {
781
+				echo "<td $attributes>"; // already escaped
782
+				echo apply_filters(
783
+					'FHEE__EE_Admin_List_Table__single_row_columns__column_default__column_content',
784
+					$this->column_default($item, $column_name),
785
+					$item,
786
+					$column_name,
787
+					$this
788
+				);
789
+				echo wp_kses($this->handle_row_actions($item, $column_name, $primary), AllowedTags::getWithFormTags());
790
+				echo "</td>";
791
+			}
792
+		}
793
+	}
794
+
795
+
796
+	/**
797
+	 * Extra controls to be displayed between bulk actions and pagination
798
+	 *
799
+	 * @access public
800
+	 * @param string $which
801
+	 * @throws EE_Error
802
+	 */
803
+	public function extra_tablenav($which)
804
+	{
805
+		if ($which === 'top') {
806
+			$this->_filters();
807
+			echo wp_kses($this->_get_hidden_fields(), AllowedTags::getWithFormTags());
808
+		} else {
809
+			echo '<div class="list-table-bottom-buttons alignleft actions">';
810
+			foreach ($this->_bottom_buttons as $type => $action) {
811
+				$route         = $action['route'] ?? '';
812
+				$extra_request = $action['extra_request'] ?? [];
813
+				$btn_class     = $action['btn_class'] ?? 'button button--secondary';
814
+				// already escaped
815
+				echo wp_kses($this->_admin_page->get_action_link_or_button(
816
+					$route,
817
+					$type,
818
+					$extra_request,
819
+					$btn_class
820
+				), AllowedTags::getWithFormTags());
821
+			}
822
+			do_action('AHEE__EE_Admin_List_Table__extra_tablenav__after_bottom_buttons', $this, $this->_screen);
823
+			echo '</div>';
824
+		}
825
+	}
826
+
827
+
828
+	/**
829
+	 * Get an associative array ( option_name => option_title ) with the list
830
+	 * of bulk actions available on this table.
831
+	 *
832
+	 * @return array
833
+	 * @since  3.1.0
834
+	 * @access protected
835
+	 */
836
+	public function get_bulk_actions()
837
+	{
838
+		return (array) $this->_get_bulk_actions();
839
+	}
840
+
841
+
842
+	/**
843
+	 * Processing bulk actions.
844
+	 */
845
+	public function process_bulk_action()
846
+	{
847
+		// this is not used it is handled by the child EE_Admin_Page class (routes).  However, including here for
848
+		// reference in case there is a case where it gets used.
849
+	}
850
+
851
+
852
+	/**
853
+	 * returns the EE admin page this list table is associated with
854
+	 *
855
+	 * @return EE_Admin_Page
856
+	 */
857
+	public function get_admin_page()
858
+	{
859
+		return $this->_admin_page;
860
+	}
861
+
862
+
863
+	/**
864
+	 * A "helper" function for all children to provide an html string of
865
+	 * actions to output in their content.  It is preferable for child classes
866
+	 * to use this method for generating their actions content so that it's
867
+	 * filterable by plugins
868
+	 *
869
+	 * @param string        $action_container           what are the html container
870
+	 *                                                  elements for this actions string?
871
+	 * @param string        $action_class               What class is for the container
872
+	 *                                                  element.
873
+	 * @param string        $action_items               The contents for the action items
874
+	 *                                                  container.  This is filtered before
875
+	 *                                                  returned.
876
+	 * @param string        $action_id                  What id (optional) is used for the
877
+	 *                                                  container element.
878
+	 * @param EE_Base_Class $item                       The object for the column displaying
879
+	 *                                                  the actions.
880
+	 * @return string The assembled action elements container.
881
+	 */
882
+	protected function _action_string(
883
+		$action_items,
884
+		$item,
885
+		$action_container = 'ul',
886
+		$action_class = '',
887
+		$action_id = ''
888
+	) {
889
+		$action_class = ! empty($action_class) ? ' class="' . esc_attr($action_class) . '"' : '';
890
+		$action_id    = ! empty($action_id) ? ' id="' . esc_attr($action_id) . '"' : '';
891
+		$open_tag     = ! empty($action_container) ? '<' . $action_container . $action_class . $action_id . '>' : '';
892
+		$close_tag    = ! empty($action_container) ? '</' . $action_container . '>' : '';
893
+		try {
894
+			$content = apply_filters(
895
+				'FHEE__EE_Admin_List_Table___action_string__action_items',
896
+				$action_items,
897
+				$item,
898
+				$this
899
+			);
900
+		} catch (Exception $e) {
901
+			if (WP_DEBUG) {
902
+				EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
903
+			}
904
+			$content = $action_items;
905
+		}
906
+		return "{$open_tag}{$content}{$close_tag}";
907
+	}
908
+
909
+
910
+	/**
911
+	 * @return string
912
+	 */
913
+	protected function getReturnUrl()
914
+	{
915
+		$host = $this->_admin_page->get_request()->getServerParam('HTTP_HOST');
916
+		$uri  = $this->_admin_page->get_request()->getServerParam('REQUEST_URI');
917
+		return urlencode(esc_url_raw("//{$host}{$uri}"));
918
+	}
919
+
920
+
921
+	/**
922
+	 * @param string $id
923
+	 * @param string $content
924
+	 * @param string $align     start (default), center, end
925
+	 * @return string
926
+	 * @since   5.0.0.p
927
+	 */
928
+	protected function columnContent($id, $content, $align = 'start')
929
+	{
930
+		if (! isset($this->_columns[ $id ])) {
931
+			throw new DomainException('missing column id');
932
+		}
933
+		$heading = $id !== 'cb' ? $this->_columns[ $id ] : '';
934
+		$align = in_array($align, ['start', 'center', 'end']) ? $align : 'start';
935
+		$align = "ee-responsive-table-cell--{$align}";
936
+
937
+		$html = "<div class='ee-responsive-table-cell ee-responsive-table-cell--column-{$id} {$align} ee-layout-row'>";
938
+		$html .= "<div class='ee-responsive-table-cell__heading'>{$heading}</div>";
939
+		$html .= "<div class='ee-responsive-table-cell__content ee-layout-row'>{$content}</div>";
940
+		$html .= "</div>";
941
+		return $html;
942
+	}
943
+
944
+
945
+	protected function actionsModalMenu($actions): string
946
+	{
947
+		return '
948 948
         <div class="ee-modal-menu">
949 949
             <button class="ee-modal-menu__button button button--secondary button--icon-only ee-aria-tooltip"
950 950
                     aria-label="' . esc_attr__('list table actions menu', 'event_espresso') . '"
@@ -956,43 +956,43 @@  discard block
 block discarded – undo
956 956
                 ' . $actions . '
957 957
             </div>
958 958
         </div>';
959
-    }
959
+	}
960 960
 
961 961
 
962
-    public function actionsColumnHeader(): string
963
-    {
964
-        return '
962
+	public function actionsColumnHeader(): string
963
+	{
964
+		return '
965 965
             <span class="ee-actions-column-header-wrap">
966 966
                 <span class="dashicons dashicons-screenoptions"></span>
967 967
                 <span class="ee-actions-column-header">' . esc_html__('Actions', 'event_espresso') . '</span>
968 968
             </span>';
969
-    }
970
-
971
-
972
-    protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
973
-    {
974
-        $class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
975
-        $class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
976
-        $label = ! empty($label) ? " aria-label='{$label}'" : '';
977
-        return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
978
-    }
979
-
980
-    /**
981
-     * Override the search box method of WP List Table to include a reset button
982
-     *
983
-     * @param string $text     The 'submit' button label.
984
-     * @param string $input_id ID attribute value for the search input field.
985
-     */
986
-    public function search_box($text, $input_id)
987
-    {
988
-        if (empty($_REQUEST['s']) && ! $this->has_items()) {
989
-            return;
990
-        }
991
-
992
-        $this->admin_list_table_filters->searchBox(
993
-            $text,
994
-            $input_id,
995
-            $this->get_admin_page()->get_current_page_view_url()
996
-        );
997
-    }
969
+	}
970
+
971
+
972
+	protected function getActionLink(string $url, string $display_text, string $label, $class = ''): string
973
+	{
974
+		$class = ! empty($class) ? "{$class} ee-list-table-action" : 'ee-list-table-action';
975
+		$class = ! empty($label) ? "{$class} ee-aria-tooltip" : $class;
976
+		$label = ! empty($label) ? " aria-label='{$label}'" : '';
977
+		return "<a href='{$url}' class='{$class}'{$label}>{$display_text}</a>";
978
+	}
979
+
980
+	/**
981
+	 * Override the search box method of WP List Table to include a reset button
982
+	 *
983
+	 * @param string $text     The 'submit' button label.
984
+	 * @param string $input_id ID attribute value for the search input field.
985
+	 */
986
+	public function search_box($text, $input_id)
987
+	{
988
+		if (empty($_REQUEST['s']) && ! $this->has_items()) {
989
+			return;
990
+		}
991
+
992
+		$this->admin_list_table_filters->searchBox(
993
+			$text,
994
+			$input_id,
995
+			$this->get_admin_page()->get_current_page_view_url()
996
+		);
997
+	}
998 998
 }
Please login to merge, or discard this patch.
core/admin/templates/admin_wrapper.template.php 2 patches
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -23,11 +23,11 @@
 block discarded – undo
23 23
 	<?php echo wp_kses($nav_tabs, AllowedTags::getWithFormTags()); ?>
24 24
 
25 25
 	<?php
26
-    do_action('AHEE__admin_wrapper__template__before_admin_page_content');
27
-    echo wp_kses($before_admin_page_content, AllowedTags::getWithFormTags());
28
-    echo wp_kses($admin_page_content, AllowedTags::getWithFullTags());
29
-    echo wp_kses($after_admin_page_content, AllowedTags::getWithFormTags());
30
-    do_action('AHEE__admin_wrapper__template__after_admin_page_content');
31
-    ?>
26
+	do_action('AHEE__admin_wrapper__template__before_admin_page_content');
27
+	echo wp_kses($before_admin_page_content, AllowedTags::getWithFormTags());
28
+	echo wp_kses($admin_page_content, AllowedTags::getWithFullTags());
29
+	echo wp_kses($after_admin_page_content, AllowedTags::getWithFormTags());
30
+	do_action('AHEE__admin_wrapper__template__after_admin_page_content');
31
+	?>
32 32
 
33 33
 </div>
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@
 block discarded – undo
15 15
 <div class="wrap espresso-admin">
16 16
 
17 17
 	<h1>
18
-		<?php echo esc_html__('Event Espresso', 'event_espresso') . ' ' . wp_kses($admin_page_title, AllowedTags::getWithFormTags()); ?>
18
+		<?php echo esc_html__('Event Espresso', 'event_espresso').' '.wp_kses($admin_page_title, AllowedTags::getWithFormTags()); ?>
19 19
 	</h1>
20 20
 
21 21
 	<div id="ajax-notices-container"></div>
Please login to merge, or discard this patch.